λ Support functions! #5
@@ -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(),
|
||||||
|
|||||||
@@ -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>>());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user