Version 9 by komaz
on Nov 22, 2010 18:07.

compared with
Version 10 by komaz
on Nov 22, 2010 18:44.

Key
This line was removed.
This word was removed. This word was added.
This line was added.

Changes (1)

View Page History

In fact, the example above have nothing common with initial purpose of DSLs, it is complete compiler plugin which significantly changes the source code meaning.

h3. Inheritance
So, using DSL plugins it is possible:
* Create objects
* Modify types by adding new methods
* Modify method bodies
* Remove compilation errors
But also, we can extend existing types! So, inside DSL plugin we can create new type extending anchor type, and then the instance of our new type will be just upcasted to the base type. On of the examples where it can be useful, is the following:
{noformat}
parser := Parser<| Value = [0-9]+ | '(' Expr ')'
Product = Value (('*' / '/') Value)*
Sum = Product (('+' / '-') Product)*
Expr = Sum |>
{noformat}
Here the parser grammar defines a set of non-terminal symbols which can refer to other symbols. We can generate the class extending 'Parser' with a set of methods corresponding to symbols right at compile time, something like that:
{noformat}
class MyParser : Parser
{
override Bool expr(InStream in, Ast ast) { sum(in, ast) }

Bool sum(InStream in, Ast ast)
{
if(!product(in, ast)) return false
while(peek == '*' || peek = '/')
{
consume
if(!product(in, ast)) return true
}
return true
}

Bool product(InStream in, Ast ast)
...
}
{noformat}
And therefore, since our parser extends {{Parser}}, the code like this will work correctly and give us great performance:
I'm not a parser guy, and don't have a complete working example on my hands, but I verified that extending types is possible on a simple synthetic example:
{noformat}
class Foo
{
virtual Str str() { return "a" }
}

class Sample
{
Void main()
{
echo(Foo<|bar|>.str) //prints 'bar'
}
}
{noformat}
The [Foo DSL plugin|^FooInheritor.fan] creates class like this:
{noformat}
class Foo1290429812650070000 : Foo
{
override Str str() { synth }
protected Str synth() { "bar" }
}
{noformat}