Support extern constants of any primitive type.
This commit is contained in:
@@ -6,8 +6,6 @@
|
|||||||
parse instead where we know the polarity of pattern-term args and parse
|
parse instead where we know the polarity of pattern-term args and parse
|
||||||
in-args as exprs.
|
in-args as exprs.
|
||||||
|
|
||||||
- Support extern constants.
|
|
||||||
|
|
||||||
- Look into whether optimizations are possible:
|
- Look into whether optimizations are possible:
|
||||||
- More in-depth fallibility analysis (avoid failure edges where possible)
|
- More in-depth fallibility analysis (avoid failure edges where possible)
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ pub enum Pattern {
|
|||||||
Var { var: Ident, pos: Pos },
|
Var { var: Ident, pos: Pos },
|
||||||
/// An operator that matches a constant integer value.
|
/// An operator that matches a constant integer value.
|
||||||
ConstInt { val: i64, pos: Pos },
|
ConstInt { val: i64, pos: Pos },
|
||||||
|
/// An operator that matches an external constant value.
|
||||||
|
ConstPrim { val: Ident, pos: Pos },
|
||||||
/// An application of a type variant or term.
|
/// An application of a type variant or term.
|
||||||
Term {
|
Term {
|
||||||
sym: Ident,
|
sym: Ident,
|
||||||
@@ -166,9 +168,10 @@ impl Pattern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&Pattern::Var { .. } | &Pattern::Wildcard { .. } | &Pattern::ConstInt { .. } => {
|
&Pattern::Var { .. }
|
||||||
self.clone()
|
| &Pattern::Wildcard { .. }
|
||||||
}
|
| &Pattern::ConstInt { .. }
|
||||||
|
| &Pattern::ConstPrim { .. } => self.clone(),
|
||||||
&Pattern::MacroArg { .. } => unreachable!(),
|
&Pattern::MacroArg { .. } => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,9 +211,10 @@ impl Pattern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&Pattern::Var { .. } | &Pattern::Wildcard { .. } | &Pattern::ConstInt { .. } => {
|
&Pattern::Var { .. }
|
||||||
self.clone()
|
| &Pattern::Wildcard { .. }
|
||||||
}
|
| &Pattern::ConstInt { .. }
|
||||||
|
| &Pattern::ConstPrim { .. } => self.clone(),
|
||||||
&Pattern::MacroArg { index, .. } => macro_args[index].clone(),
|
&Pattern::MacroArg { index, .. } => macro_args[index].clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,6 +222,7 @@ impl Pattern {
|
|||||||
pub fn pos(&self) -> Pos {
|
pub fn pos(&self) -> Pos {
|
||||||
match self {
|
match self {
|
||||||
&Pattern::ConstInt { pos, .. }
|
&Pattern::ConstInt { pos, .. }
|
||||||
|
| &Pattern::ConstPrim { pos, .. }
|
||||||
| &Pattern::And { pos, .. }
|
| &Pattern::And { pos, .. }
|
||||||
| &Pattern::Term { pos, .. }
|
| &Pattern::Term { pos, .. }
|
||||||
| &Pattern::BindPattern { pos, .. }
|
| &Pattern::BindPattern { pos, .. }
|
||||||
@@ -280,6 +285,8 @@ pub enum Expr {
|
|||||||
Var { name: Ident, pos: Pos },
|
Var { name: Ident, pos: Pos },
|
||||||
/// A constant integer.
|
/// A constant integer.
|
||||||
ConstInt { val: i64, pos: Pos },
|
ConstInt { val: i64, pos: Pos },
|
||||||
|
/// A constant of some other primitive type.
|
||||||
|
ConstPrim { val: Ident, pos: Pos },
|
||||||
/// The `(let ((var ty val)*) body)` form.
|
/// The `(let ((var ty val)*) body)` form.
|
||||||
Let {
|
Let {
|
||||||
defs: Vec<LetDef>,
|
defs: Vec<LetDef>,
|
||||||
@@ -294,6 +301,7 @@ impl Expr {
|
|||||||
&Expr::Term { pos, .. }
|
&Expr::Term { pos, .. }
|
||||||
| &Expr::Var { pos, .. }
|
| &Expr::Var { pos, .. }
|
||||||
| &Expr::ConstInt { pos, .. }
|
| &Expr::ConstInt { pos, .. }
|
||||||
|
| &Expr::ConstPrim { pos, .. }
|
||||||
| &Expr::Let { pos, .. } => pos,
|
| &Expr::Let { pos, .. } => pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,6 +352,8 @@ pub enum Extern {
|
|||||||
/// The position of this decl.
|
/// The position of this decl.
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
},
|
},
|
||||||
|
/// An external constant: `(const $IDENT type)` form.
|
||||||
|
Const { name: Ident, ty: Ident, pos: Pos },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -797,6 +797,23 @@ impl<'a> Codegen<'a> {
|
|||||||
self.const_int(val, ty)
|
self.const_int(val, ty)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
&ExprInst::ConstPrim { ty, val } => {
|
||||||
|
let value = Value::Expr {
|
||||||
|
inst: id,
|
||||||
|
output: 0,
|
||||||
|
};
|
||||||
|
self.define_val(&value, ctx, /* is_ref = */ false, ty);
|
||||||
|
let name = self.value_name(&value);
|
||||||
|
let ty_name = self.type_name(ty, /* by_ref = */ false);
|
||||||
|
writeln!(
|
||||||
|
code,
|
||||||
|
"{}let {}: {} = {};",
|
||||||
|
indent,
|
||||||
|
name,
|
||||||
|
ty_name,
|
||||||
|
self.typeenv.syms[val.index()],
|
||||||
|
)?;
|
||||||
|
}
|
||||||
&ExprInst::CreateVariant {
|
&ExprInst::CreateVariant {
|
||||||
ref inputs,
|
ref inputs,
|
||||||
ty,
|
ty,
|
||||||
@@ -955,6 +972,12 @@ impl<'a> Codegen<'a> {
|
|||||||
writeln!(code, "{}if {} == {} {{", indent, input, int_val)?;
|
writeln!(code, "{}if {} == {} {{", indent, input, int_val)?;
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
&PatternInst::MatchPrim { ref input, val, .. } => {
|
||||||
|
let input = self.value_by_val(input, ctx);
|
||||||
|
let sym = &self.typeenv.syms[val.index()];
|
||||||
|
writeln!(code, "{}if {} == {} {{", indent, input, sym)?;
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
&PatternInst::MatchVariant {
|
&PatternInst::MatchVariant {
|
||||||
ref input,
|
ref input,
|
||||||
input_ty,
|
input_ty,
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ pub enum PatternInst {
|
|||||||
int_val: i64,
|
int_val: i64,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Try matching the given value as the given constant. Produces no values.
|
||||||
|
MatchPrim { input: Value, ty: TypeId, val: Sym },
|
||||||
|
|
||||||
/// Try matching the given value as the given variant, producing
|
/// Try matching the given value as the given variant, producing
|
||||||
/// `|arg_tys|` values as output.
|
/// `|arg_tys|` values as output.
|
||||||
MatchVariant {
|
MatchVariant {
|
||||||
@@ -69,6 +72,9 @@ pub enum ExprInst {
|
|||||||
/// Produce a constant integer.
|
/// Produce a constant integer.
|
||||||
ConstInt { ty: TypeId, val: i64 },
|
ConstInt { ty: TypeId, val: i64 },
|
||||||
|
|
||||||
|
/// Produce a constant extern value.
|
||||||
|
ConstPrim { ty: TypeId, val: Sym },
|
||||||
|
|
||||||
/// Create a variant.
|
/// Create a variant.
|
||||||
CreateVariant {
|
CreateVariant {
|
||||||
inputs: Vec<(Value, TypeId)>,
|
inputs: Vec<(Value, TypeId)>,
|
||||||
@@ -96,6 +102,7 @@ impl ExprInst {
|
|||||||
pub fn visit_values<F: FnMut(Value)>(&self, mut f: F) {
|
pub fn visit_values<F: FnMut(Value)>(&self, mut f: F) {
|
||||||
match self {
|
match self {
|
||||||
&ExprInst::ConstInt { .. } => {}
|
&ExprInst::ConstInt { .. } => {}
|
||||||
|
&ExprInst::ConstPrim { .. } => {}
|
||||||
&ExprInst::Construct { ref inputs, .. }
|
&ExprInst::Construct { ref inputs, .. }
|
||||||
| &ExprInst::CreateVariant { ref inputs, .. } => {
|
| &ExprInst::CreateVariant { ref inputs, .. } => {
|
||||||
for (input, _ty) in inputs {
|
for (input, _ty) in inputs {
|
||||||
@@ -143,21 +150,6 @@ impl ExprSequence {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_const_variant(&self) -> Option<(TypeId, VariantId)> {
|
|
||||||
if self.insts.len() == 2 && matches!(&self.insts[1], &ExprInst::Return { .. }) {
|
|
||||||
match &self.insts[0] {
|
|
||||||
&ExprInst::CreateVariant {
|
|
||||||
ref inputs,
|
|
||||||
ty,
|
|
||||||
variant,
|
|
||||||
} if inputs.len() == 0 => Some((ty, variant)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@@ -196,6 +188,10 @@ impl PatternSequence {
|
|||||||
self.add_inst(PatternInst::MatchInt { input, ty, int_val });
|
self.add_inst(PatternInst::MatchInt { input, ty, int_val });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_match_prim(&mut self, input: Value, ty: TypeId, val: Sym) {
|
||||||
|
self.add_inst(PatternInst::MatchPrim { input, ty, val });
|
||||||
|
}
|
||||||
|
|
||||||
fn add_match_variant(
|
fn add_match_variant(
|
||||||
&mut self,
|
&mut self,
|
||||||
input: Value,
|
input: Value,
|
||||||
@@ -290,9 +286,15 @@ impl PatternSequence {
|
|||||||
// Assert that the value matches the constant integer.
|
// Assert that the value matches the constant integer.
|
||||||
let input_val = input
|
let input_val = input
|
||||||
.to_value()
|
.to_value()
|
||||||
.expect("Cannot match an =var pattern against root term");
|
.expect("Cannot match an integer pattern against root term");
|
||||||
self.add_match_int(input_val, ty, value);
|
self.add_match_int(input_val, ty, value);
|
||||||
}
|
}
|
||||||
|
&Pattern::ConstPrim(ty, value) => {
|
||||||
|
let input_val = input
|
||||||
|
.to_value()
|
||||||
|
.expect("Cannot match a constant-primitive pattern against root term");
|
||||||
|
self.add_match_prim(input_val, ty, value);
|
||||||
|
}
|
||||||
&Pattern::Term(ty, term, ref args) => {
|
&Pattern::Term(ty, term, ref args) => {
|
||||||
match input {
|
match input {
|
||||||
ValueOrArgs::ImplicitTermFromArgs(termid) => {
|
ValueOrArgs::ImplicitTermFromArgs(termid) => {
|
||||||
@@ -435,6 +437,12 @@ impl ExprSequence {
|
|||||||
Value::Expr { inst, output: 0 }
|
Value::Expr { inst, output: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_const_prim(&mut self, ty: TypeId, val: Sym) -> Value {
|
||||||
|
let inst = InstId(self.insts.len());
|
||||||
|
self.add_inst(ExprInst::ConstPrim { ty, val });
|
||||||
|
Value::Expr { inst, output: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
fn add_create_variant(
|
fn add_create_variant(
|
||||||
&mut self,
|
&mut self,
|
||||||
inputs: &[(Value, TypeId)],
|
inputs: &[(Value, TypeId)],
|
||||||
@@ -490,6 +498,7 @@ impl ExprSequence {
|
|||||||
log::trace!("gen_expr: expr {:?}", expr);
|
log::trace!("gen_expr: expr {:?}", expr);
|
||||||
match expr {
|
match expr {
|
||||||
&Expr::ConstInt(ty, val) => self.add_const_int(ty, val),
|
&Expr::ConstInt(ty, val) => self.add_const_int(ty, val),
|
||||||
|
&Expr::ConstPrim(ty, val) => self.add_const_prim(ty, val),
|
||||||
&Expr::Let(_ty, ref bindings, ref subexpr) => {
|
&Expr::Let(_ty, ref bindings, ref subexpr) => {
|
||||||
let mut vars = vars.clone();
|
let mut vars = vars.clone();
|
||||||
for &(var, _var_ty, ref var_expr) in bindings {
|
for &(var, _var_ty, ref var_expr) in bindings {
|
||||||
|
|||||||
@@ -72,6 +72,13 @@ impl<'a> Parser<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_const(&self) -> bool {
|
||||||
|
self.is(|tok| match tok {
|
||||||
|
&Token::Symbol(ref tok_s) if tok_s.starts_with("$") => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn lparen(&mut self) -> ParseResult<()> {
|
fn lparen(&mut self) -> ParseResult<()> {
|
||||||
self.take(|tok| *tok == Token::LParen).map(|_| ())
|
self.take(|tok| *tok == Token::LParen).map(|_| ())
|
||||||
}
|
}
|
||||||
@@ -129,20 +136,20 @@ impl<'a> Parser<'a> {
|
|||||||
|
|
||||||
fn str_to_ident(&self, pos: Pos, s: &str) -> ParseResult<Ident> {
|
fn str_to_ident(&self, pos: Pos, s: &str) -> ParseResult<Ident> {
|
||||||
let first = s.chars().next().unwrap();
|
let first = s.chars().next().unwrap();
|
||||||
if !first.is_alphabetic() && first != '_' {
|
if !first.is_alphabetic() && first != '_' && first != '$' {
|
||||||
return Err(self.error(
|
return Err(self.error(
|
||||||
pos,
|
pos,
|
||||||
format!("Identifier '{}' does not start with letter or _", s),
|
format!("Identifier '{}' does not start with letter or _ or $", s),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if s.chars()
|
if s.chars()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.any(|c| !c.is_alphanumeric() && c != '_' && c != '.')
|
.any(|c| !c.is_alphanumeric() && c != '_' && c != '.' && c != '$')
|
||||||
{
|
{
|
||||||
return Err(self.error(
|
return Err(self.error(
|
||||||
pos,
|
pos,
|
||||||
format!(
|
format!(
|
||||||
"Identifier '{}' contains invalid character (not a-z, A-Z, 0-9, _, .)",
|
"Identifier '{}' contains invalid character (not a-z, A-Z, 0-9, _, ., $)",
|
||||||
s
|
s
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
@@ -156,6 +163,20 @@ impl<'a> Parser<'a> {
|
|||||||
self.str_to_ident(pos.unwrap(), &s)
|
self.str_to_ident(pos.unwrap(), &s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_const(&mut self) -> ParseResult<Ident> {
|
||||||
|
let pos = self.pos();
|
||||||
|
let ident = self.parse_ident()?;
|
||||||
|
if ident.0.starts_with("$") {
|
||||||
|
let s = &ident.0[1..];
|
||||||
|
Ok(Ident(s.to_string(), ident.1))
|
||||||
|
} else {
|
||||||
|
Err(self.error(
|
||||||
|
pos.unwrap(),
|
||||||
|
"Not a constant identifier; must start with a '$'".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_type(&mut self) -> ParseResult<Type> {
|
fn parse_type(&mut self) -> ParseResult<Type> {
|
||||||
let pos = self.pos();
|
let pos = self.pos();
|
||||||
let name = self.parse_ident()?;
|
let name = self.parse_ident()?;
|
||||||
@@ -303,6 +324,16 @@ impl<'a> Parser<'a> {
|
|||||||
arg_polarity,
|
arg_polarity,
|
||||||
infallible,
|
infallible,
|
||||||
})
|
})
|
||||||
|
} else if self.is_sym_str("const") {
|
||||||
|
self.symbol()?;
|
||||||
|
let pos = self.pos();
|
||||||
|
let name = self.parse_const()?;
|
||||||
|
let ty = self.parse_ident()?;
|
||||||
|
Ok(Extern::Const {
|
||||||
|
name,
|
||||||
|
ty,
|
||||||
|
pos: pos.unwrap(),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(self.error(
|
Err(self.error(
|
||||||
pos.unwrap(),
|
pos.unwrap(),
|
||||||
@@ -355,6 +386,10 @@ impl<'a> Parser<'a> {
|
|||||||
val: self.int()?,
|
val: self.int()?,
|
||||||
pos,
|
pos,
|
||||||
})
|
})
|
||||||
|
} else if self.is_const() {
|
||||||
|
let pos = pos.unwrap();
|
||||||
|
let val = self.parse_const()?;
|
||||||
|
Ok(Pattern::ConstPrim { val, pos })
|
||||||
} else if self.is_sym_str("_") {
|
} else if self.is_sym_str("_") {
|
||||||
let pos = pos.unwrap();
|
let pos = pos.unwrap();
|
||||||
self.symbol()?;
|
self.symbol()?;
|
||||||
@@ -448,6 +483,10 @@ impl<'a> Parser<'a> {
|
|||||||
let pos = pos.unwrap();
|
let pos = pos.unwrap();
|
||||||
self.symbol()?;
|
self.symbol()?;
|
||||||
Ok(Expr::ConstInt { val: 0, pos })
|
Ok(Expr::ConstInt { val: 0, pos })
|
||||||
|
} else if self.is_const() {
|
||||||
|
let pos = pos.unwrap();
|
||||||
|
let val = self.parse_const()?;
|
||||||
|
Ok(Expr::ConstPrim { val, pos })
|
||||||
} else if self.is_sym() {
|
} else if self.is_sym() {
|
||||||
let pos = pos.unwrap();
|
let pos = pos.unwrap();
|
||||||
let name = self.parse_ident()?;
|
let name = self.parse_ident()?;
|
||||||
|
|||||||
@@ -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 const_types: HashMap<Sym, TypeId>,
|
||||||
pub errors: Vec<Error>,
|
pub errors: Vec<Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,6 +239,7 @@ pub enum Pattern {
|
|||||||
BindPattern(TypeId, VarId, Box<Pattern>),
|
BindPattern(TypeId, VarId, Box<Pattern>),
|
||||||
Var(TypeId, VarId),
|
Var(TypeId, VarId),
|
||||||
ConstInt(TypeId, i64),
|
ConstInt(TypeId, i64),
|
||||||
|
ConstPrim(TypeId, Sym),
|
||||||
Term(TypeId, TermId, Vec<TermArgPattern>),
|
Term(TypeId, TermId, Vec<TermArgPattern>),
|
||||||
Wildcard(TypeId),
|
Wildcard(TypeId),
|
||||||
And(TypeId, Vec<Pattern>),
|
And(TypeId, Vec<Pattern>),
|
||||||
@@ -254,6 +256,7 @@ pub enum Expr {
|
|||||||
Term(TypeId, TermId, Vec<Expr>),
|
Term(TypeId, TermId, Vec<Expr>),
|
||||||
Var(TypeId, VarId),
|
Var(TypeId, VarId),
|
||||||
ConstInt(TypeId, i64),
|
ConstInt(TypeId, i64),
|
||||||
|
ConstPrim(TypeId, Sym),
|
||||||
Let(TypeId, Vec<(VarId, TypeId, Box<Expr>)>, Box<Expr>),
|
Let(TypeId, Vec<(VarId, TypeId, Box<Expr>)>, Box<Expr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,6 +266,7 @@ impl Pattern {
|
|||||||
&Self::BindPattern(t, ..) => t,
|
&Self::BindPattern(t, ..) => t,
|
||||||
&Self::Var(t, ..) => t,
|
&Self::Var(t, ..) => t,
|
||||||
&Self::ConstInt(t, ..) => t,
|
&Self::ConstInt(t, ..) => t,
|
||||||
|
&Self::ConstPrim(t, ..) => t,
|
||||||
&Self::Term(t, ..) => t,
|
&Self::Term(t, ..) => t,
|
||||||
&Self::Wildcard(t, ..) => t,
|
&Self::Wildcard(t, ..) => t,
|
||||||
&Self::And(t, ..) => t,
|
&Self::And(t, ..) => t,
|
||||||
@@ -284,6 +288,7 @@ impl Expr {
|
|||||||
&Self::Term(t, ..) => t,
|
&Self::Term(t, ..) => t,
|
||||||
&Self::Var(t, ..) => t,
|
&Self::Var(t, ..) => t,
|
||||||
&Self::ConstInt(t, ..) => t,
|
&Self::ConstInt(t, ..) => t,
|
||||||
|
&Self::ConstPrim(t, ..) => t,
|
||||||
&Self::Let(t, ..) => t,
|
&Self::Let(t, ..) => t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,6 +302,7 @@ impl TypeEnv {
|
|||||||
sym_map: HashMap::new(),
|
sym_map: HashMap::new(),
|
||||||
types: vec![],
|
types: vec![],
|
||||||
type_map: HashMap::new(),
|
type_map: HashMap::new(),
|
||||||
|
const_types: HashMap::new(),
|
||||||
errors: vec![],
|
errors: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -340,6 +346,29 @@ impl TypeEnv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now collect types for extern constants.
|
||||||
|
for def in &defs.defs {
|
||||||
|
match def {
|
||||||
|
&ast::Def::Extern(ast::Extern::Const {
|
||||||
|
ref name,
|
||||||
|
ref ty,
|
||||||
|
pos,
|
||||||
|
}) => {
|
||||||
|
let ty = tyenv.intern_mut(ty);
|
||||||
|
let ty = match tyenv.type_map.get(&ty) {
|
||||||
|
Some(ty) => *ty,
|
||||||
|
None => {
|
||||||
|
tyenv.report_error(pos, "Unknown type for constant".into());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let name = tyenv.intern_mut(name);
|
||||||
|
tyenv.const_types.insert(name, ty);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tyenv.return_errors()?;
|
tyenv.return_errors()?;
|
||||||
|
|
||||||
Ok(tyenv)
|
Ok(tyenv)
|
||||||
@@ -674,25 +703,20 @@ impl TermEnv {
|
|||||||
vars: vec![],
|
vars: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let (lhs, ty) = match self.translate_pattern(
|
let (lhs, ty) =
|
||||||
tyenv,
|
match self.translate_pattern(tyenv, &rule.pattern, None, &mut bindings) {
|
||||||
&rule.pattern,
|
|
||||||
None,
|
|
||||||
&mut bindings,
|
|
||||||
) {
|
|
||||||
Some(x) => x,
|
|
||||||
None => {
|
|
||||||
// Keep going to collect more errors.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let rhs =
|
|
||||||
match self.translate_expr(tyenv, &rule.expr, ty, &mut bindings) {
|
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => {
|
None => {
|
||||||
|
// Keep going to collect more errors.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let rhs = match self.translate_expr(tyenv, &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 {
|
||||||
@@ -814,6 +838,20 @@ impl TermEnv {
|
|||||||
};
|
};
|
||||||
Some((Pattern::ConstInt(ty, val), ty))
|
Some((Pattern::ConstInt(ty, val), ty))
|
||||||
}
|
}
|
||||||
|
&ast::Pattern::ConstPrim { ref val, pos } => {
|
||||||
|
let val = tyenv.intern_mut(val);
|
||||||
|
let const_ty = match tyenv.const_types.get(&val) {
|
||||||
|
Some(ty) => *ty,
|
||||||
|
None => {
|
||||||
|
tyenv.report_error(pos, "Unknown constant".into());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if expected_ty.is_some() && expected_ty != Some(const_ty) {
|
||||||
|
tyenv.report_error(pos, "Type mismatch for constant".into());
|
||||||
|
}
|
||||||
|
Some((Pattern::ConstPrim(const_ty, val), const_ty))
|
||||||
|
}
|
||||||
&ast::Pattern::Wildcard { pos } => {
|
&ast::Pattern::Wildcard { pos } => {
|
||||||
let ty = match expected_ty {
|
let ty = match expected_ty {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
@@ -1045,8 +1083,7 @@ impl TermEnv {
|
|||||||
) -> Option<(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, pat, expected_ty, bindings)?;
|
||||||
self.translate_pattern(tyenv, pat, expected_ty, bindings)?;
|
|
||||||
Some((TermArgPattern::Pattern(subpat), ty))
|
Some((TermArgPattern::Pattern(subpat), ty))
|
||||||
}
|
}
|
||||||
&ast::TermArgPattern::Expr(ref expr) => {
|
&ast::TermArgPattern::Expr(ref expr) => {
|
||||||
@@ -1152,6 +1189,29 @@ impl TermEnv {
|
|||||||
Some(Expr::Var(bv.ty, bv.id))
|
Some(Expr::Var(bv.ty, bv.id))
|
||||||
}
|
}
|
||||||
&ast::Expr::ConstInt { val, .. } => Some(Expr::ConstInt(ty, val)),
|
&ast::Expr::ConstInt { val, .. } => Some(Expr::ConstInt(ty, val)),
|
||||||
|
&ast::Expr::ConstPrim { ref val, pos } => {
|
||||||
|
let val = tyenv.intern_mut(val);
|
||||||
|
let const_ty = match tyenv.const_types.get(&val) {
|
||||||
|
Some(ty) => *ty,
|
||||||
|
None => {
|
||||||
|
tyenv.report_error(pos, "Unknown constant".into());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if const_ty != ty {
|
||||||
|
tyenv.report_error(
|
||||||
|
pos,
|
||||||
|
format!(
|
||||||
|
"Constant '{}' has wrong type: expected {}, but is actually {}",
|
||||||
|
tyenv.syms[val.index()],
|
||||||
|
tyenv.types[ty.index()].name(tyenv),
|
||||||
|
tyenv.types[const_ty.index()].name(tyenv)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(Expr::ConstPrim(ty, val))
|
||||||
|
}
|
||||||
&ast::Expr::Let {
|
&ast::Expr::Let {
|
||||||
ref defs,
|
ref defs,
|
||||||
ref body,
|
ref body,
|
||||||
@@ -1191,15 +1251,13 @@ impl TermEnv {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Evaluate the variable's value.
|
// Evaluate the variable's value.
|
||||||
let val = Box::new(
|
let val = Box::new(match self.translate_expr(tyenv, &def.val, ty, bindings) {
|
||||||
match self.translate_expr(tyenv, &def.val, ty, bindings) {
|
Some(e) => e,
|
||||||
Some(e) => e,
|
None => {
|
||||||
None => {
|
// Keep going for more errors.
|
||||||
// Keep going for more errors.
|
continue;
|
||||||
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);
|
||||||
@@ -1240,14 +1298,30 @@ mod test {
|
|||||||
.expect("should parse");
|
.expect("should parse");
|
||||||
let tyenv = TypeEnv::from_ast(&ast).expect("should not have type-definition errors");
|
let tyenv = TypeEnv::from_ast(&ast).expect("should not have type-definition errors");
|
||||||
|
|
||||||
let sym_a = tyenv.intern(&Ident("A".to_string())).unwrap();
|
let sym_a = tyenv
|
||||||
let sym_b = tyenv.intern(&Ident("B".to_string())).unwrap();
|
.intern(&Ident("A".to_string(), Default::default()))
|
||||||
let sym_c = tyenv.intern(&Ident("C".to_string())).unwrap();
|
.unwrap();
|
||||||
let sym_a_b = tyenv.intern(&Ident("A.B".to_string())).unwrap();
|
let sym_b = tyenv
|
||||||
let sym_a_c = tyenv.intern(&Ident("A.C".to_string())).unwrap();
|
.intern(&Ident("B".to_string(), Default::default()))
|
||||||
let sym_u32 = tyenv.intern(&Ident("u32".to_string())).unwrap();
|
.unwrap();
|
||||||
let sym_f1 = tyenv.intern(&Ident("f1".to_string())).unwrap();
|
let sym_c = tyenv
|
||||||
let sym_f2 = tyenv.intern(&Ident("f2".to_string())).unwrap();
|
.intern(&Ident("C".to_string(), Default::default()))
|
||||||
|
.unwrap();
|
||||||
|
let sym_a_b = tyenv
|
||||||
|
.intern(&Ident("A.B".to_string(), Default::default()))
|
||||||
|
.unwrap();
|
||||||
|
let sym_a_c = tyenv
|
||||||
|
.intern(&Ident("A.C".to_string(), Default::default()))
|
||||||
|
.unwrap();
|
||||||
|
let sym_u32 = tyenv
|
||||||
|
.intern(&Ident("u32".to_string(), Default::default()))
|
||||||
|
.unwrap();
|
||||||
|
let sym_f1 = tyenv
|
||||||
|
.intern(&Ident("f1".to_string(), Default::default()))
|
||||||
|
.unwrap();
|
||||||
|
let sym_f2 = tyenv
|
||||||
|
.intern(&Ident("f2".to_string(), Default::default()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(tyenv.type_map.get(&sym_u32).unwrap(), &TypeId(0));
|
assert_eq!(tyenv.type_map.get(&sym_u32).unwrap(), &TypeId(0));
|
||||||
assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(1));
|
assert_eq!(tyenv.type_map.get(&sym_a).unwrap(), &TypeId(1));
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
(extern extractor Ext1 ext1)
|
(extern extractor Ext1 ext1)
|
||||||
(extern extractor Ext2 ext2)
|
(extern extractor Ext2 ext2)
|
||||||
|
|
||||||
|
(extern const $A u32)
|
||||||
|
(extern const $B u32)
|
||||||
|
|
||||||
(decl C (bool) A)
|
(decl C (bool) A)
|
||||||
(extern constructor C c)
|
(extern constructor C c)
|
||||||
|
|
||||||
@@ -32,3 +35,8 @@
|
|||||||
(rule
|
(rule
|
||||||
(Lower2 (Opcode.C))
|
(Lower2 (Opcode.C))
|
||||||
(MachInst.F))
|
(MachInst.F))
|
||||||
|
|
||||||
|
(decl F (Opcode) u32)
|
||||||
|
(rule
|
||||||
|
(F _)
|
||||||
|
$B)
|
||||||
Reference in New Issue
Block a user