Revamped error handling: keep going beyond some errors to accumulate a list of build errors, like most conventional compilers.
This commit is contained in:
116
cranelift/isle/Cargo.lock
generated
116
cranelift/isle/Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
36
cranelift/isle/isle_examples/error1.isle
Normal file
36
cranelift/isle/isle_examples/error1.isle
Normal 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))
|
||||
@@ -3,9 +3,9 @@
|
||||
use crate::error::Error;
|
||||
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 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])
|
||||
}
|
||||
|
||||
@@ -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<std::fmt::Error> for Error {
|
||||
fn from(e: std::fmt::Error) -> Error {
|
||||
Error::SystemError {
|
||||
msg: format!("{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::convert::From<std::io::Error> for Error {
|
||||
fn from(e: std::io::Error) -> Error {
|
||||
Error::SystemError {
|
||||
msg: format!("{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -9,15 +9,15 @@ pub struct Parser<'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> {
|
||||
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,
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::error::*;
|
||||
use crate::lexer::Pos;
|
||||
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_rules! declare_id {
|
||||
@@ -35,6 +35,7 @@ pub struct TypeEnv {
|
||||
pub sym_map: HashMap<String, Sym>,
|
||||
pub types: Vec<Type>,
|
||||
pub type_map: HashMap<Sym, TypeId>,
|
||||
pub errors: Vec<Error>,
|
||||
}
|
||||
|
||||
#[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<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();
|
||||
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::<SemaResult<Vec<TypeId>>>()?;
|
||||
.collect::<Result<Vec<TypeId>, ()>>();
|
||||
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::<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 {
|
||||
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<TypeId>,
|
||||
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<TypeId>,
|
||||
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<Expr> {
|
||||
) -> Option<Expr> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user