Last active
March 7, 2020 06:29
-
-
Save okram/ffb6fae26671d0c0f01023fad77a77cf 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
object mmlangParser extends JavaTokenParsers { | |
override val whiteSpace:Regex = """[\s\n]+""".r | |
var model:Model = Model.id | |
// all mm-ADT languages must be able to accept a string representation of an expression in the language and return an Iterator[Obj] | |
def parse[T <: Obj](input:String,_model:Model = Model.id):Iterator[T] ={ | |
if (null != _model) this.model = _model | |
this.parseAll(expr | emptySpace,input.trim).map{ | |
case itty:Iterator[T] => itty | |
case obj:T => Iterator(obj) | |
}.get | |
} | |
def emptySpace[T]:Parser[Iterator[T]] = (Tokens.empty | whiteSpace) ^^ (_ => Iterator.empty) | |
// specific to mmlang execution | |
lazy val expr :Parser[Any] = evaluation | compilation | obj | |
lazy val evaluation :Parser[Iterator[Obj]] = (strm | objValue) ~ opt(aType | anonType) ^^ (x => x._1 ===> { | |
val t = InstUtil.resolveAnonymous(x._1,x._2.getOrElse(asType(x._1).id())) | |
(t.domain() ==> this.model) (t) | |
}) | |
lazy val compilation:Parser[Obj] = (aType | recType) ^^ (x => (x.domain() ==> this.model) (x)) | |
// mmlang's language structure | |
lazy val instOp :String = Tokens.ops.foldRight(EMPTY)((a,b) => b + PIPE + a).drop(1) | |
lazy val canonicalType:Parser[Type[Obj]] = (Tokens.bool | Tokens.int | Tokens.str | Tokens.rec | ("^(?!(" + instOp + "))([a-zA-Z]+)").r <~ not(":")) ~ opt(quantifier) ^^ { | |
case atype ~ q => q.foldRight(atype match { | |
//case Tokens.obj => tobj | |
case Tokens.bool => bool | |
case Tokens.int => int | |
case Tokens.str => str | |
case Tokens.rec => rec | |
case name:String => | |
this.model.get(name) match { | |
case Some(atype) => atype | |
case None => tobj(name) | |
} | |
})((q,t) => t.q(q)) | |
} | |
// name'd objects | |
lazy val name:Parser[String] = "[a-zA-Z]+".r <~ ":" | |
lazy val obj :Parser[Obj] = objValue | objType | |
// type parsing | |
lazy val objType :Parser[Type[Obj]] = aType | recType | anonType | |
lazy val domainRange:Parser[Type[Obj]] = (Tokens.rec ~> recType) | canonicalType | |
lazy val recType :Parser[ORecType] = opt(name) ~ (LBRACKET ~> repsep((obj <~ Tokens.:->) ~ obj,(COMMA | PIPE))) <~ RBRACKET ^^ (x => trec(x._1.getOrElse(Tokens.rec),x._2.map(o => (o._1,o._2)).toMap)) | |
lazy val anonType :Parser[__] = rep1[Inst](inst | stateAccess ^^ (x => ToOp(str(x._2)))) ^^ (x => __(x:_*)) | |
lazy val aType :Parser[Type[Obj]] = opt(domainRange <~ Tokens.:<=) ~ domainRange ~ rep[Inst](inst | stateAccess ^^ (x => ToOp(str(x._2)))) ^^ { | |
case Some(range) ~ domain ~ insts => (range <= insts.foldLeft(domain)((x,y) => y(this.model.resolve(x)).asInstanceOf[Type[Obj]])) | |
case None ~ domain ~ insts => insts.foldLeft(domain)((x,y) => { | |
y(this.model.resolve(x)).asInstanceOf[Type[Obj]] | |
}) | |
} | |
// quantifier parsing | |
lazy val quantifier :Parser[IntQ] = (LCURL ~> quantifierType <~ RCURL) | (LCURL ~> intValue ~ opt(COMMA ~> intValue) <~ RCURL) ^^ (x => (x._1,x._2.getOrElse(x._1))) | |
lazy val quantifierType:Parser[IntQ] = (Tokens.q_star | Tokens.q_mark | Tokens.q_plus) ^^ { | |
case Tokens.q_star => qStar | |
case Tokens.q_mark => qMark | |
case Tokens.q_plus => qPlus | |
} | |
// value parsing | |
lazy val objValue :Parser[Value[Obj]] = (boolValue | intValue | strValue | recValue) ~ opt(quantifier) ^^ (x => x._2.map(q => x._1.q(q)).getOrElse(x._1)) | |
lazy val boolValue:Parser[BoolValue] = opt(name) ~ (Tokens.btrue | Tokens.bfalse) ^^ (x => vbool(x._1.getOrElse(Tokens.bool),x._2.toBoolean,qOne)) | |
lazy val intValue :Parser[IntValue] = opt(name) ~ wholeNumber ^^ (x => vint(x._1.getOrElse(Tokens.int),x._2.toLong,qOne)) | |
lazy val strValue :Parser[StrValue] = opt(name) ~ ("""'([^'\x00-\x1F\x7F\\]|\\[\\'"bfnrt]|\\u[a-fA-F0-9]{4})*'""").r ^^ (x => vstr(x._1.getOrElse(Tokens.str),x._2.subSequence(1,x._2.length - 1).toString,qOne)) | |
lazy val recValue :Parser[ORecValue] = opt(name) ~ (LBRACKET ~> repsep((objValue <~ Tokens.:->) ~ objValue,COMMA) <~ RBRACKET) ^^ (x => vrec(x._1.getOrElse(Tokens.rec),x._2.map(o => (o._1,o._2)).toMap,qOne)) | |
lazy val strm :Parser[Strm[Obj]] = boolStrm | intStrm | strStrm | recStrm | |
lazy val boolStrm :Parser[BoolStrm] = (boolValue <~ COMMA) ~ rep1sep(boolValue,COMMA) ^^ (x => bool(x._1,x._2.head,x._2.tail:_*)) | |
lazy val intStrm :Parser[IntStrm] = (intValue <~ COMMA) ~ rep1sep(intValue,COMMA) ^^ (x => int(x._1,x._2.head,x._2.tail:_*)) | |
lazy val strStrm :Parser[StrStrm] = (strValue <~ COMMA) ~ rep1sep(strValue,COMMA) ^^ (x => str(x._1,x._2.head,x._2.tail:_*)) | |
lazy val recStrm :Parser[ORecStrm] = (recValue <~ COMMA) ~ rep1sep(recValue,COMMA) ^^ (x => vrec(x._1,x._2.head,x._2.tail:_*)) | |
// instruction parsing | |
lazy val instArg :Parser[Obj] = (stateAccess ^^ (x => x._1.getOrElse(int).from[Obj](str(x._2)))) | obj // TODO: hardcoded int for unspecified state type | |
lazy val inst :Parser[Inst] = (sugarlessInst | infixSugar | getSugar | chooseSugar) ~ opt(quantifier) ^^ (x => x._1.q(x._2.getOrElse(qOne))) | |
lazy val infixSugar :Parser[Inst] = (Tokens.plus_op | Tokens.mult_op | Tokens.gt_op | Tokens.eqs_op) ~ instArg ^^ (x => OpInstResolver.resolve(x._1,List(x._2))) | |
lazy val chooseSugar :Parser[Inst] = (LBRACKET ~> repsep((obj <~ Tokens.:->) ~ obj,PIPE)) <~ RBRACKET ^^ (x => ChooseOp(trec(value = x.map(o => (o._1,o._2)).toMap))) | |
lazy val getSugar :Parser[Inst] = Tokens.get_op ~> "[a-zA-Z]+".r ^^ (x => GetOp(str(x))) | |
lazy val sugarlessInst:Parser[Inst] = LBRACKET ~> ("""=?[a-z]+""".r <~ opt(COMMA)) ~ repsep(instArg,COMMA) <~ RBRACKET ^^ (x => OpInstResolver.resolve(x._1,x._2)) | |
// traverser instruction parsing | |
lazy val stateAccess :Parser[Option[Type[Obj]] ~ String] = (opt(canonicalType) <~ LANGLE) ~ "[a-zA-z]+".r <~ RANGLE | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment