about summary refs log tree commit diff stats
path: root/mu.arc.t
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2014-11-01 15:06:24 -0700
committerKartik K. Agaram <vc@akkartik.com>2014-11-01 15:06:31 -0700
commiteee42c94115b6aca4b4078b7efc99d313cc097f1 (patch)
treec439a58ee2edfe90a193e2440d6c63961bdd56fd /mu.arc.t
parent47aa28545e88acf5f3c74c8cacfc5f1afdf166cd (diff)
downloadmu-eee42c94115b6aca4b4078b7efc99d313cc097f1.tar.gz
210 - go over mu.arc.t narrative
Diffstat (limited to 'mu.arc.t')
-rw-r--r--mu.arc.t103
1 files changed, 66 insertions, 37 deletions
diff --git a/mu.arc.t b/mu.arc.t
index 02fe908b..499537b3 100644
--- a/mu.arc.t
+++ b/mu.arc.t
@@ -138,6 +138,9 @@
 ; aren't provided. Instead of a monolithic compiler I want to build simple,
 ; lightweight tools that can be combined in various ways, say for using
 ; different typecheckers in different subsystems.
+;
+; In our tests we'll define such mu functions using a call to 'add-fns', so
+; look for it. Everything outside 'add-fns' is just test-harness details.
 
 (reset)
 (new-trace "literal")
@@ -1284,6 +1287,9 @@
   (prn "F - convert-names never renames nil"))
 
 ; A rudimentary memory allocator. Eventually we want to write this in mu.
+;
+; No deallocation yet; let's see how much code we can build in mu before we
+; feel the need for it.
 
 (reset)
 (new-trace "new-primitive")
@@ -1328,14 +1334,14 @@
 ; Even though our memory locations can now have names, the names are all
 ; globals, accessible from any function. To isolate functions from their
 ; callers we need local variables, and mu provides them using a special
-; variable called 'default-scope'. When you initialize such a variable (likely
+; variable called default-scope. When you initialize such a variable (likely
 ; with a call to our just-defined memory allocator) mu interprets memory
 ; locations as offsets from its value. If default-scope is set to 1000, for
 ; example, reads and writes to memory location 1 will really go to 1001.
 ;
 ; 'default-scope' is itself hard-coded to be function-local; it's nil in a new
 ; function, and it's restored when functions return to their callers. But the
-; actual scope allocation is independent. So you can define closures or do
+; actual scope allocation is independent. So you can define closures, or do
 ; even more funky things like share locals between two coroutines.
 
 (reset)
@@ -1422,6 +1428,7 @@
 (if (~iso (convert-names
             '(((x integer) <- copy (4 literal))
               ((y integer) <- copy (2 literal))
+              ; unsafe in general; don't write random values to 'default-scope'
               ((default-scope integer) <- add (x integer) (y integer))))
           '(((1 integer) <- copy (4 literal))
             ((2 integer) <- copy (2 literal))
@@ -1453,22 +1460,24 @@
             ((default-scope integer) <- add (1 integer) (y integer global))))
   (prn "F - convert-names never renames global operands"))
 
-; using tagged-values you can define generic functions that run different code
-; based on the types of their args.
+; Putting it all together, here's how you define generic functions that run
+; different code based on the types of their args.
 
 (reset)
 (new-trace "dispatch-clause")
 ;? (set dump-trace*)
 (add-fns
   '((test1
-      ((4 tagged-value-address) <- arg)
+      ((default-scope scope-address) <- new (scope literal) (20 literal))
+      ((first-arg-box tagged-value-address) <- arg)
+      ; if given integers, add them
       { begin
-        ((5 integer) (6 boolean) <- maybe-coerce (4 tagged-value-address deref) (integer literal))
-        (break-unless (6 boolean))
-        ((7 tagged-value-address) <- arg)
-        ((8 integer) (9 boolean) <- maybe-coerce (7 tagged-value-address deref) (integer literal))
-        ((9 integer) <- add (5 integer) (8 integer))
-        (reply (9 integer))
+        ((first-arg integer) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (integer literal))
+        (break-unless (match? boolean))
+        ((second-arg-box tagged-value-address) <- arg)
+        ((second-arg integer) <- maybe-coerce (second-arg-box tagged-value-address deref) (integer literal))
+        ((result integer) <- add (first-arg integer) (second-arg integer))
+        (reply (result integer))
       }
       (reply (nil literal)))
     (main
@@ -1488,22 +1497,25 @@
 ;? (set dump-trace*)
 (add-fns
   '((test1
-      ((4 tagged-value-address) <- arg)
+      ((default-scope scope-address) <- new (scope literal) (20 literal))
+      ((first-arg-box tagged-value-address) <- arg)
+      ; if given integers, add them
       { begin
-        ((5 integer) (6 boolean) <- maybe-coerce (4 tagged-value-address deref) (integer literal))
-        (break-unless (6 boolean))
-        ((7 tagged-value-address) <- arg)
-        ((8 integer) (9 boolean) <- maybe-coerce (7 tagged-value-address deref) (integer literal))
-        ((9 integer) <- add (5 integer) (8 integer))
-        (reply (9 integer))
+        ((first-arg integer) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (integer literal))
+        (break-unless (match? boolean))
+        ((second-arg-box tagged-value-address) <- arg)
+        ((second-arg integer) <- maybe-coerce (second-arg-box tagged-value-address deref) (integer literal))
+        ((result integer) <- add (first-arg integer) (second-arg integer))
+        (reply (result integer))
       }
+      ; if given booleans, or them (it's a silly kind of generic function)
       { begin
-        ((5 boolean) (6 boolean) <- maybe-coerce (4 tagged-value-address deref) (boolean literal))
-        (break-unless (6 boolean))
-        ((7 tagged-value-address) <- arg)
-        ((8 boolean) (9 boolean) <- maybe-coerce (7 tagged-value-address deref) (boolean literal))
-        ((9 boolean) <- or (5 boolean) (8 boolean))
-        (reply (9 boolean))
+        ((first-arg boolean) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (boolean literal))
+        (break-unless (match? boolean))
+        ((second-arg-box tagged-value-address) <- arg)
+        ((second-arg boolean) <- maybe-coerce (second-arg-box tagged-value-address deref) (boolean literal))
+        ((result boolean) <- or (first-arg boolean) (second-arg boolean))
+        (reply (result integer))
       }
       (reply (nil literal)))
     (main
@@ -1523,22 +1535,25 @@
 (new-trace "dispatch-multiple-calls")
 (add-fns
   '((test1
-      ((4 tagged-value-address) <- arg)
+      ((default-scope scope-address) <- new (scope literal) (20 literal))
+      ((first-arg-box tagged-value-address) <- arg)
+      ; if given integers, add them
       { begin
-        ((5 integer) (6 boolean) <- maybe-coerce (4 tagged-value-address deref) (integer literal))
-        (break-unless (6 boolean))
-        ((7 tagged-value-address) <- arg)
-        ((8 integer) (9 boolean) <- maybe-coerce (7 tagged-value-address deref) (integer literal))
-        ((9 integer) <- add (5 integer) (8 integer))
-        (reply (9 integer))
+        ((first-arg integer) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (integer literal))
+        (break-unless (match? boolean))
+        ((second-arg-box tagged-value-address) <- arg)
+        ((second-arg integer) <- maybe-coerce (second-arg-box tagged-value-address deref) (integer literal))
+        ((result integer) <- add (first-arg integer) (second-arg integer))
+        (reply (result integer))
       }
+      ; if given booleans, or them (it's a silly kind of generic function)
       { begin
-        ((5 boolean) (6 boolean) <- maybe-coerce (4 tagged-value-address deref) (boolean literal))
-        (break-unless (6 boolean))
-        ((7 tagged-value-address) <- arg)
-        ((8 boolean) (9 boolean) <- maybe-coerce (7 tagged-value-address deref) (boolean literal))
-        ((9 boolean) <- or (5 boolean) (8 boolean))
-        (reply (9 boolean))
+        ((first-arg boolean) (match? boolean) <- maybe-coerce (first-arg-box tagged-value-address deref) (boolean literal))
+        (break-unless (match? boolean))
+        ((second-arg-box tagged-value-address) <- arg)
+        ((second-arg boolean) <- maybe-coerce (second-arg-box tagged-value-address deref) (boolean literal))
+        ((result boolean) <- or (first-arg boolean) (second-arg boolean))
+        (reply (result integer))
       }
       (reply (nil literal)))
     (main
@@ -1555,8 +1570,10 @@
 
 ; A rudimentary process scheduler. You can 'run' multiple functions at once,
 ; and they share the virtual processor.
+;
 ; There's also a 'fork' primitive to let functions create new threads of
 ; execution (we call them routines).
+;
 ; Eventually we want to allow callers to influence how much of their CPU they
 ; give to their 'children', or to rescind a child's running privileges.
 
@@ -1606,6 +1623,18 @@
   (if (no rep.last-routine!error)
     (prn "F - 'index' throws an error if out of bounds")))
 
+; Lightweight tools can also operate on quoted lists of statements surrounded
+; by square brackets. In the example below, we mimic Go's 'defer' keyword
+; using 'convert-quotes'. It lets us write code anywhere in a function, but
+; have it run just before the function exits. Great for keeping code to
+; reclaim memory or other resources close to the code to allocate it. (C++
+; programmers know this as RAII.) We'll use 'defer' when we build a memory
+; deallocation routine like C's 'free'.
+;
+; More powerful reorderings are also possible like in Literate Programming or
+; Aspect-Oriented Programming; one advantage of prohibiting arbitrarily nested
+; code is that we can naturally name 'join points' wherever we want.
+
 (reset)
 (new-trace "convert-quotes-defer")
 (if (~iso (convert-quotes