Various data layout changes to support DataConstructor evaluation
This commit is contained in:
parent
a1d6661a6b
commit
e4af5beb1c
@ -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))
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
@ -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)?);
|
||||||
|
@ -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))");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user