From 64dd61be3a46e0787cfb3276ebb5ab0aeb8db68e Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Mon, 12 Jun 2023 12:46:23 +0200 Subject: [PATCH] spans --- out | 246 ------------------------------------------- src/ast/mod.rs | 76 +++++++------ src/check.rs | 31 +++--- src/codegen.rs | 76 +++++++------ src/grammar.lalrpop | 93 ++++++++-------- src/type_analysis.rs | 73 +++++++------ 6 files changed, 189 insertions(+), 406 deletions(-) delete mode 100644 out diff --git a/out b/out deleted file mode 100644 index 3abe39842..000000000 --- a/out +++ /dev/null @@ -1,246 +0,0 @@ -Program { - statements: [ - Struct( - Struct { - name: "Hello", - fields: [ - StructField { - ident: "x", - type_exp: Integer { - bits: 32, - signed: true, - }, - }, - StructField { - ident: "y", - type_exp: Integer { - bits: 32, - signed: true, - }, - }, - ], - }, - ), - Function( - Function { - name: "test", - params: [ - Parameter { - ident: "x", - type_exp: Other { - id: "Hello", - }, - }, - ], - body: [ - Return( - None, - ), - ], - return_type: None, - }, - ), - Function( - Function { - name: "works", - params: [ - Parameter { - ident: "x", - type_exp: Integer { - bits: 64, - signed: true, - }, - }, - ], - body: [ - Let { - name: "z", - value: Literal( - Integer { - value: "0", - bits: None, - signed: None, - }, - ), - value_type: None, - span: ( - 107, - 117, - ), - }, - If { - condition: BinaryOp( - Literal( - Integer { - value: "2", - bits: None, - signed: None, - }, - ), - Eq, - Variable { - name: Spanned { - span: ( - 130, - 131, - ), - value: "x", - }, - value_type: None, - }, - ), - body: [ - Mutate { - name: "z", - value: BinaryOp( - Variable { - name: Spanned { - span: ( - 146, - 147, - ), - value: "x", - }, - value_type: None, - }, - Mul, - Literal( - Integer { - value: "2", - bits: None, - signed: None, - }, - ), - ), - value_type: None, - span: ( - 142, - 152, - ), - }, - ], - else_body: Some( - [ - Mutate { - name: "z", - value: BinaryOp( - Variable { - name: Spanned { - span: ( - 178, - 179, - ), - value: "x", - }, - value_type: None, - }, - Mul, - Literal( - Integer { - value: "3", - bits: None, - signed: None, - }, - ), - ), - value_type: None, - span: ( - 174, - 184, - ), - }, - ], - ), - }, - Return( - Some( - Variable { - name: Spanned { - span: ( - 202, - 203, - ), - value: "z", - }, - value_type: None, - }, - ), - ), - ], - return_type: Some( - Integer { - bits: 64, - signed: true, - }, - ), - }, - ), - Function( - Function { - name: "main", - params: [], - body: [ - Let { - name: "y", - value: Literal( - Integer { - value: "2", - bits: None, - signed: None, - }, - ), - value_type: None, - span: ( - 231, - 241, - ), - }, - Let { - name: "z", - value: Variable { - name: Spanned { - span: ( - 254, - 255, - ), - value: "y", - }, - value_type: None, - }, - value_type: None, - span: ( - 246, - 256, - ), - }, - Return( - Some( - Call { - function: "works", - args: [ - Variable { - name: Spanned { - span: ( - 274, - 275, - ), - value: "z", - }, - value_type: None, - }, - ], - value_type: None, - }, - ), - ), - ], - return_type: Some( - Integer { - bits: 64, - signed: true, - }, - ), - }, - ), - ], -} diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 680e1039d..37313c7bd 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -43,11 +43,21 @@ impl OpCode { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum TypeExp { - Integer { bits: u32, signed: bool }, + Integer { + bits: u32, + signed: bool, + }, Boolean, - Array { of: Box, len: Option }, - Pointer { target: Box }, - Other { id: String }, + Array { + of: Spanned>, + len: Option, + }, + Pointer { + target: Spanned>, + }, + Other { + id: String, + }, } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -65,42 +75,42 @@ pub enum LiteralValue { pub enum Expression { Literal(LiteralValue), Variable { - name: Spanned, + name: String, }, Call { - function: String, - args: Vec>, + function: Spanned, + args: Vec>>, }, - BinaryOp(Box, OpCode, Box), + BinaryOp(Spanned>, OpCode, Spanned>), } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Parameter { - pub ident: String, - pub type_exp: TypeExp, + pub ident: Spanned, + pub type_exp: Spanned, } impl Parameter { - pub const fn new(ident: String, type_exp: TypeExp) -> Self { + pub const fn new(ident: Spanned, type_exp: Spanned) -> Self { Self { ident, type_exp } } } #[derive(Debug, Clone, PartialEq)] pub struct Function { - pub name: String, + pub name: Spanned, pub params: Vec, - pub body: Vec, + pub body: Vec>, pub scope_type_info: HashMap>, - pub return_type: Option, + pub return_type: Option>, } impl Function { pub fn new( - name: String, + name: Spanned, params: Vec, - body: Vec, - return_type: Option, + body: Vec>, + return_type: Option>, ) -> Self { Self { name, @@ -114,12 +124,12 @@ impl Function { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct StructField { - pub ident: String, - pub field_type: TypeExp, + pub ident: Spanned, + pub field_type: Spanned, } impl StructField { - pub const fn new(ident: String, type_name: TypeExp) -> Self { + pub const fn new(ident: Spanned, type_name: Spanned) -> Self { Self { ident, field_type: type_name, @@ -129,42 +139,40 @@ impl StructField { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Struct { - pub name: String, + pub name: Spanned, pub fields: Vec, } #[derive(Debug, Clone, PartialEq)] pub enum Statement { Let { - name: String, - value: Box, - value_type: Option, - span: (usize, usize), + name: Spanned, + value: Spanned>, + value_type: Option>, }, Mutate { - name: String, - value: Box, - span: (usize, usize), + name: Spanned, + value: Spanned>, }, If { - condition: Box, - body: Vec, + condition: Spanned>, + body: Vec>, scope_type_info: HashMap>, - else_body: Option>, + else_body: Option>>, else_body_scope_type_info: HashMap>, }, - Return(Option>), + Return(Option>>), Function(Function), Struct(Struct), } #[derive(Debug, Clone)] pub struct Program { - pub statements: Vec, + pub statements: Vec>, } impl Program { - pub fn new(statements: Vec) -> Self { + pub fn new(statements: Vec>) -> Self { Self { statements } } } diff --git a/src/check.rs b/src/check.rs index 7b9b704e9..9ce5bf051 100644 --- a/src/check.rs +++ b/src/check.rs @@ -22,8 +22,8 @@ pub fn check<'a>(data: &'a ProgramData, ast: &ast::Program) -> Vec> { let mut errors = vec![]; for statement in &ast.statements { - match &statement { - Statement::Let { name: _, span, .. } => { + match &statement.value { + Statement::Let { name, .. } => { // can't have a top level assignment yet. let snippet = Snippet { title: Some(Annotation { @@ -40,7 +40,7 @@ pub fn check<'a>(data: &'a ProgramData, ast: &ast::Program) -> Vec> { annotations: vec![SourceAnnotation { label: "unexpected statement", annotation_type: AnnotationType::Error, - range: *span, + range: name.span, }], }], opt: FormatOptions { @@ -52,7 +52,7 @@ pub fn check<'a>(data: &'a ProgramData, ast: &ast::Program) -> Vec> { let dl = DisplayList::from(snippet); errors.push(Check::Error(dl)); } - Statement::Mutate { span, .. } => { + Statement::Mutate { name, .. } => { // can't have a top level assignment yet. let snippet = Snippet { title: Some(Annotation { @@ -69,7 +69,7 @@ pub fn check<'a>(data: &'a ProgramData, ast: &ast::Program) -> Vec> { annotations: vec![SourceAnnotation { label: "unexpected statement", annotation_type: AnnotationType::Error, - range: *span, + range: name.span, }], }], opt: FormatOptions { @@ -112,9 +112,15 @@ pub fn print_error(source: &str, err: ParseError) { let dl = DisplayList::from(snippet); println!("{dl}"); } - ParseError::UnrecognizedEof { location, expected } => todo!(), - ParseError::UnrecognizedToken { token, expected } => todo!(), - ParseError::ExtraToken { token } => todo!(), + ParseError::UnrecognizedEof { + location: _, + expected: _, + } => todo!(), + ParseError::UnrecognizedToken { + token: _, + expected: _, + } => todo!(), + ParseError::ExtraToken { token: _ } => todo!(), ParseError::User { error } => match error { LexicalError::InvalidToken(err, range) => { let title = format!("invalid token (lexical error): {:?}", err); @@ -126,7 +132,7 @@ pub fn print_error(source: &str, err: ParseError) { }), footer: vec![], slices: vec![Slice { - source: source, + source, line_start: 1, fold: false, origin: None, @@ -149,11 +155,10 @@ pub fn print_error(source: &str, err: ParseError) { } pub fn print_type_error(source: &str, err: TypeError) { - dbg!(&err); match err { TypeError::Mismatch { - found, - expected, + found: _, + expected: _, span, } => { let snippet = Snippet { @@ -182,7 +187,7 @@ pub fn print_type_error(source: &str, err: TypeError) { let dl = DisplayList::from(snippet); println!("{dl}"); } - TypeError::UndeclaredVariable { name, span } => { + TypeError::UndeclaredVariable { name: _, span } => { let snippet = Snippet { title: Some(Annotation { id: None, diff --git a/src/codegen.rs b/src/codegen.rs index 88739450d..2272570f4 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -16,7 +16,7 @@ use inkwell::{ use itertools::{Either, Itertools}; use tracing::info; -use crate::ast::{self, Expression, Function, LiteralValue, OpCode, Statement, TypeExp}; +use crate::ast::{self, Expression, Function, LiteralValue, OpCode, Spanned, Statement, TypeExp}; #[derive(Debug, Clone)] pub struct ProgramData { @@ -95,22 +95,25 @@ impl<'ctx> CodeGen<'ctx> { // create types for statement in &self.ast.statements { - if let Statement::Struct(s) = &statement { + if let Statement::Struct(s) = &statement.value { let mut fields = HashMap::new(); let mut field_types = vec![]; for (i, field) in s.fields.iter().enumerate() { // todo: this doesnt handle out of order structs well - let ty = self.get_llvm_type(&field.field_type)?; + let ty = self.get_llvm_type(&field.field_type.value)?; field_types.push(ty); // todo: ensure alignment and padding here - fields.insert(field.ident.clone(), (i, field.field_type.clone())); + fields.insert( + field.ident.value.clone(), + (i, field.field_type.value.clone()), + ); } let ty = self.context.struct_type(&field_types, false); let struct_type = StructTypeInfo { fields, ty }; - struct_types.insert(s.name.clone(), struct_type); + struct_types.insert(s.name.value.clone(), struct_type); } } @@ -118,8 +121,8 @@ impl<'ctx> CodeGen<'ctx> { // create the llvm functions first. for statement in &self.ast.statements { - if let Statement::Function(function) = &statement { - functions.insert(function.name.clone(), function.clone()); + if let Statement::Function(function) = &statement.value { + functions.insert(function.name.value.clone(), function.clone()); self.compile_function_signature(function)?; } } @@ -150,11 +153,11 @@ impl<'ctx> CodeGen<'ctx> { .as_basic_type_enum(), TypeExp::Boolean => self.context.bool_type().as_basic_type_enum(), TypeExp::Array { of, len } => { - let ty = self.get_llvm_type(of)?; + let ty = self.get_llvm_type(&of.value)?; ty.array_type(len.unwrap()).as_basic_type_enum() } TypeExp::Pointer { target } => { - let ty = self.get_llvm_type(target)?; + let ty = self.get_llvm_type(&target.value)?; ty.ptr_type(Default::default()).as_basic_type_enum() } TypeExp::Other { id } => self @@ -172,7 +175,7 @@ impl<'ctx> CodeGen<'ctx> { .params .iter() .map(|param| ¶m.type_exp) - .map(|t| self.get_llvm_type(t)) + .map(|t| self.get_llvm_type(&t.value)) .try_collect()?; let args_types: Vec> = @@ -180,19 +183,20 @@ impl<'ctx> CodeGen<'ctx> { let fn_type = match &function.return_type { Some(id) => { - let return_type = self.get_llvm_type(id)?; + let return_type = self.get_llvm_type(&id.value)?; return_type.fn_type(&args_types, false) } None => self.context.void_type().fn_type(&args_types, false), }; - self.module.add_function(&function.name, fn_type, None); + self.module + .add_function(&function.name.value, fn_type, None); Ok(()) } fn compile_function(&self, function: &Function) -> Result<()> { - let func = self.module.get_function(&function.name).unwrap(); + let func = self.module.get_function(&function.name.value).unwrap(); let entry_block = self.context.append_basic_block(func, "entry"); self.builder.position_at_end(entry_block); @@ -205,7 +209,7 @@ impl<'ctx> CodeGen<'ctx> { .get_nth_param(i.try_into().unwrap()) .expect("parameter"); variables.insert( - id.clone(), + id.value.clone(), Variable { value: param_value, phi_counter: 0, @@ -217,7 +221,7 @@ impl<'ctx> CodeGen<'ctx> { let mut has_return = false; for statement in &function.body { - if let Statement::Return(_) = statement { + if let Statement::Return(_) = statement.value { has_return = true } self.compile_statement(func, statement, &mut variables, &function.scope_type_info)?; @@ -233,12 +237,12 @@ impl<'ctx> CodeGen<'ctx> { fn compile_statement( &self, function_value: FunctionValue, - statement: &Statement, + statement: &Spanned, // value, assignments variables: &mut Variables<'ctx>, scope_info: &HashMap>, ) -> Result<()> { - match statement { + match &statement.value { // Variable assignment Statement::Let { name, @@ -247,11 +251,11 @@ impl<'ctx> CodeGen<'ctx> { .. } => { let value = self - .compile_expression(value, variables, scope_info)? + .compile_expression(&value, variables, scope_info)? .expect("should have result"); variables.insert( - name.clone(), + name.value.clone(), Variable { value, phi_counter: 0, @@ -261,17 +265,19 @@ impl<'ctx> CodeGen<'ctx> { } Statement::Mutate { name, value, .. } => { let value = self - .compile_expression(value, variables, scope_info)? + .compile_expression(&value, variables, scope_info)? .expect("should have result"); - let var = variables.get_mut(name).expect("variable should exist"); + let var = variables + .get_mut(&name.value) + .expect("variable should exist"); var.phi_counter += 1; var.value = value; } Statement::Return(ret) => { if let Some(ret) = ret { let value = self - .compile_expression(ret, variables, scope_info)? + .compile_expression(&ret, variables, scope_info)? .expect("should have result"); self.builder.build_return(Some(&value)); } else { @@ -386,12 +392,12 @@ impl<'ctx> CodeGen<'ctx> { pub fn compile_expression( &self, - expr: &Expression, + expr: &Spanned>, variables: &mut Variables<'ctx>, scope_info: &HashMap>, ) -> Result>> { - Ok(match expr { - Expression::Variable { name } => Some(self.compile_variable(&name.value, variables)?), + Ok(match &*expr.value { + Expression::Variable { name } => Some(self.compile_variable(&name, variables)?), Expression::Literal(term) => Some(self.compile_literal(term)?), Expression::Call { function, args } => { self.compile_call(function, args, variables, scope_info)? @@ -404,13 +410,16 @@ impl<'ctx> CodeGen<'ctx> { pub fn compile_call( &self, - func_name: &str, - args: &[Box], + func_name: &Spanned, + args: &[Spanned>], variables: &mut Variables<'ctx>, scope_info: &HashMap>, ) -> Result>> { - info!("compiling fn call: func_name={}", func_name); - let function = self.module.get_function(func_name).expect("should exist"); + info!("compiling fn call: func_name={}", func_name.value); + let function = self + .module + .get_function(&func_name.value) + .expect("should exist"); let mut value_args: Vec = Vec::with_capacity(args.len()); @@ -423,7 +432,7 @@ impl<'ctx> CodeGen<'ctx> { let result = self .builder - .build_call(function, &value_args, &format!("{func_name}_call")) + .build_call(function, &value_args, &format!("{}_call", func_name.value)) .try_as_basic_value(); Ok(match result { @@ -434,9 +443,9 @@ impl<'ctx> CodeGen<'ctx> { pub fn compile_binary_op( &self, - lhs: &Expression, + lhs: &Spanned>, op: &OpCode, - rhs: &Expression, + rhs: &Spanned>, variables: &mut Variables<'ctx>, scope_info: &HashMap>, ) -> Result> { @@ -489,10 +498,9 @@ impl<'ctx> CodeGen<'ctx> { LiteralValue::Integer { value, bits, - signed, + signed: _, } => { let bits = *bits; - let signed = *signed; self.context .custom_width_int_type(bits) diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index d8e57e0c4..b4ff1c932 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -1,4 +1,3 @@ -use std::collections::HashMap; use crate::{ ast::{self, Spanned}, tokens::Token, @@ -76,42 +75,46 @@ pub Program: ast::Program = { Statements => ast::Program::new(<>) } -Statements: Vec = { - Statement => vec![<>], +Statements: Vec> = { + => vec![<>], => { s.push(n); s }, }; -Statement: ast::Statement = { +Statement: Spanned = { BasicStatement, - => ast::Statement::Function(f), - => ast::Statement::Struct(s), + => Spanned::new(ast::Statement::Function(f), (lo, hi)), + => Spanned::new(ast::Statement::Struct(s), (lo, hi)), }; -TypeInfo: ast::TypeExp = { +TypeInfo: Spanned = { ":" => i }; +Identifier: Spanned = { + => Spanned::new(i, (lo, hi)) +} + // statements not including function definitions -BasicStatement: ast::Statement = { - "let" "=" ";" => - ast::Statement::Let { name: i, value: e, value_type: t, span: (lo, hi) }, - "=" ";" => - ast::Statement::Mutate { name: i, value: e, span: (lo, hi) }, - "if" "{" "}" => - ast::Statement::If { +BasicStatement: Spanned = { + "let" "=" ";" => + Spanned::new(ast::Statement::Let { name: i, value: e, value_type: t }, (lo, hi)), + "=" ";" => + Spanned::new(ast::Statement::Mutate { name: i, value: e }, (lo, hi)), + "if" "{" "}" => + Spanned::new(ast::Statement::If { condition: cond, body: s, else_body: e, scope_type_info: Default::default(), else_body_scope_type_info: Default::default(), - }, - "return" ";" => ast::Statement::Return(e), + }, (lo, hi)), + "return" ";" => Spanned::new(ast::Statement::Return(e), (lo, hi)), }; -ElseExpr: Vec = { +ElseExpr: Vec> = { "else" "{" "}" => s } @@ -136,8 +139,8 @@ Level3_Op: ast::OpCode = { "%" => ast::OpCode::Rem, } -Tier: Box = { - > => Box::new(ast::Expression::BinaryOp(t, o, n)), +Tier: Spanned> = { + > => Spanned::new(Box::new(ast::Expression::BinaryOp(t, o, n)), (lo, hi)), NextTier }; @@ -147,14 +150,14 @@ Expr3 = Tier; Expr4 = Tier; // Terms: variables, literals, calls -Term: Box = { - => Box::new(ast::Expression::Variable { - name: Spanned::new(i, (lo, hi)) - }), - => Box::new(ast::Expression::Literal(n)), - => Box::new(ast::Expression::Literal(n)), - => Box::new(ast::Expression::Literal(n)), - "(" > ")" => Box::new(ast::Expression::Call { function: i, args: values }), +Term: Spanned> = { + => Spanned::new(Box::new(ast::Expression::Variable { + name: i + }), (lo, hi)), + => Spanned::new(Box::new(ast::Expression::Literal(n)), (lo, hi)), + => Spanned::new(Box::new(ast::Expression::Literal(n)), (lo, hi)), + => Spanned::new(Box::new(ast::Expression::Literal(n)), (lo, hi)), + "(" > ")" => Spanned::new(Box::new(ast::Expression::Call { function: i, args: values }), (lo, hi)), "(" ")" }; @@ -214,46 +217,46 @@ ArrayLen: u32 = { ";" => i.parse().unwrap(), } -LangType: ast::TypeExp = { - "ptr" "<" ">" => ast::TypeExp::Pointer { target: Box::new(target) }, - "[" "]" => ast::TypeExp::Array { of: Box::new(of), len }, - "i8" => ast::TypeExp::Integer { bits: 8, signed: true }, - "i16" => ast::TypeExp::Integer { bits: 16, signed: true }, - "i32" => ast::TypeExp::Integer { bits: 32, signed: true }, - "i64" => ast::TypeExp::Integer { bits: 64, signed: true }, - "u8" => ast::TypeExp::Integer { bits: 8, signed: false }, - "u16" => ast::TypeExp::Integer { bits: 16, signed: false }, - "u32" => ast::TypeExp::Integer { bits: 32, signed: false }, - "u64" => ast::TypeExp::Integer { bits: 64, signed: false }, - "bool" => ast::TypeExp::Boolean, - => ast::TypeExp::Other { id }, +LangType: Spanned = { + "ptr" "<" ">" => Spanned::new(ast::TypeExp::Pointer { target: Spanned::new(Box::new(target.value), target.span) }, (lo, hi)), + "[" "]" => Spanned::new(ast::TypeExp::Array { of: Spanned::new(Box::new(of.value), of.span), len }, (lo, hi)), + "i8" => Spanned::new(ast::TypeExp::Integer { bits: 8, signed: true }, (lo, hi)), + "i16" => Spanned::new(ast::TypeExp::Integer { bits: 16, signed: true }, (lo, hi)), + "i32" => Spanned::new(ast::TypeExp::Integer { bits: 32, signed: true }, (lo, hi)), + "i64" => Spanned::new(ast::TypeExp::Integer { bits: 64, signed: true }, (lo, hi)), + "u8" => Spanned::new(ast::TypeExp::Integer { bits: 8, signed: false }, (lo, hi)), + "u16" => Spanned::new(ast::TypeExp::Integer { bits: 16, signed: false }, (lo, hi)), + "u32" => Spanned::new(ast::TypeExp::Integer { bits: 32, signed: false }, (lo, hi)), + "u64" => Spanned::new(ast::TypeExp::Integer { bits: 64, signed: false }, (lo, hi)), + "bool" => Spanned::new(ast::TypeExp::Boolean, (lo, hi)), + => Spanned::new(ast::TypeExp::Other { id }, (lo, hi)), }; // Function handling Param: ast::Parameter = { - <"identifier"> ":" => ast::Parameter::new(<>) + ":" => ast::Parameter::new(<>) }; Params = Comma; -FunctionReturn: ast::TypeExp = { +FunctionReturn: Spanned = { "->" => i, } Function: ast::Function = { - "fn" "(" ")" "{" "}" => ast::Function::new(i, a, s, r) + "fn" "(" ")" "{" "}" => ast::Function::new(i, a, s, r) } // Structures StructField: ast::StructField = { - <"identifier"> ":" => ast::StructField::new(<>) + ":" => ast::StructField::new(<>) }; StructFields = Comma; Struct: ast::Struct = { - "struct" "{" "}" => { + "struct" "{" "}" => { ast::Struct { name: i, fields diff --git a/src/type_analysis.rs b/src/type_analysis.rs index 5777c5b4c..324c7882e 100644 --- a/src/type_analysis.rs +++ b/src/type_analysis.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet}; -use crate::ast::{self, Expression, Function, Statement, TypeExp}; +use crate::ast::{self, Expression, Function, Spanned, Statement, TypeExp}; #[derive(Debug, Clone)] pub enum TypeError { @@ -30,19 +30,19 @@ pub fn type_check(ast: &mut ast::Program) -> Result<(), TypeError> { // gather global constructs first for statement in ast.statements.iter_mut() { - match statement { + match &mut statement.value { Statement::Struct(st) => { let fields = st .fields .iter() - .map(|x| (x.ident.clone(), x.field_type.clone())) + .map(|x| (x.ident.value.clone(), x.field_type.value.clone())) .collect(); - storage.structs.insert(st.name.clone(), fields); + storage.structs.insert(st.name.value.clone(), fields); } Statement::Function(function) => { storage .functions - .insert(function.name.clone(), function.clone()); + .insert(function.name.value.clone(), function.clone()); } // todo: find globals here too _ => {} @@ -50,11 +50,14 @@ pub fn type_check(ast: &mut ast::Program) -> Result<(), TypeError> { } for statement in ast.statements.iter_mut() { - if let Statement::Function(function) = statement { + if let Statement::Function(function) = &mut statement.value { let mut scope_vars: ScopeMap = HashMap::new(); for arg in &function.params { - scope_vars.insert(arg.ident.clone(), vec![Some(arg.type_exp.clone())]); + scope_vars.insert( + arg.ident.value.clone(), + vec![Some(arg.type_exp.value.clone())], + ); } let func_info = function.clone(); @@ -72,7 +75,7 @@ pub fn type_check(ast: &mut ast::Program) -> Result<(), TypeError> { /// Finds variable types in the scope, returns newly created variables to handle shadowing fn type_inference_scope( - statements: &mut [ast::Statement], + statements: &mut [Spanned], scope_vars: &ScopeMap, func: &Function, storage: &Storage, @@ -81,43 +84,45 @@ fn type_inference_scope( let mut new_vars: HashSet = HashSet::new(); for statement in statements { - match statement { + match &mut statement.value { Statement::Let { name, value, value_type, - span, } => { - new_vars.insert(name.clone()); + new_vars.insert(name.value.clone()); - let exp_type = type_inference_expression(value, &mut scope_vars, storage, None)?; + let exp_type = type_inference_expression(&value, &mut scope_vars, storage, None)?; - if !scope_vars.contains_key(name) { - scope_vars.insert(name.clone(), vec![]); + if !scope_vars.contains_key(&name.value) { + scope_vars.insert(name.value.clone(), vec![]); } - let var = scope_vars.get_mut(name).unwrap(); + let var = scope_vars.get_mut(&name.value).unwrap(); if value_type.is_none() { var.push(exp_type); } else { - if exp_type.is_some() && &exp_type != value_type { + if exp_type.is_some() && exp_type != value_type.clone().map(|x| x.value) { Err(TypeError::Mismatch { found: exp_type.clone().unwrap(), - expected: value_type.clone().unwrap(), - span: *span, + expected: value_type.clone().map(|x| x.value).unwrap(), + span: statement.span, })?; } - var.push(value_type.clone()); + var.push(value_type.clone().map(|x| x.value)); } } - Statement::Mutate { name, value, span } => { - if !scope_vars.contains_key(name) { - panic!("undeclared variable"); + Statement::Mutate { name, value } => { + if !scope_vars.contains_key(&name.value) { + Err(TypeError::UndeclaredVariable { + name: name.value.clone(), + span: name.span, + })?; } - let exp_type = type_inference_expression(value, &mut scope_vars, storage, None)?; - let var = scope_vars.get_mut(name).unwrap().last_mut().unwrap(); + let exp_type = type_inference_expression(&value, &mut scope_vars, storage, None)?; + let var = scope_vars.get_mut(&name.value).unwrap().last_mut().unwrap(); if var.is_none() { *var = exp_type; @@ -125,7 +130,7 @@ fn type_inference_scope( Err(TypeError::Mismatch { found: exp_type.clone().unwrap(), expected: var.clone().unwrap(), - span: *span, + span: statement.span, })?; } } @@ -137,7 +142,7 @@ fn type_inference_scope( else_body_scope_type_info, } => { type_inference_expression( - condition, + &condition, &mut scope_vars, storage, Some(TypeExp::Boolean), @@ -181,7 +186,7 @@ fn type_inference_scope( exp, &mut scope_vars, storage, - func.return_type.clone(), + func.return_type.clone().map(|x| x.value), )?; } } @@ -194,12 +199,12 @@ fn type_inference_scope( } fn type_inference_expression( - exp: &Expression, + exp: &Spanned>, scope_vars: &mut ScopeMap, storage: &Storage, expected_type: Option, ) -> Result, TypeError> { - Ok(match exp { + Ok(match &*exp.value { Expression::Literal(lit) => { match lit { ast::LiteralValue::String(_) => None, // todo @@ -216,7 +221,7 @@ fn type_inference_expression( } Expression::Variable { name } => { let var = scope_vars - .get_mut(&name.value) + .get_mut(name) .expect("to exist") .last_mut() .unwrap(); @@ -230,7 +235,7 @@ fn type_inference_expression( Err(TypeError::Mismatch { found: expected_type.clone().unwrap(), expected: var.clone().unwrap(), - span: name.span, + span: exp.span, })?; } expected_type @@ -242,15 +247,15 @@ fn type_inference_expression( } } Expression::Call { function, args } => { - let func = storage.functions.get(function).cloned().unwrap(); + let func = storage.functions.get(&function.value).cloned().unwrap(); for (i, arg) in args.iter().enumerate() { let arg_type = func.params[i].type_exp.clone(); // result is ignored, but need these to infer call arg types - type_inference_expression(arg, scope_vars, storage, Some(arg_type))?; + type_inference_expression(arg, scope_vars, storage, Some(arg_type.value))?; } - func.return_type + func.return_type.map(|x| x.value) } Expression::BinaryOp(lhs, op, rhs) => match op { ast::OpCode::Eq | ast::OpCode::Ne => Some(TypeExp::Boolean),