From 616d4aafdc860e4ba5fedc1d06ee56f9fc945c01 Mon Sep 17 00:00:00 2001 From: h2oche Date: Tue, 22 Feb 2022 14:23:23 +0900 Subject: [PATCH] Fix compilation rule for NonterminalLiteral (#37) --- src/main/scala/esmeta/interp/Interp.scala | 4 ++-- src/main/scala/esmeta/interp/State.scala | 3 +++ .../esmeta/interp/util/Stringifier.scala | 9 ++++++++ src/main/scala/esmeta/ir/Expr.scala | 2 +- src/main/scala/esmeta/ir/util/Parser.scala | 4 ++-- .../scala/esmeta/ir/util/Stringifier.scala | 4 ++-- .../scala/esmeta/ir/util/UnitWalker.scala | 2 +- .../scala/esmeta/spec/util/Compiler.scala | 21 ++++++++++++++++--- src/main/scala/esmeta/spec/util/package.scala | 17 +++------------ .../esmeta/interp/StringifyTinyTest.scala | 2 ++ src/test/scala/esmeta/ir/StringifyTest.scala | 10 ++++----- 11 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/main/scala/esmeta/interp/Interp.scala b/src/main/scala/esmeta/interp/Interp.scala index 6974a6176f..b8ce690e96 100644 --- a/src/main/scala/esmeta/interp/Interp.scala +++ b/src/main/scala/esmeta/interp/Interp.scala @@ -168,8 +168,8 @@ class Interp( val r = interp(rule).escaped ??? // TODO parse `code` with `rule` } - case EParseRule(name, params) => ??? - case ESourceText(expr) => ??? + case EGrammar(name, params) => Grammar(name, params) + case ESourceText(expr) => ??? case EYet(msg) => throw NotSupported(msg) case EContains(list, elem) => diff --git a/src/main/scala/esmeta/interp/State.scala b/src/main/scala/esmeta/interp/State.scala index e8069c4033..b75646716d 100644 --- a/src/main/scala/esmeta/interp/State.scala +++ b/src/main/scala/esmeta/interp/State.scala @@ -126,6 +126,9 @@ case class Cont( /** abstract syntax tree (AST) values */ case class AstValue(ast: Ast) extends PureValue +/** grammars */ +case class Grammar(name: String, params: List[Boolean]) extends PureValue + // ----------------------------------------------------------------------------- // Literal Values // ----------------------------------------------------------------------------- diff --git a/src/main/scala/esmeta/interp/util/Stringifier.scala b/src/main/scala/esmeta/interp/util/Stringifier.scala index ba71ba5a41..ad0f13e02d 100644 --- a/src/main/scala/esmeta/interp/util/Stringifier.scala +++ b/src/main/scala/esmeta/interp/util/Stringifier.scala @@ -112,6 +112,7 @@ class Stringifier(detail: Boolean, location: Boolean) { case clo: Clo => cloRule(app, clo) case cont: Cont => contRule(app, cont) case AstValue(ast) => app >> ast + case gr: Grammar => grammarRule(app, gr) case lit: LiteralValue => litRule(app, lit) // addresses @@ -136,6 +137,14 @@ class Stringifier(detail: Boolean, location: Boolean) { if (!captured.isEmpty) app >> ", " >> captured.toList app >> ">" + // grammar + given grammarRule: Rule[Grammar] = (app, gr) => + given Rule[Boolean] = (app, bool) => app >> (if (bool) "T" else "F") + given Rule[List[Boolean]] = iterableRule() + app >> "grammar<" >> gr.name + if (!gr.params.isEmpty) app >> "[" >> gr.params >> "]" + app >> ">" + // literal values given litRule: Rule[LiteralValue] = (app, lit) => lit match diff --git a/src/main/scala/esmeta/ir/Expr.scala b/src/main/scala/esmeta/ir/Expr.scala index 5c1f1cf4b6..0e3aa6013f 100644 --- a/src/main/scala/esmeta/ir/Expr.scala +++ b/src/main/scala/esmeta/ir/Expr.scala @@ -11,7 +11,7 @@ case class EIsCompletion(expr: Expr) extends Expr case class EReturnIfAbrupt(expr: Expr, check: Boolean) extends Expr case class EPop(list: Expr, front: Boolean) extends Expr case class EParse(code: Expr, rule: Expr) extends Expr -case class EParseRule(name: String, params: List[Boolean]) extends Expr +case class EGrammar(name: String, params: List[Boolean]) extends Expr case class ESourceText(expr: Expr) extends Expr case class EYet(msg: String) extends Expr case class EContains(list: Expr, elem: Expr) extends Expr diff --git a/src/main/scala/esmeta/ir/util/Parser.scala b/src/main/scala/esmeta/ir/util/Parser.scala index 51368d39e3..11129ffbd5 100644 --- a/src/main/scala/esmeta/ir/util/Parser.scala +++ b/src/main/scala/esmeta/ir/util/Parser.scala @@ -84,8 +84,8 @@ trait Parsers extends BasicParsers { case f ~ e => EPop(e, f) } | "(" ~ "parse" ~> expr ~ expr <~ ")" ^^ { case c ~ r => EParse(c, r) - } | "(" ~ "rule" ~> ("|" ~> word <~ "|") ~ parseParams <~ ")" ^^ { - case x ~ ps => EParseRule(x, ps) + } | "(" ~ "grammar" ~> ("|" ~> word <~ "|") ~ parseParams <~ ")" ^^ { + case x ~ ps => EGrammar(x, ps) } | "(" ~ "source-text" ~> expr <~ ")" ^^ { ESourceText(_) } | "(" ~ "yet" ~> string <~ ")" ^^ { diff --git a/src/main/scala/esmeta/ir/util/Stringifier.scala b/src/main/scala/esmeta/ir/util/Stringifier.scala index dd16980439..427f034060 100644 --- a/src/main/scala/esmeta/ir/util/Stringifier.scala +++ b/src/main/scala/esmeta/ir/util/Stringifier.scala @@ -106,8 +106,8 @@ class Stringifier(detail: Boolean, location: Boolean) { app >> "(pop " >> (if (front) "<" else ">") >> " " >> list >> ")" case EParse(code, rule) => app >> "(parse " >> code >> " " >> rule >> ")" - case EParseRule(name, params) => - app >> "(rule |" >> name >> "|" + case EGrammar(name, params) => + app >> "(grammar |" >> name >> "|" given Rule[Boolean] = (app, bool) => app >> (if (bool) "T" else "F") given Rule[List[Boolean]] = iterableRule("[", "", "]") app >> params >> ")" diff --git a/src/main/scala/esmeta/ir/util/UnitWalker.scala b/src/main/scala/esmeta/ir/util/UnitWalker.scala index 9079d787d8..95ad8dff20 100644 --- a/src/main/scala/esmeta/ir/util/UnitWalker.scala +++ b/src/main/scala/esmeta/ir/util/UnitWalker.scala @@ -65,7 +65,7 @@ trait UnitWalker extends BasicUnitWalker { walk(list); walk(front) case EParse(code, rule) => walk(code); walk(rule) - case EParseRule(name, params) => + case EGrammar(name, params) => walk(name); walkList(params, walk) case ESourceText(exor) => walk(expr) diff --git a/src/main/scala/esmeta/spec/util/Compiler.scala b/src/main/scala/esmeta/spec/util/Compiler.scala index 6611fdc3ea..a93b480d37 100644 --- a/src/main/scala/esmeta/spec/util/Compiler.scala +++ b/src/main/scala/esmeta/spec/util/Compiler.scala @@ -403,7 +403,7 @@ class Compiler(val spec: Spec) { val newFb = FuncBuilder(Func.Kind.Clo, cloName, ps, body, fb.algo) newFb.result EClo(cloName, captured.map(compile)) - case lit: Literal => compile(lit) + case lit: Literal => compile(fb, lit) } // compile binary operators @@ -419,13 +419,28 @@ class Compiler(val spec: Spec) { case UnaryExpression.Op.Neg => UOp.Neg // compile literals - private def compile(lit: Literal): Expr = lit match { + private def compile(fb: FB, lit: Literal): Expr = lit match { case ThisLiteral() => ENAME_THIS case NewTargetLiteral() => ENAME_NEW_TARGET case HexLiteral(hex, name) => EMathVal(hex) case CodeLiteral(code) => EStr(code) case NonterminalLiteral(ordinal, name) => - toERef(NAME_THIS, EStr(name + ordinal.fold("")(_.toString))) + fb.algo.head match + case SyntaxDirectedOperationHead(Some(target), method, _, _) => + val rhsNames = target.rhsParams.map(_.name) + // check if it is used as reference + // TODO ClassTail[0,3].Contains + if (rhsNames contains name) { + var (idx, ord) = (0, 0) + val targetOrd = ordinal.getOrElse(1) + rhsNames.foreach { + case nt => + if (nt == name && ord < targetOrd) ord += 1 + if (ord < targetOrd) idx += 1 + } + toERef(NAME_THIS, EMathVal(idx)) + } else EGrammar(name, Nil) // TODO grammar params + case _ => EGrammar(name, Nil) // TODO grammar params case ConstLiteral(name) => EConst(name) case StringLiteral(s) => EStr(s) case FieldLiteral(field) => EStr(field) diff --git a/src/main/scala/esmeta/spec/util/package.scala b/src/main/scala/esmeta/spec/util/package.scala index ff4945b807..2e3ba8b503 100644 --- a/src/main/scala/esmeta/spec/util/package.scala +++ b/src/main/scala/esmeta/spec/util/package.scala @@ -170,20 +170,9 @@ extension (rhs: Rhs) { def getNts: List[Nonterminal] = rhs.symbols.flatMap(_.getNt) /** get parameters from RHSs */ - def getRhsParams: List[Param] = { - import Param.Kind.* - val names = rhs.getNts.map(_.name) - val duplicated = names.filter(p => names.count(_ == p) > 1).toSet - var counter = Map[String, Int]() - val paramNames = names.map(name => { - if (duplicated contains name) { - val k = counter.getOrElse(name, 0) - counter += name -> (k + 1) - s"$name$k" - } else name - }) - paramNames.map(Param(_, Normal, "unknown")) - } + // TODO give more precise type + def getRhsParams: List[Param] = + rhs.getNts.map(nt => Param(nt.name, Param.Kind.Normal, "Unknown")) } /** extensions for symbols */ diff --git a/src/test/scala/esmeta/interp/StringifyTinyTest.scala b/src/test/scala/esmeta/interp/StringifyTinyTest.scala index 0a916215c9..14a44fca74 100644 --- a/src/test/scala/esmeta/interp/StringifyTinyTest.scala +++ b/src/test/scala/esmeta/interp/StringifyTinyTest.scala @@ -119,6 +119,7 @@ class StringifyTinyTest extends InterpTest { lazy val ast = AstValue(Syntactic("Identifier", Nil, 1, Nil)) lazy val astArgs = AstValue(Syntactic("Identifier", List(true, false), 1, Nil)) + lazy val grammar = Grammar("A", List(true, false)) lazy val lex = AstValue(Lexical("Identifier", "x")) checkStringify("Value")( comp -> "comp[~throw~/to](42)", @@ -132,6 +133,7 @@ class StringifyTinyTest extends InterpTest { ast -> "|Identifier|<1>", astArgs -> "|Identifier|[TF]<1>", lex -> "|Identifier|(x)", + grammar -> "grammar", Math(3.2) -> "3.2", Number(3.2) -> "3.2f", BigInt(324) -> "324n", diff --git a/src/test/scala/esmeta/ir/StringifyTest.scala b/src/test/scala/esmeta/ir/StringifyTest.scala index dfbedd8f3d..f2cc3d262b 100644 --- a/src/test/scala/esmeta/ir/StringifyTest.scala +++ b/src/test/scala/esmeta/ir/StringifyTest.scala @@ -8,7 +8,7 @@ import esmeta.util.SystemUtils._ import scala.collection.mutable.ListBuffer class StringifyTinyTest extends IRTest { - val name: String = "cfgStringifyTest" + val name: String = "irStringifyTest" // registration def init: Unit = { @@ -135,8 +135,8 @@ class StringifyTinyTest extends IRTest { lazy val riaNoCheck = EReturnIfAbrupt(xExpr, false) lazy val popFront = EPop(xExpr, true) lazy val popBack = EPop(xExpr, false) - lazy val parse = EParse(xExpr, rule) - lazy val rule = EParseRule("A", List(true, false)) + lazy val parse = EParse(xExpr, egrammar) + lazy val egrammar = EGrammar("A", List(true, false)) lazy val yet = EYet("NOT YET") lazy val contains = EContains(xExpr, xExpr) lazy val xExpr = ERef(x) @@ -186,8 +186,8 @@ class StringifyTinyTest extends IRTest { riaNoCheck -> "[! x]", popFront -> "(pop < x)", popBack -> "(pop > x)", - parse -> "(parse x (rule |A|[TF]))", - rule -> "(rule |A|[TF])", + parse -> "(parse x (grammar |A|[TF]))", + egrammar -> "(grammar |A|[TF])", yet -> "(yet \"NOT YET\")", contains -> "(contains x x)", xExpr -> "x",