[fine] Tracking source locations

This commit is contained in:
John Doty 2024-01-01 08:56:25 -08:00
parent 24d056b198
commit 2d233244cf

View file

@ -61,16 +61,18 @@ impl ExprRef {
}
}
pub struct SyntaxTree {
pub struct SyntaxTree<'a> {
pub errors: Vec<SyntaxError>,
expressions: Vec<Expr>,
spans: Vec<(Option<Token<'a>>, Option<Token<'a>>)>,
}
impl SyntaxTree {
impl<'a> SyntaxTree<'a> {
pub fn new() -> Self {
SyntaxTree {
errors: Vec::new(),
expressions: Vec::new(),
spans: Vec::new(),
}
}
@ -78,12 +80,27 @@ impl SyntaxTree {
self.errors.push(error);
}
pub fn add_expr(&mut self, expr: Expr) -> ExprRef {
pub fn add_expr(
&mut self,
expr: Expr,
start: Option<Token<'a>>,
end: Option<Token<'a>>,
) -> ExprRef {
let index = self.expressions.len();
self.expressions.push(expr);
self.spans.push((start, end));
ExprRef(Some(index))
}
pub fn span(&self, expr: &ExprRef) -> (Option<Token<'a>>, Option<Token<'a>>) {
if let ExprRef(Some(idx)) = expr {
let (start, end) = &self.spans[*idx];
(start.clone(), end.clone())
} else {
(None, None)
}
}
pub fn dump_expr(&self, expr: &ExprRef) -> String {
match expr.0 {
Some(idx) => {
@ -153,7 +170,7 @@ fn token_power<'a>(token: &Option<Token<'a>>) -> Option<u8> {
pub struct Parser<'a> {
tokens: Tokens<'a>,
tree: SyntaxTree,
tree: SyntaxTree<'a>,
current: Option<Token<'a>>,
previous: Option<Token<'a>>,
@ -173,7 +190,7 @@ impl<'a> Parser<'a> {
parser
}
pub fn parse(mut self) -> (SyntaxTree, ExprRef) {
pub fn parse(mut self) -> (SyntaxTree<'a>, ExprRef) {
let expr = self.expression();
self.consume(None, "expected end of expression");
(self.tree, expr)
@ -238,13 +255,19 @@ impl<'a> Parser<'a> {
let token = self.previous.as_ref().unwrap();
// What kind is it? For now let's just ... make it good.
match token.as_str().parse::<f64>() {
Ok(v) => self.tree.add_expr(Expr::Literal(Literal::Float64(v))),
let literal = match token.as_str().parse::<f64>() {
Ok(v) => Literal::Float64(v),
Err(e) => {
self.error(format!("invalid f64: {e}"));
ExprRef::error()
return ExprRef::error();
}
}
};
self.tree.add_expr(
Expr::Literal(literal),
Some(token.clone()),
Some(token.clone()),
)
}
fn grouping(&mut self) -> ExprRef {
@ -257,17 +280,21 @@ impl<'a> Parser<'a> {
}
fn unary(&mut self) -> ExprRef {
let kind = self.previous.as_ref().unwrap().kind();
let token = self.previous.as_ref().unwrap().clone();
let kind = token.kind();
let expr = self.expression_with_power(UNARY_POWER);
let op = match kind {
TokenKind::Minus => UnaryOp::Negate,
_ => panic!("unsuitable unary: {:?}: no op", kind),
};
self.tree.add_expr(Expr::Unary(op, expr))
self.tree
.add_expr(Expr::Unary(op, expr), Some(token), self.previous.clone())
}
fn binary(&mut self, power: u8, left: ExprRef) -> ExprRef {
let op = match self.previous.as_ref().unwrap().kind() {
let token = self.previous.as_ref().unwrap().clone();
let op = match token.kind() {
TokenKind::Plus => BinaryOp::Add,
TokenKind::Minus => BinaryOp::Subtract,
TokenKind::Star => BinaryOp::Mutiply,
@ -278,7 +305,11 @@ impl<'a> Parser<'a> {
};
let right = self.expression_with_power(power + 1);
self.tree.add_expr(Expr::Binary(op, left, right))
let (left_start, _) = self.tree.span(&left);
let (_, right_end) = self.tree.span(&right);
self.tree
.add_expr(Expr::Binary(op, left, right), left_start, right_end)
}
fn advance(&mut self) {