///|
pub struct Parser {
lexer : Lexer
mut current_token : Token
}
///|
pub fn Parser::new(input : String) -> Parser {
let lexer = Lexer::new(input)
let current_token = lexer.next_token()
{ lexer, current_token }
}
///|
fn Parser::advance(self : Parser) -> Unit {
self.current_token = self.lexer.next_token()
}
///|
pub fn Parser::parse(self : Parser) -> Manifest raise ParseError {
let rules : Map[String, Rule] = Map([])
let builds : Array[BuildEdge] = []
while self.current_token != Eof {
match self.current_token {
Ident(kw) =>
if kw == "rule" {
self.advance()
match self.current_token {
Ident(rule_name) => {
self.advance()
if self.current_token == Newline {
self.advance()
}
match self.current_token {
Ident(cmd_kw) =>
if cmd_kw == "command" {
self.advance()
if self.current_token == Equal {
self.advance()
let cmd = self.lexer.read_rest_of_line()
if rules.contains(rule_name) {
raise SyntaxError(
"Duplicate rule declaration",
line=self.lexer.line,
col=self.lexer.col,
)
}
rules[rule_name] = { name: rule_name, command: cmd }
self.current_token = self.lexer.next_token()
} else {
raise SyntaxError(
"Expected '=' after command",
line=self.lexer.line,
col=self.lexer.col,
)
}
} else {
raise SyntaxError(
"Expected 'command' inside rule",
line=self.lexer.line,
col=self.lexer.col,
)
}
_ =>
raise SyntaxError(
"Expected command keyword in rule",
line=self.lexer.line,
col=self.lexer.col,
)
}
}
_ =>
raise SyntaxError(
"Expected rule name after 'rule'",
line=self.lexer.line,
col=self.lexer.col,
)
}
} else if kw == "build" {
self.advance()
let outputs : Array[String] = []
while self.current_token != Colon && self.current_token != Eof {
match self.current_token {
Ident(out) => {
outputs.push(out)
self.advance()
}
_ =>
raise SyntaxError(
"Expected outputs before ':'",
line=self.lexer.line,
col=self.lexer.col,
)
}
}
if self.current_token == Colon {
self.advance()
match self.current_token {
Ident(rule_name) => {
self.advance()
let inputs : Array[String] = []
while self.current_token != Newline && self.current_token != Eof {
match self.current_token {
Ident(inp) => {
inputs.push(inp)
self.advance()
}
Pipe => self.advance()
PipePipe => self.advance()
_ =>
raise SyntaxError(
"Expected input after rule name",
line=self.lexer.line,
col=self.lexer.col,
)
}
}
builds.push({ rule: rule_name, inputs, outputs })
}
_ =>
raise SyntaxError(
"Expected rule name in build statement",
line=self.lexer.line,
col=self.lexer.col,
)
}
} else {
raise SyntaxError(
"Expected ':' in build statement",
line=self.lexer.line,
col=self.lexer.col,
)
}
} else {
raise SyntaxError(
"Unknown top-level keyword: " + kw,
line=self.lexer.line,
col=self.lexer.col,
)
}
Newline => self.advance()
Error(msg) =>
raise SyntaxError(msg, line=self.lexer.line, col=self.lexer.col)
_ =>
raise UnexpectedToken(self.current_token, expected="keyword or newline")
}
}
{ rules, builds }
}