Properly track locations on every AST node. Semantic errors are much more useful now. Also print parse errors in same (pseudo-standard compiler error) output format.
This commit is contained in:
@@ -19,7 +19,7 @@ pub enum Def {
|
||||
|
||||
/// An identifier -- a variable, term symbol, or type.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Ident(pub String);
|
||||
pub struct Ident(pub String, pub Pos);
|
||||
|
||||
/// A declaration of a type.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
@@ -35,8 +35,8 @@ pub struct Type {
|
||||
/// TODO: add structs as well?
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum TypeValue {
|
||||
Primitive(Ident),
|
||||
Enum(Vec<Variant>),
|
||||
Primitive(Ident, Pos),
|
||||
Enum(Vec<Variant>, Pos),
|
||||
}
|
||||
|
||||
/// One variant of an enum type.
|
||||
@@ -44,6 +44,7 @@ pub enum TypeValue {
|
||||
pub struct Variant {
|
||||
pub name: Ident,
|
||||
pub fields: Vec<Field>,
|
||||
pub pos: Pos,
|
||||
}
|
||||
|
||||
/// One field of an enum variant.
|
||||
@@ -51,6 +52,7 @@ pub struct Variant {
|
||||
pub struct Field {
|
||||
pub name: Ident,
|
||||
pub ty: Ident,
|
||||
pub pos: Pos,
|
||||
}
|
||||
|
||||
/// A declaration of a term with its argument and return types.
|
||||
@@ -85,22 +87,27 @@ pub struct Extractor {
|
||||
pub enum Pattern {
|
||||
/// An operator that binds a variable to a subterm and match the
|
||||
/// subpattern.
|
||||
BindPattern { var: Ident, subpat: Box<Pattern> },
|
||||
BindPattern {
|
||||
var: Ident,
|
||||
subpat: Box<Pattern>,
|
||||
pos: Pos,
|
||||
},
|
||||
/// A variable that has already been bound (`=x` syntax).
|
||||
Var { var: Ident },
|
||||
Var { var: Ident, pos: Pos },
|
||||
/// An operator that matches a constant integer value.
|
||||
ConstInt { val: i64 },
|
||||
ConstInt { val: i64, pos: Pos },
|
||||
/// An application of a type variant or term.
|
||||
Term {
|
||||
sym: Ident,
|
||||
args: Vec<TermArgPattern>,
|
||||
pos: Pos,
|
||||
},
|
||||
/// An operator that matches anything.
|
||||
Wildcard,
|
||||
Wildcard { pos: Pos },
|
||||
/// N sub-patterns that must all match.
|
||||
And { subpats: Vec<Pattern> },
|
||||
And { subpats: Vec<Pattern>, pos: Pos },
|
||||
/// Internal use only: macro argument in a template.
|
||||
MacroArg { index: usize },
|
||||
MacroArg { index: usize, pos: Pos },
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
@@ -118,9 +125,11 @@ impl Pattern {
|
||||
&Pattern::BindPattern {
|
||||
ref var,
|
||||
ref subpat,
|
||||
} if matches!(&**subpat, &Pattern::Wildcard) => {
|
||||
pos,
|
||||
..
|
||||
} if matches!(&**subpat, &Pattern::Wildcard { .. }) => {
|
||||
if let Some(i) = macro_args.iter().position(|arg| arg == var) {
|
||||
Pattern::MacroArg { index: i }
|
||||
Pattern::MacroArg { index: i, pos }
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
@@ -128,18 +137,24 @@ impl Pattern {
|
||||
&Pattern::BindPattern {
|
||||
ref var,
|
||||
ref subpat,
|
||||
pos,
|
||||
} => Pattern::BindPattern {
|
||||
var: var.clone(),
|
||||
subpat: Box::new(subpat.make_macro_template(macro_args)),
|
||||
pos,
|
||||
},
|
||||
&Pattern::And { ref subpats } => {
|
||||
&Pattern::And { ref subpats, pos } => {
|
||||
let subpats = subpats
|
||||
.iter()
|
||||
.map(|subpat| subpat.make_macro_template(macro_args))
|
||||
.collect::<Vec<_>>();
|
||||
Pattern::And { subpats }
|
||||
Pattern::And { subpats, pos }
|
||||
}
|
||||
&Pattern::Term { ref sym, ref args } => {
|
||||
&Pattern::Term {
|
||||
ref sym,
|
||||
ref args,
|
||||
pos,
|
||||
} => {
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|arg| arg.make_macro_template(macro_args))
|
||||
@@ -147,10 +162,13 @@ impl Pattern {
|
||||
Pattern::Term {
|
||||
sym: sym.clone(),
|
||||
args,
|
||||
pos,
|
||||
}
|
||||
}
|
||||
|
||||
&Pattern::Var { .. } | &Pattern::Wildcard | &Pattern::ConstInt { .. } => self.clone(),
|
||||
&Pattern::Var { .. } | &Pattern::Wildcard { .. } | &Pattern::ConstInt { .. } => {
|
||||
self.clone()
|
||||
}
|
||||
&Pattern::MacroArg { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -160,18 +178,24 @@ impl Pattern {
|
||||
&Pattern::BindPattern {
|
||||
ref var,
|
||||
ref subpat,
|
||||
pos,
|
||||
} => Pattern::BindPattern {
|
||||
var: var.clone(),
|
||||
subpat: Box::new(subpat.subst_macro_args(macro_args)),
|
||||
pos,
|
||||
},
|
||||
&Pattern::And { ref subpats } => {
|
||||
&Pattern::And { ref subpats, pos } => {
|
||||
let subpats = subpats
|
||||
.iter()
|
||||
.map(|subpat| subpat.subst_macro_args(macro_args))
|
||||
.collect::<Vec<_>>();
|
||||
Pattern::And { subpats }
|
||||
Pattern::And { subpats, pos }
|
||||
}
|
||||
&Pattern::Term { ref sym, ref args } => {
|
||||
&Pattern::Term {
|
||||
ref sym,
|
||||
ref args,
|
||||
pos,
|
||||
} => {
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|arg| arg.subst_macro_args(macro_args))
|
||||
@@ -179,11 +203,26 @@ impl Pattern {
|
||||
Pattern::Term {
|
||||
sym: sym.clone(),
|
||||
args,
|
||||
pos,
|
||||
}
|
||||
}
|
||||
|
||||
&Pattern::Var { .. } | &Pattern::Wildcard | &Pattern::ConstInt { .. } => self.clone(),
|
||||
&Pattern::MacroArg { index } => macro_args[index].clone(),
|
||||
&Pattern::Var { .. } | &Pattern::Wildcard { .. } | &Pattern::ConstInt { .. } => {
|
||||
self.clone()
|
||||
}
|
||||
&Pattern::MacroArg { index, .. } => macro_args[index].clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pos(&self) -> Pos {
|
||||
match self {
|
||||
&Pattern::ConstInt { pos, .. }
|
||||
| &Pattern::And { pos, .. }
|
||||
| &Pattern::Term { pos, .. }
|
||||
| &Pattern::BindPattern { pos, .. }
|
||||
| &Pattern::Var { pos, .. }
|
||||
| &Pattern::Wildcard { pos, .. }
|
||||
| &Pattern::MacroArg { pos, .. } => pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,13 +270,32 @@ impl TermArgPattern {
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum Expr {
|
||||
/// A term: `(sym args...)`.
|
||||
Term { sym: Ident, args: Vec<Expr> },
|
||||
Term {
|
||||
sym: Ident,
|
||||
args: Vec<Expr>,
|
||||
pos: Pos,
|
||||
},
|
||||
/// A variable use.
|
||||
Var { name: Ident },
|
||||
Var { name: Ident, pos: Pos },
|
||||
/// A constant integer.
|
||||
ConstInt { val: i64 },
|
||||
ConstInt { val: i64, pos: Pos },
|
||||
/// The `(let ((var ty val)*) body)` form.
|
||||
Let { defs: Vec<LetDef>, body: Box<Expr> },
|
||||
Let {
|
||||
defs: Vec<LetDef>,
|
||||
body: Box<Expr>,
|
||||
pos: Pos,
|
||||
},
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub fn pos(&self) -> Pos {
|
||||
match self {
|
||||
&Expr::Term { pos, .. }
|
||||
| &Expr::Var { pos, .. }
|
||||
| &Expr::ConstInt { pos, .. }
|
||||
| &Expr::Let { pos, .. } => pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One variable locally bound in a `(let ...)` expression.
|
||||
@@ -246,6 +304,7 @@ pub struct LetDef {
|
||||
pub var: Ident,
|
||||
pub ty: Ident,
|
||||
pub val: Box<Expr>,
|
||||
pub pos: Pos,
|
||||
}
|
||||
|
||||
/// An external binding: an extractor or constructor function attached
|
||||
|
||||
@@ -23,7 +23,7 @@ impl fmt::Display for Error {
|
||||
ref filename,
|
||||
pos,
|
||||
} => {
|
||||
write!(f, "{}:{}: {}", filename, pos.line, msg)
|
||||
write!(f, "{}:{}:{}: error: {}", filename, pos.line, pos.col, msg)
|
||||
}
|
||||
&Error::SystemError { ref msg } => {
|
||||
write!(f, "{}", msg)
|
||||
|
||||
@@ -46,7 +46,14 @@ 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 defs = match parser.parse_defs() {
|
||||
Ok(defs) => defs,
|
||||
Err(error) => {
|
||||
eprintln!("{}", error);
|
||||
eprintln!("Failed to parse input.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
let code = match compile::compile(&defs) {
|
||||
Ok(code) => code,
|
||||
Err(errors) => {
|
||||
|
||||
@@ -147,7 +147,7 @@ impl<'a> Parser<'a> {
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(Ident(s.to_string()))
|
||||
Ok(Ident(s.to_string(), pos))
|
||||
}
|
||||
|
||||
fn parse_ident(&mut self) -> ParseResult<Ident> {
|
||||
@@ -180,7 +180,8 @@ impl<'a> Parser<'a> {
|
||||
self.symbol()?;
|
||||
let primitive_ident = self.parse_ident()?;
|
||||
self.rparen()?;
|
||||
Ok(TypeValue::Primitive(primitive_ident))
|
||||
let pos = pos.unwrap();
|
||||
Ok(TypeValue::Primitive(primitive_ident, pos))
|
||||
} else if self.is_sym_str("enum") {
|
||||
self.symbol()?;
|
||||
let mut variants = vec![];
|
||||
@@ -189,7 +190,8 @@ impl<'a> Parser<'a> {
|
||||
variants.push(variant);
|
||||
}
|
||||
self.rparen()?;
|
||||
Ok(TypeValue::Enum(variants))
|
||||
let pos = pos.unwrap();
|
||||
Ok(TypeValue::Enum(variants, pos))
|
||||
} else {
|
||||
Err(self.error(pos.unwrap(), "Unknown type definition".to_string()))
|
||||
}
|
||||
@@ -197,12 +199,15 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn parse_type_variant(&mut self) -> ParseResult<Variant> {
|
||||
if self.is_sym() {
|
||||
let pos = self.pos().unwrap();
|
||||
let name = self.parse_ident()?;
|
||||
Ok(Variant {
|
||||
name,
|
||||
fields: vec![],
|
||||
pos,
|
||||
})
|
||||
} else {
|
||||
let pos = self.pos();
|
||||
self.lparen()?;
|
||||
let name = self.parse_ident()?;
|
||||
let mut fields = vec![];
|
||||
@@ -210,16 +215,19 @@ impl<'a> Parser<'a> {
|
||||
fields.push(self.parse_type_field()?);
|
||||
}
|
||||
self.rparen()?;
|
||||
Ok(Variant { name, fields })
|
||||
let pos = pos.unwrap();
|
||||
Ok(Variant { name, fields, pos })
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_type_field(&mut self) -> ParseResult<Field> {
|
||||
let pos = self.pos();
|
||||
self.lparen()?;
|
||||
let name = self.parse_ident()?;
|
||||
let ty = self.parse_ident()?;
|
||||
self.rparen()?;
|
||||
Ok(Field { name, ty })
|
||||
let pos = pos.unwrap();
|
||||
Ok(Field { name, ty, pos })
|
||||
}
|
||||
|
||||
fn parse_decl(&mut self) -> ParseResult<Decl> {
|
||||
@@ -342,30 +350,38 @@ impl<'a> Parser<'a> {
|
||||
fn parse_pattern(&mut self) -> ParseResult<Pattern> {
|
||||
let pos = self.pos();
|
||||
if self.is_int() {
|
||||
Ok(Pattern::ConstInt { val: self.int()? })
|
||||
let pos = pos.unwrap();
|
||||
Ok(Pattern::ConstInt {
|
||||
val: self.int()?,
|
||||
pos,
|
||||
})
|
||||
} else if self.is_sym_str("_") {
|
||||
let pos = pos.unwrap();
|
||||
self.symbol()?;
|
||||
Ok(Pattern::Wildcard)
|
||||
Ok(Pattern::Wildcard { pos })
|
||||
} else if self.is_sym() {
|
||||
let pos = pos.unwrap();
|
||||
let s = self.symbol()?;
|
||||
if s.starts_with("=") {
|
||||
let s = &s[1..];
|
||||
let var = self.str_to_ident(pos.unwrap(), s)?;
|
||||
Ok(Pattern::Var { var })
|
||||
let var = self.str_to_ident(pos, s)?;
|
||||
Ok(Pattern::Var { var, pos })
|
||||
} else {
|
||||
let var = self.str_to_ident(pos.unwrap(), &s)?;
|
||||
let var = self.str_to_ident(pos, &s)?;
|
||||
if self.is_at() {
|
||||
self.at()?;
|
||||
let subpat = Box::new(self.parse_pattern()?);
|
||||
Ok(Pattern::BindPattern { var, subpat })
|
||||
Ok(Pattern::BindPattern { var, subpat, pos })
|
||||
} else {
|
||||
Ok(Pattern::BindPattern {
|
||||
var,
|
||||
subpat: Box::new(Pattern::Wildcard),
|
||||
subpat: Box::new(Pattern::Wildcard { pos }),
|
||||
pos,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if self.is_lparen() {
|
||||
let pos = pos.unwrap();
|
||||
self.lparen()?;
|
||||
if self.is_sym_str("and") {
|
||||
self.symbol()?;
|
||||
@@ -374,7 +390,7 @@ impl<'a> Parser<'a> {
|
||||
subpats.push(self.parse_pattern()?);
|
||||
}
|
||||
self.rparen()?;
|
||||
Ok(Pattern::And { subpats })
|
||||
Ok(Pattern::And { subpats, pos })
|
||||
} else {
|
||||
let sym = self.parse_ident()?;
|
||||
let mut args = vec![];
|
||||
@@ -382,7 +398,7 @@ impl<'a> Parser<'a> {
|
||||
args.push(self.parse_pattern_term_arg()?);
|
||||
}
|
||||
self.rparen()?;
|
||||
Ok(Pattern::Term { sym, args })
|
||||
Ok(Pattern::Term { sym, args, pos })
|
||||
}
|
||||
} else {
|
||||
Err(self.error(pos.unwrap(), "Unexpected pattern".into()))
|
||||
@@ -401,6 +417,7 @@ impl<'a> Parser<'a> {
|
||||
fn parse_expr(&mut self) -> ParseResult<Expr> {
|
||||
let pos = self.pos();
|
||||
if self.is_lparen() {
|
||||
let pos = pos.unwrap();
|
||||
self.lparen()?;
|
||||
if self.is_sym_str("let") {
|
||||
self.symbol()?;
|
||||
@@ -413,7 +430,7 @@ impl<'a> Parser<'a> {
|
||||
self.rparen()?;
|
||||
let body = Box::new(self.parse_expr()?);
|
||||
self.rparen()?;
|
||||
Ok(Expr::Let { defs, body })
|
||||
Ok(Expr::Let { defs, body, pos })
|
||||
} else {
|
||||
let sym = self.parse_ident()?;
|
||||
let mut args = vec![];
|
||||
@@ -421,111 +438,37 @@ impl<'a> Parser<'a> {
|
||||
args.push(self.parse_expr()?);
|
||||
}
|
||||
self.rparen()?;
|
||||
Ok(Expr::Term { sym, args })
|
||||
Ok(Expr::Term { sym, args, pos })
|
||||
}
|
||||
} else if self.is_sym_str("#t") {
|
||||
let pos = pos.unwrap();
|
||||
self.symbol()?;
|
||||
Ok(Expr::ConstInt { val: 1 })
|
||||
Ok(Expr::ConstInt { val: 1, pos })
|
||||
} else if self.is_sym_str("#f") {
|
||||
let pos = pos.unwrap();
|
||||
self.symbol()?;
|
||||
Ok(Expr::ConstInt { val: 0 })
|
||||
Ok(Expr::ConstInt { val: 0, pos })
|
||||
} else if self.is_sym() {
|
||||
let pos = pos.unwrap();
|
||||
let name = self.parse_ident()?;
|
||||
Ok(Expr::Var { name })
|
||||
Ok(Expr::Var { name, pos })
|
||||
} else if self.is_int() {
|
||||
let pos = pos.unwrap();
|
||||
let val = self.int()?;
|
||||
Ok(Expr::ConstInt { val })
|
||||
Ok(Expr::ConstInt { val, pos })
|
||||
} else {
|
||||
Err(self.error(pos.unwrap(), "Invalid expression".into()))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_letdef(&mut self) -> ParseResult<LetDef> {
|
||||
let pos = self.pos();
|
||||
self.lparen()?;
|
||||
let pos = pos.unwrap();
|
||||
let var = self.parse_ident()?;
|
||||
let ty = self.parse_ident()?;
|
||||
let val = Box::new(self.parse_expr()?);
|
||||
self.rparen()?;
|
||||
Ok(LetDef { var, ty, val })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_type() {
|
||||
let text = r"
|
||||
;; comment
|
||||
(type Inst extern (enum
|
||||
(Alu (a Reg) (b Reg) (dest Reg))
|
||||
(Load (a Reg) (dest Reg))))
|
||||
(type u32 (primitive u32))
|
||||
";
|
||||
let defs = Parser::new(Lexer::from_str(text, "(none)"))
|
||||
.parse_defs()
|
||||
.expect("should parse");
|
||||
assert_eq!(
|
||||
defs,
|
||||
Defs {
|
||||
filenames: vec!["(none)".to_string()],
|
||||
defs: vec![
|
||||
Def::Type(Type {
|
||||
name: Ident("Inst".to_string()),
|
||||
is_extern: true,
|
||||
ty: TypeValue::Enum(vec![
|
||||
Variant {
|
||||
name: Ident("Alu".to_string()),
|
||||
fields: vec![
|
||||
Field {
|
||||
name: Ident("a".to_string()),
|
||||
ty: Ident("Reg".to_string()),
|
||||
},
|
||||
Field {
|
||||
name: Ident("b".to_string()),
|
||||
ty: Ident("Reg".to_string()),
|
||||
},
|
||||
Field {
|
||||
name: Ident("dest".to_string()),
|
||||
ty: Ident("Reg".to_string()),
|
||||
},
|
||||
],
|
||||
},
|
||||
Variant {
|
||||
name: Ident("Load".to_string()),
|
||||
fields: vec![
|
||||
Field {
|
||||
name: Ident("a".to_string()),
|
||||
ty: Ident("Reg".to_string()),
|
||||
},
|
||||
Field {
|
||||
name: Ident("dest".to_string()),
|
||||
ty: Ident("Reg".to_string()),
|
||||
},
|
||||
],
|
||||
}
|
||||
]),
|
||||
pos: Pos {
|
||||
file: 0,
|
||||
offset: 42,
|
||||
line: 3,
|
||||
col: 18,
|
||||
},
|
||||
}),
|
||||
Def::Type(Type {
|
||||
name: Ident("u32".to_string()),
|
||||
is_extern: false,
|
||||
ty: TypeValue::Primitive(Ident("u32".to_string())),
|
||||
pos: Pos {
|
||||
file: 0,
|
||||
offset: 167,
|
||||
line: 6,
|
||||
col: 18,
|
||||
},
|
||||
}),
|
||||
]
|
||||
}
|
||||
);
|
||||
Ok(LetDef { var, ty, val, pos })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,17 +356,20 @@ impl TypeEnv {
|
||||
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) => Some(Type::Primitive(tid, self.intern_mut(id))),
|
||||
&ast::TypeValue::Enum(ref ty_variants) => {
|
||||
&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 {
|
||||
let combined_ident = ast::Ident(format!("{}.{}", ty.name.0, variant.name.0));
|
||||
let combined_ident =
|
||||
ast::Ident(format!("{}.{}", ty.name.0, variant.name.0), variant.name.1);
|
||||
let fullname = self.intern_mut(&combined_ident);
|
||||
let name = self.intern_mut(&variant.name);
|
||||
let id = VariantId(variants.len());
|
||||
if variants.iter().any(|v: &Variant| v.name == name) {
|
||||
self.report_error(
|
||||
ty.pos,
|
||||
variant.pos,
|
||||
format!("Duplicate variant name in type: '{}'", variant.name.0),
|
||||
);
|
||||
return None;
|
||||
@@ -376,7 +379,7 @@ impl TypeEnv {
|
||||
let field_name = self.intern_mut(&field.name);
|
||||
if fields.iter().any(|f: &Field| f.name == field_name) {
|
||||
self.report_error(
|
||||
ty.pos,
|
||||
field.pos,
|
||||
format!(
|
||||
"Duplicate field name '{}' in variant '{}' of type",
|
||||
field.name.0, variant.name.0
|
||||
@@ -389,7 +392,7 @@ impl TypeEnv {
|
||||
Some(tid) => *tid,
|
||||
None => {
|
||||
self.report_error(
|
||||
ty.pos,
|
||||
field.ty.1,
|
||||
format!(
|
||||
"Unknown type '{}' for field '{}' in variant '{}'",
|
||||
field.ty.0, field.name.0, variant.name.0
|
||||
@@ -503,10 +506,7 @@ impl TermEnv {
|
||||
.map(|id| {
|
||||
let sym = tyenv.intern_mut(id);
|
||||
tyenv.type_map.get(&sym).cloned().ok_or_else(|| {
|
||||
tyenv.report_error(
|
||||
decl.pos,
|
||||
format!("Unknown arg type: '{}'", id.0),
|
||||
);
|
||||
tyenv.report_error(id.1, format!("Unknown arg type: '{}'", id.0));
|
||||
()
|
||||
})
|
||||
})
|
||||
@@ -523,7 +523,7 @@ impl TermEnv {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
tyenv.report_error(
|
||||
decl.pos,
|
||||
decl.ret_ty.1,
|
||||
format!("Unknown return type: '{}'", decl.ret_ty.0),
|
||||
);
|
||||
continue;
|
||||
@@ -676,7 +676,6 @@ impl TermEnv {
|
||||
|
||||
let (lhs, ty) = match self.translate_pattern(
|
||||
tyenv,
|
||||
rule.pos,
|
||||
&rule.pattern,
|
||||
None,
|
||||
&mut bindings,
|
||||
@@ -688,7 +687,7 @@ impl TermEnv {
|
||||
}
|
||||
};
|
||||
let rhs =
|
||||
match self.translate_expr(tyenv, rule.pos, &rule.expr, ty, &mut bindings) {
|
||||
match self.translate_expr(tyenv, &rule.expr, ty, &mut bindings) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
continue;
|
||||
@@ -794,7 +793,6 @@ impl TermEnv {
|
||||
fn translate_pattern(
|
||||
&self,
|
||||
tyenv: &mut TypeEnv,
|
||||
pos: Pos,
|
||||
pat: &ast::Pattern,
|
||||
expected_ty: Option<TypeId>,
|
||||
bindings: &mut Bindings,
|
||||
@@ -803,7 +801,7 @@ impl TermEnv {
|
||||
log::trace!("translate_pattern: bindings = {:?}", bindings);
|
||||
match pat {
|
||||
// TODO: flag on primitive type decl indicating it's an integer type?
|
||||
&ast::Pattern::ConstInt { val } => {
|
||||
&ast::Pattern::ConstInt { val, pos } => {
|
||||
let ty = match expected_ty {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
@@ -816,7 +814,7 @@ impl TermEnv {
|
||||
};
|
||||
Some((Pattern::ConstInt(ty, val), ty))
|
||||
}
|
||||
&ast::Pattern::Wildcard => {
|
||||
&ast::Pattern::Wildcard { pos } => {
|
||||
let ty = match expected_ty {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
@@ -826,12 +824,12 @@ impl TermEnv {
|
||||
};
|
||||
Some((Pattern::Wildcard(ty), ty))
|
||||
}
|
||||
&ast::Pattern::And { ref subpats } => {
|
||||
&ast::Pattern::And { ref subpats, pos } => {
|
||||
let mut expected_ty = expected_ty;
|
||||
let mut children = vec![];
|
||||
for subpat in subpats {
|
||||
let (subpat, ty) =
|
||||
match self.translate_pattern(tyenv, pos, &*subpat, expected_ty, bindings) {
|
||||
match self.translate_pattern(tyenv, &*subpat, expected_ty, bindings) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
// Try to keep going for more errors.
|
||||
@@ -851,10 +849,11 @@ impl TermEnv {
|
||||
&ast::Pattern::BindPattern {
|
||||
ref var,
|
||||
ref subpat,
|
||||
pos,
|
||||
} => {
|
||||
// Do the subpattern first so we can resolve the type for sure.
|
||||
let (subpat, ty) =
|
||||
self.translate_pattern(tyenv, pos, &*subpat, expected_ty, bindings)?;
|
||||
self.translate_pattern(tyenv, &*subpat, expected_ty, bindings)?;
|
||||
|
||||
let name = tyenv.intern_mut(var);
|
||||
if bindings.vars.iter().any(|bv| bv.name == name) {
|
||||
@@ -871,7 +870,7 @@ impl TermEnv {
|
||||
|
||||
Some((Pattern::BindPattern(ty, id, Box::new(subpat)), ty))
|
||||
}
|
||||
&ast::Pattern::Var { ref var } => {
|
||||
&ast::Pattern::Var { ref var, pos } => {
|
||||
// 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) {
|
||||
@@ -903,7 +902,11 @@ impl TermEnv {
|
||||
};
|
||||
Some((Pattern::Var(ty, bv.id), ty))
|
||||
}
|
||||
&ast::Pattern::Term { ref sym, ref args } => {
|
||||
&ast::Pattern::Term {
|
||||
ref sym,
|
||||
ref args,
|
||||
pos,
|
||||
} => {
|
||||
let name = tyenv.intern_mut(&sym);
|
||||
// Look up the term.
|
||||
let tid = match self.term_map.get(&name) {
|
||||
@@ -950,7 +953,7 @@ impl TermEnv {
|
||||
match &termdata.kind {
|
||||
&TermKind::EnumVariant { .. } => {
|
||||
for arg in args {
|
||||
if let &ast::TermArgPattern::Expr(..) = arg {
|
||||
if let &ast::TermArgPattern::Expr(_) = arg {
|
||||
tyenv.report_error(pos, format!("Term in pattern '{}' cannot have an injected expr, because it is an enum variant", sym.0));
|
||||
}
|
||||
}
|
||||
@@ -961,16 +964,16 @@ impl TermEnv {
|
||||
for (arg, pol) in args.iter().zip(arg_polarity.iter()) {
|
||||
match (arg, pol) {
|
||||
(&ast::TermArgPattern::Expr(..), &ArgPolarity::Input) => {}
|
||||
(&ast::TermArgPattern::Expr(..), &ArgPolarity::Output) => {
|
||||
(&ast::TermArgPattern::Expr(ref e), &ArgPolarity::Output) => {
|
||||
tyenv.report_error(
|
||||
pos,
|
||||
e.pos(),
|
||||
"Expression used for output-polarity extractor arg"
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
(_, &ArgPolarity::Output) => {}
|
||||
(_, &ArgPolarity::Input) => {
|
||||
tyenv.report_error(pos, "Non-expression used in pattern but expression required for input-polarity extractor arg".to_string());
|
||||
(&ast::TermArgPattern::Pattern(ref p), &ArgPolarity::Input) => {
|
||||
tyenv.report_error(p.pos(), "Non-expression used in pattern but expression required for input-polarity extractor arg".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -993,7 +996,7 @@ impl TermEnv {
|
||||
}
|
||||
log::trace!("internal extractor macro args = {:?}", args);
|
||||
let pat = template.subst_macro_args(¯o_args[..]);
|
||||
return self.translate_pattern(tyenv, pos, &pat, expected_ty, bindings);
|
||||
return self.translate_pattern(tyenv, &pat, expected_ty, bindings);
|
||||
}
|
||||
&TermKind::ExternalConstructor { .. } | &TermKind::InternalConstructor => {
|
||||
// OK.
|
||||
@@ -1043,7 +1046,7 @@ impl TermEnv {
|
||||
match pat {
|
||||
&ast::TermArgPattern::Pattern(ref pat) => {
|
||||
let (subpat, ty) =
|
||||
self.translate_pattern(tyenv, pos, pat, expected_ty, bindings)?;
|
||||
self.translate_pattern(tyenv, pat, expected_ty, bindings)?;
|
||||
Some((TermArgPattern::Pattern(subpat), ty))
|
||||
}
|
||||
&ast::TermArgPattern::Expr(ref expr) => {
|
||||
@@ -1055,7 +1058,7 @@ impl TermEnv {
|
||||
return None;
|
||||
}
|
||||
let ty = expected_ty.unwrap();
|
||||
let expr = self.translate_expr(tyenv, pos, expr, expected_ty.unwrap(), bindings)?;
|
||||
let expr = self.translate_expr(tyenv, expr, expected_ty.unwrap(), bindings)?;
|
||||
Some((TermArgPattern::Expr(expr), ty))
|
||||
}
|
||||
}
|
||||
@@ -1064,14 +1067,17 @@ impl TermEnv {
|
||||
fn translate_expr(
|
||||
&self,
|
||||
tyenv: &mut TypeEnv,
|
||||
pos: Pos,
|
||||
expr: &ast::Expr,
|
||||
ty: TypeId,
|
||||
bindings: &mut Bindings,
|
||||
) -> Option<Expr> {
|
||||
log::trace!("translate_expr: {:?}", expr);
|
||||
match expr {
|
||||
&ast::Expr::Term { ref sym, ref args } => {
|
||||
&ast::Expr::Term {
|
||||
ref sym,
|
||||
ref args,
|
||||
pos,
|
||||
} => {
|
||||
// Look up the term.
|
||||
let name = tyenv.intern_mut(&sym);
|
||||
// Look up the term.
|
||||
@@ -1108,7 +1114,7 @@ impl TermEnv {
|
||||
let mut subexprs = vec![];
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let arg_ty = self.terms[tid.index()].arg_tys[i];
|
||||
let subexpr = match self.translate_expr(tyenv, pos, arg, arg_ty, bindings) {
|
||||
let subexpr = match self.translate_expr(tyenv, arg, arg_ty, bindings) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
continue;
|
||||
@@ -1119,7 +1125,7 @@ impl TermEnv {
|
||||
|
||||
Some(Expr::Term(ty, *tid, subexprs))
|
||||
}
|
||||
&ast::Expr::Var { ref name } => {
|
||||
&ast::Expr::Var { ref name, pos } => {
|
||||
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) {
|
||||
@@ -1145,8 +1151,12 @@ impl TermEnv {
|
||||
|
||||
Some(Expr::Var(bv.ty, bv.id))
|
||||
}
|
||||
&ast::Expr::ConstInt { val } => Some(Expr::ConstInt(ty, val)),
|
||||
&ast::Expr::Let { ref defs, ref body } => {
|
||||
&ast::Expr::ConstInt { val, .. } => Some(Expr::ConstInt(ty, val)),
|
||||
&ast::Expr::Let {
|
||||
ref defs,
|
||||
ref body,
|
||||
pos,
|
||||
} => {
|
||||
let orig_binding_len = bindings.vars.len();
|
||||
|
||||
// For each new binding...
|
||||
@@ -1182,7 +1192,7 @@ impl TermEnv {
|
||||
|
||||
// Evaluate the variable's value.
|
||||
let val = Box::new(
|
||||
match self.translate_expr(tyenv, pos, &def.val, ty, bindings) {
|
||||
match self.translate_expr(tyenv, &def.val, ty, bindings) {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
// Keep going for more errors.
|
||||
@@ -1200,7 +1210,7 @@ impl TermEnv {
|
||||
}
|
||||
|
||||
// Evaluate the body, expecting the type of the overall let-expr.
|
||||
let body = Box::new(self.translate_expr(tyenv, pos, body, ty, bindings)?);
|
||||
let body = Box::new(self.translate_expr(tyenv, body, ty, bindings)?);
|
||||
let body_ty = body.ty();
|
||||
|
||||
// Pop the bindings.
|
||||
|
||||
Reference in New Issue
Block a user