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::{
|
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
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