1
0

Begin implementing built-in functions

This commit is contained in:
Jeff 2024-03-08 22:34:17 -05:00
parent 3064a92e73
commit 5f958c72b8
2 changed files with 171 additions and 10 deletions

View File

@ -13,8 +13,9 @@ use stanza::{
}; };
use crate::{ use crate::{
abstract_tree::{Identifier, Statement, Type}, abstract_tree::{Action, Identifier, Statement, Type},
error::ValidationError, context::Context,
error::{RuntimeError, ValidationError},
}; };
pub static NONE: OnceLock<Value> = OnceLock::new(); pub static NONE: OnceLock<Value> = OnceLock::new();
@ -77,11 +78,13 @@ impl Value {
return_type: Type, return_type: Type,
body: Statement, body: Statement,
) -> Self { ) -> Self {
Value(Arc::new(ValueInner::Function(Function { Value(Arc::new(ValueInner::Function(Function::Parsed(
ParsedFunction {
parameters, parameters,
return_type, return_type,
body, body,
}))) },
))))
} }
pub fn r#type(&self) -> Type { pub fn r#type(&self) -> Type {
@ -227,11 +230,11 @@ impl Display for Value {
ValueInner::String(string) => write!(f, "{string}"), ValueInner::String(string) => write!(f, "{string}"),
ValueInner::Enum(_, _) => todo!(), ValueInner::Enum(_, _) => todo!(),
ValueInner::Function(Function { ValueInner::Function(Function::Parsed(ParsedFunction {
parameters, parameters,
return_type, return_type,
body, body,
}) => { })) => {
write!(f, "(")?; write!(f, "(")?;
for (identifier, r#type) in parameters { for (identifier, r#type) in parameters {
@ -240,6 +243,9 @@ impl Display for Value {
write!(f, "): {return_type} {body:?}") write!(f, "): {return_type} {body:?}")
} }
ValueInner::Function(Function::BuiltIn(built_in_function)) => {
write!(f, "{built_in_function}")
}
} }
} }
} }
@ -323,8 +329,48 @@ impl Ord for ValueInner {
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function { pub enum Function {
Parsed(ParsedFunction),
BuiltIn(BuiltInFunction),
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct ParsedFunction {
parameters: Vec<(Identifier, Type)>, parameters: Vec<(Identifier, Type)>,
return_type: Type, return_type: Type,
body: Statement, body: Statement,
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction {
Output(Value),
}
impl BuiltInFunction {
fn r#type(&self, context: &Context) -> Type {
match self {
BuiltInFunction::Output(_) => Type::Function {
parameter_types: vec![Type::Any],
return_type: Box::new(Type::None),
},
}
}
fn call(self, context: &Context) -> Result<Action, RuntimeError> {
match self {
BuiltInFunction::Output(value) => {
println!("{value}");
Ok(Action::None)
}
}
}
}
impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
BuiltInFunction::Output(_) => write!(f, "(to_output : any) : none rust_magic();"),
}
}
}

115
tests/functions.rs Normal file
View File

@ -0,0 +1,115 @@
use dust_lang::{
abstract_tree::Identifier,
error::{Error, ValidationError},
*,
};
#[test]
fn function_call() {
assert_eq!(
interpret(
"
foobar = (message : str) : str { message }
foobar('Hiya')
",
),
Ok(Some(Value::string("Hiya".to_string())))
);
}
#[test]
fn call_empty_function() {
assert_eq!(
interpret(
"
foobar = (message : str) : none {}
foobar('Hiya')
",
),
Ok(None)
);
}
#[test]
fn callback() {
assert_eq!(
interpret(
"
foobar = (cb : () -> str) : str {
cb()
}
foobar(() : str { 'Hiya' })
",
),
Ok(Some(Value::string("Hiya".to_string())))
);
}
#[test]
fn built_in_function_call() {
assert_eq!(interpret("output('Hiya')"), Ok(None));
}
#[test]
fn function_context_does_not_capture_values() {
assert_eq!(
interpret(
"
x = 1
foo = () : any { x }
"
),
Err(vec![Error::Validation {
error: ValidationError::VariableNotFound(Identifier::new("x")),
span: (0..0).into()
}])
);
assert_eq!(
interpret(
"
x = 1
foo = (x : int) : int { x }
foo(2)
"
),
Ok(Some(Value::integer(2)))
);
}
#[test]
fn function_context_captures_functions() {
assert_eq!(
interpret(
"
bar = () : int { 2 }
foo = () : int { bar() }
foo()
"
),
Ok(Some(Value::integer(2)))
);
}
#[test]
fn recursion() {
env_logger::builder().is_test(true).try_init().unwrap();
assert_eq!(
interpret(
"
fib = (i : int) : int {
if i <= 1 {
1
} else {
fib(i - 1) + fib(i - 2)
}
}
fib(8)
"
),
Ok(Some(Value::integer(34)))
);
}