Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Automatyczne dereferencje w języku SBQL

Podobne prezentacje


Prezentacja na temat: "Automatyczne dereferencje w języku SBQL"— Zapis prezentacji:

1 Automatyczne dereferencje w języku SBQL
Kazimierz Subieta Polsko-Japońska Wyższa Szkoła Technik Komputerowych 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 powinien pisać deref(x) +5 Zamiast pisać Emp where sal > 1000 pisze Emp where deref(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?
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 Emp where sal >1000 Start Non - algebraic where Left subquery Right subquery Name Emp Algebraic2 sal integer 1000 > Algebraic1 deref >

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 + y posiada 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) then address.city else “No address” Powinno być zamienione na: if exists(address) then deref(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 deref eksplicite 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 Procedura unifytypes(s1, s2)
Procedura unifytypes porównuje sygnatury s1 i s2 i zwraca wynikową sygnaturę dokonując unifikacji sygnatur s1 i s2 w pewną wynikową sygnaturę s. Dokonuje przy tym korekty AST poprzez wstawienie deref do odpowiedniego miejsca. Procedura sprawdza także typologiczną zgodność s1 i 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 s1 i s2, tak aby mogły one być porównywane. Serializacja jest deterministyczna, np. poprzez sprowadzenie sygnatur do polskiej notacji. Sygnatury union compatible zawsze 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] = r2 to 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.name union Dept.dname union “Doe” AST: Sygnatura Emp.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) Procedura unifytypes 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ę: idname[mutable=true, coll=bag, ASTnode=8]} [mutable=true, coll=bag, ASTnode=2]

18 Skromny przykład (3) Drugi operator union implikuje następne zastosowanie procedury unifytypes: 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 unifytypes wstawi 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 ASTnode i 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 deref eksplicite 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 = q2 intencją 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… Pytania, komentarze, narzekania?
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?


Pobierz ppt "Automatyczne dereferencje w języku SBQL"

Podobne prezentacje


Reklamy Google