Sposób użycia DSLExecutora

Dzisiaj krótko, acz treściwie. Jak stwierdziłem w poprzednim poście, zakres funkcjonalności DSLExecutora został ukończony – wypada więc pokazać sposób jego używania w aplikacji. Bez zbędnych wstępów przejdźmy do rzeczy.

Aby użyć DSLExecutora w aplikacji, należy:

  1. Zdefiniować dostępne funkcje.
  2. Przyjąć od użytkownika wejściowy DSL.
  3. Sparsować go do postaci wyrażenia.
  4. Otrzymane wyrażenie przekazać obiektowi klasy DSLExecutor.

Zatem po kolei:

Definicja funkcji

Jak już gdzieś wspomniałem, zależało mi na jak najwygodniejszym definiowaniu funkcji – i chyba się udało. Aby zdefiniować funkcję, wystarczy stworzyć dwie klasy:

  • klasę reprezentującą sygnaturę funkcji (implementującą interfejs IFunction<TResult>), np.:
 
public class AddFunction : IFunction<int> 
{ 
  public int Addend1 { get; set; } 
  public int Addend2 { get; set; } 
} 
  • klasę reprezentującą ciało funkcji (implementującą interfejs IFunctionHandler<TFunction, TResult>), np.:
 
public class AddFunctionHandler
  : IFunctionHandler<AddFunction, int> 
{ 
  public int Handle(AddFunction function) 
  { 
    return function.Addend1 + function.Addend2; 
  } 
} 

Parsowanie

(Krok drugi, czyli przyjęcie wejściowego DLSa, jest niezależny od DSLExecutora i go pomijam.)

Aby sparsować wejściowy DSL, należy stworzyć obiekt parsera i go użyć. Na tą chwilę wspierany jest tylko jeden parser: SampleDSLParser. Argumentem jego konstruktora jest lista przykładów funkcji (biblioteki, w których znajdują się przykłady zostaną przeskanowane w poszukiwaniu wszystkich dostępnych funkcji).

Po skonstruowaniu obiektu SampleDSLParser należy użyć jego metody Parse. Przykład:

 
var functionTypeSamples = new[] { typeof(AddFunction) }; 
var parser = new SampleDSLParser(functionTypeSamples); 
 
var expression = parser.Parse(dsl); 

Wykonanie wyrażenia

I ostatni krok. Aby wykonać wyrażenie otrzymane w wyniku parsowania, należy stworzyć obiekt klasy DSLExecutor i użyć jego metody ExecuteExpression. W chwili obecnej konstruktor tej klasy przyjmuje słownik [typ funkcji -> typ jej handlera]. Przykład:

 
var functionToHandlerMap = new Dictionary<Type, Type> 
  { 
    [typeof(AddFunction)] = typeof(AddFunctionHandler) 
  }; 
 
var dslExecutor = new DSLExecutor(functionToHandlerMap); 
 
var result = dslExecutor.ExecuteExpression(expression); 

I gotowe! Wejściowy DSL został sparsowany i wykonany. Zachęcam do samodzielnego wypróbowania DSLExecutora (potrzebne paczki dostępne są na NuGecie: tu i tu). A ja tymczasem wracam do tworzenia przykładowej aplikacji zbierającej do kupy wszystkie zaimplementowane funkcjonalności. Cierpliwości :)