diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/builtins.rs | 134 |
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), |
