Revamped error handling: keep going beyond some errors to accumulate a list of build errors, like most conventional compilers.

This commit is contained in:
Chris Fallin
2021-09-09 23:27:25 -07:00
parent b46fa6acb0
commit 7d38b3b6d8
8 changed files with 359 additions and 308 deletions

View File

@@ -2,15 +2,6 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 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]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@@ -64,11 +55,7 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
dependencies = [ dependencies = [
"atty",
"humantime",
"log", "log",
"regex",
"termcolor",
] ]
[[package]] [[package]]
@@ -80,12 +67,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "isle" name = "isle"
version = "0.1.0" version = "0.1.0"
@@ -93,7 +74,6 @@ dependencies = [
"clap", "clap",
"env_logger", "env_logger",
"log", "log",
"thiserror",
] ]
[[package]] [[package]]
@@ -111,73 +91,12 @@ dependencies = [
"cfg-if", "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]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 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]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.11.0" version = "0.11.0"
@@ -187,38 +106,12 @@ dependencies = [
"unicode-width", "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]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.8" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]] [[package]]
name = "vec_map" name = "vec_map"
version = "0.8.2" version = "0.8.2"
@@ -241,15 +134,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 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]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View File

@@ -7,6 +7,5 @@ license = "Apache-2.0 WITH LLVM-exception"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
env_logger = "0.8" env_logger = { version = "0.8", default-features = false }
thiserror = "1.0"
clap = "2.33" clap = "2.33"

View File

@@ -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))

View File

@@ -3,9 +3,9 @@
use crate::error::Error; use crate::error::Error;
use crate::{ast, codegen, sema}; use crate::{ast, codegen, sema};
pub fn compile(defs: &ast::Defs) -> Result<String, Error> { pub fn compile(defs: &ast::Defs) -> Result<String, Vec<Error>> {
let mut typeenv = sema::TypeEnv::from_ast(defs)?; let mut typeenv = sema::TypeEnv::from_ast(defs)?;
let termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?; let termenv = sema::TermEnv::from_ast(&mut typeenv, defs)?;
let codegen = codegen::Codegen::compile(&typeenv, &termenv)?; let codegen = codegen::Codegen::compile(&typeenv, &termenv).map_err(|e| vec![e])?;
codegen.generate_rust() codegen.generate_rust().map_err(|e| vec![e])
} }

View File

@@ -1,50 +1,50 @@
//! Error types. //! Error types.
use crate::lexer::Pos; use crate::lexer::Pos;
use thiserror::Error; use std::fmt;
#[derive(Debug, Error)] #[derive(Clone, Debug)]
pub enum Error { pub enum Error {
#[error("Parse error")] CompileError {
ParseError(#[from] ParseError), msg: String,
#[error("Semantic error")] filename: String,
SemaError(#[from] SemaError), pos: Pos,
#[error("IO error")] },
IoError(#[from] std::io::Error), SystemError {
#[error("Formatting error")] msg: String,
FmtError(#[from] std::fmt::Error), },
} }
#[derive(Clone, Debug, Error)] impl fmt::Display for Error {
pub struct ParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
pub msg: String, match self {
pub filename: String, &Error::CompileError {
pub pos: Pos, ref msg,
} ref filename,
pos,
#[derive(Clone, Debug, Error)] } => {
pub struct SemaError { write!(f, "{}:{}: {}", filename, pos.line, msg)
pub msg: String, }
pub filename: String, &Error::SystemError { ref msg } => {
pub pos: Pos, write!(f, "{}", msg)
} }
}
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 std::fmt::Display for SemaError { impl std::error::Error for Error {}
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!( impl std::convert::From<std::fmt::Error> for Error {
f, fn from(e: std::fmt::Error) -> Error {
"{}:{}:{}: {}", Error::SystemError {
self.filename, self.pos.line, self.pos.col, self.msg msg: format!("{}", e),
) }
}
}
impl std::convert::From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Error {
Error::SystemError {
msg: format!("{}", e),
}
} }
} }

View File

@@ -47,7 +47,16 @@ fn main() -> Result<(), error::Error> {
let lexer = lexer::Lexer::from_files(input_files)?; let lexer = lexer::Lexer::from_files(input_files)?;
let mut parser = parser::Parser::new(lexer); let mut parser = parser::Parser::new(lexer);
let defs = parser.parse_defs()?; 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; use std::io::Write;

View File

@@ -9,15 +9,15 @@ pub struct Parser<'a> {
lexer: Lexer<'a>, lexer: Lexer<'a>,
} }
pub type ParseResult<T> = std::result::Result<T, ParseError>; pub type ParseResult<T> = std::result::Result<T, Error>;
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
pub fn new(lexer: Lexer<'a>) -> Parser<'a> { pub fn new(lexer: Lexer<'a>) -> Parser<'a> {
Parser { lexer } Parser { lexer }
} }
pub fn error(&self, pos: Pos, msg: String) -> ParseError { pub fn error(&self, pos: Pos, msg: String) -> Error {
ParseError { Error::CompileError {
filename: self.lexer.filenames[pos.file].clone(), filename: self.lexer.filenames[pos.file].clone(),
pos, pos,
msg, msg,

View File

@@ -5,7 +5,7 @@ use crate::error::*;
use crate::lexer::Pos; use crate::lexer::Pos;
use std::collections::HashMap; use std::collections::HashMap;
pub type SemaResult<T> = std::result::Result<T, SemaError>; pub type SemaResult<T> = std::result::Result<T, Vec<Error>>;
#[macro_export] #[macro_export]
macro_rules! declare_id { macro_rules! declare_id {
@@ -35,6 +35,7 @@ pub struct TypeEnv {
pub sym_map: HashMap<String, Sym>, pub sym_map: HashMap<String, Sym>,
pub types: Vec<Type>, pub types: Vec<Type>,
pub type_map: HashMap<Sym, TypeId>, pub type_map: HashMap<Sym, TypeId>,
pub errors: Vec<Error>,
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@@ -296,6 +297,7 @@ impl TypeEnv {
sym_map: HashMap::new(), sym_map: HashMap::new(),
types: vec![], types: vec![],
type_map: HashMap::new(), type_map: HashMap::new(),
errors: vec![],
}; };
// Traverse defs, assigning type IDs to type names. We'll fill // 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 tid = TypeId(tyenv.type_map.len());
let name = tyenv.intern_mut(&td.name); let name = tyenv.intern_mut(&td.name);
if tyenv.type_map.contains_key(&name) { if tyenv.type_map.contains_key(&name) {
return Err(tyenv.error( tyenv.report_error(
td.pos, td.pos,
format!("Type name defined more than once: '{}'", td.name.0), format!("Type name defined more than once: '{}'", td.name.0),
)); );
continue;
} }
tyenv.type_map.insert(name, tid); tyenv.type_map.insert(name, tid);
} }
@@ -324,7 +327,12 @@ impl TypeEnv {
for def in &defs.defs { for def in &defs.defs {
match def { match def {
&ast::Def::Type(ref td) => { &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); tyenv.types.push(ty);
tid += 1; tid += 1;
} }
@@ -332,13 +340,23 @@ impl TypeEnv {
} }
} }
tyenv.return_errors()?;
Ok(tyenv) Ok(tyenv)
} }
fn type_from_ast(&mut self, tid: TypeId, ty: &ast::Type) -> SemaResult<Type> { 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<Type> {
let name = self.intern(&ty.name).unwrap(); let name = self.intern(&ty.name).unwrap();
match &ty.ty { 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) => { &ast::TypeValue::Enum(ref ty_variants) => {
let mut variants = vec![]; let mut variants = vec![];
for variant in ty_variants { for variant in ty_variants {
@@ -347,34 +365,37 @@ impl TypeEnv {
let name = self.intern_mut(&variant.name); let name = self.intern_mut(&variant.name);
let id = VariantId(variants.len()); let id = VariantId(variants.len());
if variants.iter().any(|v: &Variant| v.name == name) { if variants.iter().any(|v: &Variant| v.name == name) {
return Err(self.error( self.report_error(
ty.pos, ty.pos,
format!("Duplicate variant name in type: '{}'", variant.name.0), format!("Duplicate variant name in type: '{}'", variant.name.0),
)); );
return None;
} }
let mut fields = vec![]; let mut fields = vec![];
for field in &variant.fields { for field in &variant.fields {
let field_name = self.intern_mut(&field.name); let field_name = self.intern_mut(&field.name);
if fields.iter().any(|f: &Field| f.name == field_name) { if fields.iter().any(|f: &Field| f.name == field_name) {
return Err(self.error( self.report_error(
ty.pos, ty.pos,
format!( format!(
"Duplicate field name '{}' in variant '{}' of type", "Duplicate field name '{}' in variant '{}' of type",
field.name.0, variant.name.0 field.name.0, variant.name.0
), ),
)); );
return None;
} }
let field_ty = self.intern_mut(&field.ty); let field_ty = self.intern_mut(&field.ty);
let field_tid = match self.type_map.get(&field_ty) { let field_tid = match self.type_map.get(&field_ty) {
Some(tid) => *tid, Some(tid) => *tid,
None => { None => {
return Err(self.error( self.report_error(
ty.pos, ty.pos,
format!( format!(
"Unknown type '{}' for field '{}' in variant '{}'", "Unknown type '{}' for field '{}' in variant '{}'",
field.ty.0, field.name.0, variant.name.0 field.ty.0, field.name.0, variant.name.0
), ),
)); );
return None;
} }
}; };
fields.push(Field { fields.push(Field {
@@ -390,7 +411,7 @@ impl TypeEnv {
fields, fields,
}); });
} }
Ok(Type::Enum { Some(Type::Enum {
name, name,
id: tid, id: tid,
is_extern: ty.is_extern, is_extern: ty.is_extern,
@@ -401,14 +422,19 @@ impl TypeEnv {
} }
} }
fn error(&self, pos: Pos, msg: String) -> SemaError { fn error(&self, pos: Pos, msg: String) -> Error {
SemaError { Error::CompileError {
filename: self.filenames[pos.file].clone(), filename: self.filenames[pos.file].clone(),
pos, pos,
msg, 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 { pub fn intern_mut(&mut self, ident: &ast::Ident) -> Sym {
if let Some(s) = self.sym_map.get(&ident.0).cloned() { if let Some(s) = self.sym_map.get(&ident.0).cloned() {
s s
@@ -446,24 +472,27 @@ impl TermEnv {
rules: vec![], rules: vec![],
}; };
env.collect_term_sigs(tyenv, defs)?; env.collect_term_sigs(tyenv, defs);
env.collect_enum_variant_terms(tyenv)?; env.collect_enum_variant_terms(tyenv);
env.collect_constructors(tyenv, defs)?; env.collect_constructors(tyenv, defs);
env.collect_extractor_templates(tyenv, defs)?; env.collect_extractor_templates(tyenv, defs);
env.collect_rules(tyenv, defs)?; tyenv.return_errors()?;
env.collect_rules(tyenv, defs);
tyenv.return_errors()?;
Ok(env) 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 { for def in &defs.defs {
match def { match def {
&ast::Def::Decl(ref decl) => { &ast::Def::Decl(ref decl) => {
let tid = TermId(self.terms.len()); let tid = TermId(self.terms.len());
let name = tyenv.intern_mut(&decl.term); let name = tyenv.intern_mut(&decl.term);
if self.term_map.contains_key(&name) { if self.term_map.contains_key(&name) {
return Err( tyenv.report_error(
tyenv.error(decl.pos, format!("Duplicate decl for '{}'", decl.term.0)) decl.pos,
format!("Duplicate decl for '{}'", decl.term.0),
); );
} }
self.term_map.insert(name, tid); self.term_map.insert(name, tid);
@@ -474,18 +503,32 @@ impl TermEnv {
.map(|id| { .map(|id| {
let sym = tyenv.intern_mut(id); let sym = tyenv.intern_mut(id);
tyenv.type_map.get(&sym).cloned().ok_or_else(|| { 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::<SemaResult<Vec<TypeId>>>()?; .collect::<Result<Vec<TypeId>, ()>>();
let arg_tys = match arg_tys {
Ok(a) => a,
Err(_) => {
continue;
}
};
let ret_ty = { let ret_ty = {
let sym = tyenv.intern_mut(&decl.ret_ty); let sym = tyenv.intern_mut(&decl.ret_ty);
tyenv.type_map.get(&sym).cloned().ok_or_else(|| { match tyenv.type_map.get(&sym).cloned() {
tyenv.error( Some(t) => t,
decl.pos, None => {
format!("Unknown return type: '{}'", decl.ret_ty.0), tyenv.report_error(
) decl.pos,
})? format!("Unknown return type: '{}'", decl.ret_ty.0),
);
continue;
}
}
}; };
self.terms.push(Term { self.terms.push(Term {
@@ -499,12 +542,11 @@ impl TermEnv {
_ => {} _ => {}
} }
} }
Ok(())
} }
fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) -> SemaResult<()> { fn collect_enum_variant_terms(&mut self, tyenv: &mut TypeEnv) {
for ty in &tyenv.types { 'types: for i in 0..tyenv.types.len() {
let ty = &tyenv.types[i];
match ty { match ty {
&Type::Enum { &Type::Enum {
pos, pos,
@@ -514,13 +556,12 @@ impl TermEnv {
} => { } => {
for variant in variants { for variant in variants {
if self.term_map.contains_key(&variant.fullname) { 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, pos,
format!( format!("Duplicate enum variant constructor: '{}'", variant_name,),
"Duplicate enum variant constructor: '{}'", );
tyenv.syms[variant.fullname.index()] continue 'types;
),
));
} }
let tid = TermId(self.terms.len()); let tid = TermId(self.terms.len());
let arg_tys = variant.fields.iter().map(|fld| fld.ty).collect::<Vec<_>>(); let arg_tys = variant.fields.iter().map(|fld| fld.ty).collect::<Vec<_>>();
@@ -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 { for def in &defs.defs {
match def { match def {
&ast::Def::Rule(ref rule) => { &ast::Def::Rule(ref rule) => {
@@ -552,19 +591,20 @@ impl TermEnv {
let term = match rule.pattern.root_term() { let term = match rule.pattern.root_term() {
Some(t) => t, Some(t) => t,
None => { None => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
"Rule does not have a term at the LHS root".to_string(), "Rule does not have a term at the LHS root".to_string(),
)); );
continue;
} }
}; };
let sym = tyenv.intern_mut(&term); let sym = tyenv.intern_mut(&term);
let term = match self.term_map.get(&sym) { let term = match self.term_map.get(&sym) {
Some(&tid) => tid, Some(&tid) => tid,
None => { None => {
return Err( tyenv
tyenv.error(pos, "Rule LHS root term is not defined".to_string()) .report_error(pos, "Rule LHS root term is not defined".to_string());
); continue;
} }
}; };
let termdata = &mut self.terms[term.index()]; 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. // 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( fn collect_extractor_templates(&mut self, tyenv: &mut TypeEnv, defs: &ast::Defs) {
&mut self,
tyenv: &mut TypeEnv,
defs: &ast::Defs,
) -> SemaResult<()> {
for def in &defs.defs { for def in &defs.defs {
match def { match def {
&ast::Def::Extractor(ref ext) => { &ast::Def::Extractor(ref ext) => {
let sym = tyenv.intern_mut(&ext.term); let sym = tyenv.intern_mut(&ext.term);
let term = self.term_map.get(&sym).ok_or_else(|| { let term = match self.term_map.get(&sym) {
tyenv.error( Some(x) => x,
ext.pos, None => {
"Extractor macro body definition on a non-existent term".to_string(), 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 termdata = &mut self.terms[term.index()];
let template = ext.template.make_macro_template(&ext.args[..]); let template = ext.template.make_macro_template(&ext.args[..]);
log::trace!("extractor def: {:?} becomes template {:?}", def, template); log::trace!("extractor def: {:?} becomes template {:?}", def, template);
@@ -609,22 +650,21 @@ impl TermEnv {
termdata.kind = TermKind::InternalExtractor { template }; termdata.kind = TermKind::InternalExtractor { template };
} }
_ => { _ => {
return Err(tyenv.error( tyenv.report_error(
ext.pos, ext.pos,
"Extractor macro body defined on term of incorrect kind" "Extractor macro body defined on term of incorrect kind"
.to_string(), .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 { for def in &defs.defs {
match def { match def {
&ast::Def::Rule(ref rule) => { &ast::Def::Rule(ref rule) => {
@@ -634,15 +674,26 @@ impl TermEnv {
vars: vec![], vars: vec![],
}; };
let (lhs, ty) = self.translate_pattern( let (lhs, ty) = match self.translate_pattern(
tyenv, tyenv,
rule.pos, rule.pos,
&rule.pattern, &rule.pattern,
None, None,
&mut bindings, &mut bindings,
)?; ) {
Some(x) => x,
None => {
// Keep going to collect more errors.
continue;
}
};
let rhs = 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()); let rid = RuleId(self.rules.len());
self.rules.push(Rule { self.rules.push(Rule {
@@ -663,10 +714,11 @@ impl TermEnv {
let term_id = match self.term_map.get(&term_sym) { let term_id = match self.term_map.get(&term_sym) {
Some(term) => term, Some(term) => term,
None => { None => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!("Constructor declared on undefined term '{}'", term.0), format!("Constructor declared on undefined term '{}'", term.0),
)) );
continue;
} }
}; };
let termdata = &mut self.terms[term_id.index()]; let termdata = &mut self.terms[term_id.index()];
@@ -675,13 +727,13 @@ impl TermEnv {
termdata.kind = TermKind::ExternalConstructor { name: func_sym }; termdata.kind = TermKind::ExternalConstructor { name: func_sym };
} }
_ => { _ => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!( format!(
"Constructor defined on term of improper type '{}'", "Constructor defined on term of improper type '{}'",
term.0 term.0
), ),
)); );
} }
} }
} }
@@ -697,10 +749,11 @@ impl TermEnv {
let term_id = match self.term_map.get(&term_sym) { let term_id = match self.term_map.get(&term_sym) {
Some(term) => term, Some(term) => term,
None => { None => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!("Extractor declared on undefined term '{}'", term.0), 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() { let arg_polarity = if let Some(pol) = arg_polarity.as_ref() {
if pol.len() != termdata.arg_tys.len() { 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() pol.clone()
} else { } else {
@@ -724,18 +778,17 @@ impl TermEnv {
}; };
} }
_ => { _ => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!("Extractor defined on term of improper type '{}'", term.0), format!("Extractor defined on term of improper type '{}'", term.0),
)); );
continue;
} }
} }
} }
_ => {} _ => {}
} }
} }
Ok(())
} }
fn translate_pattern( fn translate_pattern(
@@ -745,37 +798,55 @@ impl TermEnv {
pat: &ast::Pattern, pat: &ast::Pattern,
expected_ty: Option<TypeId>, expected_ty: Option<TypeId>,
bindings: &mut Bindings, bindings: &mut Bindings,
) -> SemaResult<(Pattern, TypeId)> { ) -> Option<(Pattern, TypeId)> {
log::trace!("translate_pattern: {:?}", pat); log::trace!("translate_pattern: {:?}", pat);
log::trace!("translate_pattern: bindings = {:?}", bindings); log::trace!("translate_pattern: bindings = {:?}", bindings);
match pat { match pat {
// TODO: flag on primitive type decl indicating it's an integer type? // TODO: flag on primitive type decl indicating it's an integer type?
&ast::Pattern::ConstInt { val } => { &ast::Pattern::ConstInt { val } => {
let ty = expected_ty.ok_or_else(|| { let ty = match expected_ty {
tyenv.error(pos, "Need an implied type for an integer constant".into()) Some(t) => t,
})?; None => {
Ok((Pattern::ConstInt(ty, val), ty)) tyenv.report_error(
pos,
"Need an implied type for an integer constant".into(),
);
return None;
}
};
Some((Pattern::ConstInt(ty, val), ty))
} }
&ast::Pattern::Wildcard => { &ast::Pattern::Wildcard => {
let ty = expected_ty.ok_or_else(|| { let ty = match expected_ty {
tyenv.error(pos, "Need an implied type for a wildcard".into()) Some(t) => t,
})?; None => {
Ok((Pattern::Wildcard(ty), ty)) tyenv.report_error(pos, "Need an implied type for a wildcard".into());
return None;
}
};
Some((Pattern::Wildcard(ty), ty))
} }
&ast::Pattern::And { ref subpats } => { &ast::Pattern::And { ref subpats } => {
let mut expected_ty = expected_ty; let mut expected_ty = expected_ty;
let mut children = vec![]; let mut children = vec![];
for subpat in subpats { for subpat in subpats {
let (subpat, ty) = 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)); expected_ty = expected_ty.or(Some(ty));
children.push(subpat); children.push(subpat);
} }
if expected_ty.is_none() { 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(); let ty = expected_ty.unwrap();
Ok((Pattern::And(ty, children), ty)) Some((Pattern::And(ty, children), ty))
} }
&ast::Pattern::BindPattern { &ast::Pattern::BindPattern {
ref var, ref var,
@@ -787,30 +858,32 @@ impl TermEnv {
let name = tyenv.intern_mut(var); let name = tyenv.intern_mut(var);
if bindings.vars.iter().any(|bv| bv.name == name) { if bindings.vars.iter().any(|bv| bv.name == name) {
return Err(tyenv.error( tyenv.report_error(
pos, 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); let id = VarId(bindings.next_var);
bindings.next_var += 1; bindings.next_var += 1;
log::trace!("binding var {:?}", var.0); log::trace!("binding var {:?}", var.0);
bindings.vars.push(BoundVar { name, id, ty }); 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 } => { &ast::Pattern::Var { ref var } => {
// Look up the variable; it must already have been bound. // Look up the variable; it must already have been bound.
let name = tyenv.intern_mut(var); let name = tyenv.intern_mut(var);
let bv = match bindings.vars.iter().rev().find(|bv| bv.name == name) { let bv = match bindings.vars.iter().rev().find(|bv| bv.name == name) {
None => { None => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!( format!(
"Unknown variable '{}' in bound-var pattern '={}'", "Unknown variable '{}' in bound-var pattern '={}'",
var.0, var.0 var.0, var.0
), ),
)) );
return None;
} }
Some(bv) => bv, Some(bv) => bv,
}; };
@@ -818,17 +891,28 @@ impl TermEnv {
None => bv.ty, None => bv.ty,
Some(expected_ty) if expected_ty == bv.ty => bv.ty, Some(expected_ty) if expected_ty == bv.ty => bv.ty,
Some(expected_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 } => { &ast::Pattern::Term { ref sym, ref args } => {
let name = tyenv.intern_mut(&sym); let name = tyenv.intern_mut(&sym);
// Look up the term. // Look up the term.
let tid = self.term_map.get(&name).ok_or_else(|| { let tid = match self.term_map.get(&name) {
tyenv.error(pos, format!("Unknown term in pattern: '{}'", sym.0)) 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 // Get the return type and arg types. Verify the
// expected type of this pattern, if any, against the // expected type of this pattern, if any, against the
@@ -838,13 +922,19 @@ impl TermEnv {
None => ret_ty, None => ret_ty,
Some(expected_ty) if expected_ty == ret_ty => ret_ty, Some(expected_ty) if expected_ty == ret_ty => ret_ty,
Some(expected_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. // Check that we have the correct argument count.
if self.terms[tid.index()].arg_tys.len() != args.len() { if self.terms[tid.index()].arg_tys.len() != args.len() {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!( format!(
"Incorrect argument count for term '{}': got {}, expect {}", "Incorrect argument count for term '{}': got {}, expect {}",
@@ -852,7 +942,7 @@ impl TermEnv {
args.len(), args.len(),
self.terms[tid.index()].arg_tys.len() self.terms[tid.index()].arg_tys.len()
), ),
)); );
} }
let termdata = &self.terms[tid.index()]; let termdata = &self.terms[tid.index()];
@@ -861,7 +951,7 @@ impl TermEnv {
&TermKind::EnumVariant { .. } => { &TermKind::EnumVariant { .. } => {
for arg in args { for arg in args {
if let &ast::TermArgPattern::Expr(..) = arg { 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) { match (arg, pol) {
(&ast::TermArgPattern::Expr(..), &ArgPolarity::Input) => {} (&ast::TermArgPattern::Expr(..), &ArgPolarity::Input) => {}
(&ast::TermArgPattern::Expr(..), &ArgPolarity::Output) => { (&ast::TermArgPattern::Expr(..), &ArgPolarity::Output) => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
"Expression used for output-polarity extractor arg" "Expression used for output-polarity extractor arg"
.to_string(), .to_string(),
)); );
} }
(_, &ArgPolarity::Output) => {} (_, &ArgPolarity::Output) => {}
(_, &ArgPolarity::Input) => { (_, &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 { let sub_ast = match template_arg {
&ast::TermArgPattern::Pattern(ref pat) => pat.clone(), &ast::TermArgPattern::Pattern(ref pat) => pat.clone(),
&ast::TermArgPattern::Expr(_) => { &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()); macro_args.push(sub_ast.clone());
@@ -908,8 +999,10 @@ impl TermEnv {
// OK. // OK.
} }
&TermKind::Declared => { &TermKind::Declared => {
return Err(tyenv tyenv.report_error(
.error(pos, format!("Declared but undefined term '{}' used", sym.0))); pos,
format!("Declared but undefined term '{}' used", sym.0),
);
} }
} }
@@ -917,12 +1010,23 @@ impl TermEnv {
let mut subpats = vec![]; let mut subpats = vec![];
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {
let arg_ty = self.terms[tid.index()].arg_tys[i]; let arg_ty = self.terms[tid.index()].arg_tys[i];
let (subpat, _) = let (subpat, _) = match self.translate_pattern_term_arg(
self.translate_pattern_term_arg(tyenv, pos, arg, Some(arg_ty), bindings)?; tyenv,
pos,
arg,
Some(arg_ty),
bindings,
) {
Some(x) => x,
None => {
// Try to keep going for more errors.
continue;
}
};
subpats.push(subpat); subpats.push(subpat);
} }
Ok((Pattern::Term(ty, *tid, subpats), ty)) Some((Pattern::Term(ty, *tid, subpats), ty))
} }
&ast::Pattern::MacroArg { .. } => unreachable!(), &ast::Pattern::MacroArg { .. } => unreachable!(),
} }
@@ -935,23 +1039,24 @@ impl TermEnv {
pat: &ast::TermArgPattern, pat: &ast::TermArgPattern,
expected_ty: Option<TypeId>, expected_ty: Option<TypeId>,
bindings: &mut Bindings, bindings: &mut Bindings,
) -> SemaResult<(TermArgPattern, TypeId)> { ) -> Option<(TermArgPattern, TypeId)> {
match pat { match pat {
&ast::TermArgPattern::Pattern(ref pat) => { &ast::TermArgPattern::Pattern(ref pat) => {
let (subpat, ty) = let (subpat, ty) =
self.translate_pattern(tyenv, pos, pat, expected_ty, bindings)?; self.translate_pattern(tyenv, pos, pat, expected_ty, bindings)?;
Ok((TermArgPattern::Pattern(subpat), ty)) Some((TermArgPattern::Pattern(subpat), ty))
} }
&ast::TermArgPattern::Expr(ref expr) => { &ast::TermArgPattern::Expr(ref expr) => {
if expected_ty.is_none() { if expected_ty.is_none() {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
"Expression in pattern must have expected type".to_string(), "Expression in pattern must have expected type".to_string(),
)); );
return None;
} }
let ty = expected_ty.unwrap(); let ty = expected_ty.unwrap();
let expr = self.translate_expr(tyenv, pos, expr, expected_ty.unwrap(), bindings)?; 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, expr: &ast::Expr,
ty: TypeId, ty: TypeId,
bindings: &mut Bindings, bindings: &mut Bindings,
) -> SemaResult<Expr> { ) -> Option<Expr> {
log::trace!("translate_expr: {:?}", expr); log::trace!("translate_expr: {:?}", expr);
match expr { match expr {
&ast::Expr::Term { ref sym, ref args } => { &ast::Expr::Term { ref sym, ref args } => {
// Look up the term. // Look up the term.
let name = tyenv.intern_mut(&sym); let name = tyenv.intern_mut(&sym);
// Look up the term. // Look up the term.
let tid = self.term_map.get(&name).ok_or_else(|| { let tid = match self.term_map.get(&name) {
tyenv.error(pos, format!("Unknown term in pattern: '{}'", sym.0)) 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 // Get the return type and arg types. Verify the
// expected type of this pattern, if any, against the // expected type of this pattern, if any, against the
// return type of the term. // return type of the term.
let ret_ty = self.terms[tid.index()].ret_ty; let ret_ty = self.terms[tid.index()].ret_ty;
if ret_ty != 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. // Check that we have the correct argument count.
if self.terms[tid.index()].arg_tys.len() != args.len() { if self.terms[tid.index()].arg_tys.len() != args.len() {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!( format!(
"Incorrect argument count for term '{}': got {}, expect {}", "Incorrect argument count for term '{}': got {}, expect {}",
@@ -992,32 +1101,38 @@ impl TermEnv {
args.len(), args.len(),
self.terms[tid.index()].arg_tys.len() self.terms[tid.index()].arg_tys.len()
), ),
)); );
} }
// Resolve subexpressions. // Resolve subexpressions.
let mut subexprs = vec![]; let mut subexprs = vec![];
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {
let arg_ty = self.terms[tid.index()].arg_tys[i]; 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); subexprs.push(subexpr);
} }
Ok(Expr::Term(ty, *tid, subexprs)) Some(Expr::Term(ty, *tid, subexprs))
} }
&ast::Expr::Var { ref name } => { &ast::Expr::Var { ref name } => {
let sym = tyenv.intern_mut(name); let sym = tyenv.intern_mut(name);
// Look through bindings, innermost (most recent) first. // Look through bindings, innermost (most recent) first.
let bv = match bindings.vars.iter().rev().find(|b| b.name == sym) { let bv = match bindings.vars.iter().rev().find(|b| b.name == sym) {
None => { 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, Some(bv) => bv,
}; };
// Verify type. // Verify type.
if bv.ty != ty { if bv.ty != ty {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!( format!(
"Variable '{}' has type {} but we need {} in context", "Variable '{}' has type {} but we need {} in context",
@@ -1025,12 +1140,12 @@ impl TermEnv {
tyenv.types[bv.ty.index()].name(tyenv), tyenv.types[bv.ty.index()].name(tyenv),
tyenv.types[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 } => { &ast::Expr::Let { ref defs, ref body } => {
let orig_binding_len = bindings.vars.len(); let orig_binding_len = bindings.vars.len();
@@ -1040,33 +1155,41 @@ impl TermEnv {
// Check that the given variable name does not already exist. // Check that the given variable name does not already exist.
let name = tyenv.intern_mut(&def.var); let name = tyenv.intern_mut(&def.var);
if bindings.vars.iter().any(|bv| bv.name == name) { if bindings.vars.iter().any(|bv| bv.name == name) {
return Err( tyenv.report_error(pos, format!("Variable '{}' already bound", def.var.0));
tyenv.error(pos, format!("Variable '{}' already bound", def.var.0))
);
} }
// Look up the type. // Look up the type.
let tysym = match tyenv.intern(&def.ty) { let tysym = match tyenv.intern(&def.ty) {
Some(ty) => ty, Some(ty) => ty,
None => { None => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0), format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0),
)) );
continue;
} }
}; };
let tid = match tyenv.type_map.get(&tysym) { let tid = match tyenv.type_map.get(&tysym) {
Some(tid) => *tid, Some(tid) => *tid,
None => { None => {
return Err(tyenv.error( tyenv.report_error(
pos, pos,
format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0), format!("Unknown type {} for variable '{}'", def.ty.0, def.var.0),
)) );
continue;
} }
}; };
// Evaluate the variable's value. // 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. // Bind the var with the given type.
let id = VarId(bindings.next_var); let id = VarId(bindings.next_var);
@@ -1083,7 +1206,7 @@ impl TermEnv {
// Pop the bindings. // Pop the bindings.
bindings.vars.truncate(orig_binding_len); bindings.vars.truncate(orig_binding_len);
Ok(Expr::Let(body_ty, let_defs, body)) Some(Expr::Let(body_ty, let_defs, body))
} }
} }
} }