Added some partial comments to the interpreter, fixed handling numbers in 'display...
authorimode <immediate.mode@gmail.com>
Sat, 2 Mar 2019 02:22:24 +0000 (18:22 -0800)
committerimode <immediate.mode@gmail.com>
Sat, 2 Mar 2019 02:22:24 +0000 (18:22 -0800)
modal.py
prelude.modal

index 2871dcd..493d042 100644 (file)
--- a/modal.py
+++ b/modal.py
@@ -1,5 +1,21 @@
+"""
+   *------------------------------------------------------------*
+   |modal.py : An Implementation of Modal in Python             |
+   |                                                            |
+   |This is an implementation of Modal, a programming language  |
+   |based on term rewriting. This particular implementation     |
+   |is based on the idea of cyclic delimited string rewriting   |
+   |using a central queue and a dictionary of variable bindings.|
+   |                                                            |
+   |© 2019 imode, Immediate Mode Technologies                   |
+   *------------------------------------------------------------*
+"""
+
+# `sys`  for I/O and arguments.
+# `time` for measuring the runtime of the interpreter.
 import sys, time;
 
+# A decorator intended for measuring the runtime of a given function.
 def measure(function):
     def measurement(*arguments):
         start        = time.time();
@@ -10,14 +26,17 @@ def measure(function):
         return result;
     return measurement;
 
+# Enqueue an item by appending it to the queue.
 def enqueue(queue, item):
     return queue + item;
 
+# Dequeue an item by slicing the queue. The last item is the head.
 def dequeue(queue, length=1):
     if length > len(queue):
         return queue;
     return queue[length:];
 
+# Get the item(s) at the head of the queue.
 def peek(queue, length=1):
     if length > len(queue):
         return None;
@@ -25,11 +44,14 @@ def peek(queue, length=1):
         return queue[0];
     return queue[:length];
 
+# Roll/cycle the queue by a certain amount by slicing.
+# This dequeues and enqueues a number of items, "cycling" the queue.
 def roll(queue, length=1):
     if length > len(queue):
         return queue;
     return queue[length:] + queue[:length];
 
+# Seek to a certain position in the queue by repeatedly rolling it.
 def seek(queue, pattern):
     if pattern not in queue:
         return queue;
@@ -37,6 +59,7 @@ def seek(queue, pattern):
         queue = roll(queue);
     return queue;
 
+# Extract a delimited fragment (subtree) from the queue.
 def extract(queue):
     results = [];
     depth = 0;
@@ -54,6 +77,7 @@ def extract(queue):
             return results;
     return results;
 
+# Generate a list of variable bindings from the current queue and a pattern.
 def match(pattern, queue, context=None):
     if context == None:
         context = {};
@@ -78,6 +102,7 @@ def match(pattern, queue, context=None):
             queue = dequeue(queue);
     return context;
 
+# Fill in a pattern with variables in it using a list of variable bindings.
 def construct(pattern, context):
     results = [];
     for element in pattern:
@@ -91,6 +116,7 @@ def construct(pattern, context):
             results.append(element);
     return results;
 
+# Apply a pattern/replacement rule to the queue.
 def apply(queue, rules, pattern, replacement):
     context = match(pattern, queue);
     if context == None:
@@ -133,7 +159,7 @@ 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 and right:
         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])));
@@ -144,7 +170,7 @@ 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 and right:
         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])));
@@ -155,7 +181,7 @@ def multiply(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 and right:
         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])));
@@ -300,6 +326,7 @@ def main():
                    (parse("add (num ?left) (num ?right)"),      add,      []),
                    (parse("subtract (num ?left) (num ?right)"), subtract, []),
                    (parse("multiply (num ?left) (num ?right)"), multiply, []),
+                   (parse("display (num ?left)"),               display,  []),
                    (parse("display (?left)"),                   display,  [])
                ];
     rules = defaults;
index d2ac420..5e2e66b 100644 (file)
@@ -1,27 +1,35 @@
-define (def ?x ?y) (define ?x ?y);
-define (?x -> ?y) (def ?x ?y);
+define (def ?x ?y)    (define ?x ?y);
+define (?x -> ?y)     (def ?x ?y);
+define (assert ?x ?y) (?y -> ?x);
+define (fact ?x)      (?x -> true);
+define (?x ::> ?y)    (assert ?x ?y);
+define (:: ?x)        (fact ?x);
+define (?x + ?y)      (add ?x ?y);
+define (?x - ?y)      (subtract ?x ?y);
+define (?x * ?y)      (multiply ?x ?y);
 
-def (?x + ?y) (add ?x ?y);
-def (?x - ?y) (subtract ?x ?y);
-def (?x * ?y) (multiply ?x ?y);
+define (if      (true)  ?branch)      (?branch);
+define (if      (false) ?branch)      ();
+define (if/else (true)  ?true ?false) (?true);
+define (if/else (false) ?true ?false) (?false);
 
-(factorial (1))      -> (1);
-(factorial (num ?x)) -> ((num ?x) * (factorial ((num ?x) - (1))));
+define ((true)  and (true))  (true);
+define ((true)  and (false)) (false);
+define ((false) and (true))  (false);
+define ((false) and (false)) (false);
 
-(length (nil))        -> (0);
-(length (?h : (nil))) -> (1);
-(length (?h : ?t))    -> ((1) + (length ?t)));
+define ((true)  or (true))  (true);
+define ((true)  or (false)) (true);
+define ((false) or (true))  (true);
+define ((false) or (false)) (false);
 
-(contains ?x (nil))     -> (false);
-(contains ?x (?x : ?t)) -> (true);
-(contains ?x (?h : ?t)) -> (contains ?x ?t);
+define (not (true))  (false);
+define (not (false)) (true);
 
-(fold (?f) ?i (nil))       -> (?i);
-(fold (?f) ?i (?h : (nil))) -> (?f ?h ?i);
-(fold (?f) ?i (?h : ?t))   -> (?f ?h fold (?f) ?i ?t);
+(man ?x) ::> (mortal ?x);
+         ::  (man socrates);
 
-(prepend ?x (nil))     -> (?x : (nil));
-(prepend ?x (?h : ?t)) -> (?x : (?h : ?t));
+define (factorial (1)) (1);
+define (factorial (num ?x)) ((num ?x) * (factorial ((num ?x) - (1))));
 
-((K ?x) ?y)      -> (?x);
-(((S ?x) ?y) ?z) -> ((?x ?z) (?y ?z));
+display (factorial (5));