Created
December 23, 2014 13:13
-
-
Save 53ningen/135266a4e06004a02d00 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.gochiusa.golang.core | |
import scala.util.parsing.combinator.JavaTokenParsers | |
class Parser extends JavaTokenParsers { | |
val ifKeyword = "心" | |
val elseKeyword = "ぴょんぴょん" | |
val varKeyword = "心" | |
// statement | |
def statement: Parser[Statement] = ifStmt | |
// expr | |
def expr: Parser[Expr] = "("~>expr<~")" | binOpExpr1 | binOpExpr2 | relOpExp | assignExpr | term | |
def binOpExpr1: Parser[Number] = chainl1(binOpExpr2, ("+"|"-")^^{ op => (left: Number, right: Number) => BinOpExpr(left, op, right)}) | |
def binOpExpr2: Parser[Number] = chainl1(number, ("*"|"/")^^{ op => (left: Number, right: Number) => BinOpExpr(left, op, right)}) | |
def relOpExp: Parser[Bool] = number ~ ("<"|">"|"<="|">="|"==") ~ number ^^ { case left ~ op ~ right => RelOpExpr(left, op, right)} | |
def ifStmt: Parser[Statement] = ifKeyword~relOpExp~"{"~expr~"}"~elseKeyword~"{"~expr~"}" ^^ { case ifKeyword~cond~"{"~cons~"}"~elseKeyword~"{"~alt~"}" => IfStatement(cond, cons, alt)} | |
def assignExpr: Parser[Expr] = varKeyword~ident~"="~expr ^^ { case varKeyword~ident~"="~expr => AssignExpr(VariableExpr(ident), expr)} | |
def term: Parser[Expr] = number | boolean | quotedString | identifier | |
// primitive | |
def quotedString: Parser[Expr] = stringLiteral ^^ { str => StringValue(str.substring(1, str.length - 1))} | |
def number: Parser[Number] = floatingPointNumber ^^ { x => NumberValue(x.toDouble) } | |
def boolean: Parser[Expr] = ("true"|"false") ^^ { x => BooleanValue(x.toBoolean) } | |
def identifier: Parser[Number] = ident ^^ { x => VariableExpr(x) } | |
def parse(s: String) = { | |
parseAll(expr, s) match { | |
case Success(x, y) => x match { | |
case x: Number => println(x.eval(Map())) | |
case _ => println(x) | |
} | |
case x => println("Failure:" + x) | |
} | |
} | |
} | |
trait AST | |
abstract class Statement extends AST | |
case class IfStatement(condition: Bool, consequence: Expr, alternative: Expr) extends Statement | |
abstract class Expr extends AST | |
trait Number extends Expr { def eval(env: Map[String, Expr]): Double } | |
trait Bool extends Expr { def eval(env: Map[String, Expr]): Boolean } | |
trait Str extends Expr { def eval(env: Map[String, Expr]): String } | |
case class BinOpExpr(left: Number, op: String, right: Number) extends Expr with Number { | |
def eval(env: Map[String, Expr]): Double = { | |
op match { | |
case "+" => left.eval (env: Map[String, Expr]) + right.eval (env: Map[String, Expr]) | |
case "-" => left.eval (env: Map[String, Expr]) - right.eval (env: Map[String, Expr]) | |
case "*" => left.eval (env: Map[String, Expr]) * right.eval (env: Map[String, Expr]) | |
case "/" => left.eval (env: Map[String, Expr]) / right.eval (env: Map[String, Expr]) | |
} | |
} | |
} | |
case class RelOpExpr(left: Number, op: String, right: Number) extends Expr with Bool { | |
def eval(env: Map[String, Expr]): Boolean = { | |
op match { | |
case ">" => left.eval(env: Map[String, Expr]) > right.eval(env: Map[String, Expr]) | |
case "<" => left.eval(env: Map[String, Expr]) < right.eval(env: Map[String, Expr]) | |
case ">=" => left.eval(env: Map[String, Expr]) >= right.eval(env: Map[String, Expr]) | |
case "<=" => left.eval(env: Map[String, Expr]) <= right.eval(env: Map[String, Expr]) | |
case "==" => left.eval(env: Map[String, Expr]) == right.eval(env: Map[String, Expr]) | |
} | |
} | |
} | |
case class VariableExpr(name: String) extends Expr with Number { | |
def eval(env: Map[String, Expr]): Double = env.get(name) match { | |
case v: Some[Number] => v.get.eval(env) | |
case _ => throw new IllegalStateException | |
} | |
} | |
case class AssignExpr(variable: VariableExpr, expr: Expr) extends Expr { | |
def eval(env: Map[String, Expr]): Map[String, Expr] = env ++ Map(variable.name -> expr) | |
} | |
case class NumberValue(v: Double) extends Expr with Number { | |
def eval(env: Map[String, Expr]): Double = v | |
} | |
case class BooleanValue(v: Boolean) extends Expr with Bool { | |
def eval(env: Map[String, Expr]): Boolean = v | |
} | |
case class StringValue(v: String) extends Expr with Str { | |
def eval(env: Map[String, Expr]): String = v | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment