///|
using @lexer {type Token, type TokenBody}
///|
pub fn parse_tokens(tokens : Array[Token]) -> Module raise ParseError {
let scanner = Scanner::new(tokens)
parse_module(scanner)
}
///|
pub suberror ParseError {
UnexpectedToken(Token)
UnexpectedEof
}
///|
priv struct Scanner {
tokens : Array[Token]
mut cursor : Int
}
///|
fn Scanner::new(tokens : Array[Token]) -> Scanner {
Scanner::{ tokens, cursor: 0, }
}
///|
fn Scanner::empty(self : Self) -> Bool {
self.cursor >= self.tokens.length()
}
///|
fn Scanner::front(self : Self) -> Token raise ParseError {
guard !self.empty() else { raise ParseError::UnexpectedEof }
self.tokens[self.cursor]
}
///|
fn Scanner::advance(self : Self) -> Unit raise ParseError {
guard !self.empty() else { raise ParseError::UnexpectedEof }
self.cursor += 1
}
///|
fn Scanner::consume(self : Self, expected : TokenBody) -> Unit raise ParseError {
if self.front().body == expected {
self.advance()
} else {
raise ParseError::UnexpectedToken(self.front())
}
}
///|
fn parse_module(scanner : Scanner) -> Module raise ParseError {
scanner.consume(TypeId("module"))
let name = match scanner.front().body {
TypeId(id) | ConstructorId(id) => id
_ => raise ParseError::UnexpectedToken(scanner.front())
}
scanner.advance()
scanner.consume(LBrace)
let definitions : Array[Definition] = []
while !(scanner.front().body is RBrace) {
let definition = parse_definition(scanner)
definitions.push(definition)
}
scanner.advance()
guard scanner.empty() else {
raise ParseError::UnexpectedToken(scanner.front())
}
Module::{ name, definitions, }
}
///|
fn parse_definition(scanner : Scanner) -> Definition raise ParseError {
guard scanner.front().body is TypeId(name) else {
raise ParseError::UnexpectedToken(scanner.front())
}
scanner.advance()
scanner.consume(Equals)
match scanner.front().body {
LParen => {
let fields = parse_fields(scanner)
Product(name~, fields~)
}
ConstructorId(_) => {
let constructors : Array[Constructor] = []
for ;; {
let constructor_ = parse_constructor(scanner)
constructors.push(constructor_)
if scanner.front().body is Pipe {
scanner.consume(Pipe)
} else {
break
}
}
let attributes = match scanner.front().body {
TypeId("attributes") => {
scanner.advance()
parse_fields(scanner)
}
_ => []
}
Sum(name~, constructors~, attributes~)
}
_ => raise ParseError::UnexpectedToken(scanner.front())
}
}
///|
fn parse_constructor(scanner : Scanner) -> Constructor raise ParseError {
guard scanner.front().body is ConstructorId(name) else {
raise ParseError::UnexpectedToken(scanner.front())
}
scanner.advance()
let fields = match scanner.front().body {
LParen => parse_fields(scanner)
_ => []
}
Constructor::{ name, fields, }
}
///|
fn parse_fields(scanner : Scanner) -> Array[Field] raise ParseError {
scanner.consume(LParen)
let fields : Array[Field] = []
while !(scanner.front().body is RParen) {
let field = parse_field(scanner)
fields.push(field)
if scanner.front().body is Comma {
scanner.consume(Comma)
} else {
break
}
}
scanner.consume(RParen)
fields
}
///|
fn parse_field(scanner : Scanner) -> Field raise ParseError {
guard scanner.front().body is TypeId(type_) else {
raise ParseError::UnexpectedToken(scanner.front())
}
scanner.advance()
let quant = match scanner.front().body {
Question => {
scanner.advance()
Some(Optional)
}
Asterisk => {
scanner.advance()
Some(Sequence)
}
_ => None
}
let name = match scanner.front().body {
TypeId(name) | ConstructorId(name) => {
scanner.advance()
Some(name)
}
_ => None
}
Field::{ type_, quant, name, }
}