如何在特殊定义的语法中嵌入Scala代码?

时间:2013-01-19 17:19:35

标签: parsing scala functional-programming parser-combinators

我不知道这些信息是否与问题相关,但我正在学习Scala解析器组合器。 使用一些例子(在这个master thesis中)我能够编写一个简单的函数(在某种意义上说它是非命令性的)编程语言。

有没有办法改进我的解析器/评估器,以便它可以允许/评估这样的输入:

<%
import scala.<some package / classes>
import weka.<some package / classes>
%>

some DSL code (lambda calculus)

<%
System.out.println("asdasd");
J48 j48 = new J48();
%>

作为以客户语言(DSL)编写的输入?

我应该使用反射或类似的*来评估此类输入吗? 是否有一些源代码建议要研究(可能是常规来源?)?

也许这类似于runtime compilation,但我不确定这是最好的选择。

修改

完全回答“{”和“}”。也许“{{”会更好。

2 个答案:

答案 0 :(得分:0)

关于这些进口陈述的含义应该是什么问题。

也许你首先开始允许用你的语言引用java方法(我猜是Lambda微积分?)。

例如:

java.lang.System.out.println "foo"

如果你有,那么你可以添加非限定名称的分辨率,如

println "foo"

但是第一个问题出现了:println存在于System.out和System.err中,或者更正确:它是PrintStream的一种方法,System.err和System.out都是PrintStreams。

因此,您需要一些对象,类,类型等概念才能正确执行。

答案 1 :(得分:0)

我设法如何运行我解释的DSL中嵌入的Scala代码。

将DSL变量插入Scala代码并恢复返回值作为奖励。:)

解析和解释之前的最小相关代码,直到执行嵌入式Scala代码运行时执行(主分析器AST和解释器):

object Main extends App {
     val ast = Parser1 parse "some dsl code here"
     Interpreter eval ast
}

object Parser1 extends RegexParsers with ImplicitConversions {
  import AST._
  val separator = ";"
  def parse(input: String): Expr = parseAll(program, input).get
  type P[+T] = Parser[T]
  def program = rep1sep(expr, separator) <~ separator ^^ Sequence
  def expr: Parser[Expr] = (assign /*more calls here*/)
  def scalacode: P[Expr] = "{" ~> rep(scala_text) <~ "}" ^^ {case l => Scalacode(l.flatten)}
  def scala_text = text_no_braces ~ "$" ~ ident ~ text_no_braces ^^ {case a ~ b ~ c ~ d => List(a, b + c, d)}
  //more rules here
  def assign = ident ~ ("=" ~> atomic_expr) ^^ Assign
  //more rules here
  def atomic_expr = (
     ident ^^ Var
        //more calls here 
        | "(" ~> expr <~ ")"
        | scalacode
        | failure("expression expected")
     )
  def text_no_braces = """[a-zA-Z0-9\"\'\+\-\_!@#%\&\(\)\[\]\/\?\:;\.\>\<\,\|= \*\\\n]*""".r //| fail("Scala code expected")
  def ident = """[a-zA-Z]+[a-zA-Z0-9]*""".r
}

object AST {
   sealed abstract class Expr
   // more classes here
   case class Scalacode(items: List[String]) extends Expr
   case class Literal(v: Any) extends Expr
   case class Var(name: String) extends Expr
}

object Interpreter {
  import AST._
  val env = collection.immutable.Map[VarName, VarValue]()
  def run(code: String) = {
     val code2 = "val res_1 = (" + code + ")"
     interpret.interpret(code2)
     val res = interpret.valueOfTerm("res_1")
     if (res == None) Literal() else Literal(res.get)
  }

  class Context(private var env: Environment = initEnv) {
    def eval(e: Expr): Any = e match {
       case Scalacode(l: List[String]) => {
          val r = l map {
             x =>
                if (x.startsWith("$")) {
                   eval(Var(x.drop(1)))
                } else {
                   x
                }
          }
          eval(run(r.mkString))
       }
       case Assign(id, expr) => env += (id -> eval(expr))
       //more pattern matching here
       case Literal(v) => v
       case Var(id) => {
          env getOrElse(id, sys.error("Undefined " + id))
       }
     }
    }  
  }