aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.rs29
-rw-r--r--src/builtins.rs107
-rw-r--r--src/grammar.pest2
-rw-r--r--src/main.rs1
-rw-r--r--src/runtime.rs120
5 files changed, 147 insertions, 112 deletions
diff --git a/src/ast.rs b/src/ast.rs
index dc0aa79..4ecd705 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -25,6 +25,7 @@ pub type Program = Vec<Statement>;
pub enum Statement {
Definition {
symbol: Symbol,
+ parameters: Vec<Symbol>,
expression: Rc<Expression>,
},
Expression(Rc<Expression>),
@@ -37,15 +38,31 @@ impl Statement {
fn definition_from_pair(pair: pest::iterators::Pair<Rule>) -> Statement {
let mut inner = pair.into_inner();
let symbol = inner.next().unwrap().as_span().as_str();
- let expression = inner.next().unwrap();
- let expression_inners: Vec<ExpressionInner> = expression
- .into_inner()
- .map(ExpressionInner::from_pair)
- .collect();
+ let mut parameters: Vec<Symbol> = vec![];
+ let mut expression_opt: Option<Rc<Expression>> = None;
+
+ while let Some(p) = inner.next() {
+ match p.as_rule() {
+ Rule::symbol => parameters.push(String::from(p.as_span().as_str())),
+ Rule::expression => {
+ let expression_inners: Vec<ExpressionInner> =
+ p.into_inner().map(ExpressionInner::from_pair).collect();
+ expression_opt = Some(expression_vec_to_tuple(&expression_inners));
+ }
+ _ => panic!(
+ "[ast] illegal rule {:#?} as child of definition",
+ p.as_rule()
+ ),
+ }
+ }
+
+ let expression =
+ expression_opt.expect("[ast] no expression found as child of definition");
Statement::Definition {
symbol: String::from(symbol),
- expression: expression_vec_to_tuple(&expression_inners),
+ parameters: parameters,
+ expression: expression,
}
}
diff --git a/src/builtins.rs b/src/builtins.rs
new file mode 100644
index 0000000..351a652
--- /dev/null
+++ b/src/builtins.rs
@@ -0,0 +1,107 @@
+use super::ast;
+use super::runtime;
+use super::runtime::Value;
+use std::rc::Rc;
+
+pub const B_INTEGER_INCREMENT: &str = "int.increment";
+pub const B_INTEGER_DECREMENT: &str = "int.decrement";
+pub const B_INTEGER_ADD: &str = "int.add";
+pub const B_INTEGER_MULTIPLY: &str = "int.multiply";
+pub const B_INTEGER_EQ: &str = "int.eq?";
+
+#[derive(Debug, Clone)]
+pub enum BuiltinFunction {
+ IntegerIncrement,
+ IntegerDecrement,
+ IntegerAdd,
+ IntegerAdd1(i64),
+ IntegerMultiply,
+ IntegerMultiply1(i64),
+ IntegerEq,
+ IntegerEq1(i64),
+}
+
+pub fn try_builtin_symbol_to_value(symbol: &ast::Symbol) -> Option<Value> {
+ match symbol.as_str() {
+ "true" => Some(runtime::make_boolean_true_function()),
+ "false" => Some(runtime::make_boolean_false_function()),
+ "id" => Some(runtime::make_identity_function()),
+ B_INTEGER_INCREMENT => Some(Value::BuiltinFunction(BuiltinFunction::IntegerIncrement)),
+ B_INTEGER_DECREMENT => Some(Value::BuiltinFunction(BuiltinFunction::IntegerDecrement)),
+ B_INTEGER_ADD => Some(Value::BuiltinFunction(BuiltinFunction::IntegerAdd)),
+ B_INTEGER_MULTIPLY => Some(Value::BuiltinFunction(BuiltinFunction::IntegerMultiply)),
+ B_INTEGER_EQ => Some(Value::BuiltinFunction(BuiltinFunction::IntegerEq)),
+ _ => None,
+ }
+}
+
+pub fn apply_builtin(builtin: &BuiltinFunction, arg: &Value) -> Rc<Value> {
+ match builtin {
+ BuiltinFunction::IntegerIncrement => match arg {
+ Value::Integer(value) => Rc::new(Value::Integer(value + 1)),
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_INCREMENT
+ ),
+ },
+ BuiltinFunction::IntegerDecrement => match arg {
+ Value::Integer(value) => Rc::new(Value::Integer(value - 1)),
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_DECREMENT
+ ),
+ },
+ BuiltinFunction::IntegerAdd => match arg {
+ Value::Integer(value) => {
+ Rc::new(Value::BuiltinFunction(BuiltinFunction::IntegerAdd1(*value)))
+ }
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_ADD
+ ),
+ },
+ BuiltinFunction::IntegerAdd1(other) => match arg {
+ Value::Integer(value) => Rc::new(Value::Integer(other + value)),
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_ADD
+ ),
+ },
+ BuiltinFunction::IntegerMultiply => match arg {
+ Value::Integer(value) => Rc::new(Value::BuiltinFunction(
+ BuiltinFunction::IntegerMultiply1(*value),
+ )),
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_MULTIPLY
+ ),
+ },
+ BuiltinFunction::IntegerMultiply1(other) => match arg {
+ Value::Integer(value) => Rc::new(Value::Integer(other * value)),
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_MULTIPLY
+ ),
+ },
+ BuiltinFunction::IntegerEq => match arg {
+ Value::Integer(value) => {
+ Rc::new(Value::BuiltinFunction(BuiltinFunction::IntegerEq1(*value)))
+ }
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_EQ
+ ),
+ },
+ BuiltinFunction::IntegerEq1(other) => match arg {
+ Value::Integer(value) => Rc::new(if other == value {
+ runtime::make_boolean_true_function()
+ } else {
+ runtime::make_boolean_false_function()
+ }),
+ _ => panic!(
+ "[runtime] tried to apply non-integer value to {}",
+ B_INTEGER_EQ
+ ),
+ },
+ }
+}
diff --git a/src/grammar.pest b/src/grammar.pest
index 2b6cbfe..3db5519 100644
--- a/src/grammar.pest
+++ b/src/grammar.pest
@@ -2,7 +2,7 @@ COMMENT = _{ "#" ~ (!("#" | NEWLINE) ~ ANY)* ~ NEWLINE* }
WHITESPACE = _{ " " | "\t" | NEWLINE }
program = { SOI ~ statement+ ~ EOI }
statement = { (definition | expression) ~ ";"+ }
-definition = { symbol ~ "=" ~ expression }
+definition = { symbol+ ~ "=" ~ expression }
expression = { (symbol | integer_literal | string_literal | ("(" ~ expression ~ ")"))+ }
integer_literal = @{ "-"? ~ ASCII_DIGIT+ }
string_literal = { QUOTATION_MARK ~ (!QUOTATION_MARK ~ ANY)* ~ QUOTATION_MARK }
diff --git a/src/main.rs b/src/main.rs
index 98be9ea..59e91df 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,6 +4,7 @@ extern crate pest_derive;
extern crate pest;
mod ast;
+mod builtins;
mod lparser;
mod runtime;
diff --git a/src/runtime.rs b/src/runtime.rs
index 3a16567..9a5b4b4 100644
--- a/src/runtime.rs
+++ b/src/runtime.rs
@@ -1,22 +1,12 @@
use super::ast;
+use super::builtins;
+use super::builtins::BuiltinFunction;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug, Clone)]
-pub enum BuiltinFunction {
- IntegerIncrement,
- IntegerDecrement,
- IntegerAdd,
- IntegerAdd1(i64),
- IntegerMultiply,
- IntegerMultiply1(i64),
- IntegerEq,
- IntegerEq1(i64),
-}
-
-#[derive(Debug, Clone)]
pub enum Value {
Integer(i64),
String(String),
@@ -40,11 +30,6 @@ impl fmt::Display for Value {
}
static VAR_ID_INC: AtomicUsize = AtomicUsize::new(0);
-const B_INTEGER_INCREMENT: &str = "int.increment";
-const B_INTEGER_DECREMENT: &str = "int.decrement";
-const B_INTEGER_ADD: &str = "int.add";
-const B_INTEGER_MULTIPLY: &str = "int.multiply";
-const B_INTEGER_EQ: &str = "int.eq?";
fn advance_v() -> usize {
let v = VAR_ID_INC.load(Ordering::Relaxed);
@@ -52,33 +37,21 @@ fn advance_v() -> usize {
v
}
-fn make_boolean_true_function() -> Value {
+pub fn make_boolean_true_function() -> Value {
let x = advance_v();
let y = advance_v();
Value::Function(x, Rc::new(Value::Function(y, Rc::new(Value::Var(x)))))
}
-fn make_boolean_false_function() -> Value {
+pub fn make_boolean_false_function() -> Value {
let x = advance_v();
let y = advance_v();
Value::Function(x, Rc::new(Value::Function(y, Rc::new(Value::Var(y)))))
}
-fn try_builtin_symbol_to_value(symbol: &ast::Symbol) -> Option<Value> {
- match symbol.as_str() {
- "true" => Some(make_boolean_true_function()),
- "false" => Some(make_boolean_false_function()),
- "id" => {
- let v = advance_v();
- Some(Value::Function(v, Rc::new(Value::Var(v))))
- }
- B_INTEGER_INCREMENT => Some(Value::BuiltinFunction(BuiltinFunction::IntegerIncrement)),
- B_INTEGER_DECREMENT => Some(Value::BuiltinFunction(BuiltinFunction::IntegerDecrement)),
- B_INTEGER_ADD => Some(Value::BuiltinFunction(BuiltinFunction::IntegerAdd)),
- B_INTEGER_MULTIPLY => Some(Value::BuiltinFunction(BuiltinFunction::IntegerMultiply)),
- B_INTEGER_EQ => Some(Value::BuiltinFunction(BuiltinFunction::IntegerEq)),
- _ => None,
- }
+pub fn make_identity_function() -> Value {
+ let v = advance_v();
+ Value::Function(v, Rc::new(Value::Var(v)))
}
fn try_apply_function(func_rc: Rc<Value>, arg_rc: Rc<Value>, bound_v: Option<usize>) -> Rc<Value> {
@@ -103,74 +76,7 @@ fn try_apply_function(func_rc: Rc<Value>, arg_rc: Rc<Value>, bound_v: Option<usi
_ => Rc::clone(body_rc),
}
}
- Value::BuiltinFunction(builtin) => match builtin {
- BuiltinFunction::IntegerIncrement => match arg {
- Value::Integer(value) => Rc::new(Value::Integer(value + 1)),
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_INCREMENT
- ),
- },
- BuiltinFunction::IntegerDecrement => match arg {
- Value::Integer(value) => Rc::new(Value::Integer(value - 1)),
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_DECREMENT
- ),
- },
- BuiltinFunction::IntegerAdd => match arg {
- Value::Integer(value) => {
- Rc::new(Value::BuiltinFunction(BuiltinFunction::IntegerAdd1(*value)))
- }
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_ADD
- ),
- },
- BuiltinFunction::IntegerAdd1(other) => match arg {
- Value::Integer(value) => Rc::new(Value::Integer(other + value)),
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_ADD
- ),
- },
- BuiltinFunction::IntegerMultiply => match arg {
- Value::Integer(value) => Rc::new(Value::BuiltinFunction(
- BuiltinFunction::IntegerMultiply1(*value),
- )),
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_MULTIPLY
- ),
- },
- BuiltinFunction::IntegerMultiply1(other) => match arg {
- Value::Integer(value) => Rc::new(Value::Integer(other * value)),
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_MULTIPLY
- ),
- },
- BuiltinFunction::IntegerEq => match arg {
- Value::Integer(value) => {
- Rc::new(Value::BuiltinFunction(BuiltinFunction::IntegerEq1(*value)))
- }
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_EQ
- ),
- },
- BuiltinFunction::IntegerEq1(other) => match arg {
- Value::Integer(value) => Rc::new(if other == value {
- make_boolean_true_function()
- } else {
- make_boolean_false_function()
- }),
- _ => panic!(
- "[runtime] tried to apply non-integer value to {}",
- B_INTEGER_EQ
- ),
- },
- },
+ Value::BuiltinFunction(builtin) => builtins::apply_builtin(builtin, arg),
_ => func_rc,
}
}
@@ -183,7 +89,7 @@ fn evaluate_expr_inner_unary(
ast::ExpressionInner::IntegerLiteral(value) => Rc::new(Value::Integer(*value)),
ast::ExpressionInner::StringLiteral(value) => Rc::new(Value::String(value.clone())),
ast::ExpressionInner::Symbol(value) => {
- let builtin_value = try_builtin_symbol_to_value(value);
+ let builtin_value = builtins::try_builtin_symbol_to_value(value);
if builtin_value.is_some() {
return Rc::new(builtin_value.unwrap());
}
@@ -219,7 +125,7 @@ fn evaluate_expr_inner_binary(
ast::ExpressionInner::Symbol(value) => {
let lhs_value_rc: Rc<Value>;
- if let Some(builtin) = try_builtin_symbol_to_value(value) {
+ if let Some(builtin) = builtins::try_builtin_symbol_to_value(value) {
lhs_value_rc = Rc::new(builtin);
} else if let Some(lookup) = symbol_table.get(value) {
lhs_value_rc = Rc::clone(lookup);
@@ -254,7 +160,11 @@ pub fn evaluate(program: &ast::Program) {
for statement in program {
match statement {
- ast::Statement::Definition { symbol, expression } => {
+ ast::Statement::Definition {
+ symbol,
+ parameters,
+ expression,
+ } => {
println!("[runtime] defining symbol: {:#?}", symbol);
let value = evaluate_expr(&symbol_table, expression);
symbol_table.insert(symbol.clone(), value);