diff --git a/cranelift/isle/Cargo.lock b/cranelift/isle/Cargo.lock index f37ad00454..26a438a64e 100644 --- a/cranelift/isle/Cargo.lock +++ b/cranelift/isle/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - [[package]] name = "ansi_term" version = "0.11.0" @@ -64,11 +55,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ - "atty", - "humantime", "log", - "regex", - "termcolor", ] [[package]] @@ -80,12 +67,6 @@ dependencies = [ "libc", ] -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "isle" version = "0.1.0" @@ -93,7 +74,6 @@ dependencies = [ "clap", "env_logger", "log", - "thiserror", ] [[package]] @@ -111,73 +91,12 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "memchr" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" - -[[package]] -name = "proc-macro2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "syn" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "termcolor" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -dependencies = [ - "winapi-util", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -187,38 +106,12 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "thiserror" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "vec_map" version = "0.8.2" @@ -241,15 +134,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/cranelift/isle/Cargo.toml b/cranelift/isle/Cargo.toml index d3f43cb1c5..2d7da0ae6f 100644 --- a/cranelift/isle/Cargo.toml +++ b/cranelift/isle/Cargo.toml @@ -7,6 +7,5 @@ license = "Apache-2.0 WITH LLVM-exception" [dependencies] log = "0.4" -env_logger = "0.8" -thiserror = "1.0" +env_logger = { version = "0.8", default-features = false } clap = "2.33" diff --git a/cranelift/isle/isle_examples/error1.isle b/cranelift/isle/isle_examples/error1.isle new file mode 100644 index 0000000000..5d304668f6 --- /dev/null +++ b/cranelift/isle/isle_examples/error1.isle @@ -0,0 +1,36 @@ +(type u32 (primitive u32)) +(type bool (primitive bool)) +(type A (enum (A1 (x u32)))) + +(decl Ext1 (u32) A) +(decl Ext2 (u32) A) +(extern extractor Ext1 ext1) +(extern extractor Ext2 ext2) + +(decl C (bool) A) +(extern constructor C c) + +(decl Lower (A) A) + +(rule + (Lower + (and + a + (Ext1 x) + (Ext2 =q))) + (C y)) + +(type R (enum (A (x u32)))) + +(type Opcode (enum A B C)) +(type MachInst (enum D E F)) +(decl Lower2 (Opcode) MachInst) +(rule + (Lower2 (Opcode.A)) + (R.A (Opcode.A))) +(rule + (Lower2 (Opcode.B)) + (MachInst.E)) +(rule + (Lower2 (Opcode.C)) + (MachInst.F)) diff --git a/cranelift/isle/src/compile.rs b/cranelift/isle/src/compile.rs index 618998980c..8f98b8c1c6 100644 --- a/cranelift/isle/src/compile.rs +++ b/cranelift/isle/src/compile.rs @@ -3,9 +3,9 @@ use crate::error::Error; use crate::{ast, codegen, sema}; -pub fn compile(defs: &ast::Defs) -> Result { +pub fn compile(defs: &ast::Defs) -> Result> { let mut typeenv = sema::TypeEnv::from_ast(defs)?; let termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?; - let codegen = codegen::Codegen::compile(&typeenv, &termenv)?; - codegen.generate_rust() + let codegen = codegen::Codegen::compile(&typeenv, &termenv).map_err(|e| vec![e])?; + codegen.generate_rust().map_err(|e| vec![e]) } diff --git a/cranelift/isle/src/error.rs b/cranelift/isle/src/error.rs index 7fce2df669..a3afd1fce7 100644 --- a/cranelift/isle/src/error.rs +++ b/cranelift/isle/src/error.rs @@ -1,50 +1,50 @@ //! Error types. use crate::lexer::Pos; -use thiserror::Error; +use std::fmt; -#[derive(Debug, Error)] +#[derive(Clone, Debug)] pub enum Error { - #[error("Parse error")] - ParseError(#[from] ParseError), - #[error("Semantic error")] - SemaError(#[from] SemaError), - #[error("IO error")] - IoError(#[from] std::io::Error), - #[error("Formatting error")] - FmtError(#[from] std::fmt::Error), + CompileError { + msg: String, + filename: String, + pos: Pos, + }, + SystemError { + msg: String, + }, } -#[derive(Clone, Debug, Error)] -pub struct ParseError { - pub msg: String, - pub filename: String, - pub pos: Pos, -} - -#[derive(Clone, Debug, Error)] -pub struct SemaError { - pub msg: String, - pub filename: String, - pub pos: Pos, -} - -impl std::fmt::Display for ParseError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{}:{}:{}: {}", - self.filename, self.pos.line, self.pos.col, self.msg - ) +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Error::CompileError { + ref msg, + ref filename, + pos, + } => { + write!(f, "{}:{}: {}", filename, pos.line, msg) + } + &Error::SystemError { ref msg } => { + write!(f, "{}", msg) + } + } } } -impl std::fmt::Display for SemaError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{}:{}:{}: {}", - self.filename, self.pos.line, self.pos.col, self.msg - ) +impl std::error::Error for Error {} + +impl std::convert::From for Error { + fn from(e: std::fmt::Error) -> Error { + Error::SystemError { + msg: format!("{}", e), + } + } +} +impl std::convert::From for Error { + fn from(e: std::io::Error) -> Error { + Error::SystemError { + msg: format!("{}", e), + } } } diff --git a/cranelift/isle/src/main.rs b/cranelift/isle/src/main.rs index a09e21096a..5f2e168a19 100644 --- a/cranelift/isle/src/main.rs +++ b/cranelift/isle/src/main.rs @@ -47,7 +47,16 @@ fn main() -> Result<(), error::Error> { let lexer = lexer::Lexer::from_files(input_files)?; let mut parser = parser::Parser::new(lexer); let defs = parser.parse_defs()?; - let code = compile::compile(&defs)?; + let code = match compile::compile(&defs) { + Ok(code) => code, + Err(errors) => { + for error in errors { + eprintln!("{}", error); + } + eprintln!("Failed to compile."); + std::process::exit(1); + } + }; { use std::io::Write; diff --git a/cranelift/isle/src/parser.rs b/cranelift/isle/src/parser.rs index fc21f728de..8c6b080b10 100644 --- a/cranelift/isle/src/parser.rs +++ b/cranelift/isle/src/parser.rs @@ -9,15 +9,15 @@ pub struct Parser<'a> { lexer: Lexer<'a>, } -pub type ParseResult = std::result::Result; +pub type ParseResult = std::result::Result; impl<'a> Parser<'a> { pub fn new(lexer: Lexer<'a>) -> Parser<'a> { Parser { lexer } } - pub fn error(&self, pos: Pos, msg: String) -> ParseError { - ParseError { + pub fn error(&self, pos: Pos, msg: String) -> Error { + Error::CompileError { filename: self.lexer.filenames[pos.file].clone(), pos, msg, diff --git a/cranelift/isle/src/sema.rs b/cranelift/isle/src/sema.rs index df5854c2c4..19f136acf0 100644 --- a/cranelift/isle/src/sema.rs +++ b/cranelift/isle/src/sema.rs @@ -5,7 +5,7 @@ use crate::error::*; use crate::lexer::Pos; use std::collections::HashMap; -pub type SemaResult = std::result::Result; +pub type SemaResult = std::result::Result>; #[macro_export] macro_rules! declare_id { @@ -35,6 +35,7 @@ pub struct TypeEnv { pub sym_map: HashMap, pub types: Vec, pub type_map: HashMap, + pub errors: Vec, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -296,6 +297,7 @@ impl TypeEnv { sym_map: HashMap::new(), types: vec![], type_map: HashMap::new(), + errors: vec![], }; // Traverse defs, assigning type IDs to type names. We'll fill @@ -306,10 +308,11 @@ impl TypeEnv { let tid = TypeId(tyenv.type_map.len()); let name = tyenv.intern_mut(&td.name); if tyenv.type_map.contains_key(&name) { - return Err(tyenv.error( + tyenv.report_error( td.pos, format!("Type name defined more than once: '{}'", td.name.0), - )); + ); + continue; } tyenv.type_map.insert(name, tid); } @@ -324,7 +327,12 @@ impl TypeEnv { for def in &defs.defs { match def { &ast::Def::Type(ref td) => { - let ty = tyenv.type_from_ast(TypeId(tid), td)?; + let ty = match tyenv.type_from_ast(TypeId(tid), td) { + Some(ty) => ty, + None => { + continue; + } + }; tyenv.types.push(ty); tid += 1; } @@ -332,13 +340,23 @@ impl TypeEnv { } } + tyenv.return_errors()?; + Ok(tyenv) } - fn type_from_ast(&mut self, tid: TypeId, ty: &ast::Type) -> SemaResult { + fn return_errors(&mut self) -> SemaResult<()> { + if self.errors.len() > 0 { + Err(std::mem::take(&mut self.errors)) + } else { + Ok(()) + } + } + + fn type_from_ast(&mut self, tid: TypeId, ty: &ast::Type) -> Option { let name = self.intern(&ty.name).unwrap(); match &ty.ty { - &ast::TypeValue::Primitive(ref id) => Ok(Type::Primitive(tid, self.intern_mut(id))), + &ast::TypeValue::Primitive(ref id) => Some(Type::Primitive(tid, self.intern_mut(id))), &ast::TypeValue::Enum(ref ty_variants) => { let mut variants = vec![]; for variant in ty_variants { @@ -347,34 +365,37 @@ impl TypeEnv { let name = self.intern_mut(&variant.name); let id = VariantId(variants.len()); if variants.iter().any(|v: &Variant| v.name == name) { - return Err(self.error( + self.report_error( ty.pos, format!("Duplicate variant name in type: '{}'", variant.name.0), - )); + ); + return None; } let mut fields = vec![]; for field in &variant.fields { let field_name = self.intern_mut(&field.name); if fields.iter().any(|f: &Field| f.name == field_name) { - return Err(self.error( + self.report_error( ty.pos, format!( "Duplicate field name '{}' in variant '{}' of type", field.name.0, variant.name.0 ), - )); + ); + return None; } let field_ty = self.intern_mut(&field.ty); let field_tid = match self.type_map.get(&field_ty) { Some(tid) => *tid, None => { - return Err(self.error( + self.report_error( ty.pos, format!( "Unknown type '{}' for field '{}' in variant '{}'", field.ty.0, field.name.0, variant.name.0 ), - )); + ); + return None; } }; fields.push(Field { @@ -390,7 +411,7 @@ impl TypeEnv { fields, }); } - Ok(Type::Enum { + Some(Type::Enum { name, id: tid, is_extern: ty.is_extern, @@ -401,14 +422,19 @@ impl TypeEnv { } } - fn error(&self, pos: Pos, msg: String) -> SemaError { - SemaError { + fn error(&self, pos: Pos, msg: String) -> Error { + Error::CompileError { filename: self.filenames[pos.file].clone(), pos, msg, } } + fn report_error(&mut self, pos: Pos, msg: String) { + let err = self.error(pos, msg); + self.errors.push(err); + } + pub fn intern_mut(&mut self, ident: &ast::Ident) -> Sym { if let Some(s) = self.sym_map.get(&ident.0).cloned() { s @@ -446,24 +472,27 @@ impl TermEnv { rules: vec![], }; - env.collect_term_sigs(tyenv, defs)?; - env.collect_enum_variant_terms(tyenv)?; - env.collect_constructors(tyenv, defs)?; - env.collect_extractor_templates(tyenv, defs)?; - env.collect_rules(tyenv, defs)?; + env.collect_term_sigs(tyenv, defs); + env.collect_enum_variant_terms(tyenv); + env.collect_constructors(tyenv, defs); + env.collect_extractor_templates(tyenv, defs); + tyenv.return_errors()?; + env.collect_rules(tyenv, defs); + tyenv.return_errors()?; Ok(env) } - fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) -> SemaResult<()> { + fn collect_term_sigs(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) { for def in &defs.defs { match def { &ast::Def::Decl(ref decl) => { let tid = TermId(self.terms.len()); let name = tyenv.intern_mut(&decl.term); if self.term_map.contains_key(&name) { - return Err( - tyenv.error(decl.pos, format!("Duplicate decl for '{}'", decl.term.0)) + tyenv.report_error( + decl.pos, + format!("Duplicate decl for '{}'", decl.term.0), ); } self.term_map.insert(name, tid); @@ -474,18 +503,32 @@ impl TermEnv { .map(|id| { let sym = tyenv.intern_mut(id); tyenv.type_map.get(&sym).cloned().ok_or_else(|| { - tyenv.error(decl.pos, format!("Unknown arg type: '{}'", id.0)) + tyenv.report_error( + decl.pos, + format!("Unknown arg type: '{}'", id.0), + ); + () }) }) - .collect::>>()?; + .collect::, ()>>(); + let arg_tys = match arg_tys { + Ok(a) => a, + Err(_) => { + continue; + } + }; let ret_ty = { let sym = tyenv.intern_mut(&decl.ret_ty); - tyenv.type_map.get(&sym).cloned().ok_or_else(|| { - tyenv.error( - decl.pos, - format!("Unknown return type: '{}'", decl.ret_ty.0), - ) - })? + match tyenv.type_map.get(&sym).cloned() { + Some(t) => t, + None => { + tyenv.report_error( + decl.pos, + format!("Unknown return type: '{}'", decl.ret_ty.0), + ); + continue; + } + } }; self.terms.push(Term { @@ -499,12 +542,11 @@ impl TermEnv { _ => {} } } - - Ok(()) } - fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) -> SemaResult<()> { - for ty in &tyenv.types { + fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) { + 'types: for i in 0..tyenv.types.len() { + let ty = &tyenv.types[i]; match ty { &Type::Enum { pos, @@ -514,13 +556,12 @@ impl TermEnv { } => { for variant in variants { if self.term_map.contains_key(&variant.fullname) { - return Err(tyenv.error( + let variant_name = tyenv.syms[variant.fullname.index()].clone(); + tyenv.report_error( pos, - format!( - "Duplicate enum variant constructor: '{}'", - tyenv.syms[variant.fullname.index()] - ), - )); + format!("Duplicate enum variant constructor: '{}'", variant_name,), + ); + continue 'types; } let tid = TermId(self.terms.len()); let arg_tys = variant.fields.iter().map(|fld| fld.ty).collect::>(); @@ -540,11 +581,9 @@ impl TermEnv { _ => {} } } - - Ok(()) } - fn collect_constructors(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) -> SemaResult<()> { + fn collect_constructors(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) { for def in &defs.defs { match def { &ast::Def::Rule(ref rule) => { @@ -552,19 +591,20 @@ impl TermEnv { let term = match rule.pattern.root_term() { Some(t) => t, None => { - return Err(tyenv.error( + tyenv.report_error( pos, "Rule does not have a term at the LHS root".to_string(), - )); + ); + continue; } }; let sym = tyenv.intern_mut(&term); let term = match self.term_map.get(&sym) { Some(&tid) => tid, None => { - return Err( - tyenv.error(pos, "Rule LHS root term is not defined".to_string()) - ); + tyenv + .report_error(pos, "Rule LHS root term is not defined".to_string()); + continue; } }; let termdata = &mut self.terms[term.index()]; @@ -576,31 +616,32 @@ impl TermEnv { // OK, no error; multiple rules can apply to one internal constructor term. } _ => { - return Err(tyenv.error(pos, "Rule LHS root term is incorrect kind; cannot be internal constructor".to_string())); + tyenv.report_error(pos, "Rule LHS root term is incorrect kind; cannot be internal constructor".to_string()); + continue; } } } _ => {} } } - Ok(()) } - fn collect_extractor_templates( - &mut self, - tyenv: &mut TypeEnv, - defs: &ast::Defs, - ) -> SemaResult<()> { + fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) { for def in &defs.defs { match def { &ast::Def::Extractor(ref ext) => { let sym = tyenv.intern_mut(&ext.term); - let term = self.term_map.get(&sym).ok_or_else(|| { - tyenv.error( - ext.pos, - "Extractor macro body definition on a non-existent term".to_string(), - ) - })?; + let term = match self.term_map.get(&sym) { + Some(x) => x, + None => { + tyenv.report_error( + ext.pos, + "Extractor macro body definition on a non-existent term" + .to_string(), + ); + return; + } + }; let termdata = &mut self.terms[term.index()]; let template = ext.template.make_macro_template(&ext.args[..]); log::trace!("extractor def: {:?} becomes template {:?}", def, template); @@ -609,22 +650,21 @@ impl TermEnv { termdata.kind = TermKind::InternalExtractor { template }; } _ => { - return Err(tyenv.error( + tyenv.report_error( ext.pos, "Extractor macro body defined on term of incorrect kind" .to_string(), - )); + ); + continue; } } } _ => {} } } - - Ok(()) } - fn collect_rules(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) -> SemaResult<()> { + fn collect_rules(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) { for def in &defs.defs { match def { &ast::Def::Rule(ref rule) => { @@ -634,15 +674,26 @@ impl TermEnv { vars: vec![], }; - let (lhs, ty) = self.translate_pattern( + let (lhs, ty) = match self.translate_pattern( tyenv, rule.pos, &rule.pattern, None, &mut bindings, - )?; + ) { + Some(x) => x, + None => { + // Keep going to collect more errors. + continue; + } + }; let rhs = - self.translate_expr(tyenv, rule.pos, &rule.expr, ty, &mut bindings)?; + match self.translate_expr(tyenv, rule.pos, &rule.expr, ty, &mut bindings) { + Some(x) => x, + None => { + continue; + } + }; let rid = RuleId(self.rules.len()); self.rules.push(Rule { @@ -663,10 +714,11 @@ impl TermEnv { let term_id = match self.term_map.get(&term_sym) { Some(term) => term, None => { - return Err(tyenv.error( + tyenv.report_error( pos, format!("Constructor declared on undefined term '{}'", term.0), - )) + ); + continue; } }; let termdata = &mut self.terms[term_id.index()]; @@ -675,13 +727,13 @@ impl TermEnv { termdata.kind = TermKind::ExternalConstructor { name: func_sym }; } _ => { - return Err(tyenv.error( + tyenv.report_error( pos, format!( "Constructor defined on term of improper type '{}'", term.0 ), - )); + ); } } } @@ -697,10 +749,11 @@ impl TermEnv { let term_id = match self.term_map.get(&term_sym) { Some(term) => term, None => { - return Err(tyenv.error( + tyenv.report_error( pos, format!("Extractor declared on undefined term '{}'", term.0), - )) + ); + continue; } }; @@ -708,7 +761,8 @@ impl TermEnv { let arg_polarity = if let Some(pol) = arg_polarity.as_ref() { if pol.len() != termdata.arg_tys.len() { - return Err(tyenv.error(pos, "Incorrect number of argument-polarity directions in extractor definition".to_string())); + tyenv.report_error(pos, "Incorrect number of argument-polarity directions in extractor definition".to_string()); + continue; } pol.clone() } else { @@ -724,18 +778,17 @@ impl TermEnv { }; } _ => { - return Err(tyenv.error( + tyenv.report_error( pos, format!("Extractor defined on term of improper type '{}'", term.0), - )); + ); + continue; } } } _ => {} } } - - Ok(()) } fn translate_pattern( @@ -745,37 +798,55 @@ impl TermEnv { pat: &ast::Pattern, expected_ty: Option, bindings: &mut Bindings, - ) -> SemaResult<(Pattern, TypeId)> { + ) -> Option<(Pattern, TypeId)> { log::trace!("translate_pattern: {:?}", pat); log::trace!("translate_pattern: bindings = {:?}", bindings); match pat { // TODO: flag on primitive type decl indicating it's an integer type? &ast::Pattern::ConstInt { val } => { - let ty = expected_ty.ok_or_else(|| { - tyenv.error(pos, "Need an implied type for an integer constant".into()) - })?; - Ok((Pattern::ConstInt(ty, val), ty)) + let ty = match expected_ty { + Some(t) => t, + None => { + tyenv.report_error( + pos, + "Need an implied type for an integer constant".into(), + ); + return None; + } + }; + Some((Pattern::ConstInt(ty, val), ty)) } &ast::Pattern::Wildcard => { - let ty = expected_ty.ok_or_else(|| { - tyenv.error(pos, "Need an implied type for a wildcard".into()) - })?; - Ok((Pattern::Wildcard(ty), ty)) + let ty = match expected_ty { + Some(t) => t, + None => { + tyenv.report_error(pos, "Need an implied type for a wildcard".into()); + return None; + } + }; + Some((Pattern::Wildcard(ty), ty)) } &ast::Pattern::And { ref subpats } => { let mut expected_ty = expected_ty; let mut children = vec![]; for subpat in subpats { let (subpat, ty) = - self.translate_pattern(tyenv, pos, &*subpat, expected_ty, bindings)?; + match self.translate_pattern(tyenv, pos, &*subpat, expected_ty, bindings) { + Some(x) => x, + None => { + // Try to keep going for more errors. + continue; + } + }; expected_ty = expected_ty.or(Some(ty)); children.push(subpat); } if expected_ty.is_none() { - return Err(tyenv.error(pos, "No type for (and ...) form.".to_string())); + tyenv.report_error(pos, "No type for (and ...) form.".to_string()); + return None; } let ty = expected_ty.unwrap(); - Ok((Pattern::And(ty, children), ty)) + Some((Pattern::And(ty, children), ty)) } &ast::Pattern::BindPattern { ref var, @@ -787,30 +858,32 @@ impl TermEnv { let name = tyenv.intern_mut(var); if bindings.vars.iter().any(|bv| bv.name == name) { - return Err(tyenv.error( + tyenv.report_error( pos, - format!("Rebound variable name in LHS pattern: '{}'", var.0), - )); + format!("Re-bound variable name in LHS pattern: '{}'", var.0), + ); + // Try to keep going. } let id = VarId(bindings.next_var); bindings.next_var += 1; log::trace!("binding var {:?}", var.0); bindings.vars.push(BoundVar { name, id, ty }); - Ok((Pattern::BindPattern(ty, id, Box::new(subpat)), ty)) + Some((Pattern::BindPattern(ty, id, Box::new(subpat)), ty)) } &ast::Pattern::Var { ref var } => { // Look up the variable; it must already have been bound. let name = tyenv.intern_mut(var); let bv = match bindings.vars.iter().rev().find(|bv| bv.name == name) { None => { - return Err(tyenv.error( + tyenv.report_error( pos, format!( "Unknown variable '{}' in bound-var pattern '={}'", var.0, var.0 ), - )) + ); + return None; } Some(bv) => bv, }; @@ -818,17 +891,28 @@ impl TermEnv { None => bv.ty, Some(expected_ty) if expected_ty == bv.ty => bv.ty, Some(expected_ty) => { - return Err(tyenv.error(pos, format!("Mismatched types: pattern expects type '{}' but already-bound var '{}' has type '{}'", tyenv.types[expected_ty.index()].name(tyenv), var.0, tyenv.types[bv.ty.index()].name(tyenv)))); + tyenv.report_error( + pos, + format!( + "Mismatched types: pattern expects type '{}' but already-bound var '{}' has type '{}'", + tyenv.types[expected_ty.index()].name(tyenv), + var.0, + tyenv.types[bv.ty.index()].name(tyenv))); + bv.ty // Try to keep going for more errors. } }; - Ok((Pattern::Var(ty, bv.id), ty)) + Some((Pattern::Var(ty, bv.id), ty)) } &ast::Pattern::Term { ref sym, ref args } => { let name = tyenv.intern_mut(&sym); // Look up the term. - let tid = self.term_map.get(&name).ok_or_else(|| { - tyenv.error(pos, format!("Unknown term in pattern: '{}'", sym.0)) - })?; + let tid = match self.term_map.get(&name) { + Some(t) => t, + None => { + tyenv.report_error(pos, format!("Unknown term in pattern: '{}'", sym.0)); + return None; + } + }; // Get the return type and arg types. Verify the // expected type of this pattern, if any, against the @@ -838,13 +922,19 @@ impl TermEnv { None => ret_ty, Some(expected_ty) if expected_ty == ret_ty => ret_ty, Some(expected_ty) => { - return Err(tyenv.error(pos, format!("Mismatched types: pattern expects type '{}' but term has return type '{}'", tyenv.types[expected_ty.index()].name(tyenv), tyenv.types[ret_ty.index()].name(tyenv)))); + tyenv.report_error( + pos, + format!( + "Mismatched types: pattern expects type '{}' but term has return type '{}'", + tyenv.types[expected_ty.index()].name(tyenv), + tyenv.types[ret_ty.index()].name(tyenv))); + ret_ty // Try to keep going for more errors. } }; // Check that we have the correct argument count. if self.terms[tid.index()].arg_tys.len() != args.len() { - return Err(tyenv.error( + tyenv.report_error( pos, format!( "Incorrect argument count for term '{}': got {}, expect {}", @@ -852,7 +942,7 @@ impl TermEnv { args.len(), self.terms[tid.index()].arg_tys.len() ), - )); + ); } let termdata = &self.terms[tid.index()]; @@ -861,7 +951,7 @@ impl TermEnv { &TermKind::EnumVariant { .. } => { for arg in args { if let &ast::TermArgPattern::Expr(..) = arg { - return Err(tyenv.error(pos, format!("Term in pattern '{}' cannot have an injected expr, because it is an enum variant", sym.0))); + tyenv.report_error(pos, format!("Term in pattern '{}' cannot have an injected expr, because it is an enum variant", sym.0)); } } } @@ -872,15 +962,15 @@ impl TermEnv { match (arg, pol) { (&ast::TermArgPattern::Expr(..), &ArgPolarity::Input) => {} (&ast::TermArgPattern::Expr(..), &ArgPolarity::Output) => { - return Err(tyenv.error( + tyenv.report_error( pos, "Expression used for output-polarity extractor arg" .to_string(), - )); + ); } (_, &ArgPolarity::Output) => {} (_, &ArgPolarity::Input) => { - return Err(tyenv.error(pos, "Non-expression used in pattern but expression required for input-polarity extractor arg".to_string())); + tyenv.report_error(pos, "Non-expression used in pattern but expression required for input-polarity extractor arg".to_string()); } } } @@ -895,7 +985,8 @@ impl TermEnv { let sub_ast = match template_arg { &ast::TermArgPattern::Pattern(ref pat) => pat.clone(), &ast::TermArgPattern::Expr(_) => { - return Err(tyenv.error(pos, "Cannot expand an extractor macro with an expression in a macro argument".to_string())); + tyenv.report_error(pos, "Cannot expand an extractor macro with an expression in a macro argument".to_string()); + return None; } }; macro_args.push(sub_ast.clone()); @@ -908,8 +999,10 @@ impl TermEnv { // OK. } &TermKind::Declared => { - return Err(tyenv - .error(pos, format!("Declared but undefined term '{}' used", sym.0))); + tyenv.report_error( + pos, + format!("Declared but undefined term '{}' used", sym.0), + ); } } @@ -917,12 +1010,23 @@ impl TermEnv { let mut subpats = vec![]; for (i, arg) in args.iter().enumerate() { let arg_ty = self.terms[tid.index()].arg_tys[i]; - let (subpat, _) = - self.translate_pattern_term_arg(tyenv, pos, arg, Some(arg_ty), bindings)?; + let (subpat, _) = match self.translate_pattern_term_arg( + tyenv, + pos, + arg, + Some(arg_ty), + bindings, + ) { + Some(x) => x, + None => { + // Try to keep going for more errors. + continue; + } + }; subpats.push(subpat); } - Ok((Pattern::Term(ty, *tid, subpats), ty)) + Some((Pattern::Term(ty, *tid, subpats), ty)) } &ast::Pattern::MacroArg { .. } => unreachable!(), } @@ -935,23 +1039,24 @@ impl TermEnv { pat: &ast::TermArgPattern, expected_ty: Option, bindings: &mut Bindings, - ) -> SemaResult<(TermArgPattern, TypeId)> { + ) -> Option<(TermArgPattern, TypeId)> { match pat { &ast::TermArgPattern::Pattern(ref pat) => { let (subpat, ty) = self.translate_pattern(tyenv, pos, pat, expected_ty, bindings)?; - Ok((TermArgPattern::Pattern(subpat), ty)) + Some((TermArgPattern::Pattern(subpat), ty)) } &ast::TermArgPattern::Expr(ref expr) => { if expected_ty.is_none() { - return Err(tyenv.error( + tyenv.report_error( pos, "Expression in pattern must have expected type".to_string(), - )); + ); + return None; } let ty = expected_ty.unwrap(); let expr = self.translate_expr(tyenv, pos, expr, expected_ty.unwrap(), bindings)?; - Ok((TermArgPattern::Expr(expr), ty)) + Some((TermArgPattern::Expr(expr), ty)) } } } @@ -963,28 +1068,32 @@ impl TermEnv { expr: &ast::Expr, ty: TypeId, bindings: &mut Bindings, - ) -> SemaResult { + ) -> Option { log::trace!("translate_expr: {:?}", expr); match expr { &ast::Expr::Term { ref sym, ref args } => { // Look up the term. let name = tyenv.intern_mut(&sym); // Look up the term. - let tid = self.term_map.get(&name).ok_or_else(|| { - tyenv.error(pos, format!("Unknown term in pattern: '{}'", sym.0)) - })?; + let tid = match self.term_map.get(&name) { + Some(t) => t, + None => { + tyenv.report_error(pos, format!("Unknown term in pattern: '{}'", sym.0)); + return None; + } + }; // Get the return type and arg types. Verify the // expected type of this pattern, if any, against the // return type of the term. let ret_ty = self.terms[tid.index()].ret_ty; if ret_ty != ty { - return Err(tyenv.error(pos, format!("Mismatched types: expression expects type '{}' but term has return type '{}'", tyenv.types[ty.index()].name(tyenv), tyenv.types[ret_ty.index()].name(tyenv)))); + tyenv.report_error(pos, format!("Mismatched types: expression expects type '{}' but term has return type '{}'", tyenv.types[ty.index()].name(tyenv), tyenv.types[ret_ty.index()].name(tyenv))); } // Check that we have the correct argument count. if self.terms[tid.index()].arg_tys.len() != args.len() { - return Err(tyenv.error( + tyenv.report_error( pos, format!( "Incorrect argument count for term '{}': got {}, expect {}", @@ -992,32 +1101,38 @@ impl TermEnv { args.len(), self.terms[tid.index()].arg_tys.len() ), - )); + ); } // Resolve subexpressions. let mut subexprs = vec![]; for (i, arg) in args.iter().enumerate() { let arg_ty = self.terms[tid.index()].arg_tys[i]; - let subexpr = self.translate_expr(tyenv, pos, arg, arg_ty, bindings)?; + let subexpr = match self.translate_expr(tyenv, pos, arg, arg_ty, bindings) { + Some(s) => s, + None => { + continue; + } + }; subexprs.push(subexpr); } - Ok(Expr::Term(ty, *tid, subexprs)) + Some(Expr::Term(ty, *tid, subexprs)) } &ast::Expr::Var { ref name } => { let sym = tyenv.intern_mut(name); // Look through bindings, innermost (most recent) first. let bv = match bindings.vars.iter().rev().find(|b| b.name == sym) { None => { - return Err(tyenv.error(pos, format!("Unknown variable '{}'", name.0))); + tyenv.report_error(pos, format!("Unknown variable '{}'", name.0)); + return None; } Some(bv) => bv, }; // Verify type. if bv.ty != ty { - return Err(tyenv.error( + tyenv.report_error( pos, format!( "Variable '{}' has type {} but we need {} in context", @@ -1025,12 +1140,12 @@ impl TermEnv { tyenv.types[bv.ty.index()].name(tyenv), tyenv.types[ty.index()].name(tyenv) ), - )); + ); } - Ok(Expr::Var(bv.ty, bv.id)) + Some(Expr::Var(bv.ty, bv.id)) } - &ast::Expr::ConstInt { val } => Ok(Expr::ConstInt(ty, val)), + &ast::Expr::ConstInt { val } => Some(Expr::ConstInt(ty, val)), &ast::Expr::Let { ref defs, ref body } => { let orig_binding_len = bindings.vars.len(); @@ -1040,33 +1155,41 @@ impl TermEnv { // Check that the given variable name does not already exist. let name = tyenv.intern_mut(&def.var); if bindings.vars.iter().any(|bv| bv.name == name) { - return Err( - tyenv.error(pos, format!("Variable '{}' already bound", def.var.0)) - ); + tyenv.report_error(pos, format!("Variable '{}' already bound", def.var.0)); } // Look up the type. let tysym = match tyenv.intern(&def.ty) { Some(ty) => ty, None => { - return Err(tyenv.error( + tyenv.report_error( pos, format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0), - )) + ); + continue; } }; let tid = match tyenv.type_map.get(&tysym) { Some(tid) => *tid, None => { - return Err(tyenv.error( + tyenv.report_error( pos, format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0), - )) + ); + continue; } }; // Evaluate the variable's value. - let val = Box::new(self.translate_expr(tyenv, pos, &def.val, ty, bindings)?); + let val = Box::new( + match self.translate_expr(tyenv, pos, &def.val, ty, bindings) { + Some(e) => e, + None => { + // Keep going for more errors. + continue; + } + }, + ); // Bind the var with the given type. let id = VarId(bindings.next_var); @@ -1083,7 +1206,7 @@ impl TermEnv { // Pop the bindings. bindings.vars.truncate(orig_binding_len); - Ok(Expr::Let(body_ty, let_defs, body)) + Some(Expr::Let(body_ty, let_defs, body)) } } }