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.
|
# 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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
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::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])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user