///|
fn ast_object(fields : Array[(String, Json)]) -> Json {
Json::object(Map::from_array(fields))
}
///|
fn span_json(span : SourceSpan) -> Json {
ast_object([
("start", Json::number(span.start.to_double(), repr=span.start.to_string())),
("end", Json::number(span.end.to_double(), repr=span.end.to_string())),
("line", Json::number(span.line.to_double(), repr=span.line.to_string())),
(
"column",
Json::number(span.column.to_double(), repr=span.column.to_string()),
),
])
}
///|
fn literal_json(literal : Literal) -> Json {
match literal {
Null =>
ast_object([("type", Json::string("null")), ("value", Json::null())])
Bool(value) =>
ast_object([
("type", Json::string("bool")),
("value", Json::boolean(value)),
])
Int(value) =>
ast_object([
("type", Json::string("int")),
("value", Json::string(value.to_string())),
])
UInt(value) =>
ast_object([
("type", Json::string("uint")),
("value", Json::string(value.to_string())),
])
Double(value) =>
ast_object([
("type", Json::string("double")),
("value", Json::number(value)),
])
String(value) =>
ast_object([
("type", Json::string("string")),
("value", Json::string(value)),
])
Bytes(value) =>
ast_object([
("type", Json::string("bytes")),
(
"length",
Json::number(
value.length().to_double(),
repr=value.length().to_string(),
),
),
])
}
}
///|
fn expr_base(
expr : Expr,
kind : String,
fields : Array[(String, Json)],
) -> Json {
let result : Array[(String, Json)] = [
("id", Json::number(expr.id.to_double(), repr=expr.id.to_string())),
("kind", Json::string(kind)),
("span", span_json(expr.span)),
]
result.append(fields)
ast_object(result)
}
///|
/// Convert an expression and all descendants to a stable JSON AST.
pub fn Expr::to_json(self : Expr) -> Json {
match self.kind {
Literal(value) =>
expr_base(self, "literal", [("literal", literal_json(value))])
Identifier(name) =>
expr_base(self, "identifier", [("name", Json::string(name))])
List(items) =>
expr_base(self, "list", [
("items", Json::array(items.map(item => item.to_json()))),
])
Map(entries) =>
expr_base(self, "map", [
(
"entries",
Json::array(
entries.map(entry => {
ast_object([
("key", entry.key.to_json()),
("value", entry.value.to_json()),
("span", span_json(entry.span)),
])
}),
),
),
])
Unary(operator, operand) =>
expr_base(self, "unary", [
("operator", Json::string(operator.symbol())),
("operand", operand.to_json()),
])
Binary(operator, left, right) =>
expr_base(self, "binary", [
("operator", Json::string(operator.symbol())),
("left", left.to_json()),
("right", right.to_json()),
])
Conditional(condition, when_true, when_false) =>
expr_base(self, "conditional", [
("condition", condition.to_json()),
("when_true", when_true.to_json()),
("when_false", when_false.to_json()),
])
Select(target, field) =>
expr_base(self, "select", [
("target", target.to_json()),
("field", Json::string(field)),
])
Index(target, index) =>
expr_base(self, "index", [
("target", target.to_json()),
("index", index.to_json()),
])
Call(name, args) =>
expr_base(self, "call", [
("name", Json::string(name)),
("arguments", Json::array(args.map(arg => arg.to_json()))),
])
ReceiverCall(target, name, args) =>
expr_base(self, "receiver_call", [
("target", target.to_json()),
("name", Json::string(name)),
("arguments", Json::array(args.map(arg => arg.to_json()))),
])
}
}
///|
pub fn ParsedExpr::to_json(self : ParsedExpr) -> Json {
ast_object([
("schema", Json::string("moon-cel.ast/1")),
("source", Json::string(self.source())),
("root", self.root().to_json()),
])
}
///|
pub fn ParsedExpr::to_json_string(
self : ParsedExpr,
indent? : Int = 2,
) -> String {
self.to_json().stringify(indent~)
}