An embeddable, lazy Jsonnet interpreter for MoonBit native applications
| Reference corpus | Raw result |
|---|---|
| C++ | 108 cases: 98 compatible + 10 declared differences |
| Go whole CLI | ARM64 1132/1150; AMD64 1131/1150 |
| Go reusable evaluator / lint | 20/21 / 409/410 |
moon add pangbit/moonjsonnet@0.1.0# moon.pkg
import { "pangbit/moonjsonnet" }
supported_targets = "native"
pkgtype(kind: "executable")///|
fn main raise {
let value = @moonjsonnet.evaluate("{ answer: 6 * 7 }")
println(value.stringify())
}///|
test "readme embedded evaluation" {
let value = @moonjsonnet.evaluate(
"local template(n=1) = { replicas: n, port: 8080 }; template(3)",
)
assert_eq(value, { "replicas": 3, "port": 8080 })
assert_eq(
@moonjsonnet.evaluate("std.thisFile", filename="<cmdline>", anonymous=true),
Json::string(""),
)
assert_eq(
@moonjsonnet.evaluate_text("'hello'", string_output=true),
"hello\n",
)
assert_eq(@moonjsonnet.evaluate_stream("[42,'hello']"), [
"42\n", "\"hello\"\n",
])
assert_eq(@moonjsonnet.evaluate_multi("{a:42}")["a"], "42\n")
}///|
test "readme code and top-level arguments" {
let result = @moonjsonnet.evaluate(
"function(replicas, port=8080) {replicas:replicas,port:port}",
ext_code=Map([("base", "1+2")]),
tla_code=Map([("replicas", "std.extVar('base')")]),
)
assert_eq(result, { "replicas": 3, "port": 8080 })
}///|
test "readme native callback and trace" {
let identity : @moonjsonnet.NativeFunction = {
params: ["value"],
callback: args => args[0],
}
let messages : Array[String] = []
let result = @moonjsonnet.evaluate(
"std.trace('calling host', std.native('identity')(value=42))",
native_functions=Map([("identity", identity)]),
trace=fn(_, message) { messages.push(message) },
)
assert_eq(result, 42)
assert_eq(messages, ["calling host"])
}///|
test "readme structured diagnostic trace" {
let formatter = @moonjsonnet.DiagnosticFormatter::new()
try @moonjsonnet.evaluate("error 'failed'", filename="entry") catch {
@moonjsonnet.Error(d) => {
assert_eq(d.trace.length(), 2)
assert_eq(
formatter.format(d),
"RUNTIME ERROR: failed\n\tentry:1:1-15\t$\n\tDuring evaluation\t\n",
)
}
} noraise {
_ => fail("runtime diagnostic expected")
}
}///|
test "readme evaluation hook" {
let evaluator = @moonjsonnet.Evaluator::new()
let values : Array[Json] = []
evaluator.set_eval_hook(hook={
before: ctx => {
if ctx.node().kind is Var("x") {
values.push(ctx.lookup("x").json())
}
},
after: (_, _) => (),
})
assert_eq(
evaluator.evaluate(@moonjsonnet.Program::parse("local x=21;x*2")),
42,
)
assert_eq(values, [21])
evaluator.set_eval_hook()
}///|
test "readme source formatting" {
assert_eq(@moonjsonnet.format_source("{\"a\":[1,2]}"), "{ a: [1, 2] }\n")
let source = "0" + "+1".repeat(299)
let syntax = @moonjsonnet.SyntaxDocument::parse(source)
assert_eq(syntax.format(), "0" + " + 1".repeat(299) + "\n")
}///|
test "readme raw syntax editing" {
let raw = @moonjsonnet.RawAst::parse("/*head*/ 1 //tail\n")
let original = raw.clone()
for i, part in raw.root.parts {
if part is Text(text) && text.kind is TokenText {
raw.root.parts[i] = Text({ ..text, text: "42", })
}
}
assert_eq(original.text(), "/*head*/ 1 //tail\n")
assert_eq(raw.text(), "/*head*/ 42 //tail\n")
assert_eq(raw.format(), "/*head*/ 42 //tail\n")
}moon check --target native --deny-warn
moon test --target native --deny-warn
moon run cmd/main -- examples/environments/main.jsonnet
moon run cmd/main -- examples/dashboards/main.jsonnet
moon run examples/embeddedmoon run cmd/main -- --root examples/embedded/config --ext-code replicas=3 main.jsonnet
moon run cmd/main -- --root examples/environments -o result.json main.jsonnettest {
let node = @moonjsonnet.Program::parse("'中'", filename="example").ast()
assert_eq(node.source_range().unwrap().format(), "example:1:1-6")
}pub(all) enum AstKind {
NumberLiteral(String)
Literal(Json)
Var(String)
Local(Array[AstBinding], Ast)
If(Ast, Ast, Ast)
Func(Array[AstParameter], Ast)
Call(Ast, Array[(String?, Ast)], Bool)
Arr(Array[Ast])
Obj(Array[AstField], Array[AstBinding], Array[(Ast, Ast?)])
ArrayComp(Ast, Array[AstClause])
ObjectComp(Ast, Ast, Array[AstClause], Array[AstBinding])
Index(Ast, Ast)
Slice(Ast, Ast?, Ast?, Ast?)
Unary(String, Ast)
Binary(String, Ast, Ast)
Assert(Ast, Ast?, Ast)
Fail(Ast)
ImportFile(String, Bool)
ImportBinary(String)
}pub(all) enum DebugCommand {
Continue
Step
Finish
Terminate
}pub struct DebugValue {
// private fields
}pub struct Debugger {
// private fields
}fn Debugger::run(self : Debugger, program : Program, on_stop~ : (DebugStop) -> DebugCommand raise, start_with_step? : Bool) -> String raise JsonnetErrorfn Debugger::set_breakpoint(self : Debugger, program : Program, line : Int, column? : Int) -> String raise JsonnetErrorimpl Show for Diagnostictest {
let loc : @moonjsonnet.Location = { file: "example", line: 1, column: 1, }
let diagnostic : @moonjsonnet.Diagnostic = {
kind: @moonjsonnet.Runtime,
message: "failed",
location: loc,
context: [loc, loc, loc],
trace: [],
}
assert_eq(
diagnostic.format(max_trace=1),
"example:1:1: Runtime: failed\n ...\n at example:1:1",
)
}pub struct DiagnosticFormatter {
// private fields
}pub struct EvalContext {
// private fields
}pub(all) struct EvalHook {
before : (EvalContext) -> Unit raise
after : (EvalContext, EvalOutcome) -> Unit raise
}pub struct Evaluator {
// private fields
}fn Evaluator::evaluate_multi(self : Evaluator, program : Program) -> Map[String, String] raise JsonnetErrorfn Evaluator::evaluate_stream(self : Evaluator, program : Program) -> Array[String] raise JsonnetErrorfn Evaluator::ext_program(self : Evaluator, name : String, value : Program) -> Unit raise JsonnetErrorfn Evaluator::find_dependencies(self : Evaluator, imported_from : String, imported_paths : Array[String]) -> Array[String] raise JsonnetErrorfn Evaluator::import_ast(self : Evaluator, imported_from : String, imported_path : String) -> (Program?, String) raise JsonnetErrortest {
let evaluator = @moonjsonnet.Evaluator::new()
evaluator.set_importer(resolver=fn(_, path) { { id: path, text: "missing", } })
try evaluator.import_ast("", "main") catch {
@moonjsonnet.Error(d) => assert_eq(d.kind, @moonjsonnet.Static)
} noraise {
_ => fail("expected first parse error")
}
let (program, id) = evaluator.import_ast("", "main")
assert_true(program is None)
assert_eq(id, "main")
}fn Evaluator::import_data(self : Evaluator, imported_from : String, imported_path : String) -> BinarySource raise JsonnetErrorfn Evaluator::import_program(self : Evaluator, imported_from : String, imported_path : String) -> (Program, String) raise JsonnetErrortest {
let evaluator = @moonjsonnet.Evaluator::new()
evaluator.set_importer(binary_resolver=fn(_, _) {
{ id: "lib/answer", bytes: b"42", }
})
let (program, identity) = evaluator.import_program("", "answer")
assert_eq(identity, "lib/answer")
assert_eq(evaluator.evaluate(program), 42)
}fn Evaluator::native_function(self : Evaluator, name : String, native : NativeFunction) -> Unit raise JsonnetErrortest {
let evaluator = @moonjsonnet.Evaluator::new()
let program = @moonjsonnet.Program::parse("std.extVar('x')")
evaluator.ext_var("x", 42)
assert_eq(evaluator.evaluate(program), 42)
evaluator.ext_var("x", 7)
assert_eq(evaluator.evaluate(program), 7)
}fn Evaluator::resolve_import(self : Evaluator, imported_from : String, imported_path : String) -> String raise JsonnetErrorfn Evaluator::set_diagnostic_formatter(self : Evaluator, formatter? : DiagnosticFormatter) -> Unit raise JsonnetErrorfn Evaluator::set_importer(self : Evaluator, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise) -> Unit raise JsonnetErrorfn Evaluator::set_trace(self : Evaluator, trace : (Location, String) -> Unit) -> Unit raise JsonnetErrorfn Evaluator::tla_program(self : Evaluator, name : String, value : Program) -> Unit raise JsonnetErrorpub(all) struct FormatOptions {
indent : Int
max_blank_lines : Int
string_style : FormatStringStyle
comment_style : FormatCommentStyle
pretty_field_names : Bool
pad_arrays : Bool
pad_objects : Bool
sort_imports : Bool
use_implicit_plus : Bool
strip_everything : Bool
strip_comments : Bool
strip_all_but_comments : Bool
}pub(all) struct Limits {
steps : Int
depth : Int
stack : Int
source_bytes : Int
import_bytes : Int
imports : Int
output_bytes : Int
} derive(Debug)test {
let limits = { ..@moonjsonnet.Limits::default(), stack: 2, }
assert_eq(@moonjsonnet.evaluate("local x=42; x", limits~), 42)
}pub struct ParsedSource {
// private fields
}fn ParsedSource::format(self : ParsedSource, options? : FormatOptions, limits? : Limits) -> String raise JsonnetErrorfn ParsedSource::parse(source : String, filename? : String, limits? : Limits) -> ParsedSource raise JsonnetErrorpub struct Program {
// private fields
}fn Program::evaluate(self : Program, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> Json raise JsonnetErrorfn Program::evaluate_multi(self : Program, string_output? : Bool, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> Map[String, String] raise JsonnetErrorfn Program::evaluate_stream(self : Program, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> Array[String] raise JsonnetErrorfn Program::evaluate_text(self : Program, string_output? : Bool, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> String raise JsonnetErrorfn Program::from_ast(tree : Ast, filename? : String, anonymous? : Bool, limits? : Limits, assertion_ranges? : Map[String, SourceRange]) -> Program raise JsonnetErrortest {
let tree = @moonjsonnet.Program::parse("21").ast()
let edited = { ..tree, kind: @moonjsonnet.AstKind::Binary("*", tree, tree), }
assert_eq(@moonjsonnet.Program::from_ast(edited).evaluate(), 441)
}fn Program::parse(source : String, filename? : String, anonymous? : Bool, limits? : Limits) -> Program raise JsonnetErrortest {
let program = @moonjsonnet.Program::parse("std.extVar('x') * 2")
assert_eq(program.evaluate(ext_vars=Map([("x", 21)])), 42)
assert_eq(program.evaluate(ext_vars=Map([("x", 3)])), 6)
}fn RawAst::format(self : RawAst, options? : FormatOptions, limits? : SyntaxLimits) -> String raise JsonnetErrorfn RawAst::parse(source : String, filename? : String, limits? : SyntaxLimits) -> RawAst raise JsonnetErrorpub(all) enum RawNodeKind {
Literal
Number
StringLiteral
TextBlock
Variable
Parens
Local
Binding
Parameter
Argument
If
Function
Array
Object
Field
ObjectLocal
ObjectAssert
ArrayComp
ObjectComp
ForClause
IfClause
Call
ApplyBrace
Index
DotIndex
Slice
Unary(String)
Binary(String)
Assert
ErrorExpr
Import
ImportStr
ImportBin
} derive(Eq, Debug)pub struct SyntaxDocument {
// private fields
}fn SyntaxDocument::format(self : SyntaxDocument, options? : FormatOptions, limits? : SyntaxLimits) -> String raise JsonnetErrorfn SyntaxDocument::parse(source : String, filename? : String, limits? : SyntaxLimits) -> SyntaxDocument raise JsonnetErrorfn SyntaxDocument::raw_ast(self : SyntaxDocument, limits? : SyntaxLimits) -> RawAst raise JsonnetErrorpub(all) struct SyntaxLimits {
parser_depth : Int
tree_depth : Int
nodes : Int
steps : Int
source_bytes : Int
output_bytes : Int
} derive(Debug)fn evaluate(source : String, filename? : String, anonymous? : Bool, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> Json raise JsonnetErrortest {
let result = @moonjsonnet.evaluate("local x = 6; { answer: x * 7 }")
assert_eq(result.stringify(), "{\"answer\":42}")
}fn evaluate_multi(source : String, string_output? : Bool, filename? : String, anonymous? : Bool, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> Map[String, String] raise JsonnetErrortest {
let files = @moonjsonnet.evaluate_multi("{'a.json':42,'b.json':[]}")
assert_eq(files["a.json"], "42\n")
assert_eq(files["b.json"], "[ ]\n")
}fn evaluate_stream(source : String, filename? : String, anonymous? : Bool, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> Array[String] raise JsonnetErrortest {
assert_eq(@moonjsonnet.evaluate_stream("[1,'x']"), ["1\n", "\"x\"\n"])
}fn evaluate_text(source : String, string_output? : Bool, filename? : String, anonymous? : Bool, ext_vars? : Map[String, Json], ext_code? : Map[String, String], ext_programs? : Map[String, Program], tla_vars? : Map[String, Json], tla_code? : Map[String, String], tla_programs? : Map[String, Program], native_functions? : Map[String, NativeFunction], trace? : (Location, String) -> Unit, resolver? : (String, String) -> Source raise, binary_resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> String raise JsonnetErrortest {
assert_eq(
@moonjsonnet.evaluate_text("'hello'", string_output=true),
"hello\n",
)
}fn find_dependencies(imported_from : String, imported_paths : Array[String], resolver~ : (String, String) -> BinarySource raise, limits? : Limits) -> Array[String] raise JsonnetErrortest {
let files = Map([
("main", b"if false then import 'data' else 1"),
("data", b"42"),
])
let dependencies = @moonjsonnet.find_dependencies("", ["main"], resolver=fn(
_,
path,
) {
{ id: path, bytes: files[path], }
})
assert_eq(dependencies, ["data"])
}fn format_node(node : RawNode, final_fodder? : Array[SourcePart], options? : FormatOptions, limits? : SyntaxLimits) -> String raise JsonnetErrorfn format_source(source : String, filename? : String, options? : FormatOptions, limits? : Limits) -> String raise JsonnetErrorfn format_syntax_source(source : String, filename? : String, options? : FormatOptions, limits? : SyntaxLimits) -> String raise JsonnetErrortest {
assert_eq(@moonjsonnet.format_syntax_source("[1,2]"), "[1, 2]\n")
}fn lint(snippets : Array[Source], resolver? : (String, String) -> BinarySource raise, limits? : Limits) -> Array[Diagnostic] raise JsonnetErrortest {
let issues = @moonjsonnet.lint([{ id: "entry", text: "local unused=1;42", }])
assert_eq(issues[0].message, "Unused variable: unused")
}Install
Download zipAn embeddable, lazy Jsonnet interpreter for MoonBit native applications