///|
/// Source location. Lines and UTF-8 byte columns are one-based, matching Go.
pub(all) struct Location {
file : String
line : Int
column : Int
} derive(Debug, Eq)
///|
pub(all) enum ErrorKind {
Syntax
Static
Type
Runtime
Assertion
Import
Limit
Unsupported
} derive(Debug, Eq)
///|
pub(all) struct Diagnostic {
kind : ErrorKind
message : String
location : Location
context : Array[Location]
trace : Array[TraceFrame]
} derive(Debug)
///|
pub(all) suberror JsonnetError {
Error(Diagnostic)
} derive(Debug)
///|
pub impl Show for Diagnostic with fn output(self, logger) {
logger.write_string(self.format())
}
///|
/// Render the error header and context. A positive limit keeps half the context
/// at each end (the outer end gets the odd frame); zero or negative is unlimited.
/// The primary location stays in the header and the stored context is unchanged.
///
/// ```mbt check
/// test {
/// 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 fn Diagnostic::format(self : Diagnostic, max_trace? : Int = 0) -> String {
let logger = StringBuilder()
logger.write_string(
"\{self.location.file}:\{self.location.line}:\{self.location.column}: \{Repr(self.kind)}: \{self.message}",
)
let write = fn(loc : Location) {
logger.write_string("\n at \{loc.file}:\{loc.line}:\{loc.column}")
}
let size = self.context.length()
if max_trace > 0 && size > max_trace {
let above = max_trace / 2
let below = max_trace - above
for loc in self.context[:above] {
write(loc)
}
logger.write_string("\n ...")
for loc in self.context[size - below:] {
write(loc)
}
} else {
for loc in self.context {
write(loc)
}
}
logger.to_string()
}
///|
/// A host import response. `id` must be a stable canonical identity.
pub(all) struct Source {
id : String
text : String
} derive(Debug)
///|
/// Raw import response. Binary data is never decoded as UTF-8.
pub(all) struct BinarySource {
id : String
bytes : Bytes
} derive(Debug)
///|
pub extend BinarySource with @debug.Debug::{to_repr}
///|
/// Limits are per evaluation. Byte limits count UTF-8; all must be positive.
/// `stack` counts runtime frames independently of the syntax/evaluation `depth`.
///
/// ```mbt check
/// test {
/// let limits = { ..@moonjsonnet.Limits::default(), stack: 2, }
/// assert_eq(@moonjsonnet.evaluate("local x=42; x", limits~), 42)
/// }
/// ```
pub(all) struct Limits {
steps : Int
depth : Int
stack : Int
source_bytes : Int
import_bytes : Int
imports : Int
output_bytes : Int
} derive(Debug)
///|
pub fn Limits::default() -> Limits {
{
steps: 1000000,
depth: 200,
stack: 500,
source_bytes: 1048576,
import_bytes: 4194304,
imports: 128,
output_bytes: 4194304,
}
}
///|
fn problem(kind : ErrorKind, loc : Location, message : String) -> JsonnetError {
Error({ kind, message, location: loc, context: [], trace: [], })
}
///|
pub extend Location with @debug.Debug::{to_repr}
///|
pub extend Location with Eq::{equal, not_equal}
///|
pub extend ErrorKind with @debug.Debug::{to_repr}
///|
pub extend ErrorKind with Eq::{equal, not_equal}
///|
pub extend Diagnostic with @debug.Debug::{to_repr}
///|
pub extend Diagnostic with Show::{output, to_string}
///|
pub extend JsonnetError with @debug.Debug::{to_repr}
///|
pub extend Source with @debug.Debug::{to_repr}
///|
pub extend Limits with @debug.Debug::{to_repr}
///|
priv struct Expr {
kind : ExprKind
loc : Location
end : Location?
}
///|
priv struct ExprBinding {
name : String
value : Expr
range : SourceRange?
}
///|
priv struct ExprParameter {
name : String
default_value : Expr?
range : SourceRange?
}
///|
priv enum ExprKind {
NumberLiteral(String)
Literal(Json)
Var(String)
Local(Array[ExprBinding], Expr)
If(Expr, Expr, Expr)
Func(Array[ExprParameter], Expr)
Call(Expr, Array[(String?, Expr)], Bool)
Arr(Array[Expr])
Obj(
Array[Field],
Array[ExprBinding],
Array[(Expr, Expr?)],
Array[SourceRange?]
)
ArrayComp(Expr, Array[Clause])
ObjectComp(Expr, Expr, Array[Clause], Array[ExprBinding])
Index(Expr, Expr)
Slice(Expr, Expr?, Expr?, Expr?)
Unary(String, Expr)
Binary(String, Expr, Expr)
Assert(Expr, Expr?, Expr)
Fail(Expr)
ImportFile(String, Bool)
ImportBinary(String)
StandardFunction(String)
StandardValue(Json)
}
///|
priv struct Field {
key : Expr
value : Expr
visibility : Int
additive : Bool
}
///|
priv enum Clause {
For(String, Expr)
When(Expr)
}