From 741e762b9d80b6422d73f01f91e39eab77bbc9c2 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 5 Jun 2023 17:15:47 -0700 Subject: [PATCH 1/6] . --- .../sjsonnet/SjsonnetMain.scala | 14 ++++----- sjsonnet/src/sjsonnet/Interpreter.scala | 26 +++++++++++------ sjsonnet/src/sjsonnet/Parser.scala | 2 +- .../src-jvm-native/sjsonnet/FileTests.scala | 2 +- .../src/sjsonnet/Std0150FunctionsTests.scala | 29 +++++++++++++++++++ 5 files changed, 55 insertions(+), 18 deletions(-) diff --git a/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala b/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala index 54246b22..26d2b192 100644 --- a/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala +++ b/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala @@ -159,23 +159,23 @@ object SjsonnetMain { varBinding = varBinding ++ Seq(x -> os.read(os.Path(v, wd))) } - var tlaBinding = Map.empty[String, ujson.Value] + var tlaBinding = Map.empty[String, String] config.tlaStr.map(_.split("=", 2)).foreach{ - case Array(x) => tlaBinding = tlaBinding ++ Seq(x -> ujson.Str(System.getenv(x))) - case Array(x, v) => tlaBinding = tlaBinding ++ Seq(x -> ujson.Str(v)) + case Array(x) => tlaBinding = tlaBinding ++ Seq(x -> ujson.write(System.getenv(x))) + case Array(x, v) => tlaBinding = tlaBinding ++ Seq(x -> ujson.write(v)) } config.tlaStrFile.map(_.split("=", 2)).foreach { case Array(x, v) => - tlaBinding = tlaBinding ++ Seq(x -> ujson.Str(os.read(os.Path(v, wd)))) + tlaBinding = tlaBinding ++ Seq(x -> ujson.write(os.read(os.Path(v, wd)))) } config.tlaCode.map(_.split("=", 2)).foreach { - case Array(x) => tlaBinding = tlaBinding ++ Seq(x -> ujson.read(System.getenv(x))) - case Array(x, v) => tlaBinding = tlaBinding ++ Seq(x -> ujson.read(v)) + case Array(x) => tlaBinding = tlaBinding ++ Seq(x -> System.getenv(x)) + case Array(x, v) => tlaBinding = tlaBinding ++ Seq(x -> v) } config.tlaCodeFile.map(_.split("=", 2)).foreach { case Array(x, v) => - tlaBinding = tlaBinding ++ Seq(x -> ujson.read(os.read(os.Path(v, wd)))) + tlaBinding = tlaBinding ++ Seq(x -> os.read(os.Path(v, wd))) } var currentPos: Position = null val interp = new Interpreter( diff --git a/sjsonnet/src/sjsonnet/Interpreter.scala b/sjsonnet/src/sjsonnet/Interpreter.scala index 06a066d1..3579c4bb 100644 --- a/sjsonnet/src/sjsonnet/Interpreter.scala +++ b/sjsonnet/src/sjsonnet/Interpreter.scala @@ -12,7 +12,7 @@ import scala.util.control.NonFatal * evaluation to materialization, into a convenient wrapper class. */ class Interpreter(extVars: Map[String, String], - tlaVars: Map[String, ujson.Value], + tlaVars: Map[String, String], wd: Path, importer: Importer, val parseCache: ParseCache, @@ -33,12 +33,15 @@ class Interpreter(extVars: Map[String, String], settings: Settings, warn: Error => Unit): Evaluator = new Evaluator(resolver, extVars, wd, settings, warn) + + def parseVar(k: String, v: String) = { + resolver.parse(wd / s"<$k>", v)(evaluator).fold(throw _, _._1) + } + lazy val evaluator: Evaluator = createEvaluator( resolver, // parse extVars lazily, because they can refer to each other and be recursive - extVars - .mapValues{ v => resolver.parse(wd / s"", v)(evaluator).fold(throw _, _._1) } - .lift, + k => extVars.get(k).map(v => parseVar(s"ext-var $k", v)), wd, settings, warn @@ -73,7 +76,7 @@ class Interpreter(extVars: Map[String, String], } } - def evaluate[T](txt: String, path: Path): Either[Error, Val] = { + def evaluate(txt: String, path: Path): Either[Error, Val] = { resolver.cache(path) = txt for{ res <- resolver.parse(path, txt)(evaluator) @@ -84,15 +87,20 @@ class Interpreter(extVars: Map[String, String], val defaults2 = f.params.defaultExprs.clone() var i = 0 while(i < defaults2.length) { - tlaVars.get(f.params.names(i)) match { - case Some(v) => defaults2(i) = Materializer.toExpr(v)(evaluator) + val k = f.params.names(i) + tlaVars.get(k) match { + case Some(v) => defaults2(i) = parseVar(s"tla-var $k", v) case None => } i += 1 } new Val.Func(f.pos, f.defSiteValScope, Params(f.params.names, defaults2)) { - def evalRhs(vs: ValScope, es: EvalScope, fs: FileScope, pos: Position) = f.evalRhs(vs, es, fs, pos) - override def evalDefault(expr: Expr, vs: ValScope, es: EvalScope) = f.evalDefault(expr, vs, es) + def evalRhs(vs: ValScope, es: EvalScope, fs: FileScope, pos: Position) = { + f.evalRhs(vs, es, fs, pos) + } + override def evalDefault(expr: Expr, vs: ValScope, es: EvalScope) = { + evaluator.visitExpr(expr)(ValScope.empty) + } } case x => x } diff --git a/sjsonnet/src/sjsonnet/Parser.scala b/sjsonnet/src/sjsonnet/Parser.scala index 3d549569..60f01b6a 100644 --- a/sjsonnet/src/sjsonnet/Parser.scala +++ b/sjsonnet/src/sjsonnet/Parser.scala @@ -432,7 +432,7 @@ final class Position(val fileScope: FileScope, val offset: Int) { } override def toString = { val name = if(fileScope == null) "null" else fileScope.currentFileLastPathElement - s"Position($name, $offset)" + s"p" } } diff --git a/sjsonnet/test/src-jvm-native/sjsonnet/FileTests.scala b/sjsonnet/test/src-jvm-native/sjsonnet/FileTests.scala index df4bb487..6d5ca2a8 100644 --- a/sjsonnet/test/src-jvm-native/sjsonnet/FileTests.scala +++ b/sjsonnet/test/src-jvm-native/sjsonnet/FileTests.scala @@ -7,7 +7,7 @@ object FileTests extends TestSuite{ def eval(p: os.Path) = { val interp = new Interpreter( Map("var1" -> "\"test\"", "var2" -> """local f(a, b) = {[a]: b, "y": 2}; f("x", 1)"""), - Map("var1" -> "test", "var2" -> ujson.Obj("x" -> 1, "y" -> 2)), + Map("var1" -> "\"test\"", "var2" -> """{"x": 1, "y": 2}"""), OsPath(testSuiteRoot), importer = sjsonnet.SjsonnetMain.resolveImport(Array(OsPath(testSuiteRoot))), parseCache = new DefaultParseCache diff --git a/sjsonnet/test/src/sjsonnet/Std0150FunctionsTests.scala b/sjsonnet/test/src/sjsonnet/Std0150FunctionsTests.scala index 7c92ca3e..69ec7485 100644 --- a/sjsonnet/test/src/sjsonnet/Std0150FunctionsTests.scala +++ b/sjsonnet/test/src/sjsonnet/Std0150FunctionsTests.scala @@ -103,5 +103,34 @@ object Std0150FunctionsTests extends TestSuite { check("""std.extVar("stdExtVarRecursive")""", 115) } + test("tlaVars"){ + val interpreter = new Interpreter( + Map(), + Map( + "num" -> "1", + "str" -> "\"hello\"", + "bool" -> "true", + "jsonArrNums" -> """[1, 2, 3]""", + "jsonObjBools" -> """{"hello": false}""", + "code" -> """local f(a, b) = {[a]: b, "y": 2}; f("x", 1)""", + "std" -> """std.length("hello")""", + ), + DummyPath(), + Importer.empty, + parseCache = new DefaultParseCache, + ) + + def check(s: String, expected: ujson.Value) = + interpreter.interpret(s, DummyPath("(memory)")) ==> Right(expected) + + check("""function(num) num""", 1) + check("""function(str) str""", "hello") + check("""function(bool) bool""", ujson.True) + check("""function(jsonArrNums) jsonArrNums""", ujson.Arr(1, 2, 3)) + check("""function(jsonObjBools) jsonObjBools""", ujson.Obj("hello" -> false)) + check("""function(code) code""", ujson.Obj("x" -> 1, "y" -> 2)) + check("""function(std) std""", 5) + } + } } From 24af58d0e87638d44f69817772c814405266c3e2 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 5 Jun 2023 17:18:06 -0700 Subject: [PATCH 2/6] . --- sjsonnet/src/sjsonnet/Interpreter.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sjsonnet/src/sjsonnet/Interpreter.scala b/sjsonnet/src/sjsonnet/Interpreter.scala index 3579c4bb..15d18589 100644 --- a/sjsonnet/src/sjsonnet/Interpreter.scala +++ b/sjsonnet/src/sjsonnet/Interpreter.scala @@ -95,9 +95,7 @@ class Interpreter(extVars: Map[String, String], i += 1 } new Val.Func(f.pos, f.defSiteValScope, Params(f.params.names, defaults2)) { - def evalRhs(vs: ValScope, es: EvalScope, fs: FileScope, pos: Position) = { - f.evalRhs(vs, es, fs, pos) - } + def evalRhs(vs: ValScope, es: EvalScope, fs: FileScope, pos: Position) = f.evalRhs(vs, es, fs, pos) override def evalDefault(expr: Expr, vs: ValScope, es: EvalScope) = { evaluator.visitExpr(expr)(ValScope.empty) } From 0e598356ae872885c3a658fabbbc09fa11744502 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 5 Jun 2023 17:18:41 -0700 Subject: [PATCH 3/6] . --- sjsonnet/src/sjsonnet/Parser.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sjsonnet/src/sjsonnet/Parser.scala b/sjsonnet/src/sjsonnet/Parser.scala index 60f01b6a..3d549569 100644 --- a/sjsonnet/src/sjsonnet/Parser.scala +++ b/sjsonnet/src/sjsonnet/Parser.scala @@ -432,7 +432,7 @@ final class Position(val fileScope: FileScope, val offset: Int) { } override def toString = { val name = if(fileScope == null) "null" else fileScope.currentFileLastPathElement - s"p" + s"Position($name, $offset)" } } From 24dfc277f64eddffa7e56e8553ccadfa606e9e38 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 5 Jun 2023 17:23:52 -0700 Subject: [PATCH 4/6] . --- sjsonnet/src-js/sjsonnet/SjsonnetMain.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sjsonnet/src-js/sjsonnet/SjsonnetMain.scala b/sjsonnet/src-js/sjsonnet/SjsonnetMain.scala index 8ee10165..f88ab814 100644 --- a/sjsonnet/src-js/sjsonnet/SjsonnetMain.scala +++ b/sjsonnet/src-js/sjsonnet/SjsonnetMain.scala @@ -16,7 +16,7 @@ object SjsonnetMain { preserveOrder: Boolean = false): js.Any = { val interp = new Interpreter( ujson.WebJson.transform(extVars, ujson.Value).obj.toMap.map{case (k, ujson.Str(v)) => (k, v)}, - ujson.WebJson.transform(tlaVars, ujson.Value).obj.toMap, + ujson.WebJson.transform(tlaVars, ujson.Value).obj.toMap.map{case (k, ujson.Str(v)) => (k, v)}, JsVirtualPath(wd0), new Importer { def resolve(docBase: Path, importName: String): Option[Path] = From 1219f3a11dcce1967dcf4dc56e796ef52b344482 Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 5 Jun 2023 17:36:29 -0700 Subject: [PATCH 5/6] . --- bench/src/main/scala/sjsonnet/MainBenchmark.scala | 2 +- bench/src/main/scala/sjsonnet/MaterializerBenchmark.scala | 2 +- bench/src/main/scala/sjsonnet/RunProfiler.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bench/src/main/scala/sjsonnet/MainBenchmark.scala b/bench/src/main/scala/sjsonnet/MainBenchmark.scala index 54722a1a..bd3ab6d9 100644 --- a/bench/src/main/scala/sjsonnet/MainBenchmark.scala +++ b/bench/src/main/scala/sjsonnet/MainBenchmark.scala @@ -22,7 +22,7 @@ object MainBenchmark { val parseCache = new DefaultParseCache val interp = new Interpreter( Map.empty[String, String], - Map.empty[String, ujson.Value], + Map.empty[String, String], OsPath(wd), importer = SjsonnetMain.resolveImport(config.jpaths.map(os.Path(_, wd)).map(OsPath(_)), None), parseCache = parseCache diff --git a/bench/src/main/scala/sjsonnet/MaterializerBenchmark.scala b/bench/src/main/scala/sjsonnet/MaterializerBenchmark.scala index b23c86fe..9152f6f0 100644 --- a/bench/src/main/scala/sjsonnet/MaterializerBenchmark.scala +++ b/bench/src/main/scala/sjsonnet/MaterializerBenchmark.scala @@ -29,7 +29,7 @@ class MaterializerBenchmark { var currentPos: Position = null this.interp = new Interpreter( Map.empty[String, String], - Map.empty[String, ujson.Value], + Map.empty[String, String], OsPath(wd), importer = SjsonnetMain.resolveImport(config.jpaths.map(os.Path(_, wd)).map(OsPath(_)), None), parseCache = new DefaultParseCache diff --git a/bench/src/main/scala/sjsonnet/RunProfiler.scala b/bench/src/main/scala/sjsonnet/RunProfiler.scala index 9b5d8ecd..85177b7a 100644 --- a/bench/src/main/scala/sjsonnet/RunProfiler.scala +++ b/bench/src/main/scala/sjsonnet/RunProfiler.scala @@ -11,7 +11,7 @@ object RunProfiler extends App { val parseCache = new DefaultParseCache val interp = new Interpreter( Map.empty[String, String], - Map.empty[String, ujson.Value], + Map.empty[String, String], OsPath(wd), importer = SjsonnetMain.resolveImport(config.jpaths.map(os.Path(_, wd)).map(OsPath(_)), None), parseCache = parseCache From dc6bab72a0cbe5c407f7a2996b0f468280d4376d Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Mon, 5 Jun 2023 17:47:36 -0700 Subject: [PATCH 6/6] . --- .../sjsonnet/SjsonnetMain.scala | 67 +++++++++---------- sjsonnet/src/sjsonnet/Interpreter.scala | 1 - 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala b/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala index 26d2b192..cc2a79f8 100644 --- a/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala +++ b/sjsonnet/src-jvm-native/sjsonnet/SjsonnetMain.scala @@ -133,6 +133,27 @@ object SjsonnetMain { def isScalar(v: ujson.Value) = !v.isInstanceOf[ujson.Arr] && !v.isInstanceOf[ujson.Obj] + def parseBindings(strs: Seq[String], + strFiles: Seq[String], + codes: Seq[String], + codeFiles: Seq[String], + wd: os.Path) = { + + def split(s: String) = s.split("=", 2) match{ + case Array(x) => (x, System.getenv(x)) + case Array(x, v) => (x, v) + } + + def splitMap(s: Seq[String], f: String => String) = s.map(split).map{case (x, v) => (x, f(v))} + def readPath(v: String) = os.read(os.Path(v, wd)) + + Map() ++ + splitMap(strs, v => ujson.write(v)) ++ + splitMap(strFiles, v => ujson.write(readPath(v))) ++ + splitMap(codes, identity) ++ + splitMap(codeFiles, readPath) + } + def mainConfigured(file: String, config: Config, parseCache: ParseCache, @@ -141,45 +162,21 @@ object SjsonnetMain { importer: Option[(Path, String) => Option[os.Path]] = None, warnLogger: String => Unit = null): Either[String, String] = { val path = os.Path(file, wd) - var varBinding = Map.empty[String, String] - config.extStr.map(_.split("=", 2)).foreach{ - case Array(x) => varBinding = varBinding ++ Seq(x -> ujson.write(System.getenv(x))) - case Array(x, v) => varBinding = varBinding ++ Seq(x -> ujson.write(v)) - } - config.extStrFile.map(_.split("=", 2)).foreach { - case Array(x, v) => - varBinding = varBinding ++ Seq(x -> ujson.write(os.read(os.Path(v, wd)))) - } - config.extCode.map(_.split("=", 2)).foreach { - case Array(x) => varBinding = varBinding ++ Seq(x -> System.getenv(x)) - case Array(x, v) => varBinding = varBinding ++ Seq(x -> v) - } - config.extCodeFile.map(_.split("=", 2)).foreach { - case Array(x, v) => - varBinding = varBinding ++ Seq(x -> os.read(os.Path(v, wd))) - } + val extBinding = parseBindings( + config.extStr, config.extStrFile, + config.extCode, config.extCodeFile, + wd + ) - var tlaBinding = Map.empty[String, String] + val tlaBinding = parseBindings( + config.tlaStr, config.tlaStrFile, + config.tlaCode, config.tlaCodeFile, + wd + ) - config.tlaStr.map(_.split("=", 2)).foreach{ - case Array(x) => tlaBinding = tlaBinding ++ Seq(x -> ujson.write(System.getenv(x))) - case Array(x, v) => tlaBinding = tlaBinding ++ Seq(x -> ujson.write(v)) - } - config.tlaStrFile.map(_.split("=", 2)).foreach { - case Array(x, v) => - tlaBinding = tlaBinding ++ Seq(x -> ujson.write(os.read(os.Path(v, wd)))) - } - config.tlaCode.map(_.split("=", 2)).foreach { - case Array(x) => tlaBinding = tlaBinding ++ Seq(x -> System.getenv(x)) - case Array(x, v) => tlaBinding = tlaBinding ++ Seq(x -> v) - } - config.tlaCodeFile.map(_.split("=", 2)).foreach { - case Array(x, v) => - tlaBinding = tlaBinding ++ Seq(x -> os.read(os.Path(v, wd))) - } var currentPos: Position = null val interp = new Interpreter( - varBinding, + extBinding, tlaBinding, OsPath(wd), importer = importer match{ diff --git a/sjsonnet/src/sjsonnet/Interpreter.scala b/sjsonnet/src/sjsonnet/Interpreter.scala index 15d18589..b415df08 100644 --- a/sjsonnet/src/sjsonnet/Interpreter.scala +++ b/sjsonnet/src/sjsonnet/Interpreter.scala @@ -4,7 +4,6 @@ import java.io.{PrintWriter, StringWriter} import sjsonnet.Expr.Params -import scala.collection.mutable import scala.util.control.NonFatal /**