Various data layout changes to support DataConstructor evaluation

This commit is contained in:
Greg Shuflin 2021-10-25 19:08:03 -07:00
parent a1d6661a6b
commit e4af5beb1c
5 changed files with 68 additions and 29 deletions

View File

@ -134,7 +134,7 @@ impl<'a> Reducer<'a> {
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, } => self.reduce_if_expression(discriminator.as_ref().map(|x| x.as_ref()), body),
Lambda { params, body, .. } => { Lambda { params, body, .. } => {
Expression::Callable(Function::Lambda { Expression::Callable(Callable::Lambda {
arity: params.len() as u8, arity: params.len() as u8,
body: self.function(body), body: self.function(body),
}) })
@ -169,7 +169,7 @@ impl<'a> Reducer<'a> {
match builtin { match builtin {
Some(op) => { Some(op) => {
Expression::Call { Expression::Call {
f: Box::new(Expression::Callable(Function::Builtin(op))), f: Box::new(Expression::Callable(Callable::Builtin(op))),
args: vec![self.expression(arg)], args: vec![self.expression(arg)],
} }
} }
@ -181,7 +181,8 @@ impl<'a> Reducer<'a> {
} }
fn binop(&mut self, binop: &ast::BinOp, lhs: &ast::Expression, rhs: &ast::Expression) -> Expression { fn binop(&mut self, binop: &ast::BinOp, lhs: &ast::Expression, rhs: &ast::Expression) -> Expression {
use Expression::*; use Expression::ReductionError;
let operation = Builtin::from_str(binop.sigil()).ok(); let operation = Builtin::from_str(binop.sigil()).ok();
match operation { match operation {
Some(Builtin::Assignment) => { Some(Builtin::Assignment) => {
@ -196,13 +197,13 @@ impl<'a> Reducer<'a> {
_ => return ReductionError("Trying to assign to a non-name".to_string()), _ => return ReductionError("Trying to assign to a non-name".to_string()),
}; };
Assign { Expression::Assign {
lval, lval,
rval: Box::new(self.expression(rhs)), rval: Box::new(self.expression(rhs)),
} }
}, },
Some(op) => Expression::Call { Some(op) => Expression::Call {
f: Box::new(Expression::Callable(Function::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
@ -225,9 +226,11 @@ 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 { index, arity, type_id } => { DataConstructor { index, arity, type_id } => Expression::Callable(Callable::DataConstructor {
Expression::ReductionError("DataConstructor not supported".to_string()) type_id: type_id.clone(),
}, arity: arity as u32, //TODO fix up these modifiers
tag: index as u32,
}),
RecordConstructor { .. } => { RecordConstructor { .. } => {
Expression::ReductionError(format!("The symbol for value {:?} is unexpectdly a RecordConstructor", qualified_name)) Expression::ReductionError(format!("The symbol for value {:?} is unexpectdly a RecordConstructor", qualified_name))
}, },

View File

@ -3,6 +3,7 @@ use std::rc::Rc;
use crate::builtin::Builtin; use crate::builtin::Builtin;
use crate::symbol_table::{DefId, SymbolTable}; use crate::symbol_table::{DefId, SymbolTable};
use crate::typechecking::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.
@ -55,7 +56,7 @@ pub enum Expression {
lval: DefId, lval: DefId,
rval: Box<Expression>, rval: Box<Expression>,
}, },
Callable(Function), Callable(Callable),
Call { Call {
f: Box<Expression>, f: Box<Expression>,
args: Vec<Expression> args: Vec<Expression>
@ -75,7 +76,7 @@ pub struct FunctionDefinition {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Function { pub enum Callable {
Builtin(Builtin), Builtin(Builtin),
UserDefined(DefId), UserDefined(DefId),
Lambda { Lambda {
@ -83,7 +84,7 @@ pub enum Function {
body: Vec<Statement> body: Vec<Statement>
}, },
DataConstructor { DataConstructor {
type_id: Rc<String>, //TODO this can't last type_id: TypeId,
arity: u32, arity: u32,
tag: u32 tag: u32
}, },

View File

@ -1,7 +1,8 @@
use crate::reduced_ir::{ReducedIR, Expression, Lookup, Function, FunctionDefinition, Statement, Literal}; use crate::reduced_ir::{ReducedIR, Expression, Lookup, Callable, FunctionDefinition, Statement, Literal};
use crate::symbol_table::{DefId}; use crate::symbol_table::{DefId};
use crate::util::ScopeStack; use crate::util::ScopeStack;
use crate::builtin::Builtin; use crate::builtin::Builtin;
use crate::typechecking::TypeId;
use std::fmt::Write; use std::fmt::Write;
use std::rc::Rc; use std::rc::Rc;
@ -106,10 +107,21 @@ fn expr_to_repl(expr: &Expression) -> String {
} }
} }
impl Primitive {
fn to_repl(&self) -> String {
match self {
Primitive::Object { type_id, items, .. } => {
format!("{}{}", type_id.local_name(), paren_wrapped(items.iter().map(|item| item.to_repl())))
},
prim => expr_to_repl(&prim.to_expr()),
}
}
}
impl RuntimeValue { impl RuntimeValue {
fn to_repl(&self) -> String { fn to_repl(&self) -> String {
match self { match self {
RuntimeValue::Primitive(ref prim) => expr_to_repl(&prim.to_expr()), RuntimeValue::Primitive(ref prim) => prim.to_repl(),
RuntimeValue::Function(..) => "<function>".to_string(), RuntimeValue::Function(..) => "<function>".to_string(),
} }
} }
@ -120,14 +132,12 @@ impl RuntimeValue {
enum Primitive { enum Primitive {
Tuple(Vec<Primitive>), Tuple(Vec<Primitive>),
Literal(Literal), Literal(Literal),
Callable(Function), Callable(Callable),
/* Object {
PrimObject { type_id: TypeId,
name: Rc<String>, tag: u32,
tag: usize, items: Vec<Primitive>
items: Vec<Node>,
}, },
*/
} }
impl Primitive { impl Primitive {
@ -148,6 +158,13 @@ impl Primitive {
Primitive::Tuple(items) => Expression::Tuple(items.iter().map(|item| item.to_expr()).collect()), Primitive::Tuple(items) => Expression::Tuple(items.iter().map(|item| item.to_expr()).collect()),
Primitive::Literal(lit) => Expression::Literal(lit.clone()), Primitive::Literal(lit) => Expression::Literal(lit.clone()),
Primitive::Callable(function) => Expression::Callable(function.clone()), Primitive::Callable(function) => Expression::Callable(function.clone()),
Primitive::Object { type_id, tag, items } if items.len() == 0 => {
Expression::Literal(Literal::Nat(420))
},
Primitive::Object { type_id, tag, items } => Expression::Call {
f: Box::new(Expression::Callable(Callable::DataConstructor { type_id: type_id.clone(), arity: items.len() as u32, tag: *tag as u32 })),
args: items.iter().map(|arg| arg.to_expr()).collect(),
},
} }
} }
} }
@ -223,7 +240,7 @@ impl<'a> State<'a> {
match self.environments.lookup(&mem) { match self.environments.lookup(&mem) {
// This just checks that the function exists in "memory" by ID, we don't // This just checks that the function exists in "memory" by ID, we don't
// actually retrieve it until `apply_function()` // actually retrieve it until `apply_function()`
Some(RuntimeValue::Function(_)) => Primitive::Callable(Function::UserDefined(id.clone())), Some(RuntimeValue::Function(_)) => Primitive::Callable(Callable::UserDefined(id.clone())),
x => return Err(format!("Function not found for id: {} : {:?}", id, x).into()), x => return Err(format!("Function not found for id: {} : {:?}", id, x).into()),
} }
}, },
@ -260,8 +277,8 @@ impl<'a> State<'a> {
other => return Err(format!("Trying to call non-function value: {:?}", other).into()), other => return Err(format!("Trying to call non-function value: {:?}", other).into()),
}; };
match func { match func {
Function::Builtin(builtin) => self.apply_builtin(builtin, args), Callable::Builtin(builtin) => self.apply_builtin(builtin, args),
Function::UserDefined(def_id) => { Callable::UserDefined(def_id) => {
let mem = (&def_id).into(); let mem = (&def_id).into();
match self.environments.lookup(&mem) { match self.environments.lookup(&mem) {
Some(RuntimeValue::Function(FunctionDefinition { body })) => { Some(RuntimeValue::Function(FunctionDefinition { body })) => {
@ -271,14 +288,28 @@ impl<'a> State<'a> {
e => Err(format!("Error looking up function with id {}: {:?}", def_id, e).into()) e => Err(format!("Error looking up function with id {}: {:?}", def_id, e).into())
} }
}, },
Function::Lambda { arity, body } => { Callable::Lambda { arity, body } => {
if arity as usize != args.len() { if arity as usize != args.len() {
return Err(format!("Lambda expression requries {} arguments, only {} provided", arity, args.len()).into()); return Err(format!("Lambda expression requries {} arguments, only {} provided", arity, args.len()).into());
} }
let body = body.clone(); //TODO again ideally, no cloning here let body = body.clone(); //TODO again ideally, no cloning here
self.apply_function(body, args) self.apply_function(body, args)
} }
Function::DataConstructor { .. } => panic!(), Callable::DataConstructor { type_id, arity, tag } => {
if arity as usize != args.len() {
return Err(format!("Constructor expression requries {} arguments, only {} provided", arity, args.len()).into());
}
let mut evaluated_args: Vec<Primitive> = vec![];
for arg in args.into_iter() {
evaluated_args.push(self.expression(arg)?);
}
Ok(Primitive::Object {
type_id,
tag,
items: evaluated_args
})
}
} }
} }
@ -365,7 +396,6 @@ impl<'a> State<'a> {
} }
fn apply_function(&mut self, body: Vec<Statement>, args: Vec<Expression>) -> EvalResult<Primitive> { fn apply_function(&mut self, body: Vec<Statement>, args: Vec<Expression>) -> EvalResult<Primitive> {
let mut evaluated_args: Vec<Primitive> = vec![]; let mut evaluated_args: Vec<Primitive> = vec![];
for arg in args.into_iter() { for arg in args.into_iter() {
evaluated_args.push(self.expression(arg)?); evaluated_args.push(self.expression(arg)?);

View File

@ -68,10 +68,11 @@ fn adt_output_1() {
let source = r#" let source = r#"
type Option<T> = Some(T) | None type Option<T> = Some(T) | None
let x = Option::Some(10) let a = Option::None
x let b = Option::Some(10)
(a, b)
"#; "#;
eval_assert(source, "Option::Some(10)"); eval_assert(source, "(Option::None, Option::Some(10))");
} }
/* /*

View File

@ -35,6 +35,10 @@ impl TypeId {
local_name: Rc::new(name.to_string()) local_name: Rc::new(name.to_string())
} }
} }
pub fn local_name(&self) -> &str {
self.local_name.as_ref()
}
} }
impl fmt::Display for TypeId { impl fmt::Display for TypeId {