0

I don't know if this info is relevant to the question, but I am learning Scala parser combinators. Using some examples (in this master thesis) I was able to write a simple functional (in the sense that it is non imperative) programming language.

Is there a way to improve my parser/evaluator such that it could allow/evaluate input like this:

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

some DSL code (lambda calculus)

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

as input written in the guest language (DSL)?

Should I use reflection or something similar* to evaluate such input? Is there some source code recommendation to study (may be groovy sources?)?

Maybe this is something similar: runtime compilation, but I am not sure this is the best alternative.

EDIT

Complete answer given bellow with "{" and "}". Maybe "{{" would be better.

Community
  • 1
  • 1
  • 2
    What's your problem specifically? Parsing it? Going from the parser's output to *locating* the libraries? Using knowledge of the imported libraries to handle the rest of the input program? Actually loading the package for your language to use? –  Jan 19 '13 at 17:31
  • @delnan I need some guidelines, and your comment is already helping me in the process. May be the simplest way is to define a syntax to wrap Scala code. The rest, in pure DSL code, would be translated to Scala, so I could join the wrapped Scala code with my DSL-translated -to-Scala code and evaluate it somehow as pure Scala code. Am I missing something? –  Jan 19 '13 at 17:58
  • And the Java Classes would come for free with Scala. –  Jan 19 '13 at 17:59
  • 2
    Yes, this is probably the simplest solution. – Alexey Romanov Jan 19 '13 at 18:16

2 Answers2

0

It is the question as to what the meaning of such import statements should be.

Perhaps you start first with allowing references to java methods in your language (the Lambda Calculus, I guess?).

For example:

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

If you have that, you can then add resolution of unqualified names like

println "foo"

But here comes the first problem: println exists in System.out and System.err, or, to be more correct: it is a method of PrintStream, and both System.err and System.out are PrintStreams.

Hence you would need some notion of Objects, Classes, Types, and so on to do it right.

Ingo
  • 36,037
  • 5
  • 53
  • 100
0

I managed how to run Scala code embedded in my interpreted DSL.

Insertion of DSL vars into Scala code and recovering returning value comes as a bonus. :)

Minimal relevant code from parsing and interpreting until performing embedded Scala code run-time execution (Main Parser AST and Interpreter):

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))
       }
     }
    }  
  }