aboutsummaryrefslogtreecommitdiff
path: root/src/primitives/conditional.d
diff options
context:
space:
mode:
Diffstat (limited to 'src/primitives/conditional.d')
-rw-r--r--src/primitives/conditional.d77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/primitives/conditional.d b/src/primitives/conditional.d
new file mode 100644
index 0000000..ee89ea5
--- /dev/null
+++ b/src/primitives/conditional.d
@@ -0,0 +1,77 @@
+module src.primitives.conditional;
+
+import std.variant;
+import std.typecons;
+import std.container : DList;
+
+import src.stack;
+
+Nullable!(DList!Token) buffer;
+bool concluded = true;
+bool drop_mode = false;
+
+void capture(Token token) {
+ if ( !drop_mode ) {
+ buffer.insertBack(token);
+ }
+}
+
+bool drop(Token token) {
+ if ( concluded && buffer.isNull ) {
+ return false;
+ }
+
+ if ( token.type == typeid(string) ) {
+ switch ( *token.peek!string ) {
+ case "if" : eval_if; break;
+ case "then" : eval_then; break;
+ case "else" : eval_else; break;
+ default : capture(token); break;
+ }
+ } else {
+ capture(token);
+ }
+
+ return true;
+}
+
+void eval_if() {
+ if ( concluded ) {
+ buffer = DList!Token();
+ drop_mode = !stack.pop.get!bool;
+ concluded = false;
+ } else {
+ throw new Exception("conditionals may not be nested directly");
+ }
+}
+
+void eval_then() {
+ if ( concluded ) {
+ throw new Exception("`then` without preceding `if`");
+ } else {
+ drop_mode = !drop_mode;
+ }
+}
+
+void eval_else() {
+ if ( concluded ) {
+ throw new Exception("`else` without preceding `if`");
+ } else {
+ drop_mode = false;
+ concluded = true;
+ }
+}
+
+bool dischargeable() {
+ return concluded && !buffer.isNull;
+}
+
+Stack!Token discharge() {
+ if ( concluded ) {
+ Stack!Token result = buffer[];
+ buffer.nullify;
+ return result;
+ } else {
+ throw new Exception("unconcluded conditional may not be discharged");
+ }
+}