diff --git a/src/ast.rs b/src/ast.rs index c249247..9f8f9e0 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -28,7 +28,8 @@ pub struct TrailBlock(pub Vec>, pub Option>>); #[derive(Debug)] pub enum Expr { - Int(i32), + Int(i64), + Float(f64), Bool(bool), Var(Spanned), Block(TrailBlock), diff --git a/src/eval.rs b/src/eval.rs index 6075c71..e074b94 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -2,9 +2,10 @@ use std::collections::HashMap; use crate::{ast, span::Span}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] pub enum Value { - Int(i32), + Int(i64), + Float(f64), Bool(bool), Nil, } @@ -13,6 +14,7 @@ impl Value { pub fn ty(&self) -> ValueType { match self { Value::Int(_) => ValueType::Int, + Value::Float(_) => ValueType::Float, Value::Bool(_) => ValueType::Bool, Value::Nil => ValueType::Nil, } @@ -21,6 +23,7 @@ impl Value { pub fn repr(&self) -> String { match self { Value::Int(v) => format!("{}", v), + Value::Float(f) => format!("{}", f), Value::Bool(v) => match v { true => "true".to_string(), false => "false".to_string(), @@ -32,6 +35,7 @@ impl Value { pub enum ValueType { Int, + Float, Bool, Nil, } @@ -40,6 +44,7 @@ impl std::fmt::Display for ValueType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ValueType::Int => write!(f, "int"), + ValueType::Float => write!(f, "float"), ValueType::Bool => write!(f, "bool"), ValueType::Nil => write!(f, "nil"), } @@ -201,6 +206,7 @@ impl Evaluator { Ok(match expr { ast::Expr::Int(i) => Value::Int(*i), + ast::Expr::Float(f) => Value::Float(*f), ast::Expr::Bool(b) => Value::Bool(*b), ast::Expr::Var(ident) => match self.lookup(&ident.v) { Some(val) => val.clone(), diff --git a/src/parser.lalrpop b/src/parser.lalrpop index dc5c542..7c3c8fa 100644 --- a/src/parser.lalrpop +++ b/src/parser.lalrpop @@ -85,6 +85,9 @@ Term: ast::Expr = { => ast::Expr::Int(int_s.parse().unwrap()), + + + => ast::Expr::Float(float_s.parse().unwrap()), } Spanned: Spanned diff --git a/src/saft.rs b/src/saft.rs index a31d5b0..9cb9c29 100644 --- a/src/saft.rs +++ b/src/saft.rs @@ -4,6 +4,7 @@ use crate::{ parser::SpannedStmtOrExprParser, span::{Span, Spanned}, }; +use std::fmt::Write; pub struct SaftError { pub span: Span, @@ -49,16 +50,16 @@ pub fn eval_stmt_or_expr(evaluator: &mut Evaluator, src: &str) -> Res<()> { } => bail!( s, "Parse error", - "Got unexpected EOF, expected {:?}", - expected + "Got unexpected EOF, expected {}", + expected_list(expected) ), lalrpop_util::ParseError::UnrecognizedToken { token, expected } => bail!( s, "Parse error", - "Got unexpected token '{}', expected {:?}", + "Got unexpected token '{}', expected {}", token.1, - expected + expected_list(expected) ), lalrpop_util::ParseError::ExtraToken { token } => { bail!(s, "Parse error", "Unexpected extra token '{}'", token.1) @@ -92,3 +93,25 @@ fn parse_error_span(err: &lalrpop_util::ParseError) -> Span { lalrpop_util::ParseError::User { .. } => unreachable!(), } } + +fn expected_list(options: Vec) -> String { + match &options[..] { + [] => unreachable!("Should be at least one expected item"), + [choice] => choice.to_string(), + [one, two] => format!("{} or {}", one, two), + many => { + let mut buf = String::new(); + let last = many.len() - 1; + for (i, alt) in many.iter().enumerate() { + if i == 0 { + write!(buf, "{}", alt).unwrap(); + } else if i == last { + write!(buf, ", or {}", alt).unwrap(); + } else { + write!(buf, ", {}", alt).unwrap(); + } + } + buf + } + } +} diff --git a/src/sexpr.rs b/src/sexpr.rs index e1fab64..4107c29 100644 --- a/src/sexpr.rs +++ b/src/sexpr.rs @@ -87,6 +87,7 @@ impl From<&ast::Expr> for SExpr { fn from(value: &ast::Expr) -> Self { match value { ast::Expr::Int(i) => format!("{}", i).into(), + ast::Expr::Float(f) => format!("{}", f).into(), ast::Expr::Bool(b) => format!("{}", b).into(), ast::Expr::Var(v) => v.v.clone().into(), ast::Expr::Call { expr, args } => list!(