1 / 21

Automatyczne dereferencje w języku SBQL Kazimierz Subieta

Automatyczne dereferencje w języku SBQL Kazimierz Subieta Polsko-Japońska Wyższa Szkoła Technik Komputerowych subieta@pjwstk.edu.pl Seminarium badawcze Katedry Inżynierii Oprogramowania PJWSTK 20 października 2011 r. Skąd wziął się problem?.

shani
Télécharger la présentation

Automatyczne dereferencje w języku SBQL Kazimierz Subieta

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Automatyczne dereferencje w języku SBQL Kazimierz Subieta Polsko-Japońska Wyższa Szkoła Technik Komputerowych subieta@pjwstk.edu.pl Seminarium badawcze Katedry Inżynierii Oprogramowania PJWSTK 20 października 2011 r.

  2. Skąd wziął się problem? • SBQL postawił znak równości pomiędzy zapytaniami i wyrażeniami języka programowania. • Jest pierwszym językiem w historii informatyki, w którym zapytania są budulcem dla konstrukcji imperatywnych i abstrakcji języka programowania. • Jego semantyka musi więc uwzględniać fakt, ze niektóre (pod) zapytania będą zwracały referencje, a nie wartości. • Np. dla operatora podstawienia zapytanie z lewej strony operatora musi zwrócić referencję. • Inny języki zapytań nie wspominają o referencjach. • Semantyka i implementacja języka SBQL jest fundamentalnie oparta na przetwarzaniu referencji.

  3. Niedobre podejście do problemu • Programista wstawia funkcję deref wszędzie tam, gdzie chce zmienić referencję na wartość z nią skojarzoną: • Zamiast pisać x + 5powinien pisać deref(x) +5 • Zamiast pisać Empwheresal > 1000 pisze Empwherederef(sal)> 1000 • Taki styl byłby dla programistów bardzo irytujący. • Funkcja deref została źle odebrana przez studentów zapoznających się z językiem SBQL. • Stąd należy jej się pozbyć z kodu programu poprzez automatyczne jej wstawianie do drzew syntaktycznych zapytań podczas kontroli typologicznej. • Najlepiej pozbyć się jej wszędzie, gdzie to jest możliwe.

  4. Jak pozbyć się pisania deref? Start Start Non - algebraic where Non - algebraic where Left subquery Right subquery Left subquery Right subquery > Name Emp Algebraic2 Name Emp Algebraic2 Left subquery Right subquery Left subquery Right subquery Name sal integer 1000 Algebraic1 deref integer 1000 Name sal • Podczas kontroli typologicznej, na podstawie sąsiedztwa z operatorem, następuje wniosek, że deref jest potrzebna: • Następuje więc jej automatyczne wstawienie do AST. • Np. dla zapytania Empwheresal >1000 >

  5. Kiedy należy pozbyć się pisania deref? (1) • Jeżeli sąsiadujący operator bezpośrednio wskazuje, że działa na wartościach, a nie na referencjach. • Np. x + yposiada operator arytmetyczny + wskazujący, że argumentami powinny być wartości, zatem zmieniamy wyrażenie na deref(x) + deref(y). • Wszystkie operatory arytmetyczne, stringowe, itd. • Cecha zaimplementowana w systemie ODRA. • Dla wyrażeń warunkowych: if exists(address) thenaddress.cityelse “No address” Powinno być zamienione na: if exists(address) thenderef(address.city)else “No address” • Nie jest to zaimplementowane.

  6. Kiedy należy pozbyć się pisania deref? (2) • Jeżeli bag lub sekwencja (lub inna kolekcja) miesza referencje i wartości, to wszystkie wyrażenia zwracające referencje powinny być objęte funkcją deref: • Np. bag(x, y, 5) powinien być zmieniony na bag(deref(x), deref(y), 5). • Argument funkcji sum, avg, min, max zwracający referencję powinien być objęty funkcją deref. • Jeżeli argumentem operacji na bagach lub sekwencjach jest kolekcja referencji, zaś drugim argumentem jest kolekcja wartości, to do zapytań zwracających referencje powinien by zastosowany deref.

  7. Poszukiwanie generalnego przypadku • Jest więcej takich przypadków. • Problem jest rekurencyjny, wymagający generalnego podejścia. • Sygnatury typów s1 i s2 mogą być typologicznie kompatybilne, ale różnić się wyłączcie tym, że w pewnym miejscu s1 zawiera wartość, zaś s2 zawiera referencję. • To może zdarzyć się przy dowolnej złożoności s1 i s2, na dowolnym poziomie hierarchii zanurzenia sygnatur w sygnatury • To zmusza do stosowania w ODRA funkcji derefeksplicite • Problem wygląda na dość trudny w ogólnym przypadku. • Szczęśliwie, znalazłem proste rozwiązanie • … no może nie takie proste….

  8. Przypomnienie: jak działa kontrola typów w SBQL • Mechanizm symuluje rzeczywiste obliczenia podczas czasu kompilacji. • Zamiast rzeczywistej bazy obiektów i stosów używa metabazy oraz statycznych stosów S_ENVS i S_QRES • Symulacji dokonuje procedura static_eval, która działa prawie tak samo jak eval, ale nie przetwarza rzeczywistych obiektów • Elementami przetwarzanymi na tych stosach są sygnatury, • czyli typologiczne charakterystyki rezultatów zapytań. • Sygnaturą może być typ atomowy (integer, string,…), identyfikator węzła metabazy, statyczny binder n(s), gdzie s jest sygnaturą, itd. • Analogicznie do funkcji nested działa funkcja static_nested.

  9. Suplementy (atrybuty) sygnatur • Suplementy sygnatur przekazują dodatkową informację związaną z daną sygnaturą, taką jak: • Mutowalność (zdolność do aktualizacji) • Liczność (cardinality) informacja o potencjalnej liczność danej kolekcji, np. [0..*], [0..1], … • Rodzaj kolekcji: element, bag, sequence, … • Nazwa typu (dla nazwowej zgodności typów) • …. parę innych da się jeszcze wymyśleć • Każdy operator języka zapytań implikuje prostą arytmetykę suplementów sygnatur • np. integer[mutable = true] + integer[mutable = true] = integer[mutable = false]

  10. Gdzie jest problem? • Jeżeli mamy operator  języka SBQL, który żąda unifikacji sygnatur (np. +, <, union, if,…), to mechanizm kontroli typów ma do czynienia z wyrażeniem s1s2, gdzie s1,s2 są sygnaturami argumentów operatora . • Jeżeli s1,s2 różnią się tym, że w pewnym miejscu jeden z nich zawiera typ atomowy t, a drugi identyfikator węzła metabazy typu t, to sygnatury są zgodne, ale przed wyrażenie zwracające id. węzła metabazy należy wstawić węzeł deref. • Niestety, sygnatury nie zawierają informacji o tym, który fragment AST odpowiada za wygenerowanie tego identyfikatora. • Wobec tego w ogólnym przypadku nie wiadomo gdzie deref wstawić.

  11. No to rozwiązanie narzuca się samo… • Trzeba do sygnatur dołożyć informację o węźle AST odpowiedzialnym za daną sygnaturę • Tę informację wprowadzamy w postaci dodatkowego suplementu: • Nazwałem go ASTnode. Wartością suplementu jest identyfikator węzła AST. • Przykładowo: iname[mutable=true, coll=bag, ASTnode=5] sygnatura suplement mutable suplement rodzaj kolekcji suplement węzeł AST

  12. Proceduraunifytypes(s1, s2) • Procedura unifytypesporównuje sygnatury s1i s2i zwraca wynikową sygnaturę dokonując unifikacji sygnatur s1i s2 w pewną wynikową sygnaturę s. • Dokonuje przy tym korekty AST poprzez wstawienie deref do odpowiedniego miejsca. • Procedura sprawdza także typologiczną zgodność s1i s2 ; jeżeli tej zgodności nie ma sygnalizuje błąd typologiczny. • Następnie naprawia AST tak, aby kontrola typów mogła być kontynuowana. • Procedura może być zastosowana we wszystkich przypadkach wymagających dereferencji, a także w innych przypadkach, np. zamiany elementu na bag.

  13. Szkic procedury unifytypes(1) • W pierwszym kroku procedura dokonuje serializacji sygnatur s1is2, tak aby mogły one być porównywane. • Serializacja jest deterministyczna, np. poprzez sprowadzenie sygnatur do polskiej notacji. • Sygnatury union compatiblezawsze są serializowane w ten sam sposób. • Każdy element struktury występujący w sygnaturach jest elementem serializacji, ale variant{v1, v2, …, vk} jest uważany za pojedynczy element serializacji. • Po serializacji procedura obiega obie sygnatury w ten sam sposób i kolejności: dla i = 1,2,3,… porównuje s1[i] oraz s2[i].

  14. Szkic procedury unifytypes(2) • Błąd typologiczy jest sygnalizowany jeżeli s1[i] oraz s2[i] są typologicznie niezgodne. • Błąd występuje jeżeli np. statyczne bindery mają różne nazwy, lub nie zgadzają się typy atomowe, lub liczność struktur jest różna. • Następnie sygnatury są naprawiane i procedura jest kontynowana • Dla automatycznych dereferencji istotny jest przypadek, kiedy w pewnym miejscu s1[i] ma wartość (nazwijmy ją a) zaś s2[i] jest identyfikatorem węzła metabazy (nazwijmy go r), przy czym typ r jest zgodny z a. • W takim przypadku procedura korzysta z suplementu ASTnode przypisanego do s2[i] i wstawia przed ten węzeł funkcję deref.

  15. Szkic procedury unifytypes(3) • Analogicznie dla przypadku s1[i] = r i s2[i] = a • Jeżeli s1[i] = r1, s2[i] = r2to porównywane są typy siedzące pod r1 i r2. Jeżeli są zgodne, to deref wstawia się zarówno przed ASTnode pobrane z s1[i] jak przed ASTnode pobrane z s2[i]. • Jeżeli typy są niezgodne, to sygnalizuje się błąd i naprawia AST. • Dalsze założenia dotyczą przypadku z wariantami. • Szczegóły w nowym rozdziale książki, która się piszeeeeeeee…

  16. Skromny przykład (1) Zapytanie: Emp.nameunionDept.dnameunion “Doe” AST: SygnaturaEmp.name:iname[mutable=true, coll=bag, ASTnode = 5] Sygnatura Dept.dname:idname[mutable=true, coll=bag, ASTnode = 8] Sygnatura “Doe”: string[mutable=false, coll=null, ASTnode=9]

  17. Skromny przykład (2) • Proceduraunifytypes is zastosowana dla pierwszego union unifytypes(iname[mutable=true, coll=bag, ASTnode=5], idname[mutable=true, coll=bag, ASTnode=8]) = variant{iname[mutable=true, coll=bag, ASTnode=5], idname[mutable=true, coll=bag, ASTnode=8]} • static_eval zastosowany dla tego union zwróci sygnaturę: variant{iname[mutable=true, coll=bag, ASTnode=5], idname[mutable=true, coll=bag, ASTnode=8]}[mutable=true, coll=bag, ASTnode=2]

  18. Skromny przykład (3) • Drugi operator unionimplikuje następne zastosowanie proceduryunifytypes: unifytypes(variant{iname[mutable=true, coll=bag, ASTnode=5], idname[mutable=true, coll=bag, ASTnode=8]} [mutable=true, coll=bag, ASTnode=2], string[mutable=false, coll=null, ASTnode=9]) = string[mutable=false, coll=bag] • Procedura unifytypeswstawi węzły deref przed węzły ASTnode=5 i ASTnode=8. • Zastosowanie drugiego union zwróci sygnaturę string[mutable=false, coll=bag, ASTnode=1]

  19. Inne role ASTnodei unifytypes • W ten sam sposób można dokonywać koercji pojedynczych elementów na bagi, sekwencji na bagi, itd. • Identycznie z koercją integer na real i odwrotnie. • Identycznie z rzutowanie obiektu na obiekt z klasy bardziej generalnej, np. Prac  Osoba • Podobnie z rzutowaniem dynamicznej roli na jej nadrolę. • Sygnalizacja błędów typologicznych: unifytypes potrafi zrobić to precyzyjniej, z dokładnością do węzła AST. • Jeżeli w tym węźle będzie jeszcze informacja o koordynatach kodu źródłowego, który go wygenerował, to można łatwo przenieść sygnalizację na poziom kodu źródłowego, np. przez podświetlenie błędnego kodu.

  20. Czy da się w ogóle usunąć deref z języka? • Naszkicowana metoda pozwala uniknąć pisania derefeksplicite w większości przypadków. • Nie da się jednak tego zrobić we wszystkich przypadkach bez obniżania mocy języka. • Np. przy porównaniu q1= q2intencją programisty może być porównanie referencji lub porównanie wartości siedzących pod tymi referencjami • Zatem potrzebny będzie kod deref( q1) = deref( q2) • Podobnie z usuwaniem duplikatów. • Można próbować to zastąpić jakimiś słowami kluczowymi, ale to wygląda na zamianę siekierki na kijek.

  21. Na zakończenie… • Pozornie nieduży problem przerodził się w całkiem spory. • Nie będzie łatwo zaimplementować go w ogólnym przypadku. • Mogą być dalsze komplikacje związane z dereferencjami dla złożonych obiektów. • Może trochę za mało tego na pracę doktorską, ale jeżeli problem byłby dostatecznie uogólniony, zaś implementacja powiązana z optymalizacjami, to kto wie… Dziękuję za uwagę. Pytania, komentarze, narzekania?

More Related