Remove arity from ReducedIR, symbol table
Instead look this up via the type context
This commit is contained in:
parent
6b9ca92e00
commit
304df5c50e
@ -1,12 +1,13 @@
|
|||||||
use crate::ast;
|
use std::{collections::HashMap, str::FromStr};
|
||||||
use crate::symbol_table::{DefId, SymbolSpec, SymbolTable};
|
|
||||||
use crate::builtin::Builtin;
|
|
||||||
|
|
||||||
use std::str::FromStr;
|
use crate::{
|
||||||
use std::collections::HashMap;
|
ast,
|
||||||
|
builtin::Builtin,
|
||||||
|
symbol_table::{DefId, SymbolSpec, SymbolTable},
|
||||||
|
};
|
||||||
|
|
||||||
mod types;
|
|
||||||
mod test;
|
mod test;
|
||||||
|
mod types;
|
||||||
|
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
||||||
@ -22,10 +23,7 @@ struct Reducer<'a> {
|
|||||||
|
|
||||||
impl<'a> Reducer<'a> {
|
impl<'a> Reducer<'a> {
|
||||||
fn new(symbol_table: &'a SymbolTable) -> Self {
|
fn new(symbol_table: &'a SymbolTable) -> Self {
|
||||||
Self {
|
Self { symbol_table, functions: HashMap::new() }
|
||||||
symbol_table,
|
|
||||||
functions: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce(mut self, ast: &ast::AST) -> ReducedIR {
|
fn reduce(mut self, ast: &ast::AST) -> ReducedIR {
|
||||||
@ -43,20 +41,26 @@ impl<'a> Reducer<'a> {
|
|||||||
match &kind {
|
match &kind {
|
||||||
ast::StatementKind::Expression(expr) => {
|
ast::StatementKind::Expression(expr) => {
|
||||||
entrypoint.push(Statement::Expression(self.expression(expr)));
|
entrypoint.push(Statement::Expression(self.expression(expr)));
|
||||||
},
|
}
|
||||||
ast::StatementKind::Declaration(ast::Declaration::Binding { name: _, constant, expr, ..}) => {
|
ast::StatementKind::Declaration(ast::Declaration::Binding {
|
||||||
|
name: _,
|
||||||
|
constant,
|
||||||
|
expr,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
||||||
let def_id = symbol.def_id().unwrap();
|
let def_id = symbol.def_id().unwrap();
|
||||||
entrypoint.push(Statement::Binding { id: def_id, constant: *constant, expr: self.expression(expr) });
|
entrypoint.push(Statement::Binding {
|
||||||
},
|
id: def_id,
|
||||||
_ => ()
|
constant: *constant,
|
||||||
|
expr: self.expression(expr),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReducedIR {
|
ReducedIR { functions: self.functions, entrypoint }
|
||||||
functions: self.functions,
|
|
||||||
entrypoint,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn top_level_statement(&mut self, statement: &ast::Statement) {
|
fn top_level_statement(&mut self, statement: &ast::Statement) {
|
||||||
@ -65,11 +69,10 @@ impl<'a> Reducer<'a> {
|
|||||||
ast::StatementKind::Expression(_expr) => {
|
ast::StatementKind::Expression(_expr) => {
|
||||||
//TODO expressions can in principle contain definitions, but I won't worry
|
//TODO expressions can in principle contain definitions, but I won't worry
|
||||||
//about it now
|
//about it now
|
||||||
},
|
}
|
||||||
ast::StatementKind::Declaration(decl) => {
|
ast::StatementKind::Declaration(decl) =>
|
||||||
if let ast::Declaration::FuncDecl(_, statements) = decl {
|
if let ast::Declaration::FuncDecl(_, statements) = decl {
|
||||||
self.insert_function_definition(item_id, statements);
|
self.insert_function_definition(item_id, statements);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ast::StatementKind::Import(..) => (),
|
ast::StatementKind::Import(..) => (),
|
||||||
ast::StatementKind::Module(_modspec) => {
|
ast::StatementKind::Module(_modspec) => {
|
||||||
@ -81,32 +84,28 @@ impl<'a> Reducer<'a> {
|
|||||||
fn function_internal_statement(&mut self, statement: &ast::Statement) -> Option<Statement> {
|
fn function_internal_statement(&mut self, statement: &ast::Statement) -> Option<Statement> {
|
||||||
let ast::Statement { id: item_id, kind, .. } = statement;
|
let ast::Statement { id: item_id, kind, .. } = statement;
|
||||||
match kind {
|
match kind {
|
||||||
ast::StatementKind::Expression(expr) => {
|
ast::StatementKind::Expression(expr) => Some(Statement::Expression(self.expression(expr))),
|
||||||
Some(Statement::Expression(self.expression(expr)))
|
|
||||||
},
|
|
||||||
ast::StatementKind::Declaration(decl) => match decl {
|
ast::StatementKind::Declaration(decl) => match decl {
|
||||||
ast::Declaration::FuncDecl(_, statements) => {
|
ast::Declaration::FuncDecl(_, statements) => {
|
||||||
self.insert_function_definition(item_id, statements);
|
self.insert_function_definition(item_id, statements);
|
||||||
None
|
None
|
||||||
},
|
}
|
||||||
ast::Declaration::Binding { constant, expr, ..} => {
|
ast::Declaration::Binding { constant, expr, .. } => {
|
||||||
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
||||||
let def_id = symbol.def_id().unwrap();
|
let def_id = symbol.def_id().unwrap();
|
||||||
Some(Statement::Binding { id: def_id, constant: *constant, expr: self.expression(expr) })
|
Some(Statement::Binding { id: def_id, constant: *constant, expr: self.expression(expr) })
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => None
|
_ => None,
|
||||||
},
|
},
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_function_definition(&mut self, item_id: &ast::ItemId, statements: &ast::Block) {
|
fn insert_function_definition(&mut self, item_id: &ast::ItemId, statements: &ast::Block) {
|
||||||
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
||||||
let def_id = symbol.def_id().unwrap();
|
let def_id = symbol.def_id().unwrap();
|
||||||
let function_def = FunctionDefinition {
|
let function_def = FunctionDefinition { body: self.function_internal_block(statements) };
|
||||||
body: self.function_internal_block(statements)
|
|
||||||
};
|
|
||||||
self.functions.insert(def_id, function_def);
|
self.functions.insert(def_id, function_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,26 +122,20 @@ impl<'a> Reducer<'a> {
|
|||||||
Value(qualified_name) => self.value(qualified_name),
|
Value(qualified_name) => self.value(qualified_name),
|
||||||
Call { f, arguments } => Expression::Call {
|
Call { f, arguments } => Expression::Call {
|
||||||
f: Box::new(self.expression(f)),
|
f: Box::new(self.expression(f)),
|
||||||
args: arguments
|
args: arguments.iter().map(|arg| self.invocation_argument(arg)).collect(),
|
||||||
.iter()
|
|
||||||
.map(|arg| self.invocation_argument(arg))
|
|
||||||
.collect(),
|
|
||||||
},
|
},
|
||||||
TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
|
TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
|
||||||
IfExpression { discriminator, body, } => self.reduce_if_expression(discriminator.as_ref().map(|x| x.as_ref()), body),
|
IfExpression { discriminator, body } =>
|
||||||
Lambda { params, body, .. } => {
|
self.reduce_if_expression(discriminator.as_ref().map(|x| x.as_ref()), body),
|
||||||
Expression::Callable(Callable::Lambda {
|
Lambda { params, body, .. } => Expression::Callable(Callable::Lambda {
|
||||||
arity: params.len() as u8,
|
arity: params.len() as u8,
|
||||||
body: self.function_internal_block(body),
|
body: self.function_internal_block(body),
|
||||||
})
|
}),
|
||||||
},
|
|
||||||
NamedStruct { name, fields } => {
|
NamedStruct { name, fields } => {
|
||||||
let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap();
|
||||||
let constructor = match symbol.spec() {
|
let constructor = match symbol.spec() {
|
||||||
SymbolSpec::RecordConstructor { tag, members: _, type_id } => Expression::Callable(Callable::RecordConstructor {
|
SymbolSpec::RecordConstructor { tag, members: _, type_id } =>
|
||||||
type_id,
|
Expression::Callable(Callable::RecordConstructor { type_id, tag }),
|
||||||
tag,
|
|
||||||
}),
|
|
||||||
e => return Expression::ReductionError(format!("Bad symbol for NamedStruct: {:?}", e)),
|
e => return Expression::ReductionError(format!("Bad symbol for NamedStruct: {:?}", e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,11 +146,8 @@ impl<'a> Reducer<'a> {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Call {
|
Expression::Call { f: Box::new(constructor), args: ordered_args }
|
||||||
f: Box::new(constructor),
|
|
||||||
args: ordered_args,
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Index { .. } => Expression::ReductionError("Index expr not implemented".to_string()),
|
Index { .. } => Expression::ReductionError("Index expr not implemented".to_string()),
|
||||||
WhileExpression { .. } => Expression::ReductionError("While expr not implemented".to_string()),
|
WhileExpression { .. } => Expression::ReductionError("While expr not implemented".to_string()),
|
||||||
ForExpression { .. } => Expression::ReductionError("For expr not implemented".to_string()),
|
ForExpression { .. } => Expression::ReductionError("For expr not implemented".to_string()),
|
||||||
@ -165,7 +155,11 @@ impl<'a> Reducer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_if_expression(&mut self, discriminator: Option<&ast::Expression>, body: &ast::IfExpressionBody) -> Expression {
|
fn reduce_if_expression(
|
||||||
|
&mut self,
|
||||||
|
discriminator: Option<&ast::Expression>,
|
||||||
|
body: &ast::IfExpressionBody,
|
||||||
|
) -> Expression {
|
||||||
use ast::IfExpressionBody::*;
|
use ast::IfExpressionBody::*;
|
||||||
|
|
||||||
let cond = Box::new(match discriminator {
|
let cond = Box::new(match discriminator {
|
||||||
@ -173,26 +167,15 @@ impl<'a> Reducer<'a> {
|
|||||||
None => return Expression::ReductionError("blank cond if-expr not supported".to_string()),
|
None => return Expression::ReductionError("blank cond if-expr not supported".to_string()),
|
||||||
});
|
});
|
||||||
match body {
|
match body {
|
||||||
SimpleConditional {
|
SimpleConditional { then_case, else_case } => {
|
||||||
then_case,
|
|
||||||
else_case,
|
|
||||||
} => {
|
|
||||||
let then_clause = self.function_internal_block(then_case);
|
let then_clause = self.function_internal_block(then_case);
|
||||||
let else_clause = match else_case.as_ref() {
|
let else_clause = match else_case.as_ref() {
|
||||||
None => vec![],
|
None => vec![],
|
||||||
Some(stmts) => self.function_internal_block(stmts),
|
Some(stmts) => self.function_internal_block(stmts),
|
||||||
};
|
};
|
||||||
Expression::Conditional {
|
Expression::Conditional { cond, then_clause, else_clause }
|
||||||
cond,
|
|
||||||
then_clause,
|
|
||||||
else_clause,
|
|
||||||
}
|
}
|
||||||
},
|
SimplePatternMatch { pattern, then_case, else_case } => {
|
||||||
SimplePatternMatch {
|
|
||||||
pattern,
|
|
||||||
then_case,
|
|
||||||
else_case,
|
|
||||||
} => {
|
|
||||||
let alternatives = vec![
|
let alternatives = vec![
|
||||||
Alternative {
|
Alternative {
|
||||||
pattern: match pattern.reduce(self.symbol_table) {
|
pattern: match pattern.reduce(self.symbol_table) {
|
||||||
@ -211,24 +194,28 @@ impl<'a> Reducer<'a> {
|
|||||||
];
|
];
|
||||||
|
|
||||||
Expression::CaseMatch { cond, alternatives }
|
Expression::CaseMatch { cond, alternatives }
|
||||||
},
|
}
|
||||||
CondList(ref condition_arms) => {
|
CondList(ref condition_arms) => {
|
||||||
let mut alternatives = vec![];
|
let mut alternatives = vec![];
|
||||||
for arm in condition_arms {
|
for arm in condition_arms {
|
||||||
match arm.condition {
|
match arm.condition {
|
||||||
ast::Condition::Expression(ref _expr) => return Expression::ReductionError("case-expression".to_string()),
|
ast::Condition::Expression(ref _expr) =>
|
||||||
|
return Expression::ReductionError("case-expression".to_string()),
|
||||||
ast::Condition::Pattern(ref pat) => {
|
ast::Condition::Pattern(ref pat) => {
|
||||||
let alt = Alternative {
|
let alt = Alternative {
|
||||||
pattern: match pat.reduce(self.symbol_table) {
|
pattern: match pat.reduce(self.symbol_table) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => return Expression::ReductionError(format!("Bad pattern: {:?}", e)),
|
Err(e) =>
|
||||||
|
return Expression::ReductionError(format!("Bad pattern: {:?}", e)),
|
||||||
},
|
},
|
||||||
item: self.function_internal_block(&arm.body),
|
item: self.function_internal_block(&arm.body),
|
||||||
};
|
};
|
||||||
alternatives.push(alt);
|
alternatives.push(alt);
|
||||||
},
|
}
|
||||||
ast::Condition::TruncatedOp(_, _) => return Expression::ReductionError("case-expression-trunc-op".to_string()),
|
ast::Condition::TruncatedOp(_, _) =>
|
||||||
ast::Condition::Else => return Expression::ReductionError("case-expression-else".to_string()),
|
return Expression::ReductionError("case-expression-trunc-op".to_string()),
|
||||||
|
ast::Condition::Else =>
|
||||||
|
return Expression::ReductionError("case-expression-else".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::CaseMatch { cond, alternatives }
|
Expression::CaseMatch { cond, alternatives }
|
||||||
@ -252,12 +239,10 @@ impl<'a> Reducer<'a> {
|
|||||||
fn prefix(&mut self, prefix: &ast::PrefixOp, arg: &ast::Expression) -> Expression {
|
fn prefix(&mut self, prefix: &ast::PrefixOp, arg: &ast::Expression) -> Expression {
|
||||||
let builtin: Option<Builtin> = TryFrom::try_from(prefix).ok();
|
let builtin: Option<Builtin> = TryFrom::try_from(prefix).ok();
|
||||||
match builtin {
|
match builtin {
|
||||||
Some(op) => {
|
Some(op) => Expression::Call {
|
||||||
Expression::Call {
|
|
||||||
f: Box::new(Expression::Callable(Callable::Builtin(op))),
|
f: Box::new(Expression::Callable(Callable::Builtin(op))),
|
||||||
args: vec![self.expression(arg)],
|
args: vec![self.expression(arg)],
|
||||||
}
|
},
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
//TODO need this for custom prefix ops
|
//TODO need this for custom prefix ops
|
||||||
Expression::ReductionError("User-defined prefix ops not supported".to_string())
|
Expression::ReductionError("User-defined prefix ops not supported".to_string())
|
||||||
@ -278,21 +263,18 @@ impl<'a> Reducer<'a> {
|
|||||||
} else {
|
} else {
|
||||||
return ReductionError(format!("Couldn't look up name: {:?}", qualified_name));
|
return ReductionError(format!("Couldn't look up name: {:?}", qualified_name));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => return ReductionError("Trying to assign to a non-name".to_string()),
|
_ => return ReductionError("Trying to assign to a non-name".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
Expression::Assign {
|
Expression::Assign { lval, rval: Box::new(self.expression(rhs)) }
|
||||||
lval,
|
|
||||||
rval: Box::new(self.expression(rhs)),
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Some(op) => Expression::Call {
|
Some(op) => Expression::Call {
|
||||||
f: Box::new(Expression::Callable(Callable::Builtin(op))),
|
f: Box::new(Expression::Callable(Callable::Builtin(op))),
|
||||||
args: vec![self.expression(lhs), self.expression(rhs)],
|
args: vec![self.expression(lhs), self.expression(rhs)],
|
||||||
},
|
},
|
||||||
//TODO handle a user-defined operation
|
//TODO handle a user-defined operation
|
||||||
None => ReductionError("User-defined operations not supported".to_string())
|
None => ReductionError("User-defined operations not supported".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,7 +283,8 @@ impl<'a> Reducer<'a> {
|
|||||||
|
|
||||||
let symbol = match self.symbol_table.lookup_symbol(&qualified_name.id) {
|
let symbol = match self.symbol_table.lookup_symbol(&qualified_name.id) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Expression::ReductionError(format!("No symbol found for name: {:?}", qualified_name))
|
None =>
|
||||||
|
return Expression::ReductionError(format!("No symbol found for name: {:?}", qualified_name)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let def_id = symbol.def_id();
|
let def_id = symbol.def_id();
|
||||||
@ -311,14 +294,12 @@ impl<'a> Reducer<'a> {
|
|||||||
GlobalBinding => Expression::Lookup(Lookup::GlobalVar(def_id.unwrap())),
|
GlobalBinding => Expression::Lookup(Lookup::GlobalVar(def_id.unwrap())),
|
||||||
LocalVariable => Expression::Lookup(Lookup::LocalVar(def_id.unwrap())),
|
LocalVariable => Expression::Lookup(Lookup::LocalVar(def_id.unwrap())),
|
||||||
FunctionParam(n) => Expression::Lookup(Lookup::Param(n)),
|
FunctionParam(n) => Expression::Lookup(Lookup::Param(n)),
|
||||||
DataConstructor { tag, arity, type_id } => Expression::Callable(Callable::DataConstructor {
|
DataConstructor { tag, type_id } =>
|
||||||
type_id,
|
Expression::Callable(Callable::DataConstructor { type_id, tag }),
|
||||||
arity: arity as u32,
|
RecordConstructor { .. } => Expression::ReductionError(format!(
|
||||||
tag,
|
"The symbol for value {:?} is unexpectdly a RecordConstructor",
|
||||||
}),
|
qualified_name
|
||||||
RecordConstructor { .. } => {
|
)),
|
||||||
Expression::ReductionError(format!("The symbol for value {:?} is unexpectdly a RecordConstructor", qualified_name))
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,60 +309,53 @@ impl ast::Pattern {
|
|||||||
Ok(match self {
|
Ok(match self {
|
||||||
ast::Pattern::Ignored => Pattern::Ignored,
|
ast::Pattern::Ignored => Pattern::Ignored,
|
||||||
ast::Pattern::TuplePattern(subpatterns) => {
|
ast::Pattern::TuplePattern(subpatterns) => {
|
||||||
let items: Result<Vec<Pattern>, PatternError> = subpatterns.iter()
|
let items: Result<Vec<Pattern>, PatternError> =
|
||||||
.map(|pat| pat.reduce(symbol_table)).into_iter().collect();
|
subpatterns.iter().map(|pat| pat.reduce(symbol_table)).into_iter().collect();
|
||||||
let items = items?;
|
let items = items?;
|
||||||
Pattern::Tuple {
|
Pattern::Tuple { tag: None, subpatterns: items }
|
||||||
tag: None,
|
|
||||||
subpatterns: items,
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
ast::Pattern::Literal(lit) => Pattern::Literal(match lit {
|
ast::Pattern::Literal(lit) => Pattern::Literal(match lit {
|
||||||
ast::PatternLiteral::NumPattern { neg, num } => match (neg, num) {
|
ast::PatternLiteral::NumPattern { neg, num } => match (neg, num) {
|
||||||
(false, ast::ExpressionKind::NatLiteral(n)) => Literal::Nat(*n),
|
(false, ast::ExpressionKind::NatLiteral(n)) => Literal::Nat(*n),
|
||||||
(false, ast::ExpressionKind::FloatLiteral(f)) => Literal::Float(*f),
|
(false, ast::ExpressionKind::FloatLiteral(f)) => Literal::Float(*f),
|
||||||
(true, ast::ExpressionKind::NatLiteral(n)) => Literal::Int(-(*n as i64)),
|
(true, ast::ExpressionKind::NatLiteral(n)) => Literal::Int(-(*n as i64)),
|
||||||
(true, ast::ExpressionKind::FloatLiteral(f)) => Literal::Float(-f),
|
(true, ast::ExpressionKind::FloatLiteral(f)) => Literal::Float(-f),
|
||||||
(_, e) => return Err(format!("Internal error, unexpected pattern literal: {:?}", e).into())
|
(_, e) =>
|
||||||
|
return Err(format!("Internal error, unexpected pattern literal: {:?}", e).into()),
|
||||||
},
|
},
|
||||||
ast::PatternLiteral::StringPattern(s) => Literal::StringLit(s.clone()),
|
ast::PatternLiteral::StringPattern(s) => Literal::StringLit(s.clone()),
|
||||||
ast::PatternLiteral::BoolPattern(b) => Literal::Bool(*b),
|
ast::PatternLiteral::BoolPattern(b) => Literal::Bool(*b),
|
||||||
}),
|
}),
|
||||||
ast::Pattern::TupleStruct(name, subpatterns) => {
|
ast::Pattern::TupleStruct(name, subpatterns) => {
|
||||||
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
||||||
if let SymbolSpec::DataConstructor { tag, type_id: _, arity: _ } = symbol.spec() {
|
if let SymbolSpec::DataConstructor { tag, type_id: _ } = symbol.spec() {
|
||||||
let items: Result<Vec<Pattern>, PatternError> = subpatterns.iter().map(|pat| pat.reduce(symbol_table))
|
let items: Result<Vec<Pattern>, PatternError> =
|
||||||
.into_iter().collect();
|
subpatterns.iter().map(|pat| pat.reduce(symbol_table)).into_iter().collect();
|
||||||
let items = items?;
|
let items = items?;
|
||||||
Pattern::Tuple {
|
Pattern::Tuple { tag: Some(tag), subpatterns: items }
|
||||||
tag: Some(tag),
|
|
||||||
subpatterns: items,
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return Err("Internal error, trying to match something that's not a DataConstructor".into());
|
return Err(
|
||||||
|
"Internal error, trying to match something that's not a DataConstructor".into()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
ast::Pattern::VarOrName(name) => {
|
ast::Pattern::VarOrName(name) => {
|
||||||
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
||||||
match symbol.spec() {
|
match symbol.spec() {
|
||||||
SymbolSpec::DataConstructor { tag, type_id: _, arity: _ } => {
|
SymbolSpec::DataConstructor { tag, type_id: _ } =>
|
||||||
Pattern::Tuple {
|
Pattern::Tuple { tag: Some(tag), subpatterns: vec![] },
|
||||||
tag: Some(tag),
|
|
||||||
subpatterns: vec![]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
SymbolSpec::LocalVariable => {
|
SymbolSpec::LocalVariable => {
|
||||||
let def_id = symbol.def_id().unwrap();
|
let def_id = symbol.def_id().unwrap();
|
||||||
Pattern::Binding(def_id)
|
Pattern::Binding(def_id)
|
||||||
},
|
|
||||||
spec => return Err(format!("Unexpected VarOrName symbol: {:?}", spec).into())
|
|
||||||
}
|
}
|
||||||
},
|
spec => return Err(format!("Unexpected VarOrName symbol: {:?}", spec).into()),
|
||||||
ast::Pattern::Record(name, _specified_members/*Vec<(Rc<String>, Pattern)>*/) => {
|
}
|
||||||
|
}
|
||||||
|
ast::Pattern::Record(name, _specified_members /*Vec<(Rc<String>, Pattern)>*/) => {
|
||||||
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
||||||
match symbol.spec() {
|
match symbol.spec() {
|
||||||
SymbolSpec::RecordConstructor { tag: _, members: _, type_id: _ } => unimplemented!(),
|
SymbolSpec::RecordConstructor { tag: _, members: _, type_id: _ } => unimplemented!(),
|
||||||
spec => return Err(format!("Unexpected Record pattern symbol: {:?}", spec).into())
|
spec => return Err(format!("Unexpected Record pattern symbol: {:?}", spec).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, convert::From, rc::Rc};
|
||||||
use std::rc::Rc;
|
|
||||||
use std::convert::From;
|
|
||||||
|
|
||||||
use crate::builtin::Builtin;
|
use crate::{
|
||||||
use crate::symbol_table::{DefId, SymbolTable};
|
builtin::Builtin,
|
||||||
use crate::type_inference::TypeId;
|
symbol_table::{DefId, SymbolTable},
|
||||||
|
type_inference::TypeId,
|
||||||
|
};
|
||||||
|
|
||||||
//TODO most of these Clone impls only exist to support function application, because the
|
//TODO most of these Clone impls only exist to support function application, because the
|
||||||
//tree-walking evaluator moves the reduced IR members.
|
//tree-walking evaluator moves the reduced IR members.
|
||||||
@ -41,11 +41,7 @@ impl ReducedIR {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
Binding {
|
Binding { id: DefId, constant: bool, expr: Expression },
|
||||||
id: DefId,
|
|
||||||
constant: bool,
|
|
||||||
expr: Expression
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -53,24 +49,11 @@ pub enum Expression {
|
|||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Tuple(Vec<Expression>),
|
Tuple(Vec<Expression>),
|
||||||
Lookup(Lookup),
|
Lookup(Lookup),
|
||||||
Assign {
|
Assign { lval: DefId, rval: Box<Expression> },
|
||||||
lval: DefId,
|
|
||||||
rval: Box<Expression>,
|
|
||||||
},
|
|
||||||
Callable(Callable),
|
Callable(Callable),
|
||||||
Call {
|
Call { f: Box<Expression>, args: Vec<Expression> },
|
||||||
f: Box<Expression>,
|
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
|
||||||
args: Vec<Expression>
|
CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> },
|
||||||
},
|
|
||||||
Conditional {
|
|
||||||
cond: Box<Expression>,
|
|
||||||
then_clause: Vec<Statement>,
|
|
||||||
else_clause: Vec<Statement>,
|
|
||||||
},
|
|
||||||
CaseMatch {
|
|
||||||
cond: Box<Expression>,
|
|
||||||
alternatives: Vec<Alternative>,
|
|
||||||
},
|
|
||||||
ReductionError(String),
|
ReductionError(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,26 +65,16 @@ impl Expression {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDefinition {
|
pub struct FunctionDefinition {
|
||||||
pub body: Vec<Statement>
|
pub body: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Callable {
|
pub enum Callable {
|
||||||
Builtin(Builtin),
|
Builtin(Builtin),
|
||||||
UserDefined(DefId),
|
UserDefined(DefId),
|
||||||
Lambda {
|
Lambda { arity: u8, body: Vec<Statement> },
|
||||||
arity: u8,
|
DataConstructor { type_id: TypeId, tag: u32 },
|
||||||
body: Vec<Statement>
|
RecordConstructor { type_id: TypeId, tag: u32 },
|
||||||
},
|
|
||||||
DataConstructor {
|
|
||||||
type_id: TypeId,
|
|
||||||
arity: u32,
|
|
||||||
tag: u32
|
|
||||||
},
|
|
||||||
RecordConstructor {
|
|
||||||
type_id: TypeId,
|
|
||||||
tag: u32,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -129,13 +102,10 @@ pub struct Alternative {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Tuple {
|
Tuple { subpatterns: Vec<Pattern>, tag: Option<u32> },
|
||||||
subpatterns: Vec<Pattern>,
|
|
||||||
tag: Option<u32>,
|
|
||||||
},
|
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Ignored,
|
Ignored,
|
||||||
Binding(DefId)
|
Binding(DefId),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -257,9 +257,7 @@ impl fmt::Display for Symbol {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SymbolSpec {
|
pub enum SymbolSpec {
|
||||||
Func,
|
Func,
|
||||||
// The tag and arity here are *surface* tags, computed from the order in which they were
|
DataConstructor { tag: u32, type_id: TypeId },
|
||||||
// defined. The type context may create a different ordering.
|
|
||||||
DataConstructor { tag: u32, arity: usize, type_id: TypeId },
|
|
||||||
RecordConstructor { tag: u32, members: HashMap<Rc<String>, TypeId>, type_id: TypeId },
|
RecordConstructor { tag: u32, members: HashMap<Rc<String>, TypeId>, type_id: TypeId },
|
||||||
GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context
|
GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context
|
||||||
LocalVariable,
|
LocalVariable,
|
||||||
@ -271,8 +269,7 @@ impl fmt::Display for SymbolSpec {
|
|||||||
use self::SymbolSpec::*;
|
use self::SymbolSpec::*;
|
||||||
match self {
|
match self {
|
||||||
Func => write!(f, "Func"),
|
Func => write!(f, "Func"),
|
||||||
DataConstructor { tag, type_id, arity } =>
|
DataConstructor { tag, type_id } => write!(f, "DataConstructor(tag: {}, type: {})", tag, type_id),
|
||||||
write!(f, "DataConstructor(tag: {}, arity: {}, type: {})", tag, arity, type_id),
|
|
||||||
RecordConstructor { type_id, tag, .. } =>
|
RecordConstructor { type_id, tag, .. } =>
|
||||||
write!(f, "RecordConstructor(tag: {})(<members> -> {})", tag, type_id),
|
write!(f, "RecordConstructor(tag: {})(<members> -> {})", tag, type_id),
|
||||||
GlobalBinding => write!(f, "GlobalBinding"),
|
GlobalBinding => write!(f, "GlobalBinding"),
|
||||||
@ -484,10 +481,8 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
let id = fqsn_id_map.get(&fqsn).unwrap();
|
let id = fqsn_id_map.get(&fqsn).unwrap();
|
||||||
let tag = index as u32;
|
let tag = index as u32;
|
||||||
let spec = match &variant.members {
|
let spec = match &variant.members {
|
||||||
type_inference::VariantMembers::Unit =>
|
type_inference::VariantMembers::Unit => SymbolSpec::DataConstructor { tag, type_id },
|
||||||
SymbolSpec::DataConstructor { tag, arity: 0, type_id },
|
type_inference::VariantMembers::Tuple(..) => SymbolSpec::DataConstructor { tag, type_id },
|
||||||
type_inference::VariantMembers::Tuple(items) =>
|
|
||||||
SymbolSpec::DataConstructor { tag, arity: items.len(), type_id },
|
|
||||||
type_inference::VariantMembers::Record(..) =>
|
type_inference::VariantMembers::Record(..) =>
|
||||||
SymbolSpec::RecordConstructor { tag, members: HashMap::new(), type_id },
|
SymbolSpec::RecordConstructor { tag, members: HashMap::new(), type_id },
|
||||||
};
|
};
|
||||||
|
@ -106,8 +106,14 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
Primitive::unit()
|
Primitive::unit()
|
||||||
}
|
}
|
||||||
Expression::Call { box f, args } => self.call_expression(f, args)?,
|
Expression::Call { box f, args } => self.call_expression(f, args)?,
|
||||||
Expression::Callable(Callable::DataConstructor { type_id, arity, tag }) if arity == 0 =>
|
Expression::Callable(Callable::DataConstructor { type_id, tag }) => {
|
||||||
Primitive::Object { type_id, tag, items: vec![] },
|
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
|
||||||
|
if arity == 0 {
|
||||||
|
Primitive::Object { type_id, tag, items: vec![] }
|
||||||
|
} else {
|
||||||
|
Primitive::Callable(Callable::DataConstructor { type_id, tag })
|
||||||
|
}
|
||||||
|
}
|
||||||
Expression::Callable(func) => Primitive::Callable(func),
|
Expression::Callable(func) => Primitive::Callable(func),
|
||||||
Expression::Conditional { box cond, then_clause, else_clause } => {
|
Expression::Conditional { box cond, then_clause, else_clause } => {
|
||||||
let cond = self.expression(cond)?;
|
let cond = self.expression(cond)?;
|
||||||
@ -205,7 +211,8 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
}
|
}
|
||||||
self.apply_function(body, args)
|
self.apply_function(body, args)
|
||||||
}
|
}
|
||||||
Callable::DataConstructor { type_id, arity, tag } => {
|
Callable::DataConstructor { type_id, tag } => {
|
||||||
|
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
|
||||||
if arity as usize != args.len() {
|
if arity as usize != args.len() {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Constructor expression requries {} arguments, only {} provided",
|
"Constructor expression requries {} arguments, only {} provided",
|
||||||
|
@ -31,9 +31,7 @@ impl TypeContext {
|
|||||||
let record_variant = matches!(members.get(0).unwrap(), VariantMemberBuilder::KeyVal(..));
|
let record_variant = matches!(members.get(0).unwrap(), VariantMemberBuilder::KeyVal(..));
|
||||||
|
|
||||||
if record_variant {
|
if record_variant {
|
||||||
let pending_members = members
|
let pending_members = members.into_iter().map(|var| match var {
|
||||||
.into_iter()
|
|
||||||
.map(|var| match var {
|
|
||||||
VariantMemberBuilder::KeyVal(name, ty) => (name, ty),
|
VariantMemberBuilder::KeyVal(name, ty) => (name, ty),
|
||||||
_ => panic!("Compiler internal error: variant mismatch"),
|
_ => panic!("Compiler internal error: variant mismatch"),
|
||||||
});
|
});
|
||||||
@ -46,9 +44,7 @@ impl TypeContext {
|
|||||||
pending_variants
|
pending_variants
|
||||||
.push(Variant { name: variant_builder.name, members: VariantMembers::Record(type_ids) });
|
.push(Variant { name: variant_builder.name, members: VariantMembers::Record(type_ids) });
|
||||||
} else {
|
} else {
|
||||||
let pending_members = members
|
let pending_members = members.into_iter().map(|var| match var {
|
||||||
.into_iter()
|
|
||||||
.map(|var| match var {
|
|
||||||
VariantMemberBuilder::Pending(pending_type) => pending_type,
|
VariantMemberBuilder::Pending(pending_type) => pending_type,
|
||||||
_ => panic!("Compiler internal error: variant mismatch"),
|
_ => panic!("Compiler internal error: variant mismatch"),
|
||||||
});
|
});
|
||||||
@ -78,6 +74,16 @@ impl TypeContext {
|
|||||||
.map(|variant| variant.name.as_ref())
|
.map(|variant| variant.name.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lookup_variant_arity(&self, type_id: &TypeId, tag: u32) -> Option<u32> {
|
||||||
|
self.defined_types.get(type_id).and_then(|defined| defined.variants.get(tag as usize)).map(
|
||||||
|
|variant| match &variant.members {
|
||||||
|
VariantMembers::Unit => 0,
|
||||||
|
VariantMembers::Tuple(items) => items.len() as u32,
|
||||||
|
VariantMembers::Record(items) => items.len() as u32,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lookup_type(&self, type_id: &TypeId) -> Option<&DefinedType> {
|
pub fn lookup_type(&self, type_id: &TypeId) -> Option<&DefinedType> {
|
||||||
self.defined_types.get(type_id)
|
self.defined_types.get(type_id)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user