feat(tazjin/rlox): Set up precedence parsing scaffolding
Defines a new precedence levels enum which can be used to restrict the parser precedence in any given location. As an example, unary expressions and grouping are implemented, as these have a different precedence from e.g. expression() Change-Id: I91f299fc77530f76c3aba717f638985428104ee5 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2558 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
This commit is contained in:
parent
b13a6736dd
commit
1d3d9d32e3
1 changed files with 67 additions and 12 deletions
|
@ -1,25 +1,44 @@
|
|||
use super::chunk::Chunk;
|
||||
use super::errors::{Error, ErrorKind, LoxResult};
|
||||
use super::opcode::OpCode;
|
||||
use crate::scanner;
|
||||
use super::value::Value;
|
||||
use crate::scanner::{self, Token, TokenKind};
|
||||
|
||||
struct Compiler<T: Iterator<Item = scanner::Token>> {
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
struct Compiler<T: Iterator<Item = Token>> {
|
||||
tokens: T,
|
||||
chunk: Chunk,
|
||||
panic: bool,
|
||||
errors: Vec<Error>,
|
||||
|
||||
// TODO(tazjin): Restructure so that these don't need to be Option?
|
||||
current: Option<scanner::Token>,
|
||||
previous: Option<scanner::Token>,
|
||||
current: Option<Token>,
|
||||
previous: Option<Token>,
|
||||
}
|
||||
|
||||
impl<T: Iterator<Item = scanner::Token>> Compiler<T> {
|
||||
#[derive(Debug, PartialEq, PartialOrd)]
|
||||
enum Precedence {
|
||||
None,
|
||||
Assignment, // =
|
||||
Or, // or
|
||||
And, // and
|
||||
Equality, // == !=
|
||||
Comparison, // < > <= >=
|
||||
Term, // + -
|
||||
Factor, // * /
|
||||
Unary, // ! -
|
||||
Call, // . ()
|
||||
Primary,
|
||||
}
|
||||
|
||||
impl<T: Iterator<Item = Token>> Compiler<T> {
|
||||
fn compile(&mut self) -> LoxResult<()> {
|
||||
self.advance();
|
||||
self.expression();
|
||||
self.expression()?;
|
||||
self.consume(
|
||||
&scanner::TokenKind::Eof,
|
||||
&TokenKind::Eof,
|
||||
ErrorKind::ExpectedToken("Expected end of expression"),
|
||||
)?;
|
||||
|
||||
|
@ -31,13 +50,44 @@ impl<T: Iterator<Item = scanner::Token>> Compiler<T> {
|
|||
self.current = self.tokens.next();
|
||||
}
|
||||
|
||||
fn expression(&mut self) {
|
||||
unimplemented!()
|
||||
fn expression(&mut self) -> LoxResult<()> {
|
||||
self.parse_precedence(Precedence::Assignment)
|
||||
}
|
||||
|
||||
// TODO(tazjin): Assumption is that we have access to the previous
|
||||
// token wherever this ends up invoked. True?
|
||||
fn number(&mut self, num: f64) {
|
||||
self.emit_constant(num);
|
||||
}
|
||||
|
||||
fn grouping(&mut self, num: f64) -> LoxResult<()> {
|
||||
self.expression()?;
|
||||
self.consume(
|
||||
&TokenKind::RightParen,
|
||||
ErrorKind::ExpectedToken("Expected ')' after expression"),
|
||||
)
|
||||
}
|
||||
|
||||
fn unary(&mut self, kind: &TokenKind) -> LoxResult<()> {
|
||||
// Compile the operand
|
||||
self.parse_precedence(Precedence::Unary)?;
|
||||
|
||||
// Emit operator instruction
|
||||
match kind {
|
||||
TokenKind::Minus => self.emit_op(OpCode::OpNegate),
|
||||
_ => unreachable!("only called for unary operator tokens"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_precedence(&mut self, precedence: Precedence) -> LoxResult<()> {
|
||||
unimplemented!("what goes here?")
|
||||
}
|
||||
|
||||
fn consume(
|
||||
&mut self,
|
||||
expected: &scanner::TokenKind,
|
||||
expected: &TokenKind,
|
||||
err: ErrorKind,
|
||||
) -> LoxResult<()> {
|
||||
unimplemented!()
|
||||
|
@ -57,13 +107,18 @@ impl<T: Iterator<Item = scanner::Token>> Compiler<T> {
|
|||
self.current_chunk().add_op(op, line);
|
||||
}
|
||||
|
||||
fn previous(&self) -> &scanner::Token {
|
||||
fn emit_constant(&mut self, val: Value) {
|
||||
let idx = self.chunk.add_constant(val);
|
||||
self.emit_op(OpCode::OpConstant(idx));
|
||||
}
|
||||
|
||||
fn previous(&self) -> &Token {
|
||||
self.previous
|
||||
.as_ref()
|
||||
.expect("invalid internal compiler state: missing previous token")
|
||||
}
|
||||
|
||||
fn error_at(&mut self, token: &scanner::Token, kind: ErrorKind) {
|
||||
fn error_at(&mut self, token: &Token, kind: ErrorKind) {
|
||||
if self.panic {
|
||||
return;
|
||||
}
|
Loading…
Reference in a new issue