aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbnewbold <bnewbold@robocracy.org>2016-04-25 16:13:03 -0400
committerbnewbold <bnewbold@robocracy.org>2016-04-25 16:13:03 -0400
commitcc1b67c459c400d0865498ed00ddd4c09c4497b7 (patch)
tree5d8af606620df702c0a57e29cc57ab9d4c43efff
parent39aaba04246dae4ce5f6a2a2489294261582adf7 (diff)
downloadspectrum-cc1b67c459c400d0865498ed00ddd4c09c4497b7.zip
spectrum-cc1b67c459c400d0865498ed00ddd4c09c4497b7.tar.gz
rust: refactor apply_action to accomodate define and set!
-rw-r--r--TODO3
-rw-r--r--rust/spectrum.rs84
2 files changed, 62 insertions, 25 deletions
diff --git a/TODO b/TODO
index 79888da..644128b 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,6 @@
- rust:
- - my own refactorings and comments
- - symbols separate from identifiers
- define/set! support (at the REPL?)
+ - refactor out lifetime specifiers
- add file input support (eg, comments in parser, multi-line, tty detect)
- multi-part lambdas
- begin (?)
diff --git a/rust/spectrum.rs b/rust/spectrum.rs
index be0d6d7..2c88ae3 100644
--- a/rust/spectrum.rs
+++ b/rust/spectrum.rs
@@ -383,7 +383,48 @@ fn apply_action<'a, 'b>(list: &Vec<SchemeExpr>,
return Ok(SchemeExpr::SchemeNull);
}
let action = &list[0];
- // TODO: make this a single line?
+ let mut procedure = SchemeExpr::SchemeNull;
+
+ /*
+ * First pass:
+ * - execute special case built-ins (eg, those which take non-symbol identifiers as args)
+ * - lambdas and identifiers which need to be expanded
+ */
+ match action {
+ &SchemeExpr::SchemeBuiltin(ref builtin) => {
+ match builtin.as_str() {
+ "define" | "set!" => {
+ if list.len() != 3 {
+ return Err(format!("define takes two arguments (lambda syntax not supported)"));
+ }
+ match &list[1] {
+ &SchemeExpr::SchemeIdentifier(ref sym) => {
+ if builtin == "set!" && !env.contains_key(sym) {
+ return Err(format!("tried to `set!` an undefined identifier: {}", sym));
+ }
+ let val = try!(scheme_meaning(&list[2], ctx.clone(), env));
+ env.insert(sym.clone(), val);
+ return Ok(SchemeExpr::SchemeNull);
+ },
+ _ => { return Err(format!("define requires an identifier")); },
+ }
+ },
+ _ => (), // fall through to second pass
+ }
+ },
+ &SchemeExpr::SchemeProcedure(_, _, _) => (), // fall through to second pass
+ _ => {
+ // expand, eg, lambdas and non-builtin identifiers in the head position of the apply
+ procedure = try!(scheme_meaning(action, ctx.clone(), env));
+ },
+ }
+
+ let action = if procedure != SchemeExpr::SchemeNull { &procedure } else { action };
+
+ // Second pass:
+ // - evaluate all arguments
+ // - dispatch to builtin handlers or procedure handler
+ // TODO: make this arg meaning .map() a single line?
let arg_meanings: Result<Vec<_>, _> = list.iter().skip(1).map(|x| scheme_meaning(x, ctx.clone(), env)).collect();
let args: Vec<SchemeExpr> = try!(arg_meanings);
match action {
@@ -437,28 +478,25 @@ fn apply_action<'a, 'b>(list: &Vec<SchemeExpr>,
}
},
_ => Err(format!("unimplemented builtin: {}", builtin)),
- }; },
- &SchemeExpr::SchemeList(_) => {
- let procedure: SchemeExpr = try!(scheme_meaning(&action, ctx.clone(), env));
- match procedure {
- SchemeExpr::SchemeProcedure(binds, body, proc_ctx) => {
- // This block of code implements procedure (lambda) application
- if body.len() != 1 {
- return Err(format!("prodedure must have single-expression body"));
- }
- if binds.len() != args.len() {
- return Err(format!("wrong number of args to procedure"));
- }
- let mut closure = proc_ctx.clone();
- for (name, arg) in binds.iter().zip(args) {
- closure.insert(name.clone(), arg.clone());
- }
- return scheme_meaning(&body[0], closure, env);
- },
- _ => { return Err(format!("non-procedure at head of expression: {}",
- scheme_repr(&procedure).unwrap())); },
- } },
- _ => { return Err(format!("apply called with something non-applicable")); },
+ };
+ },
+ &SchemeExpr::SchemeProcedure(ref binds, ref body, ref proc_ctx) => {
+ // This block of code implements procedure (lambda) application
+ if body.len() != 1 {
+ return Err(format!("prodedure must have single-expression body"));
+ }
+ if binds.len() != args.len() {
+ return Err(format!("wrong number of args to procedure"));
+ }
+ let mut closure = proc_ctx.clone();
+ for (name, arg) in binds.iter().zip(args) {
+ closure.insert(name.clone(), arg.clone());
+ }
+ return scheme_meaning(&body[0], closure, env);
+ },
+ _ => { return Err(format!("non-procedure at head of expression: {}",
+ scheme_repr(&action).unwrap()));
+ },
}
}