///|
priv struct Parser {
tokens : Array[Token]
mut idx : Int
}
///|
fn Parser::peek(self : Parser) -> Token {
self.peek_nth(0)
}
///|
fn Parser::peek_nth(self : Parser, n : Int) -> Token {
let pos = self.idx + n
if pos >= self.tokens.length() {
self.tokens[self.tokens.length() - 1]
} else {
self.tokens[pos]
}
}
///|
fn Parser::skip(self : Parser) -> Unit {
self.idx += 1
}
///|
fn Parser::parse_id(self : Parser) -> String raise ParseError {
match self.peek() {
LIdent(_, s) => {
self.skip()
s
}
other => raise UnexpectedToken(other)
}
}
///|
fn Parser::parse_string(self : Parser) -> String raise ParseError {
match self.peek() {
String(_, s) => {
self.skip()
s
}
other => raise UnexpectedToken(other)
}
}
///|
fn Parser::parse_array(self : Parser) -> Json raise ParseError {
match self.peek() {
LBracket(_) => {
let elems = self.surround_series_values(LBracket, RBracket, Comma)
Json::array(elems)
}
other => raise UnexpectedToken(other)
}
}
///|
fn Parser::surround_series_values(
self : Parser,
l : TokenKind,
r : TokenKind,
sep : TokenKind,
) -> Array[Json] raise ParseError {
if self.peek().kind() != l {
raise UnexpectedToken(self.peek())
}
self.skip() // skip l
let elems : Array[Json] = []
if self.peek().kind() != r {
while true {
let expr = self.parse_expr()
elems.push(expr)
let next = self.peek().kind()
if next == r {
break
} else if next == sep {
self.skip()
if self.peek().kind() == r {
break
}
} else {
raise UnexpectedToken(self.peek())
}
}
}
self.skip() // skip r
elems
}
///|
fn Parser::surround_series_pairs(
self : Parser,
l : TokenKind,
r : TokenKind,
sep : TokenKind,
) -> Array[(String, Json)] raise ParseError {
if self.peek().kind() != l {
raise UnexpectedToken(self.peek())
}
self.skip() // skip l
let elems : Array[(String, Json)] = []
if self.peek().kind() != r {
while true {
let pair = self.parse_map_elem()
elems.push(pair)
let next = self.peek().kind()
if next == r {
break
} else if next == sep {
self.skip()
if self.peek().kind() == r {
break
}
} else {
raise UnexpectedToken(self.peek())
}
}
}
self.skip() // skip r
elems
}
///|
fn Parser::parse_map_elem(self : Parser) -> (String, Json) raise ParseError {
let key = match self.peek() {
LIdent(_, s) => {
self.skip()
s
}
String(_, s) => {
self.skip()
s
}
other => raise UnexpectedToken(other)
}
if self.peek().kind() != Colon {
raise UnexpectedToken(self.peek())
}
self.skip() // skip ':'
let value = self.parse_expr()
(key, value)
}
///|
fn Parser::parse_map(self : Parser) -> Json raise ParseError {
let elems = self.surround_series_pairs(LBrace, RBrace, Comma)
Json::object(Map::from_iter(elems.iter()))
}
///|
fn Parser::parse_expr(self : Parser) -> Json raise ParseError {
match self.peek() {
LBracket(_) => self.parse_array()
LBrace(_) => self.parse_map()
True(_) => {
self.skip()
Json::boolean(true)
}
False(_) => {
self.skip()
Json::boolean(false)
}
String(_, s) => {
self.skip()
Json::string(s)
}
Int(_, n) => {
self.skip()
Json::number(n.to_double())
}
other => raise UnexpectedToken(other)
}
}
///|
fn Parser::parse_apply(self : Parser) -> (String, Json) raise ParseError {
let func_name = self.parse_id()
let args = self.surround_series_pairs(LParen, RParen, Comma)
(func_name, Json::object(Map::from_iter(args.iter())))
}
///|
fn Parser::parse_assign(self : Parser) -> (String, Json) raise ParseError {
let key = self.parse_id()
if self.peek().kind() != Equal {
raise UnexpectedToken(self.peek())
}
self.skip() // skip '='
let value = self.parse_expr()
(key, value)
}
///|
fn Parser::parse_import(self : Parser) -> (String, Json) raise ParseError {
self.skip() // skip 'import'
let legacy_kind : String? = match self.peek() {
String(_, "test") => {
self.skip()
Some("test-import")
}
String(_, "wbtest") => {
self.skip()
Some("wbtest-import")
}
String(_, _) => raise UnexpectedToken(self.peek())
_ => None
}
let import_items = self.parse_import_items()
let import_kind : String = match legacy_kind {
Some(kind) => kind
None =>
if self.peek().kind() == For {
self.skip()
match self.peek() {
String(_, "test") => {
self.skip()
"test-import"
}
String(_, "wbtest") => {
self.skip()
"wbtest-import"
}
_ => raise UnexpectedToken(self.peek())
}
} else {
"import"
}
}
(import_kind, Json::array(import_items))
}
///|
fn Parser::parse_import_items(self : Parser) -> Array[Json] raise ParseError {
if self.peek().kind() != LBrace {
raise UnexpectedToken(self.peek())
}
self.skip() // skip {
let items : Array[Json] = []
if self.peek().kind() != RBrace {
while true {
let path = self.parse_string()
let synonym = match self.peek() {
As(_) => {
self.skip()
match self.peek() {
PkgName(_, synonym) => {
self.skip()
Some(synonym)
}
other => raise UnexpectedToken(other)
}
}
PkgName(_, synonym) => {
self.skip()
Some(synonym)
}
_ => None
}
let item = match synonym {
None => Json::string(path)
Some(a) => { "path": path, "alias": a }
}
items.push(item)
let next = self.peek().kind()
if next == RBrace {
break
} else if next == Comma {
self.skip()
if self.peek().kind() == RBrace {
break
}
} else {
raise UnexpectedToken(self.peek())
}
}
}
self.skip() // skip }
items
}
///|
fn Parser::parse_statement(self : Parser) -> (String, Json) raise ParseError {
match self.peek() {
Import(_) => self.parse_import()
LIdent(_, _) =>
match self.peek_nth(1).kind() {
Equal => self.parse_assign()
LParen => self.parse_apply()
_ => raise UnexpectedToken(self.peek())
}
other => raise UnexpectedToken(other)
}
}
///|
fn Parser::parse_statements(self : Parser) -> Json raise ParseError {
let statements : Array[(String, Json)] = []
while self.peek().kind() != Eof {
let stmt = self.parse_statement()
statements.push(stmt)
if self.peek().kind() == Semi {
self.skip()
}
}
Json::object(Map::from_iter(statements.iter()))
}
///|
fn parse_tokens(tokens : Array[Token]) -> Json raise ParseError {
let parser : Parser = { tokens, idx: 0 }
parser.parse_statements()
}
///|
pub fn parse(input : String) -> Json raise ParseError {
let tokens = tokenize(input) catch {
LexError(loc, msg) => raise LexError(loc, msg)
UnexpectedToken(tok) => raise UnexpectedToken(tok)
}
parse_tokens(tokens)
}