DSL z prawdziwego zdarzenia: wstęp do generowania wyrażeń

Wynikiem ostatnich postów (i odpowiadającej im implementacji) jest to, że potrafię już przetłumaczyć tekst na tokeny. A jak te tokeny mają się do bytów z dziedziny wykonywania wyrażeń? Dzisiejszy post traktuje właśnie o tym, a jednocześnie podsumowuje moje dotychczasowe osiągnięcia w temacie kompilacji DSLa.

Do tej pory opisywałem tokeny osobno – pokazałem ich klasy i odpowiadające im parsery. Czas poskładać informacje do kupy. Zróbmy to na przykładzie zapisu, który przewijał się w poprzednich postach:

 
log('Calculating...') 
sub(add('1' '2') '3') 

Wspominałem już, że wynikiem parsowania całego zapisu jest drzewo tokenów. Zamiast obrazowo to opisywać, lepiej opisać to obrazem. Dla powyższego zestawu instrukcji drzewo wygląda tak:

DSLExecutor_SampleDSL_TokenTree

Jak z takiego drzewa uzyskać strukturę gotową do wykonania, czyli zrozumiałą dla DSLExecutora, czyli drzewo wyrażeń? Koncepcyjnie – bardzo prosto. Zauważmy, że każdy token reprezentuje wyrażenie:

  • TokenTree to BatchExpression,
  • FunctionCall to FunctionExpression,
  • Literal to ConstantExpression.

Wystarczy więc przekształcić każdy token w odpowiadające mu wyrażenie. W wyniku takiego przekształcenia dostaniemy drzewo wyrażeń, które pojawiło się już w jednym z postów:

DSLExecutor_use_case

Jak widać, koncepcja jest prosta. W kolejnych postach będę ją wprowadzał w życie, pokazując implementację przekształceń poszczególnych tokenów – zapraszam!