[fine] Tracking source locations
This commit is contained in:
parent
24d056b198
commit
2d233244cf
1 changed files with 44 additions and 13 deletions
|
|
@ -61,16 +61,18 @@ impl ExprRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SyntaxTree {
|
pub struct SyntaxTree<'a> {
|
||||||
pub errors: Vec<SyntaxError>,
|
pub errors: Vec<SyntaxError>,
|
||||||
expressions: Vec<Expr>,
|
expressions: Vec<Expr>,
|
||||||
|
spans: Vec<(Option<Token<'a>>, Option<Token<'a>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyntaxTree {
|
impl<'a> SyntaxTree<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SyntaxTree {
|
SyntaxTree {
|
||||||
errors: Vec::new(),
|
errors: Vec::new(),
|
||||||
expressions: Vec::new(),
|
expressions: Vec::new(),
|
||||||
|
spans: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,12 +80,27 @@ impl SyntaxTree {
|
||||||
self.errors.push(error);
|
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();
|
let index = self.expressions.len();
|
||||||
self.expressions.push(expr);
|
self.expressions.push(expr);
|
||||||
|
self.spans.push((start, end));
|
||||||
ExprRef(Some(index))
|
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 {
|
pub fn dump_expr(&self, expr: &ExprRef) -> String {
|
||||||
match expr.0 {
|
match expr.0 {
|
||||||
Some(idx) => {
|
Some(idx) => {
|
||||||
|
|
@ -153,7 +170,7 @@ fn token_power<'a>(token: &Option<Token<'a>>) -> Option<u8> {
|
||||||
|
|
||||||
pub struct Parser<'a> {
|
pub struct Parser<'a> {
|
||||||
tokens: Tokens<'a>,
|
tokens: Tokens<'a>,
|
||||||
tree: SyntaxTree,
|
tree: SyntaxTree<'a>,
|
||||||
current: Option<Token<'a>>,
|
current: Option<Token<'a>>,
|
||||||
previous: Option<Token<'a>>,
|
previous: Option<Token<'a>>,
|
||||||
|
|
||||||
|
|
@ -173,7 +190,7 @@ impl<'a> Parser<'a> {
|
||||||
parser
|
parser
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(mut self) -> (SyntaxTree, ExprRef) {
|
pub fn parse(mut self) -> (SyntaxTree<'a>, ExprRef) {
|
||||||
let expr = self.expression();
|
let expr = self.expression();
|
||||||
self.consume(None, "expected end of expression");
|
self.consume(None, "expected end of expression");
|
||||||
(self.tree, expr)
|
(self.tree, expr)
|
||||||
|
|
@ -238,13 +255,19 @@ impl<'a> Parser<'a> {
|
||||||
let token = self.previous.as_ref().unwrap();
|
let token = self.previous.as_ref().unwrap();
|
||||||
// What kind is it? For now let's just ... make it good.
|
// What kind is it? For now let's just ... make it good.
|
||||||
|
|
||||||
match token.as_str().parse::<f64>() {
|
let literal = match token.as_str().parse::<f64>() {
|
||||||
Ok(v) => self.tree.add_expr(Expr::Literal(Literal::Float64(v))),
|
Ok(v) => Literal::Float64(v),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
self.error(format!("invalid f64: {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 {
|
fn grouping(&mut self) -> ExprRef {
|
||||||
|
|
@ -257,17 +280,21 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(&mut self) -> ExprRef {
|
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 expr = self.expression_with_power(UNARY_POWER);
|
||||||
let op = match kind {
|
let op = match kind {
|
||||||
TokenKind::Minus => UnaryOp::Negate,
|
TokenKind::Minus => UnaryOp::Negate,
|
||||||
_ => panic!("unsuitable unary: {:?}: no op", kind),
|
_ => 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 {
|
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::Plus => BinaryOp::Add,
|
||||||
TokenKind::Minus => BinaryOp::Subtract,
|
TokenKind::Minus => BinaryOp::Subtract,
|
||||||
TokenKind::Star => BinaryOp::Mutiply,
|
TokenKind::Star => BinaryOp::Mutiply,
|
||||||
|
|
@ -278,7 +305,11 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
let right = self.expression_with_power(power + 1);
|
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) {
|
fn advance(&mut self) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue