aboutsummaryrefslogtreecommitdiffstats
path: root/src/builtins.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/builtins.rs')
-rw-r--r--src/builtins.rs134
1 files changed, 124 insertions, 10 deletions
diff --git a/src/builtins.rs b/src/builtins.rs
index 652fb3b..4ffd197 100644
--- a/src/builtins.rs
+++ b/src/builtins.rs
@@ -74,14 +74,26 @@ macro_rules! boolean_function {
pub const B_TRUE: &str = "true";
pub const B_FALSE: &str = "false";
pub const B_ID: &str = "id";
+
pub const B_INTEGER_EQ: &str = "int.eq?";
+pub const B_INTEGER_LT: &str = "int.lt?";
+pub const B_INTEGER_GT: &str = "int.gt?";
pub const B_INTEGER_INCREMENT: &str = "int.inc";
pub const B_INTEGER_ADD: &str = "int.add";
pub const B_INTEGER_SUBTRACT: &str = "int.sub";
pub const B_INTEGER_MULTIPLY: &str = "int.mul";
pub const B_INTEGER_DIVIDE: &str = "int.div";
+
pub const B_STRING_EQ: &str = "string.eq?";
+pub const B_STRING_CONCAT: &str = "string.concat";
+pub const B_STRING_HEAD: &str = "string.head";
+pub const B_STRING_TAIL: &str = "string.tail";
+
pub const B_BOOL_TO_STRING: &str = "bool.to-string";
+pub const B_BOOL_NOT: &str = "not?";
+pub const B_BOOL_AND: &str = "and?";
+pub const B_BOOL_OR: &str = "or?";
+
pub const B_COMMAND_PRINTLN: &str = "cmd.println!";
pub const C_PRINTLN: &str = "PrintLn";
@@ -92,13 +104,21 @@ pub fn try_ast_symbol_to_builtin_term(symbol: &str) -> Option<Term> {
B_FALSE => Builtin::new(B_FALSE, 0),
B_ID => Builtin::new(B_ID, 0),
B_INTEGER_EQ => Builtin::new(B_INTEGER_EQ, 2),
+ B_INTEGER_LT => Builtin::new(B_INTEGER_LT, 2),
+ B_INTEGER_GT => Builtin::new(B_INTEGER_GT, 2),
B_INTEGER_INCREMENT => Builtin::new(B_INTEGER_INCREMENT, 1),
B_INTEGER_ADD => Builtin::new(B_INTEGER_ADD, 2),
B_INTEGER_SUBTRACT => Builtin::new(B_INTEGER_SUBTRACT, 2),
B_INTEGER_MULTIPLY => Builtin::new(B_INTEGER_MULTIPLY, 2),
B_INTEGER_DIVIDE => Builtin::new(B_INTEGER_DIVIDE, 2),
B_STRING_EQ => Builtin::new(B_STRING_EQ, 2),
+ B_STRING_CONCAT => Builtin::new(B_STRING_CONCAT, 2),
+ B_STRING_HEAD => Builtin::new(B_STRING_HEAD, 1),
+ B_STRING_TAIL => Builtin::new(B_STRING_TAIL, 1),
B_BOOL_TO_STRING => Builtin::new(B_BOOL_TO_STRING, 1),
+ B_BOOL_NOT => Builtin::new(B_BOOL_NOT, 1),
+ B_BOOL_AND => Builtin::new(B_BOOL_AND, 2), // note: transforms into lambda after 1 argument
+ B_BOOL_OR => Builtin::new(B_BOOL_OR, 2), // note: transforms into lambda after 1 argument
B_COMMAND_PRINTLN => Builtin::new(B_COMMAND_PRINTLN, 1),
_ => return None,
};
@@ -118,15 +138,47 @@ pub fn evaluate_builtin(builtin: &Builtin, rhs: Rc<Term>) -> Result<(Rc<Term>, u
}
B_ID => return Ok((rhs, 1)),
B_INTEGER_EQ => match &*rhs {
- Term::Primitive(primitive @ Value::Integer(value)) => match builtin.n_arguments {
- 2 => Term::Builtin(builtin.bind_arg(primitive)),
- 1 => {
- let other_value = extract_enum_value!(&builtin.arguments[0], Value::Integer(other_value) => other_value);
+ Term::Primitive(primitive @ Value::Integer(second_value)) => {
+ match builtin.n_arguments {
+ 2 => Term::Builtin(builtin.bind_arg(primitive)),
+ 1 => {
+ let first_value = extract_enum_value!(&builtin.arguments[0], Value::Integer(other_value) => other_value);
- boolean_function!(value == other_value)
+ boolean_function!(first_value == second_value)
+ }
+ _ => return argument_n_error(builtin.identifier, builtin.n_arguments),
}
- _ => return argument_n_error(builtin.identifier, builtin.n_arguments),
- },
+ }
+ Term::Primitive(_) => return argument_type_error(builtin.identifier, &*rhs),
+ _ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
+ },
+ B_INTEGER_LT => match &*rhs {
+ Term::Primitive(primitive @ Value::Integer(second_value)) => {
+ match builtin.n_arguments {
+ 2 => Term::Builtin(builtin.bind_arg(primitive)),
+ 1 => {
+ let first_value = extract_enum_value!(&builtin.arguments[0], Value::Integer(other_value) => other_value);
+
+ boolean_function!(first_value < second_value)
+ }
+ _ => return argument_n_error(builtin.identifier, builtin.n_arguments),
+ }
+ }
+ Term::Primitive(_) => return argument_type_error(builtin.identifier, &*rhs),
+ _ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
+ },
+ B_INTEGER_GT => match &*rhs {
+ Term::Primitive(primitive @ Value::Integer(second_value)) => {
+ match builtin.n_arguments {
+ 2 => Term::Builtin(builtin.bind_arg(primitive)),
+ 1 => {
+ let first_value = extract_enum_value!(&builtin.arguments[0], Value::Integer(other_value) => other_value);
+
+ boolean_function!(first_value > second_value)
+ }
+ _ => return argument_n_error(builtin.identifier, builtin.n_arguments),
+ }
+ }
Term::Primitive(_) => return argument_type_error(builtin.identifier, &*rhs),
_ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
},
@@ -187,24 +239,86 @@ pub fn evaluate_builtin(builtin: &Builtin, rhs: Rc<Term>) -> Result<(Rc<Term>, u
_ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
},
B_STRING_EQ => match &*rhs {
- Term::Primitive(primitive @ Value::String(value)) => match builtin.n_arguments {
+ Term::Primitive(primitive @ Value::String(second_value)) => match builtin.n_arguments {
2 => Term::Builtin(builtin.bind_arg(primitive)),
1 => {
- let other_value = extract_enum_value!(&builtin.arguments[0], Value::String(other_value) => other_value);
+ let first_value = extract_enum_value!(&builtin.arguments[0], Value::String(other_value) => other_value);
- boolean_function!(value == other_value)
+ boolean_function!(first_value == second_value)
+ }
+ _ => return argument_n_error(builtin.identifier, builtin.n_arguments),
+ },
+ Term::Primitive(_) => return argument_type_error(builtin.identifier, &*rhs),
+ _ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
+ },
+ B_STRING_CONCAT => match &*rhs {
+ Term::Primitive(primitive @ Value::String(second_value)) => match builtin.n_arguments {
+ 2 => Term::Builtin(builtin.bind_arg(primitive)),
+ 1 => {
+ let first_value_str = extract_enum_value!(&builtin.arguments[0], Value::String(other_value) => other_value);
+ let mut first_value = first_value_str.to_owned();
+ first_value.push_str(second_value);
+ Term::Primitive(Value::String(first_value.clone()))
}
_ => return argument_n_error(builtin.identifier, builtin.n_arguments),
},
Term::Primitive(_) => return argument_type_error(builtin.identifier, &*rhs),
_ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
},
+ B_STRING_HEAD => match &*rhs {
+ Term::Primitive(Value::String(value)) => {
+ let head = value.chars().next().ok_or("[runtime] string is empty")?;
+ Term::Primitive(Value::String(String::from(head)))
+ }
+ Term::Primitive(_) => return argument_type_error(builtin.identifier, &*rhs),
+ _ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
+ },
+ B_STRING_TAIL => match &*rhs {
+ Term::Primitive(Value::String(value)) => {
+ if value.len() <= 1 {
+ // TODO: how is tail defined exactly for a string?
+ Term::Primitive(Value::String("".to_owned()))
+ } else {
+ let tail = value[1..].to_owned();
+ Term::Primitive(Value::String(tail))
+ }
+ }
+ Term::Primitive(_) => return argument_type_error(builtin.identifier, &*rhs),
+ _ => return Ok((Rc::new(Term::Builtin(builtin.clone())), 0)),
+ },
B_BOOL_TO_STRING => {
let true_str_rc = Rc::new(Term::Primitive(Value::String("true".to_owned())));
let false_str_rc = Rc::new(Term::Primitive(Value::String("false".to_owned())));
let inner = Rc::new(Term::Application(rhs, true_str_rc));
Term::Application(inner, false_str_rc)
}
+ B_BOOL_NOT => Term::Application(
+ Rc::new(Term::Application(rhs, Rc::new(boolean_function!(false)))),
+ Rc::new(boolean_function!(true)),
+ ),
+ B_BOOL_AND => {
+ let v = advance_v();
+ Term::Abstraction(
+ v,
+ Rc::new(Term::Application(
+ Rc::new(Term::Application(
+ Rc::clone(&rhs),
+ Rc::new(Term::Variable(v)),
+ )),
+ Rc::clone(&rhs),
+ )),
+ )
+ }
+ B_BOOL_OR => {
+ let v = advance_v();
+ Term::Abstraction(
+ v,
+ Rc::new(Term::Application(
+ Rc::new(Term::Application(Rc::clone(&rhs), Rc::clone(&rhs))),
+ Rc::new(Term::Variable(v)),
+ )),
+ )
+ }
B_COMMAND_PRINTLN => match &*rhs {
Term::Primitive(Value::String(_)) => match builtin.n_arguments {
1 => Term::Command(C_PRINTLN, rhs),