// Portions adapted from google/go-jsonnet v0.21.0 (Apache-2.0).
// https://github.com/google/go-jsonnet/tree/67968688d9952f50662e979fab1bef889d0d3e57
// Source: internal/parser/lexer.go
// Copyright 2016 Google Inc. All rights reserved.
// Modifications: Adapted token classification, numeric scanning and errors to MoonBit source spans.
// License and retained attribution: LICENSE and NOTICE at the module root.
// Diagnostic token names and rendering follow the pinned Go parser/lexer.
// Copyright Google Inc.; Apache-2.0; see NOTICE.
///|
fn operator_char(c : Char) -> Bool {
match c {
'!'
| '$'
| ':'
| '~'
| '+'
| '-'
| '&'
| '|'
| '^'
| '='
| '<'
| '>'
| '*'
| '/'
| '%' => true
_ => false
}
}
///|
fn Token::literal_kind(self : Token) -> ExprKind raise JsonnetError {
match self.value.unwrap() {
String(raw) if self.text == "" && !self.raw.has_prefix("@") => {
let decoded = unescape_literal(raw, self.loc) catch {
Error(d) => {
let range : SourceRange = { begin: self.loc, end: self.end, }
raise problem(Syntax, self.loc, range.format() + " " + d.message)
}
}
Literal(Json::string(decoded))
}
value => Literal(value)
}
}
///|
fn Token::is_operator(self : Token) -> Bool {
self.value is None &&
self.text != "" &&
self.text != "" &&
self.text != "$" &&
self.text.to_array().get(0) is Some(c) &&
operator_char(c)
}
///|
fn token_kind_name(text : String) -> String {
match text {
"" => "end of file"
"(" | ")" | "[" | "]" | "{" | "}" | "," | ";" | "." | "$" =>
"\"" + text + "\""
_ => text
}
}
///|
fn Token::describe(self : Token) -> String {
if self.text == "" {
return "end of file"
}
let (kind, data) = if self.text == "" {
("NUMBER", self.raw)
} else if self.text == "" {
(
"STRING_BLOCK",
match self.value {
Some(String(s)) => s
_ => ""
},
)
} else if self.text == "" {
let verbatim = self.raw.has_prefix("@")
let single = self.raw.has_prefix("'") || self.raw.has_prefix("@'")
let kind = (if verbatim { "VERBATIM_STRING_" } else { "STRING_" }) +
(if single { "SINGLE" } else { "DOUBLE" })
let data = if verbatim {
match self.value {
Some(String(s)) => s
_ => ""
}
} else {
self.raw[1:self.raw.length() - 1].to_owned()
}
(kind, data)
} else if is_name(self.text) {
("IDENTIFIER", self.text)
} else if self.is_operator() {
("OPERATOR", self.text)
} else {
return "\"" + self.text + "\""
}
if data.is_empty() {
kind
} else {
"(" + kind + ", \"" + data + "\")"
}
}
///|
fn Parser::end_list(
self : Parser,
close : String,
element : String,
describe? : Bool = true,
) -> Unit raise JsonnetError {
if !self.eat(close) {
raise problem(
Syntax,
self.peek().loc,
"Expected a comma before next " +
element +
(if describe { ", got " + self.peek().describe() } else { "" }),
)
}
}