diff --git a/src/expr.rs b/src/expr.rs index 7159651..c370816 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1,11 +1,17 @@ -use std::{ - boxed::Box, - sync::{Arc, RwLock}, +use { + std::{ + boxed::Box, + sync::{Arc, RwLock} + }, + crate::{ + lexer::InputRegionTag + } }; #[derive(Clone, Debug)] pub enum Statement { Assignment { + name_region: InputRegionTag, var_id: String, val_expr: LTExpr, }, @@ -40,6 +46,7 @@ pub enum LTExpr { val: tisc::VM_Word, }, Symbol { + region: InputRegionTag, typ: Option, symbol: String, }, @@ -49,7 +56,7 @@ pub enum LTExpr { body: Vec, }, Abstraction { - args: Vec<(String, Option)>, + args: Vec<(InputRegionTag, String, Option)>, body: Box, }, Branch { @@ -66,20 +73,21 @@ pub enum LTExpr { } impl LTExpr { + /* pub fn symbol(str: &str) -> Self { LTExpr::Symbol { typ: None, //typectx.write().unwrap().parse("~Symbol~").expect("parse typeterm"), symbol: String::from(str), } } - +*/ pub fn lit_uint(val: u64) -> Self { LTExpr::Literal { typ: None, //typectx.write().unwrap().parse("ℤ_2^64~machine::UInt64~machine::Word").expect("parse typeterm"), val: val as tisc::VM_Word, } } - +/* pub fn abstraction(args: Vec<(&str, &str)>, body: LTExpr) -> LTExpr { LTExpr::Abstraction { args: args @@ -91,7 +99,7 @@ impl LTExpr { body: Box::new(body), } } - +*/ pub fn application(head: LTExpr, body: Vec) -> Self { LTExpr::Application { typ: None, diff --git a/src/lexer.rs b/src/lexer.rs index 3ddf49f..d20dbaa 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -79,7 +79,7 @@ where } } -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct InputRegionTag { pub begin: usize, pub end: usize diff --git a/src/main.rs b/src/main.rs index e9dc49f..c050779 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,7 +76,7 @@ fn print_diagnostic( } /* TODO: - * - export / import , load multiple files + * - import function symbols * - Compiler error reporting * - parse float literals * - return type annotation @@ -121,10 +121,14 @@ fn main() { match parser::parse_expr( &typectx, &mut program_tokens ) { Ok( ast ) => { - let (exports, bytecode) = ProcedureCompiler::new(&main_scope) + let (exports, diagnostics, bytecode) = ProcedureCompiler::new(&main_scope) .compile(&ast) .into_asm(&path); + for (region, message) in diagnostics { + print_diagnostic(path.as_str(), region, message); + } + eprintln!("{} {}", "Compiled".green(), path.bold()); for (name, def) in exports.iter() { eprintln!("export {}: {:?}", name.yellow().bold(), def); diff --git a/src/parser.rs b/src/parser.rs index a882f9e..3ca413b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -39,11 +39,11 @@ where It: Iterator)> /* parse symbol name */ -pub fn parse_symbol(tokens: &mut Peekable) -> Result +pub fn parse_symbol(tokens: &mut Peekable) -> Result<(InputRegionTag, String), (InputRegionTag, ParseError)> where It: Iterator)> { match tokens.next() { - Some((region, Ok(LTIRToken::Symbol(name)))) => Ok(name), + Some((region, Ok(LTIRToken::Symbol(name)))) => Ok((region, name)), Some((region, Ok(_))) => Err((region, ParseError::UnexpectedToken)), Some((region, Err(err))) => Err((region, ParseError::LexError(err))), None => Err((InputRegionTag::default(), ParseError::UnexpectedEnd)), @@ -79,6 +79,7 @@ where It: Iterator)> #[derive(Debug, PartialEq, Eq)] pub enum VariableBinding { Atomic { + region: InputRegionTag, symbol: String, typtag: Option }, @@ -89,10 +90,10 @@ pub enum VariableBinding { } impl VariableBinding { - pub fn flatten(self) -> Vec<(String, Option)> { + pub fn flatten(self) -> Vec<(InputRegionTag, String, Option)> { match self { - VariableBinding::Atomic{ symbol, typtag } => - vec![ (symbol, typtag) ], + VariableBinding::Atomic{ region, symbol, typtag } => + vec![ (region, symbol, typtag) ], VariableBinding::Struct{ members, typtag } => members .into_iter() @@ -122,13 +123,15 @@ where It: Iterator)> }) } Ok(LTIRToken::Symbol(_)) => { + let (name_region, name) = parse_symbol(tokens)?; Ok(VariableBinding::Atomic{ - symbol: parse_symbol(tokens)?, + region: name_region, + symbol: name, typtag: parse_type_tag(typectx, tokens)? }) } - Err(err) => Err((*region, ParseError::LexError(err.clone()))), - _ => Err((*region, ParseError::UnexpectedToken)) + Err(err) => Err((region.clone(), ParseError::LexError(err.clone()))), + _ => Err((region.clone(), ParseError::UnexpectedToken)) } } else { Err((InputRegionTag::default(), ParseError::UnexpectedEnd)) @@ -184,18 +187,19 @@ where It: Iterator)> "!" => { tokens.next(); // todo accept address-expression instead of symbol - let name = parse_symbol(tokens)?; + let (name_region, name) = parse_symbol(tokens)?; let val_expr = parse_expr(typectx, tokens)?; let _ = parse_expect(tokens, LTIRToken::StatementSep)?; Ok(Statement::Assignment { + name_region, var_id: name, val_expr, }) } "let" => { tokens.next(); - let name = parse_symbol(tokens)?; + let (name_region, name) = parse_symbol(tokens)?; let typ = parse_type_tag(typectx, tokens)?; /* todo let mut variable_bindings = parse_binding_expr(typectx, tokens)?; @@ -281,7 +285,7 @@ pub fn parse_atom( where It: Iterator)> { match tokens.next() { - Some((region, Ok(LTIRToken::Symbol(sym)))) => Ok(LTExpr::symbol(sym.as_str())), + Some((region, Ok(LTIRToken::Symbol(sym)))) => Ok(LTExpr::Symbol{ region, symbol: sym, typ: None }), Some((region, Ok(LTIRToken::Char(c)))) => Ok(LTExpr::lit_uint(c as u64)), Some((region, Ok(LTIRToken::Num(n)))) => Ok(LTExpr::lit_uint(n as u64)), Some((region, Ok(_))) => Err((region, ParseError::UnexpectedToken)), @@ -309,7 +313,7 @@ where It: Iterator)> let body = parse_expr(typectx, tokens)?; return Ok(LTExpr::Abstraction { - args: variable_bindings.flatten().into_iter().map(|(s,t)| (s,t.map(|t|Ok(t))) ).collect(), + args: variable_bindings.flatten().into_iter().map(|(r,s,t)| (r,s,t.map(|t|Ok(t))) ).collect(), body: Box::new(body), }); } else { diff --git a/src/procedure_compiler.rs b/src/procedure_compiler.rs index 85e9a92..a756917 100644 --- a/src/procedure_compiler.rs +++ b/src/procedure_compiler.rs @@ -1,5 +1,6 @@ use { crate::{ + lexer::InputRegionTag, expr::{LTExpr, Statement}, symbols::{Scope, SymbolDef}, }, @@ -15,6 +16,8 @@ pub struct ProcedureCompiler { asm: tisc::Assembler, linker: tisc::Linker, result_size: usize, + + pub diagnostics: Vec<( InputRegionTag, String )> } impl ProcedureCompiler { @@ -24,10 +27,12 @@ impl ProcedureCompiler { asm: tisc::Assembler::new(), linker: tisc::Linker::new(), result_size: 0, + + diagnostics: Vec::new() } } - pub fn into_asm(mut self, proc_symbol: &String) -> (Vec<(String, SymbolDef)>, Vec) { + pub fn into_asm(mut self, proc_symbol: &String) -> (Vec<(String, SymbolDef)>, Vec<(InputRegionTag, String)>, Vec) { let mut symbols = Arc::try_unwrap(self.symbols).ok().unwrap() .into_inner().unwrap(); @@ -91,7 +96,7 @@ impl ProcedureCompiler { } } let bytecode = superlink.link_relative(proc_symbol).expect("link error"); - (symbol_exports, bytecode) + (symbol_exports, self.diagnostics, bytecode) } pub fn verify(&self) { @@ -100,7 +105,7 @@ impl ProcedureCompiler { pub fn compile_statement(mut self, statement: &Statement, enable_export: bool) -> Self { match statement { - Statement::Assignment { var_id, val_expr } => { + Statement::Assignment { name_region, var_id, val_expr } => { self = self.compile(val_expr); match self.symbols.read().unwrap().get(var_id) { @@ -125,7 +130,10 @@ impl ProcedureCompiler { .inst(tisc::VM_Instruction::Store); } None => { - eprintln!("cannot assign undefined symbol '{}'!", var_id); + self.diagnostics.push( + (name_region.clone(), + format!("cannot assign undefined symbol '{}'!", var_id)) + ); } } } @@ -140,19 +148,18 @@ impl ProcedureCompiler { .unwrap() .declare_proc(var_id.clone(), vec![], vec![], enable_export); - let (exports, lambda_procedure) = ProcedureCompiler::new(&self.symbols) + let (exports, mut diagnostics, lambda_procedure) = ProcedureCompiler::new(&self.symbols) .compile(val_expr) .into_asm(var_id); + self.diagnostics.append(&mut diagnostics); + self.linker.add_procedure(var_id, lambda_procedure); let offset = self.linker.get_link_addr(var_id).unwrap(); + // forward already exported symbols if enable_export { - for (name, def) in exports.iter() { - eprintln!("Procedure compiler: export {}", name); - } - self.symbols.write().unwrap().import( exports ); } } @@ -161,7 +168,9 @@ impl ProcedureCompiler { .write() .unwrap() .declare_var(var_id.clone(), laddertypes::TypeTerm::unit()); + self = self.compile_statement(&Statement::Assignment { + name_region: InputRegionTag::default(), var_id: var_id.clone(), val_expr: val_expr.clone(), }, false); @@ -195,7 +204,7 @@ impl ProcedureCompiler { pub fn compile(mut self, expr: <Expr) -> Self { match expr { - LTExpr::Symbol { typ, symbol } => match self.symbols.read().unwrap().get(symbol) { + LTExpr::Symbol { region, typ, symbol } => match self.symbols.read().unwrap().get(symbol) { Some(SymbolDef::FrameRef { typ, stack_ref }) => { self.asm = self.asm.lit(stack_ref).call("data-frame-get"); } @@ -211,20 +220,22 @@ impl ProcedureCompiler { self.asm = self.asm.call_symbol(link_addr); } None => { - eprintln!("undefined symbol '{}'!", symbol); + self.diagnostics.push( + (region.clone(), format!("undefined symbol '{}'!", symbol)) + ); } }, LTExpr::Literal { typ, val } => { self.asm = self.asm.lit(*val); } - LTExpr::Application { typ, head, body } => { + LTExpr::Application { typ, head, body } => { for arg in body.iter().rev() { self = self.compile(arg); } self = self.compile(head); } LTExpr::Abstraction { args, body } => { - for (arg_name, arg_type) in args.iter() { + for (region, arg_name, arg_type) in args.iter() { if let Some(Ok(typeterm)) = arg_type { let id = self .symbols @@ -233,7 +244,10 @@ impl ProcedureCompiler { .declare_var(arg_name.clone(), typeterm.clone()); self.asm = self.asm.lit(id).call("data-frame-set"); } else { - eprintln!("invalid type {:?} for argument {}", arg_type, arg_name); + self.diagnostics.push(( + region.clone(), + format!("invalid type {:?} for argument {}", arg_type, arg_name) + )); } } self = self.compile(body);