///|
/// `use a, b <- call`, with `use` consumed.
fn Parser::parse_use(
self : Parser,
start : Int32,
end : Int32,
) -> @ast.Statement raise ParseError {
let assignments : Array[@ast.UseAssignment] = if self.token0
is Some({ kind: LArrow, .. }) {
[]
} else {
self.series_of(p => p.parse_use_assignment(), Some(Comma))
}
let _ = self.expect_one_following_series(LArrow, "a use variable assignment")
let call = self.expect_expression()
let assignments_location = if assignments.length() > 0 {
sp(
assignments[0].location.start,
assignments[assignments.length() - 1].location.end,
)
} else {
sp(start, end)
}
Use({
location: sp(start, call.location().end),
assignments_location,
right_hand_side_location: call.location(),
assignments: assignments[:],
call,
})
}
///|
fn Parser::parse_use_assignment(
self : Parser,
) -> @ast.UseAssignment? raise ParseError {
let start = match self.token0 {
Some(t) => t.span.start
None => 0
}
let pattern = match self.parse_pattern() {
Some(p) => p
None => parse_error(ExpectedPattern, sp(start, start))
}
let annotation = self.parse_type_annotation(Colon)
let end = match annotation {
Some(a) => a.location().end
None => pattern.location().end
}
Some({ location: sp(start, end), pattern, annotation, })
}
///|
/// `let` (`assert`)? pattern (`: T`)? `=` expr (`as` unit)?, with `let`
/// consumed.
fn Parser::parse_assignment(
self : Parser,
start : Int32,
) -> @ast.Statement raise ParseError {
let mut kind : @ast.AssignmentKind = match self.token0 {
Some({ kind: Keyword(Assert), span, .. }) => {
self.advance()
Assert(
location=sp(start, span.end),
assert_keyword_start=span.start,
message=None,
)
}
_ => Let
}
let pattern = match self.parse_pattern() {
Some(p) => p
None => self.next_token_unexpected(["A pattern"])
}
let annotation = self.parse_type_annotation(Colon)
let (eq_s, eq_e) = match self.maybe_one(Equal) {
Some(r) => r
None => parse_error(ExpectedEqual, pattern.location())
}
let value = match self.parse_expression_inner(true) {
Some(v) => v
None =>
match self.token0 {
Some({ kind: DiscardName(_), span, .. }) =>
parse_error(IncorrectName(Variable), span)
_ => parse_error(ExpectedValue, sp(eq_s, eq_e))
}
}
let mut end = value.location().end
if kind is Assert(location~, assert_keyword_start~, ..) {
if self.maybe_one(Keyword(As)) is Some(_) {
let message = self.expect_expression_unit(Other)
end = message.location().end
kind = Assert(location~, assert_keyword_start~, message=Some(message))
}
}
Assignment({ location: sp(start, end), value, pattern, kind, annotation, })
}
///|
/// `assert expr (as unit)?`, with `assert` consumed.
fn Parser::parse_assert(
self : Parser,
start : Int32,
) -> @ast.Statement raise ParseError {
let value = self.expect_expression()
let mut end = value.location().end
let message = if self.maybe_one(Keyword(As)) is Some(_) {
let m = self.expect_expression_unit(Other)
end = m.location().end
Some(m)
} else {
None
}
Assert({ location: sp(start, end), value, message, })
}
///|
/// One or more statements; `None` when there is none. Also the end of the
/// last one.
fn Parser::parse_statement_sequence(
self : Parser,
) -> (Array[@ast.Statement], Int32)? raise ParseError {
let statements : Array[@ast.Statement] = []
let mut end = 0
while self.parse_statement() is Some(statement) {
end = statement.location().end
statements.push(statement)
}
if statements.length() == 0 {
None
} else {
Some((statements, end))
}
}
///|
fn Parser::parse_statement(self : Parser) -> @ast.Statement? raise ParseError {
match self.token0 {
Some({ kind: Keyword(Use), span, .. }) => {
self.advance()
Some(self.parse_use(span.start, span.end))
}
Some({ kind: Keyword(Let), span, .. }) => {
self.advance()
Some(self.parse_assignment(span.start))
}
Some({ kind: Keyword(Assert), span, .. }) => {
self.advance()
Some(self.parse_assert(span.start))
}
// A constant inside a function
Some({ kind: Keyword(Const), span, .. }) =>
parse_error(ConstantInsideFunction, span)
_ => {
self.parse_statement_errors()
self.parse_expression().map(e => @ast.Statement::Expression(e))
}
}
}
///|
/// A name followed by `=` or `:` needs `let`.
fn Parser::parse_statement_errors(self : Parser) -> Unit raise ParseError {
if self.token0 is Some({ kind: Name(_), .. }) {
if self.token1 is Some({ kind: Equal | Colon, span, .. }) {
parse_error(NoLetBinding, span)
}
}
}
///|
/// `{ statements }` with `{` consumed; an empty block is a `Todo`.
fn Parser::parse_block(
self : Parser,
start : Int32,
) -> @ast.Expr raise ParseError {
let body = self.parse_statement_sequence()
let (_, end) = self.expect_one(RightBrace)
let location = sp(start, end)
let statements : Array[@ast.Statement] = match body {
Some((statements, _)) => statements
None => [Expression(Todo(kind=EmptyBlock, location~, message=None))]
}
Block(location~, statements=statements[:])
}