// Canonical JSON for the AST: the schema of docs/ast-json.md. `canonical`
// writes objects with their keys in code-unit order (MoonBit's `Map` keeps
// insertion order and its `String` compare is length-first, so neither is
// used). The Rust oracle (tools/gleam-ast-oracle) writes the same bytes.
///|
/// An object; `canonical` sorts the keys when it writes.
fn obj(fields : Array[(String, Json)]) -> Json {
Json::object(Map::from_array(fields))
}
///|
fn num(n : Int32) -> Json {
Json::number(n.to_double())
}
///|
/// A `u64` of the compiler, written with its exact digits (a `Double`
/// alone loses precision above 2^53).
fn num64(u : UInt64) -> Json {
Json::number(u.to_double(), repr=u.to_string())
}
///|
fn str(s : String) -> Json {
Json::string(s)
}
///|
fn[T] opt(o : T?, f : (T) -> Json) -> Json {
match o {
Some(v) => f(v)
None => Json::null()
}
}
///|
fn[T] list(xs : ArrayView[T], f : (T) -> Json) -> Json {
Json::array(xs.iter().map(f).collect())
}
///|
/// The canonical text of an encoded value: keys in sorted (byte) order at
/// every level, no whitespace, serde_json's string escaping (`\"`, `\\`,
/// `\b`, `\f`, `\n`, `\r`, `\t`, other controls as `\u00xx`, everything
/// else raw). Map order is not relied on.
pub fn canonical(json : Json) -> String {
let sb = StringBuilder()
write_canonical(sb, json)
sb.to_string()
}
///|
fn write_canonical(sb : StringBuilder, json : Json) -> Unit {
match json {
Null => sb.write_string("null")
True => sb.write_string("true")
False => sb.write_string("false")
Number(d, repr~) =>
// Byte offsets and small values fit a Double; a `u64` carries its
// exact digits in `repr`.
if repr is Some(digits) {
sb.write_string(digits)
} else if d == d.floor() && d.abs() < 9007199254740992.0 {
sb.write_string(d.to_int64().to_string())
} else {
sb.write_string(d.to_string())
}
String(s) => write_json_string(sb, s)
Array(items) => {
sb.write_char('[')
for i, item in items {
if i > 0 {
sb.write_char(',')
}
write_canonical(sb, item)
}
sb.write_char(']')
}
Object(m) => {
let keys = m.keys().collect()
keys.sort_by(byte_order)
sb.write_char('{')
for i, key in keys {
if i > 0 {
sb.write_char(',')
}
write_json_string(sb, key)
sb.write_char(':')
write_canonical(sb, m.get(key).unwrap())
}
sb.write_char('}')
}
}
}
///|
/// Keys compared code unit by code unit, as serde_json's `BTreeMap`
/// compares bytes (the keys are ASCII). MoonBit's `String` `Compare`
/// orders by length first, so it is not used.
fn byte_order(a : String, b : String) -> Int32 {
let n = if a.length() < b.length() { a.length() } else { b.length() }
for i = 0; i < n; i = i + 1 {
let d = a.code_unit_at(i).to_int() - b.code_unit_at(i).to_int()
if d != 0 {
return d
}
}
a.length() - b.length()
}
///|
fn write_json_string(sb : StringBuilder, s : String) -> Unit {
let hex = "0123456789abcdef"
sb.write_char('"')
for i = 0; i < s.length(); i = i + 1 {
let c = s.code_unit_at(i).to_int()
if c == '"'.to_int() {
sb.write_string("\\\"")
} else if c == '\\'.to_int() {
sb.write_string("\\\\")
} else if c == 0x08 {
sb.write_string("\\b")
} else if c == 0x0C {
sb.write_string("\\f")
} else if c == 0x0A {
sb.write_string("\\n")
} else if c == 0x0D {
sb.write_string("\\r")
} else if c == 0x09 {
sb.write_string("\\t")
} else if c < 0x20 {
sb.write_string("\\u00")
sb.write_char(hex.code_unit_at(c / 16).to_int().unsafe_to_char())
sb.write_char(hex.code_unit_at(c % 16).to_int().unsafe_to_char())
} else {
sb.write_char(c.unsafe_to_char())
}
}
sb.write_char('"')
}
///|
pub fn encode_span(s : @span.SrcSpan) -> Json {
obj([("start", num(s.start)), ("end", num(s.end))])
}
///|
fn spanned_string(s : SpannedString) -> Json {
obj([("location", encode_span(s.location)), ("name", str(s.name))])
}
///|
fn documentation(d : Documentation) -> Json {
obj([("start", num(d.start)), ("text", str(d.text))])
}
///|
fn external(e : External) -> Json {
obj([
("module", str(e.module_)),
("function", str(e.function)),
("location", encode_span(e.location)),
])
}
///|
pub fn encode_publicity(p : Publicity) -> Json {
match p {
Public => obj([("kind", str("public"))])
Private => obj([("kind", str("private"))])
Internal(attribute_location~) =>
obj([
("kind", str("internal")),
("attribute_location", opt(attribute_location, encode_span)),
])
}
}
///|
fn deprecation(d : Deprecation) -> Json {
match d {
NotDeprecated => obj([("kind", str("not_deprecated"))])
Deprecated(message~) =>
obj([("kind", str("deprecated")), ("message", str(message))])
}
}
///|
fn assign_name(a : AssignName) -> Json {
match a {
Variable(name) => obj([("kind", str("variable")), ("name", str(name))])
Discard(name) => obj([("kind", str("discard")), ("name", str(name))])
}
}
///|
pub fn encode_parsed(p : Parsed) -> Json {
obj([
("module", encode_module(p.module_)),
("extra", encode_extra(p.extra)),
("warnings", list(p.warnings, encode_warning)),
])
}
///|
pub fn encode_module(m : Module) -> Json {
obj([("definitions", list(m.definitions, encode_targeted_definition))])
}
///|
pub fn encode_targeted_definition(d : TargetedDefinition) -> Json {
obj([
("definition", encode_definition(d.definition)),
("target", opt(d.target, t => str(t.name()))),
])
}
///|
pub fn encode_definition(d : Definition) -> Json {
match d {
Function(f) => encode_function(f, "function")
TypeAlias(t) =>
obj([
("kind", str("type_alias")),
("location", encode_span(t.location)),
("alias", str(t.alias_)),
("name_location", encode_span(t.name_location)),
("parameters", list(t.parameters, spanned_string)),
("type_ast", encode_type_ast(t.type_ast)),
("publicity", encode_publicity(t.publicity)),
("documentation", opt(t.documentation, documentation)),
("deprecation", deprecation(t.deprecation)),
])
CustomType(c) =>
obj([
("kind", str("custom_type")),
("location", encode_span(c.location)),
("end_position", num(c.end_position)),
("name", str(c.name)),
("name_location", encode_span(c.name_location)),
("publicity", encode_publicity(c.publicity)),
("constructors", list(c.constructors, record_constructor)),
("documentation", opt(c.documentation, documentation)),
("deprecation", deprecation(c.deprecation)),
("opaque", Json::boolean(c.opaque_)),
("parameters", list(c.parameters, spanned_string)),
("external_erlang", opt(c.external_erlang, external)),
("external_javascript", opt(c.external_javascript, external)),
])
Import(i) =>
obj([
("kind", str("import")),
("documentation", opt(i.documentation, str)),
("location", encode_span(i.location)),
("module_location", encode_span(i.module_location)),
("module", str(i.module_)),
(
"as_name",
opt(i.as_name, a => {
obj([
("name", assign_name(a.name)),
("location", encode_span(a.location)),
])
}),
),
("unqualified_values", list(i.unqualified_values, unqualified_import)),
("unqualified_types", list(i.unqualified_types, unqualified_import)),
])
ModuleConstant(c) =>
obj([
("kind", str("module_constant")),
("documentation", opt(c.documentation, documentation)),
("location", encode_span(c.location)),
("publicity", encode_publicity(c.publicity)),
("name", str(c.name)),
("name_location", encode_span(c.name_location)),
("annotation", opt(c.annotation, encode_type_ast)),
("value", encode_constant(c.value)),
("deprecation", deprecation(c.deprecation)),
])
}
}
///|
fn encode_function(f : Function, kind : String) -> Json {
obj([
("kind", str(kind)),
("location", encode_span(f.location)),
("body_start", opt(f.body_start, num)),
("end_position", num(f.end_position)),
("name", opt(f.name, spanned_string)),
("arguments", list(f.arguments, arg)),
("body", list(f.body, encode_statement)),
("publicity", encode_publicity(f.publicity)),
("deprecation", deprecation(f.deprecation)),
("return_annotation", opt(f.return_annotation, encode_type_ast)),
("documentation", opt(f.documentation, documentation)),
("external_erlang", opt(f.external_erlang, external)),
("external_javascript", opt(f.external_javascript, external)),
])
}
///|
fn unqualified_import(u : UnqualifiedImport) -> Json {
obj([
("location", encode_span(u.location)),
("name", str(u.name)),
("name_position", num(u.name_position)),
("as_name", opt(u.as_name, str)),
])
}
///|
fn record_constructor(r : RecordConstructor) -> Json {
obj([
("location", encode_span(r.location)),
("name_location", encode_span(r.name_location)),
("name", str(r.name)),
("arguments", list(r.arguments, record_constructor_arg)),
("documentation", opt(r.documentation, documentation)),
("deprecation", deprecation(r.deprecation)),
])
}
///|
fn record_constructor_arg(a : RecordConstructorArg) -> Json {
obj([
("label", opt(a.label, spanned_string)),
("ast", encode_type_ast(a.ast)),
("location", encode_span(a.location)),
("doc", opt(a.doc, documentation)),
])
}
///|
fn arg(a : Arg) -> Json {
obj([
("names", arg_names(a.names)),
("location", encode_span(a.location)),
("annotation", opt(a.annotation, encode_type_ast)),
])
}
///|
fn arg_names(n : ArgNames) -> Json {
match n {
Discard(name~, location~) =>
obj([
("kind", str("discard")),
("name", str(name)),
("location", encode_span(location)),
])
LabelledDiscard(label~, label_location~, name~, name_location~) =>
obj([
("kind", str("labelled_discard")),
("label", str(label)),
("label_location", encode_span(label_location)),
("name", str(name)),
("name_location", encode_span(name_location)),
])
Named(name~, location~) =>
obj([
("kind", str("named")),
("name", str(name)),
("location", encode_span(location)),
])
NamedLabelled(label~, label_location~, name~, name_location~) =>
obj([
("kind", str("named_labelled")),
("label", str(label)),
("label_location", encode_span(label_location)),
("name", str(name)),
("name_location", encode_span(name_location)),
])
}
}
///|
pub fn encode_type_ast(t : TypeAst) -> Json {
match t {
Constructor(c) =>
obj([
("kind", str("constructor")),
("location", encode_span(c.location)),
("name", type_ast_constructor_name(c.name)),
("arguments", list(c.arguments, encode_type_ast)),
("start_parentheses", opt(c.start_parentheses, num)),
])
Fn(f) =>
obj([
("kind", str("fn")),
("location", encode_span(f.location)),
("arguments", list(f.arguments, encode_type_ast)),
("return_", encode_type_ast(f.return_)),
])
Var(v) =>
obj([
("kind", str("var")),
("location", encode_span(v.location)),
("name", str(v.name)),
])
Tuple(t) =>
obj([
("kind", str("tuple")),
("location", encode_span(t.location)),
("elements", list(t.elements, encode_type_ast)),
])
Hole(h) =>
obj([
("kind", str("hole")),
("location", encode_span(h.location)),
("name", str(h.name)),
])
}
}
///|
fn type_ast_constructor_name(n : TypeAstConstructorName) -> Json {
match n {
Qualified(module_~, module_location~, dot_location~, name~) =>
obj([
("kind", str("qualified")),
("module", str(module_)),
("module_location", encode_span(module_location)),
("dot_location", num(dot_location)),
("name", opt(name, spanned_string)),
])
Unqualified(name~, location~) =>
obj([
("kind", str("unqualified")),
("name", str(name)),
("location", encode_span(location)),
])
}
}
///|
pub fn encode_statement(s : Statement) -> Json {
match s {
Expression(e) =>
obj([("kind", str("expression")), ("expression", encode_expr(e))])
Assignment(a) =>
obj([
("kind", str("assignment")),
("location", encode_span(a.location)),
("value", encode_expr(a.value)),
("pattern", encode_pattern(a.pattern)),
("assignment_kind", assignment_kind(a.kind)),
("annotation", opt(a.annotation, encode_type_ast)),
])
Use(u) =>
obj([
("kind", str("use")),
("call", encode_expr(u.call)),
("location", encode_span(u.location)),
("right_hand_side_location", encode_span(u.right_hand_side_location)),
("assignments_location", encode_span(u.assignments_location)),
("assignments", list(u.assignments, use_assignment)),
])
Assert(a) =>
obj([
("kind", str("assert")),
("location", encode_span(a.location)),
("value", encode_expr(a.value)),
("message", opt(a.message, encode_expr)),
])
}
}
///|
/// `Assignment.kind` is written under `assignment_kind`, because `kind`
/// names the statement.
fn assignment_kind(k : AssignmentKind) -> Json {
match k {
Let => obj([("kind", str("let"))])
Generated => obj([("kind", str("generated"))])
Assert(location~, assert_keyword_start~, message~) =>
obj([
("kind", str("assert")),
("location", encode_span(location)),
("assert_keyword_start", num(assert_keyword_start)),
("message", opt(message, encode_expr)),
])
}
}
///|
fn use_assignment(u : UseAssignment) -> Json {
obj([
("location", encode_span(u.location)),
("pattern", encode_pattern(u.pattern)),
("annotation", opt(u.annotation, encode_type_ast)),
])
}
///|
fn[A] call_arg(a : CallArg[A], f : (A) -> Json) -> Json {
obj([
("label", opt(a.label, str)),
("location", encode_span(a.location)),
("value", f(a.value)),
("implicit", opt(a.implicit, i => str(i.name()))),
])
}
///|
fn[A] record_being_updated(r : RecordBeingUpdated[A], f : (A) -> Json) -> Json {
obj([("base", f(r.base)), ("location", encode_span(r.location))])
}
///|
fn[A] record_update_arg(a : RecordUpdateArg[A], f : (A) -> Json) -> Json {
obj([
("label", str(a.label)),
("location", encode_span(a.location)),
("value", f(a.value)),
])
}
///|
fn[V] bit_array_segment(s : BitArraySegment[V], f : (V) -> Json) -> Json {
obj([
("location", encode_span(s.location)),
("value", f(s.value)),
("options", list(s.options, o => bit_array_option(o, f))),
])
}
///|
fn[V] bit_array_option(o : BitArrayOption[V], f : (V) -> Json) -> Json {
let simple = (kind : String, location : @span.SrcSpan) => {
obj([("kind", str(kind)), ("location", encode_span(location))])
}
match o {
Bytes(location~) => simple("bytes", location)
Int(location~) => simple("int", location)
Float(location~) => simple("float", location)
Bits(location~) => simple("bits", location)
Utf8(location~) => simple("utf8", location)
Utf16(location~) => simple("utf16", location)
Utf32(location~) => simple("utf32", location)
Utf8Codepoint(location~) => simple("utf8_codepoint", location)
Utf16Codepoint(location~) => simple("utf16_codepoint", location)
Utf32Codepoint(location~) => simple("utf32_codepoint", location)
Signed(location~) => simple("signed", location)
Unsigned(location~) => simple("unsigned", location)
Big(location~) => simple("big", location)
Little(location~) => simple("little", location)
Native(location~) => simple("native", location)
Size(location~, value~, short_form~) =>
obj([
("kind", str("size")),
("location", encode_span(location)),
("value", f(value)),
("short_form", Json::boolean(short_form)),
])
Unit(location~, value~) =>
obj([
("kind", str("unit")),
("location", encode_span(location)),
("value", num(value)),
])
}
}
///|
fn todo_kind(k : TodoKind) -> Json {
match k {
Keyword => obj([("kind", str("keyword"))])
EmptyFunction(function_location~) =>
obj([
("kind", str("empty_function")),
("function_location", encode_span(function_location)),
])
IncompleteUse => obj([("kind", str("incomplete_use"))])
EmptyBlock => obj([("kind", str("empty_block"))])
}
}
///|
fn function_literal_kind(k : FunctionLiteralKind) -> Json {
match k {
Capture(hole~) =>
obj([("kind", str("capture")), ("hole", encode_span(hole))])
Anonymous(head~) =>
obj([("kind", str("anonymous")), ("head", encode_span(head))])
Use(location~) =>
obj([("kind", str("use")), ("location", encode_span(location))])
}
}
///|
pub fn encode_expr(e : Expr) -> Json {
match e {
Int(location~, value~, int_value~) =>
obj([
("kind", str("int")),
("location", encode_span(location)),
("value", str(value)),
("int_value", str(int_value.to_string())),
])
Float(location~, value~, ..) =>
obj([
("kind", str("float")),
("location", encode_span(location)),
("value", str(value)),
])
String(location~, value~) =>
obj([
("kind", str("string")),
("location", encode_span(location)),
("value", str(value)),
])
Block(location~, statements~) =>
obj([
("kind", str("block")),
("location", encode_span(location)),
("statements", list(statements, encode_statement)),
])
Var(location~, name~) =>
obj([
("kind", str("var")),
("location", encode_span(location)),
("name", str(name)),
])
Fn(
location~,
kind~,
end_of_head_byte_index~,
arguments~,
body~,
return_annotation~
) =>
obj([
("kind", str("fn")),
("location", encode_span(location)),
("fn_kind", function_literal_kind(kind)),
("end_of_head_byte_index", num(end_of_head_byte_index)),
("arguments", list(arguments, arg)),
("body", list(body, encode_statement)),
("return_annotation", opt(return_annotation, encode_type_ast)),
])
List(location~, elements~, tail~) =>
obj([
("kind", str("list")),
("location", encode_span(location)),
("elements", list(elements, encode_expr)),
("tail", opt(tail, encode_expr)),
])
Call(location~, fun~, arguments~, open_parenthesis~) =>
obj([
("kind", str("call")),
("location", encode_span(location)),
("fun", encode_expr(fun)),
("arguments", list(arguments, a => call_arg(a, encode_expr))),
("open_parenthesis", num(open_parenthesis)),
])
BinOp(location~, operator~, operator_start~, left~, right~) =>
obj([
("kind", str("bin_op")),
("location", encode_span(location)),
("operator", str(operator.name())),
("operator_start", num(operator_start)),
("left", encode_expr(left)),
("right", encode_expr(right)),
])
Pipeline(expressions~) =>
obj([
("kind", str("pipeline")),
("expressions", list(expressions, encode_expr)),
])
Case(location~, subjects~, clauses~) =>
obj([
("kind", str("case")),
("location", encode_span(location)),
("subjects", list(subjects, encode_expr)),
("clauses", opt(clauses, cs => list(cs, clause))),
])
FieldAccess(location~, label_location~, label~, container~) =>
obj([
("kind", str("field_access")),
("location", encode_span(location)),
("label_location", encode_span(label_location)),
("label", str(label)),
("container", encode_expr(container)),
])
Tuple(location~, elements~) =>
obj([
("kind", str("tuple")),
("location", encode_span(location)),
("elements", list(elements, encode_expr)),
])
TupleIndex(location~, index~, tuple~) =>
obj([
("kind", str("tuple_index")),
("location", encode_span(location)),
("index", num64(index)),
("tuple", encode_expr(tuple)),
])
Todo(kind~, location~, message~) =>
obj([
("kind", str("todo")),
("todo_kind", todo_kind(kind)),
("location", encode_span(location)),
("message", opt(message, encode_expr)),
])
Panic(location~, message~) =>
obj([
("kind", str("panic")),
("location", encode_span(location)),
("message", opt(message, encode_expr)),
])
Echo(location~, keyword_end~, expression~, message~) =>
obj([
("kind", str("echo")),
("location", encode_span(location)),
("keyword_end", num(keyword_end)),
("expression", opt(expression, encode_expr)),
("message", opt(message, encode_expr)),
])
BitArray(location~, segments~) =>
obj([
("kind", str("bit_array")),
("location", encode_span(location)),
("segments", list(segments, s => bit_array_segment(s, encode_expr))),
])
RecordUpdate(location~, spread_start~, constructor_~, record~, arguments~) =>
obj([
("kind", str("record_update")),
("location", encode_span(location)),
("spread_start", num(spread_start)),
("constructor", encode_expr(constructor_)),
("record", record_being_updated(record, encode_expr)),
("arguments", list(arguments, a => record_update_arg(a, encode_expr))),
])
NegateBool(location~, value~) =>
obj([
("kind", str("negate_bool")),
("location", encode_span(location)),
("value", encode_expr(value)),
])
NegateInt(location~, value~) =>
obj([
("kind", str("negate_int")),
("location", encode_span(location)),
("value", encode_expr(value)),
])
}
}
///|
fn clause(c : Clause) -> Json {
obj([
("location", encode_span(c.location)),
("pattern", list(c.pattern, encode_pattern)),
(
"alternative_patterns",
list(c.alternative_patterns, ps => list(ps, encode_pattern)),
),
("guard", opt(c.guard_, encode_clause_guard)),
("then", encode_expr(c.then)),
])
}
///|
pub fn encode_clause_guard(g : ClauseGuard) -> Json {
match g {
Block(location~, value~) =>
obj([
("kind", str("block")),
("location", encode_span(location)),
("value", encode_clause_guard(value)),
])
BinaryOperator(location~, operator~, operator_start~, left~, right~) =>
obj([
("kind", str("binary_operator")),
("location", encode_span(location)),
("operator", str(operator.name())),
("operator_start", num(operator_start)),
("left", encode_clause_guard(left)),
("right", encode_clause_guard(right)),
])
Not(location~, expression~) =>
obj([
("kind", str("not")),
("location", encode_span(location)),
("expression", encode_clause_guard(expression)),
])
Var(location~, name~) =>
obj([
("kind", str("var")),
("location", encode_span(location)),
("name", str(name)),
])
TupleIndex(location~, index~, tuple~) =>
obj([
("kind", str("tuple_index")),
("location", encode_span(location)),
("index", num64(index)),
("tuple", encode_clause_guard(tuple)),
])
FieldAccess(label_location~, index~, label~, container~) =>
obj([
("kind", str("field_access")),
("label_location", encode_span(label_location)),
("index", opt(index, num64)),
("label", str(label)),
("container", encode_clause_guard(container)),
])
Constant(c) =>
obj([("kind", str("constant")), ("constant", encode_constant(c))])
}
}
///|
pub fn encode_pattern(p : Pattern) -> Json {
match p {
Int(location~, value~, int_value~) =>
obj([
("kind", str("int")),
("location", encode_span(location)),
("value", str(value)),
("int_value", str(int_value.to_string())),
])
Float(location~, value~, ..) =>
obj([
("kind", str("float")),
("location", encode_span(location)),
("value", str(value)),
])
String(location~, value~) =>
obj([
("kind", str("string")),
("location", encode_span(location)),
("value", str(value)),
])
Variable(location~, name~) =>
obj([
("kind", str("variable")),
("location", encode_span(location)),
("name", str(name)),
])
BitArraySize(s) =>
obj([("kind", str("bit_array_size")), ("size", bit_array_size(s))])
Assign(name~, location~, pattern~) =>
obj([
("kind", str("assign")),
("name", str(name)),
("location", encode_span(location)),
("pattern", encode_pattern(pattern)),
])
Discard(name~, location~) =>
obj([
("kind", str("discard")),
("name", str(name)),
("location", encode_span(location)),
])
List(location~, elements~, tail~) =>
obj([
("kind", str("list")),
("location", encode_span(location)),
("elements", list(elements, encode_pattern)),
(
"tail",
opt(tail, t => {
obj([
("location", encode_span(t.location)),
("pattern", encode_pattern(t.pattern)),
])
}),
),
])
Constructor(location~, name_location~, name~, arguments~, module_~, spread~) =>
obj([
("kind", str("constructor")),
("location", encode_span(location)),
("name_location", encode_span(name_location)),
("name", str(name)),
("arguments", list(arguments, a => call_arg(a, encode_pattern))),
("module", opt(module_, spanned_string)),
("spread", opt(spread, encode_span)),
])
Tuple(location~, elements~) =>
obj([
("kind", str("tuple")),
("location", encode_span(location)),
("elements", list(elements, encode_pattern)),
])
BitArray(location~, segments~) =>
obj([
("kind", str("bit_array")),
("location", encode_span(location)),
("segments", list(segments, s => bit_array_segment(s, encode_pattern))),
])
StringPrefix(
location~,
left_location~,
left_side_assignment~,
right_location~,
left_side_string~,
right_side_assignment~
) =>
obj([
("kind", str("string_prefix")),
("location", encode_span(location)),
("left_location", encode_span(left_location)),
(
"left_side_assignment",
opt(left_side_assignment, a => {
obj([
("name", str(a.name)),
("name_start_position", num(a.name_start_position)),
("location", encode_span(a.location)),
])
}),
),
("right_location", encode_span(right_location)),
("left_side_string", str(left_side_string)),
("right_side_assignment", assign_name(right_side_assignment)),
])
}
}
///|
fn bit_array_size(s : BitArraySize) -> Json {
match s {
Int(location~, value~, int_value~) =>
obj([
("kind", str("int")),
("location", encode_span(location)),
("value", str(value)),
("int_value", str(int_value.to_string())),
])
Variable(location~, name~) =>
obj([
("kind", str("variable")),
("location", encode_span(location)),
("name", str(name)),
])
BinaryOperator(location~, operator~, left~, right~) =>
obj([
("kind", str("binary_operator")),
("location", encode_span(location)),
("operator", str(operator.name())),
("left", bit_array_size(left)),
("right", bit_array_size(right)),
])
Block(location~, inner~) =>
obj([
("kind", str("block")),
("location", encode_span(location)),
("inner", bit_array_size(inner)),
])
}
}
///|
pub fn encode_constant(c : Constant) -> Json {
match c {
Int(location~, value~, int_value~) =>
obj([
("kind", str("int")),
("location", encode_span(location)),
("value", str(value)),
("int_value", str(int_value.to_string())),
])
Float(location~, value~, ..) =>
obj([
("kind", str("float")),
("location", encode_span(location)),
("value", str(value)),
])
String(location~, value~) =>
obj([
("kind", str("string")),
("location", encode_span(location)),
("value", str(value)),
])
Tuple(location~, elements~) =>
obj([
("kind", str("tuple")),
("location", encode_span(location)),
("elements", list(elements, encode_constant)),
])
List(location~, elements~, tail~) =>
obj([
("kind", str("list")),
("location", encode_span(location)),
("elements", list(elements, encode_constant)),
("tail", opt(tail, encode_constant)),
])
Record(location~, arguments_start_position~, module_~, name~, arguments~) =>
obj([
("kind", str("record")),
("location", encode_span(location)),
("arguments_start_position", num(arguments_start_position)),
("module", opt(module_, spanned_string)),
("name", str(name)),
(
"arguments",
opt(arguments, xs => list(xs, a => call_arg(a, encode_constant))),
),
])
RecordUpdate(
location~,
constructor_location~,
module_~,
name~,
record~,
arguments~
) =>
obj([
("kind", str("record_update")),
("location", encode_span(location)),
("constructor_location", encode_span(constructor_location)),
("module", opt(module_, spanned_string)),
("name", str(name)),
("record", record_being_updated(record, encode_constant)),
(
"arguments",
list(arguments, a => record_update_arg(a, encode_constant)),
),
])
BitArray(location~, segments~) =>
obj([
("kind", str("bit_array")),
("location", encode_span(location)),
("segments", list(segments, s => bit_array_segment(s, encode_constant))),
])
Var(location~, module_~, name~) =>
obj([
("kind", str("var")),
("location", encode_span(location)),
("module", opt(module_, spanned_string)),
("name", str(name)),
])
BinaryOperator(location~, operator_start~, operator~, left~, right~) =>
obj([
("kind", str("binary_operator")),
("location", encode_span(location)),
("operator_start", num(operator_start)),
("operator", str(operator.name())),
("left", encode_constant(left)),
("right", encode_constant(right)),
])
Todo(location~, message~) =>
obj([
("kind", str("todo")),
("location", encode_span(location)),
("message", opt(message, encode_constant)),
])
}
}
///|
pub fn encode_extra(x : ModuleExtra) -> Json {
obj([
("module_comments", list(x.module_comments, encode_span)),
("doc_comments", list(x.doc_comments, encode_span)),
("comments", list(x.comments, encode_span)),
("empty_lines", list(x.empty_lines, num)),
("new_lines", list(x.new_lines, num)),
("trailing_commas", list(x.trailing_commas, num)),
])
}
///|
pub fn encode_warning(w : Warning) -> Json {
let simple = (kind : String, location : @span.SrcSpan) => {
obj([("kind", str(kind)), ("location", encode_span(location))])
}
match w {
DeprecatedListPrepend(location~) =>
simple("deprecated_list_prepend", location)
DeprecatedListPattern(location~) =>
simple("deprecated_list_pattern", location)
DeprecatedListCatchAllPattern(location~) =>
simple("deprecated_list_catch_all_pattern", location)
DeprecatedListSpreadAsVariablePattern(location~, name~) =>
obj([
("kind", str("deprecated_list_spread_as_variable_pattern")),
("location", encode_span(location)),
("name", str(name)),
])
DeprecatedRecordSpreadPattern(location~) =>
simple("deprecated_record_spread_pattern", location)
DeprecatedEmptyClauseGuard(location~) =>
simple("deprecated_empty_clause_guard", location)
DeprecatedTargetShorthand(target~, location~) =>
obj([
("kind", str("deprecated_target_shorthand")),
("target", str(target.name())),
("location", encode_span(location)),
])
DetachedDocComment(location~) => simple("detached_doc_comment", location)
}
}