Numbers are now supported, though not in the best way possible. The only two built...
authorimode <immediate.mode@gmail.com>
Tue, 13 Nov 2018 18:11:41 +0000 (10:11 -0800)
committerimode <immediate.mode@gmail.com>
Tue, 13 Nov 2018 18:11:41 +0000 (10:11 -0800)
modal.py
prelude.modal

index 70a158b..34092a6 100644 (file)
--- a/modal.py
+++ b/modal.py
@@ -82,14 +82,14 @@ def construct(pattern, context):
 def apply(queue, rules, pattern, replacement):
     context = match(pattern, queue);
     if context == None:
-        return queue;
+        return (False, roll(queue));
     pattern = construct(pattern, context);
     if not pattern:
-        return queue;
+        return (False, roll(queue));
     replacement = construct(replacement, context);
     if not replacement:
-        return dequeue(queue, len(pattern));
-    return enqueue(dequeue(queue, len(pattern)), replacement);
+        return (False, roll(queue));
+    return (True, enqueue(dequeue(queue, len(pattern)), replacement));
 
 def define(queue, rules, pattern):
     context = match(pattern, queue);
@@ -101,8 +101,8 @@ def define(queue, rules, pattern):
         if len(right) > 1:
             right = right[1:][:-1];
         rules.append((left, apply, [right]));
-        return dequeue(queue, len(construct(pattern, context)));
-    return queue;
+        return (True, dequeue(queue, len(construct(pattern, context))));
+    return (False, roll(queue));
 
 def undefine(queue, rules, pattern):
     context = match(pattern, queue);
@@ -114,8 +114,30 @@ def undefine(queue, rules, pattern):
             candidate , _, _ = rule;
             if candidate == left:
                 del rules[index];
-        return dequeue(queue, len(construct(pattern, context)));
-    return queue;
+        return (True, dequeue(queue, len(construct(pattern, context))));
+    return (False, roll(queue));
+
+def add(queue, rules, pattern):
+    context = match(pattern, queue);
+    left    = context["left"];
+    right   = context["right"];
+    if left and right and len(left) == 1 and len(right) == 1:
+        if left[0][0] == "NUM" and right[0][0] == "NUM":
+            queue = dequeue(queue, len(construct(pattern, context)));
+            queue = enqueue(queue, parse(str(left[0][1] + right[0][1])));
+            return (True, queue);
+    return (False, roll(queue));
+
+def subtract(queue, rules, pattern):
+    context = match(pattern, queue);
+    left    = context["left"];
+    right   = context["right"];
+    if left and right and len(left) == 1 and len(right) == 1:
+        if left[0][0] == "NUM" and right[0][0] == "NUM":
+            queue = dequeue(queue, len(construct(pattern, context)));
+            queue = enqueue(queue, parse(str(left[0][1] - right[0][1])));
+            return (True, queue);
+    return (False, roll(queue));
 
 def applicable(rules, queue):
     results = [];
@@ -135,12 +157,21 @@ def reconstruct(pattern):
             yield '(';
         elif element[0] == "DEC":
             yield ')';
+        elif element[0] == "NUM":
+            yield str(element[1]);
         elif element[0] == "LIT":
             yield element[1];
         elif element[0] == "VAR":
             yield '?' + element[1];
         yield ' ';
 
+def number(string):
+    try:
+        result = int(string);
+        return True;
+    except:
+        return False;
+
 def literal(string, index=0):
     token = "";
     while index != len(string):
@@ -166,13 +197,9 @@ def parse(string, index=0):
             token, index = literal(string, index);
             if character == '?':
                 results.append(["VAR", token]);
-            elif character == '~' and token.isdigit():
-                for _ in range(0, int(token)):
-                    results.append(["LIT", 's']);
-                    results.append(["INC"]);
-                results.append(["LIT", '0']);
-                for _ in range(0, int(token)):
-                    results.append(["DEC"]);
+            elif number(token):
+                results.append(["LIT", "num"]);
+                results.append(["NUM", int(token)]);
             else:
                 results.append(["LIT", token]);
     return results;
@@ -188,8 +215,9 @@ def run(rules, queue, limit=pow(2, 16)):
             failures = failures + 1;
         else:
             pattern, operation, parameters = rule;
-            queue = operation(queue, rules, pattern, *parameters);
-            failures = 0;
+            result, queue = operation(queue, rules, pattern, *parameters);
+            if result == True:
+                failures = 0;
         steps = steps + 1;
     if steps == limit:
         print("Execution limit reached.");
@@ -227,8 +255,10 @@ def help():
 
 def main():
     defaults = [
-                   (parse("define ?left ?right"), define,   []),
-                   (parse("undefine ?left"),      undefine, [])
+                   (parse("define ?left ?right"),               define,   []),
+                   (parse("undefine ?left"),                    undefine, []),
+                   (parse("add (num ?left) (num ?right)"),      add,      []),
+                   (parse("subtract (num ?left) (num ?right)"), subtract, [])
                ];
     rules = defaults;
     if len(sys.argv) >= 2:
index 5452f5c..b0a6a4f 100644 (file)
@@ -1,12 +1,18 @@
-define (?x -> ?y)  (define ?x ?y)
+Let's give ourselves some sugar.
 define (def ?x ?y) (define ?x ?y)
 
-Now, anything can be a comment! And it'll be ignored.
-Provided you don't use any keywords.
+Even more sugar.
+def (?x -> ?y)  (def ?x ?y)
 
-(add (s ?x) (s ?y)) -> (s (add ?x (s ?y)))
-(add (0)    (s ?x)) -> (s ?x)
-(add (s ?x) (0))    -> (s ?x)
-(add (0)    (0))    -> (0)
+Maybe some Prolog?
+(assert ?x ?y) -> (?y -> ?x)
+(retract ?x)   -> (undefine ?x)
+(fact ?x)      -> (?x -> true)
 
-(?x + ?y) -> (add ?x ?y)
+Looking good.
+fact (man socrates)
+
+Looking really good.
+assert (man ?x) (mortal ?x)
+
+Now you can query for `mortal socrates` and get back `true`.