λ Support functions! #5

Open
acw wants to merge 59 commits from awick/functions into develop
3 changed files with 31 additions and 89 deletions
Showing only changes of commit cf7eff7a93 - Show all commits

View File

@@ -1,7 +1,5 @@
use crate::eval::PrimitiveType; use crate::eval::PrimitiveType;
use crate::ir::{ use crate::ir::{Expression, Name, Primitive, Program, Type, TypeWithVoid, Value, ValueOrRef};
Expression, Name, Primitive, Program, TopLevel, Type, TypeWithVoid, Value, ValueOrRef,
};
use crate::syntax::Location; use crate::syntax::Location;
use crate::util::scoped_map::ScopedMap; use crate::util::scoped_map::ScopedMap;
use proptest::strategy::{NewTree, Strategy, ValueTree}; use proptest::strategy::{NewTree, Strategy, ValueTree};
@@ -183,37 +181,37 @@ pub struct ProgramTree {
impl ProgramTree { impl ProgramTree {
fn new(mut rng: TestRng) -> Self { fn new(mut rng: TestRng) -> Self {
let mut items = vec![]; // let mut items = vec![];
let program_length = PROGRAM_LENGTH_DISTRIBUTION.sample(&mut rng); let program_length = PROGRAM_LENGTH_DISTRIBUTION.sample(&mut rng);
let mut env = ScopedMap::new(); // let mut env = ScopedMap::new();
for _ in 0..program_length { // for _ in 0..program_length {
match STATEMENT_TYPE_FREQUENCIES[STATEMENT_TYPE_DISTRIBUTION.sample(&mut rng)].0 { // match STATEMENT_TYPE_FREQUENCIES[STATEMENT_TYPE_DISTRIBUTION.sample(&mut rng)].0 {
StatementType::Binding => { // StatementType::Binding => {
let binding = generate_random_binding(&mut rng, &mut env); // let binding = generate_random_binding(&mut rng, &mut env);
items.push(TopLevel::Statement(binding)); // items.push(TopLevel::Statement(binding));
} // }
StatementType::Expression => { // StatementType::Expression => {
let expr = generate_random_expression(&mut rng, &mut env); // let expr = generate_random_expression(&mut rng, &mut env);
items.push(TopLevel::Statement(expr)); // items.push(TopLevel::Statement(expr));
} // }
StatementType::Function => { // StatementType::Function => {
env.new_scope(); // env.new_scope();
let name = generate_random_name(&mut rng); // let name = generate_random_name(&mut rng);
let mut args = vec![]; // let mut args = vec![];
let arg_count = FUNCTION_ARGUMENTS_DISTRIBUTION.sample(&mut rng); // let arg_count = FUNCTION_ARGUMENTS_DISTRIBUTION.sample(&mut rng);
for _ in 0..arg_count { // for _ in 0..arg_count {
let name = generate_random_name(&mut rng); // let name = generate_random_name(&mut rng);
let ty = generate_random_argument_type(&mut rng); // let ty = generate_random_argument_type(&mut rng);
args.push((name, ty)); // args.push((name, ty));
} // }
let body = generate_random_expression(&mut rng, &mut env); // let body = generate_random_expression(&mut rng, &mut env);
let rettype = body.type_of(); // let rettype = body.type_of();
env.release_scope(); // env.release_scope();
items.push(TopLevel::Function(name, args, rettype, body)) // items.push(TopLevel::Function(name, args, rettype, body))
} // }
} // }
} // }
let current = Program { let current = Program {
functions: HashMap::new(), functions: HashMap::new(),

View File

@@ -52,32 +52,6 @@ impl Arbitrary for Program<Type> {
} }
} }
/// A thing that can sit at the top level of a file.
///
/// For the moment, these are statements and functions. Other things
/// will likely be added in the future, but for now: just statements
/// and functions
#[derive(Clone, Debug)]
pub enum TopLevel<Type> {
Statement(Expression<Type>),
// FIXME: Is the return type actually necessary, given we can infer it from
// the expression type?
Function(Name, Vec<(Name, Type)>, Type, Expression<Type>),
}
impl<T: Clone + TypeWithVoid + TypeWithFunction> TopLevel<T> {
/// Return the type of the item, as inferred or recently
/// computed.
pub fn type_of(&self) -> T {
match self {
TopLevel::Statement(expr) => expr.type_of(),
TopLevel::Function(_, args, ret, _) => {
T::build_function_type(args.iter().map(|(_, t)| t.clone()).collect(), ret.clone())
}
}
}
}
/// The representation of an expression. /// The representation of an expression.
/// ///
/// Note that expressions, like everything else in this syntax tree, /// Note that expressions, like everything else in this syntax tree,
@@ -479,8 +453,6 @@ fn struct_sizes_are_rational() {
assert_eq!(80, std::mem::size_of::<ValueOrRef<TypeOrVar>>()); assert_eq!(80, std::mem::size_of::<ValueOrRef<TypeOrVar>>());
assert_eq!(200, std::mem::size_of::<Expression<Type>>()); assert_eq!(200, std::mem::size_of::<Expression<Type>>());
assert_eq!(200, std::mem::size_of::<Expression<TypeOrVar>>()); assert_eq!(200, std::mem::size_of::<Expression<TypeOrVar>>());
assert_eq!(272, std::mem::size_of::<TopLevel<Type>>());
assert_eq!(272, std::mem::size_of::<TopLevel<TypeOrVar>>());
assert_eq!(72, std::mem::size_of::<Program<Type>>()); assert_eq!(72, std::mem::size_of::<Program<Type>>());
assert_eq!(72, std::mem::size_of::<Program<TypeOrVar>>()); assert_eq!(72, std::mem::size_of::<Program<TypeOrVar>>());
} }

View File

@@ -1,4 +1,4 @@
use crate::ir::{Expression, Primitive, Program, TopLevel, Type, TypeOrVar, Value, ValueOrRef}; use crate::ir::{Expression, Primitive, Program, Type, TypeOrVar, Value, ValueOrRef};
use crate::syntax::{self, ConstantType}; use crate::syntax::{self, ConstantType};
use crate::util::pretty::{derived_display, pretty_function_type, Allocator}; use crate::util::pretty::{derived_display, pretty_function_type, Allocator};
use pretty::{Arena, DocAllocator, DocBuilder}; use pretty::{Arena, DocAllocator, DocBuilder};
@@ -57,33 +57,6 @@ impl Program<Type> {
} }
} }
impl TopLevel<Type> {
pub fn pretty<'a>(
&self,
allocator: &'a Arena<'a, ()>,
) -> pretty::DocBuilder<'a, Arena<'a, ()>, ()> {
match self {
TopLevel::Function(name, args, _, expr) => allocator
.text("function")
.append(allocator.space())
.append(allocator.text(name.current_name().to_string()))
.append(allocator.space())
.append(
allocator
.intersperse(
args.iter().map(|(x, _)| allocator.text(x.to_string())),
allocator.text(","),
)
.parens(),
)
.append(allocator.space())
.append(expr.pretty(allocator)),
TopLevel::Statement(stmt) => stmt.pretty(allocator),
}
}
}
impl Expression<Type> { impl Expression<Type> {
pub fn pretty<'a>( pub fn pretty<'a>(
&self, &self,
@@ -267,7 +240,6 @@ impl TypeOrVar {
} }
derived_display!(Program<Type>); derived_display!(Program<Type>);
derived_display!(TopLevel<Type>);
derived_display!(Expression<Type>); derived_display!(Expression<Type>);
derived_display!(Primitive); derived_display!(Primitive);
derived_display!(Type); derived_display!(Type);