Begin implementing built-in functions
This commit is contained in:
parent
3064a92e73
commit
5f958c72b8
60
src/value.rs
60
src/value.rs
@ -13,8 +13,9 @@ use stanza::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{Identifier, Statement, Type},
|
||||
error::ValidationError,
|
||||
abstract_tree::{Action, Identifier, Statement, Type},
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
};
|
||||
|
||||
pub static NONE: OnceLock<Value> = OnceLock::new();
|
||||
@ -77,11 +78,13 @@ impl Value {
|
||||
return_type: Type,
|
||||
body: Statement,
|
||||
) -> Self {
|
||||
Value(Arc::new(ValueInner::Function(Function {
|
||||
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
||||
ParsedFunction {
|
||||
parameters,
|
||||
return_type,
|
||||
body,
|
||||
})))
|
||||
},
|
||||
))))
|
||||
}
|
||||
|
||||
pub fn r#type(&self) -> Type {
|
||||
@ -227,11 +230,11 @@ impl Display for Value {
|
||||
ValueInner::String(string) => write!(f, "{string}"),
|
||||
|
||||
ValueInner::Enum(_, _) => todo!(),
|
||||
ValueInner::Function(Function {
|
||||
ValueInner::Function(Function::Parsed(ParsedFunction {
|
||||
parameters,
|
||||
return_type,
|
||||
body,
|
||||
}) => {
|
||||
})) => {
|
||||
write!(f, "(")?;
|
||||
|
||||
for (identifier, r#type) in parameters {
|
||||
@ -240,6 +243,9 @@ impl Display for Value {
|
||||
|
||||
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)]
|
||||
pub struct Function {
|
||||
pub enum Function {
|
||||
Parsed(ParsedFunction),
|
||||
BuiltIn(BuiltInFunction),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ParsedFunction {
|
||||
parameters: Vec<(Identifier, Type)>,
|
||||
return_type: Type,
|
||||
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
115
tests/functions.rs
Normal 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)))
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user