///|
fn Cursor::placeable(self : Cursor) -> Node raise ParseFailure {
if self.depth >= self.max_depth {
raise ParseFailure("E9001", [])
}
self.depth += 1
errdefer {
self.depth -= 1
}
let result = {
let start = self.index
self.expect('{')
self.skip_blank()
let expr = self.expression()
self.expect('}')
Node::with_span(Placeable(expr), start, self.index)
}
self.depth -= 1
result
}
///|
fn Cursor::inline_expression(self : Cursor) -> Node raise ParseFailure {
let start = self.index
if self.current() == Some('{') {
return self.placeable()
}
if self.is_number_start() {
return self.number()
}
if self.current() == Some('"') {
return self.string_literal()
}
if self.current() == Some('$') {
ignore(self.next())
let id = self.identifier()
return Node::with_span(VariableReference(id), start, self.index)
}
if self.current() == Some('-') {
ignore(self.next())
let id = self.identifier()
let attribute = if self.current() == Some('.') {
ignore(self.next())
Some(self.identifier())
} else {
None
}
self.peek_blank()
let arguments = if self.current_peek() == Some('(') {
self.skip_to_peek()
Some(self.call_arguments())
} else {
None
}
return Node::with_span(
TermReference(id, attribute, arguments),
start,
self.index,
)
}
if is_id_start(self.current_peek()) {
let id = self.identifier()
self.peek_blank()
if self.current_peek() == Some('(') {
if !uppercase_function(identifier_name(id)) {
raise ParseFailure("E0008", [])
}
self.skip_to_peek()
let arguments = self.call_arguments()
return Node::with_span(
FunctionReference(id, arguments),
start,
self.index,
)
}
let attribute = if self.current() == Some('.') {
ignore(self.next())
Some(self.identifier())
} else {
None
}
return Node::with_span(MessageReference(id, attribute), start, self.index)
}
raise ParseFailure("E0028", [])
}
///|
fn Cursor::call_argument(self : Cursor) -> Node raise ParseFailure {
let start = self.index
let expr = self.inline_expression()
self.skip_blank()
if self.current() != Some(':') {
return expr
}
match expr.kind {
MessageReference(id, None) => {
ignore(self.next())
self.skip_blank()
let value = self.literal()
Node::with_span(NamedArgument(id, value), start, self.index)
}
_ => raise ParseFailure("E0009", [])
}
}
///|
fn Cursor::call_arguments(self : Cursor) -> Node raise ParseFailure {
if self.depth >= self.max_depth {
raise ParseFailure("E9001", [])
}
self.depth += 1
errdefer {
self.depth -= 1
}
let start = self.index
let positional : Array[Node] = []
let named : Array[Node] = []
let names : Map[String, Bool] = Map([])
self.expect('(')
self.skip_blank()
while self.current() != Some(')') {
let argument = self.call_argument()
match argument.kind {
NamedArgument(id, _) => {
let name = identifier_name(id)
if names.contains(name) {
raise ParseFailure("E0022", [])
}
names[name] = true
named.push(argument)
}
_ => {
if !names.is_empty() {
raise ParseFailure("E0021", [])
}
positional.push(argument)
}
}
self.skip_blank()
if self.current() == Some(',') {
ignore(self.next())
self.skip_blank()
continue
}
break
}
self.expect(')')
self.depth -= 1
Node::with_span(CallArguments(positional, named), start, self.index)
}
///|
fn Cursor::expression(self : Cursor) -> Node raise ParseFailure {
let start = self.index
let selector = self.inline_expression()
self.skip_blank()
if self.current() == Some('-') {
if self.peek() != Some('>') {
self.reset_peek()
return selector
}
match selector.kind {
MessageReference(_, None) => raise ParseFailure("E0016", [])
MessageReference(_, Some(_)) => raise ParseFailure("E0018", [])
TermReference(_, None, _) => raise ParseFailure("E0017", [])
TermReference(_, Some(_), _)
| StringLiteral(_)
| NumberLiteral(_)
| VariableReference(_)
| FunctionReference(_, _) => ()
_ => raise ParseFailure("E0029", [])
}
ignore(self.next())
ignore(self.next())
ignore(self.skip_blank_inline())
self.expect_line_end()
let variants = self.variants()
return Node::with_span(
SelectExpression(selector, variants),
start,
self.index,
)
}
match selector.kind {
TermReference(_, Some(_), _) => raise ParseFailure("E0019", [])
_ => selector
}
}
///|
fn Cursor::variant(
self : Cursor,
has_default : Bool,
) -> Node raise ParseFailure {
let start = self.index
let default = self.current() == Some('*')
if default {
if has_default {
raise ParseFailure("E0015", [])
}
ignore(self.next())
}
self.expect('[')
self.skip_blank()
if self.current() == None {
raise ParseFailure("E0013", [])
}
let key = if self.current() == Some('-') || is_digit(self.current()) {
self.number()
} else {
self.identifier()
}
self.skip_blank()
self.expect(']')
let value = match self.maybe_pattern() {
Some(n) => n
None => raise ParseFailure("E0012", [])
}
Node::with_span(Variant(key, value, default), start, self.index)
}
///|
fn Cursor::variants(self : Cursor) -> Array[Node] raise ParseFailure {
let variants : Array[Node] = []
let mut has_default = false
self.skip_blank()
while self.is_variant_start() {
let v = self.variant(has_default)
match v.kind {
Variant(_, _, d) => has_default = has_default || d
_ => ()
}
variants.push(v)
self.skip_blank()
}
if variants.is_empty() {
raise ParseFailure("E0011", [])
}
if !has_default {
raise ParseFailure("E0010", [])
}
variants
}