feat(tazjin/rlox): Add runtime type error handling
Change-Id: I0d52bc9ff5be6421cb4131265ed28ce1ea7d8ff3 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2282 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
This commit is contained in:
		
							parent
							
								
									bc6775c318
								
							
						
					
					
						commit
						5ebe28cca2
					
				
					 2 changed files with 32 additions and 14 deletions
				
			
		| 
						 | 
					@ -4,6 +4,7 @@ pub enum ErrorKind {
 | 
				
			||||||
    UnterminatedString,
 | 
					    UnterminatedString,
 | 
				
			||||||
    UnmatchedParens,
 | 
					    UnmatchedParens,
 | 
				
			||||||
    ExpectedExpression(String),
 | 
					    ExpectedExpression(String),
 | 
				
			||||||
 | 
					    TypeError(String),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
use crate::errors::{report, Error};
 | 
					use crate::errors::{report, Error, ErrorKind};
 | 
				
			||||||
use crate::parser::{self, Expr, Literal};
 | 
					use crate::parser::{self, Expr, Literal};
 | 
				
			||||||
use crate::scanner::{self, Token, TokenKind};
 | 
					use crate::scanner::{self, Token, TokenKind};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,21 +44,28 @@ fn eval_truthy(lit: &Literal) -> bool {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn eval_unary<'a>(expr: &parser::Unary<'a>) -> Literal {
 | 
					fn eval_unary<'a>(expr: &parser::Unary<'a>) -> Result<Literal, Error> {
 | 
				
			||||||
    let right = eval(&*expr.right);
 | 
					    let right = eval(&*expr.right)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match (&expr.operator.kind, right) {
 | 
					    match (&expr.operator.kind, right) {
 | 
				
			||||||
        (TokenKind::Minus, Literal::Number(num)) => Literal::Number(-num),
 | 
					        (TokenKind::Minus, Literal::Number(num)) => Ok(Literal::Number(-num)),
 | 
				
			||||||
        (TokenKind::Bang, right) => Literal::Boolean(!eval_truthy(&right)),
 | 
					        (TokenKind::Bang, right) => Ok(Literal::Boolean(!eval_truthy(&right))),
 | 
				
			||||||
        _ => unimplemented!("no handling of type errors"),
 | 
					
 | 
				
			||||||
 | 
					        (op, right) => Err(Error {
 | 
				
			||||||
 | 
					            line: expr.operator.line,
 | 
				
			||||||
 | 
					            kind: ErrorKind::TypeError(format!(
 | 
				
			||||||
 | 
					                "Operator '{:?}' can not be called with argument '{:?}'",
 | 
				
			||||||
 | 
					                op, right
 | 
				
			||||||
 | 
					            )),
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn eval_binary<'a>(expr: &parser::Binary<'a>) -> Literal {
 | 
					fn eval_binary<'a>(expr: &parser::Binary<'a>) -> Result<Literal, Error> {
 | 
				
			||||||
    let left = eval(&*expr.left);
 | 
					    let left = eval(&*expr.left)?;
 | 
				
			||||||
    let right = eval(&*expr.right);
 | 
					    let right = eval(&*expr.right)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    match (&expr.operator.kind, left, right) {
 | 
					    let result = match (&expr.operator.kind, left, right) {
 | 
				
			||||||
        // Numeric
 | 
					        // Numeric
 | 
				
			||||||
        (TokenKind::Minus, Literal::Number(l), Literal::Number(r)) => Literal::Number(l - r),
 | 
					        (TokenKind::Minus, Literal::Number(l), Literal::Number(r)) => Literal::Number(l - r),
 | 
				
			||||||
        (TokenKind::Slash, Literal::Number(l), Literal::Number(r)) => Literal::Number(l / r),
 | 
					        (TokenKind::Slash, Literal::Number(l), Literal::Number(r)) => Literal::Number(l / r),
 | 
				
			||||||
| 
						 | 
					@ -82,13 +89,23 @@ fn eval_binary<'a>(expr: &parser::Binary<'a>) -> Literal {
 | 
				
			||||||
        (TokenKind::Equal, l, r) => Literal::Boolean(l == r),
 | 
					        (TokenKind::Equal, l, r) => Literal::Boolean(l == r),
 | 
				
			||||||
        (TokenKind::BangEqual, l, r) => Literal::Boolean(l != r),
 | 
					        (TokenKind::BangEqual, l, r) => Literal::Boolean(l != r),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        _ => unimplemented!("type errors unhandled"),
 | 
					        (op, left, right) => {
 | 
				
			||||||
 | 
					            return Err(Error {
 | 
				
			||||||
 | 
					                line: expr.operator.line,
 | 
				
			||||||
 | 
					                kind: ErrorKind::TypeError(format!(
 | 
				
			||||||
 | 
					                    "Operator '{:?}' can not be called with arguments '({:?}, {:?})'",
 | 
				
			||||||
 | 
					                    op, left, right
 | 
				
			||||||
 | 
					                )),
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(result)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn eval<'a>(expr: &Expr<'a>) -> Literal {
 | 
					fn eval<'a>(expr: &Expr<'a>) -> Result<Literal, Error> {
 | 
				
			||||||
    match expr {
 | 
					    match expr {
 | 
				
			||||||
        Expr::Literal(lit) => lit.clone(),
 | 
					        Expr::Literal(lit) => Ok(lit.clone()),
 | 
				
			||||||
        Expr::Grouping(grouping) => eval(&*grouping.0),
 | 
					        Expr::Grouping(grouping) => eval(&*grouping.0),
 | 
				
			||||||
        Expr::Unary(unary) => eval_unary(unary),
 | 
					        Expr::Unary(unary) => eval_unary(unary),
 | 
				
			||||||
        Expr::Binary(binary) => eval_binary(binary),
 | 
					        Expr::Binary(binary) => eval_binary(binary),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue