#1125 Just for fun - playing with DSLs

ivan Tue 22 Jun 2010

Wanted to write some very-very simple DSL for a long, time, but only today got an interesting idea and free hour to play. I often been using constructions like switch(obj.typeof) { case Type#: }, but this approach does not work in case of inheritance. So I tried to write some alternative. Here's the result:

obj := 5
Pattern.match(obj,
  [
    Fits<|sys::Num|> : |->| { echo("this is num") },
    Fits<|sys::List|> : |->| { echo("this is list") } 
  ]) 

output is very predictive:

this is num

Implementation is trivial too: Base class Pattern:

abstract const class Pattern
{
  static Void match(Obj obj, Pattern:|->| map)
  {
    map.find |f, p| { p.matches(obj) }?.call
  }

  abstract Bool matches(Obj? obj)

}

Inheritor:

const class Fits : Pattern 
{
  private const Type type
  new make(Type type) { this.type = type }

  override Bool matches(Obj? other)
  {
    other?.typeof?.fits(type) ?: false
  }
}

DSL:

class FitterDsl : DslPlugin
{
  new make(Compiler compiler) : super(compiler) {}

  override Expr compile(DslExpr expr)
  {
    CallExpr.makeWithMethod(expr.loc, 
      null, 
      ns.resolveType("pattern::Fits").method("make"), 
      Expr[LiteralExpr(expr.loc, ExprId.typeLiteral, ns.typeType, 
      ns.resolveType(expr.src.trim))])
  }
}

There're several disadvantages with this code (like unpredicted order of pattern calling because of unordered map) and overall it is even bigger than using chain of ifs, just wanted to share overall idea

tactics Tue 22 Jun 2010

(like unpredicted order of pattern calling because of unordered map)

See Map.ordered.

ivan Tue 22 Jun 2010

yep, I know about this slot, but I don't know how to write ordered map as Literal :)

Login or Signup to reply.