diff options
-rw-r--r-- | Readme.md | 95 | ||||
-rw-r--r-- | channel.mu | 48 | ||||
-rw-r--r-- | edit.arc.t | 2 | ||||
-rw-r--r-- | edit.mu | 24 | ||||
-rw-r--r-- | factorial.mu | 26 | ||||
-rw-r--r-- | fork.mu | 14 | ||||
-rw-r--r-- | generic.mu | 26 | ||||
-rw-r--r-- | tangle.mu | 26 | ||||
-rw-r--r-- | x.mu | 6 |
9 files changed, 146 insertions, 121 deletions
diff --git a/Readme.md b/Readme.md index 4b7a4a49..03cac815 100644 --- a/Readme.md +++ b/Readme.md @@ -71,46 +71,71 @@ As a sneak peek, here's how you compute factorial in mu: ```lisp function factorial [ - ; allocate some space for local variables - default-scope/scope-address <- new scope/literal, 30/literal + ; create some space for the variables below + default-scope:scope-address <- new scope:literal, 30:literal ; receive inputs in a queue - n/integer <- next-input + n:integer <- next-input { ; if n=0 return 1 - zero?/boolean <- equal n/integer, 0/literal - break-unless zero?/boolean - reply 1/literal + zero?:boolean <- equal n:integer, 0:literal + break-unless zero?:boolean + reply 1:literal } ; return n*factorial(n-1) - tmp1/integer <- subtract n/integer, 1/literal - tmp2/integer <- factorial tmp1/integer - result/integer <- multiply tmp2/integer, n/integer - reply result/integer + tmp1:integer <- subtract n:integer, 1:literal + tmp2:integer <- factorial tmp1:integer + result:integer <- multiply n:integer, tmp2:integer + reply result:integer ] ``` Programs are lists of instructions, each on a line, sometimes grouped with -brackets. Instructions take the form: +brackets. Each instruction operates on some *operands* and returns some *results*. ``` - oargs <- OP args + [results] <- instruction [operands] ``` -Input and output args have to be simple; no sub-expressions are permitted. But -you can have any number of them. In particular, instructions can return -multiple output arguments. For example, you can perform integer division as -follows: +Result and operand values have to be simple; you can't nest operations. But +you can have any number of values. In particular you can have any number of +results. For example, you can perform integer division as follows: ``` - quotient/integer, remainder/integer <- divide-with-remainder 11/literal, 3/literal + quotient:integer, remainder:integer <- divide-with-remainder 11:literal, 3:literal ``` -Each arg can have any number of bits of metadata like the types above, -separated by slashes. Anybody can write tools to statically analyze or verify -programs using new metadata. Or they can just be documentation; any metadata -the system doesn't recognize gets silently ignored. +Each value provides its data as well as its type separated by a colon. Types +can be multiple words, like: -Try this program out now: +```lisp + x:integer-array:3 ; x is an array of 3 integers + y:list:integer ; y is a list of integers +``` + +In addition you can store other properties in values, separated by slashes. + +```lisp + x:integer-array:3/uninitialized + y:string/tainted:yes + z:list:integer/assign-once:true/assigned:false +``` + +These properties don't mean anything to mu, and it'll silently skip them when +running, but they'll allow you to write *meta-programs* to check or modify +your programs, a task other languages typically hide from their programmers. +For example, where other programmers are restricted to the checks their type +system permits and forces them to use, you'll learn to create new checks that +make sense for your specific program. If it makes sense to perform different +checks in different parts of your program, you'll be able to do that. + +To summarize: instructions have multiple operand and result values, values can +have multiple rows separated by slashes, and rows can have multiple columns +separated by colons. Only the very first column of the first row in each +value's table is required to run mu programs, but the rest of the value +'table' helps *manage* them over time. Management over time is why programming +has traditionally been hard. + +Try out the factorial program now: ```shell $ ./mu factorial.mu @@ -118,8 +143,8 @@ Try this program out now: ... # ignore the memory dump for now ``` -(The code in `factorial.mu` looks different from the idealized syntax above. -We'll get to an actual parser in time.) +(The code in `factorial.mu` has a few more parentheses than the idealized +syntax above. We'll drop them when we build a real parser.) --- @@ -128,27 +153,27 @@ inserting code at them. ```lisp function factorial [ - default-scope/scope-address <- new scope/literal, 30/literal - n/integer <- next-input + default-scope:scope-address <- new scope:literal, 30:literal + n:integer <- next-operand { - base-case + base-case: } - recursive-case + recursive-case: ] after base-case [ ; if n=0 return 1 - zero?/boolean <- equal n/integer, 0/literal - break-unless zero?/boolean - reply 1/literal + zero?:boolean <- equal n:integer, 0:literal + break-unless zero?:boolean + reply 1:literal ] after recursive-case [ ; return n*factorial(n-1) - tmp1/integer <- subtract n/integer, 1/literal - tmp2/integer <- factorial tmp1/integer - result/integer <- multiply tmp2/integer, n/integer - reply result/integer + tmp1:integer <- subtract n:integer, 1:literal + tmp2:integer <- factorial tmp1:integer + result:integer <- multiply n:integer, tmp2:integer + reply result:integer ] ``` diff --git a/channel.mu b/channel.mu index fa6d89c3..0ee53774 100644 --- a/channel.mu +++ b/channel.mu @@ -1,48 +1,48 @@ (function producer [ ; produce numbers 1 to 5 on a channel - ((default-scope scope-address) <- new (scope literal) (30 literal)) - ((chan channel-address) <- next-input) + (default-scope:scope-address <- new scope:literal 30:literal) + (chan:channel-address <- next-input) ; n = 0 - ((n integer) <- copy (0 literal)) + (n:integer <- copy 0:literal) { begin - ((done? boolean) <- less-than (n integer) (5 literal)) - (break-unless (done? boolean)) + (done?:boolean <- less-than n:integer 5:literal) + (break-unless done?:boolean) ; other threads might get between these prints - (print-primitive ("produce: " literal)) - (print-primitive (n integer)) - (print-primitive ("\n" literal)) + (print-primitive (("produce: " literal))) + (print-primitive n:integer) + (print-primitive (("\n" literal))) ; 'box' n into a dynamically typed 'tagged value' because that's what ; channels take - ((n2 integer-address) <- new (integer literal)) - ((n2 integer-address deref) <- copy (n integer)) - ((n3 tagged-value-address) <- new-tagged-value (integer-address literal) (n2 integer-address)) - ((chan channel-address deref) <- write (chan channel-address) (n3 tagged-value-address deref)) - ((n integer) <- add (n integer) (1 literal)) + (n2:integer-address <- new integer:literal) + (n2:integer-address/deref <- copy n:integer) + (n3:tagged-value-address <- new-tagged-value integer-address:literal n2:integer-address) + (chan:channel-address/deref <- write chan:channel-address n3:tagged-value-address/deref) + (n:integer <- add n:integer 1:literal) (loop) } ]) (function consumer [ ; consume and print integers from a channel - ((default-scope scope-address) <- new (scope literal) (30 literal)) - ((chan channel-address) <- next-input) + (default-scope:scope-address <- new scope:literal 30:literal) + (chan:channel-address <- next-input) { begin ; read a tagged value from the channel - ((x tagged-value) (chan channel-address deref) <- read (chan channel-address)) + (x:tagged-value chan:channel-address/deref <- read chan:channel-address) ; unbox the tagged value into an integer - ((n2 integer-address) <- maybe-coerce (x tagged-value) (integer-address literal)) + (n2:integer-address <- maybe-coerce x:tagged-value integer-address:literal) ; other threads might get between these prints - (print-primitive ("consume: " literal)) - (print-primitive (n2 integer-address deref)) - (print-primitive ("\n" literal)) + (print-primitive (("consume: " literal))) + (print-primitive n2:integer-address/deref) + (print-primitive (("\n" literal))) (loop) } ]) (function main [ - ((chan channel-address) <- new-channel (3 literal)) + (chan:channel-address <- new-channel 3:literal) ; create two background 'routines' that communicate by a channel - (fork (consumer fn) (chan channel-address)) - (fork (producer fn) (chan channel-address)) - (sleep (2000 literal)) ; wait for forked routines to effect the transfer + (fork consumer:fn chan:channel-address) + (fork producer:fn chan:channel-address) + (sleep 2000:literal) ; wait for forked routines to effect the transfer ]) diff --git a/edit.arc.t b/edit.arc.t index 8f2a6643..7a9d4f20 100644 --- a/edit.arc.t +++ b/edit.arc.t @@ -7,7 +7,7 @@ (add-code:readfile "edit.mu") (add-code '((function test-new-screen [ - ((1 screen-address global) <- new-screen (5 literal) (5 literal)) + (1:screen-address/global <- new-screen 5:literal 5:literal) ]))) ;? (each stmt function*!new-screen ;? (prn stmt)) diff --git a/edit.mu b/edit.mu index d4937c60..706d5de4 100644 --- a/edit.mu +++ b/edit.mu @@ -1,18 +1,18 @@ ; a screen is an array of pointers to lines, in turn arrays of characters (function new-screen [ - ((default-scope scope-address) <- new (scope literal) (30 literal)) - ((nrows integer) <- next-input) - ((ncols integer) <- next-input) - ((result screen-address) <- new (screen literal) (nrows integer)) - ((rowidx integer) <- copy (0 literal)) + (default-scope:scope-address <- new scope:literal 30:literal) + (nrows:integer <- next-input) + (ncols:integer <- next-input) + (result:screen-address <- new screen:literal nrows:integer) + (rowidx:integer <- copy 0:literal) { begin - ((curr-line-address-address line-address-address) <- index-address (result screen-address deref) (rowidx integer)) - ((curr-line-address-address line-address-address deref) <- new (line literal) (ncols integer)) - ((curr-line-address line-address) <- copy (curr-line-address-address line-address-address deref)) - ((rowidx integer) <- add (rowidx integer) (1 literal)) - ((x boolean) <- not-equal (rowidx integer) (nrows integer)) - (loop-if (x boolean)) + (curr-line-address-address:line-address-address <- index-address result:screen-address/deref rowidx:integer) + (curr-line-address-address:line-address-address/deref <- new line:literal ncols:integer) + (curr-line-address:line-address <- copy curr-line-address-address:line-address-address/deref) + (rowidx:integer <- add rowidx:integer 1:literal) + (x:boolean <- not-equal rowidx:integer nrows:integer) + (loop-if x:boolean) } - (reply (result screen-address)) + (reply result:screen-address) ]) diff --git a/factorial.mu b/factorial.mu index 707e04f9..580b30d4 100644 --- a/factorial.mu +++ b/factorial.mu @@ -1,22 +1,22 @@ (function factorial [ - ((default-scope scope-address) <- new (scope literal) (30 literal)) - ((n integer) <- next-input) + (default-scope:scope-address <- new scope:literal 30:literal) + (n:integer <- next-input) { begin ; if n=0 return 1 - ((zero? boolean) <- equal (n integer) (0 literal)) - (break-unless (zero? boolean)) - (reply (1 literal)) + (zero?:boolean <- equal n:integer 0:literal) + (break-unless zero?:boolean) + (reply 1:literal) } ; return n*factorial(n-1) - ((x integer) <- subtract (n integer) (1 literal)) - ((subresult integer) <- factorial (x integer)) - ((result integer) <- multiply (subresult integer) (n integer)) - (reply (result integer)) + (x:integer <- subtract n:integer 1:literal) + (subresult:integer <- factorial x:integer) + (result:integer <- multiply subresult:integer n:integer) + (reply result:integer) ]) (function main [ - ((1 integer) <- factorial (5 literal)) - (print-primitive ("result: " literal)) - (print-primitive (1 integer)) - (print-primitive ("\n" literal)) + (1:integer <- factorial 5:literal) + (print-primitive (("result: " literal))) + (print-primitive 1:integer) + (print-primitive (("\n" literal))) ]) diff --git a/fork.mu b/fork.mu index 3a4c1437..1cf7aa71 100644 --- a/fork.mu +++ b/fork.mu @@ -1,18 +1,18 @@ (function main [ - (fork (thread2 fn)) - ((default-scope scope-address) <- new (scope literal) (2 literal)) - ((x integer) <- copy (34 literal)) + (fork thread2:fn) + (default-scope:scope-address <- new scope:literal 2:literal) + (x:integer <- copy 34:literal) { begin - (print-primitive (x integer)) + (print-primitive x:integer) (loop) } ]) (function thread2 [ - ((default-scope scope-address) <- new (scope literal) (2 literal)) - ((y integer) <- copy (35 literal)) + (default-scope:scope-address <- new scope:literal 2:literal) + (y:integer <- copy 35:literal) { begin - (print-primitive (y integer)) + (print-primitive y:integer) (loop) } ]) diff --git a/generic.mu b/generic.mu index 351d4552..2a487a96 100644 --- a/generic.mu +++ b/generic.mu @@ -3,27 +3,27 @@ ; factorial n = n*factorial(n-1) (function factorial [ - ((default-scope scope-address) <- new (scope literal) (30 literal)) - ((n integer) <- input (0 literal)) + (default-scope:scope-address <- new scope:literal 30:literal) + (n:integer <- input 0:literal) more-clauses - ((x integer) <- subtract (n integer) (1 literal)) - ((subresult integer) <- factorial (x integer)) - ((result integer) <- multiply (subresult integer) (n integer)) - (reply (result integer)) + (x:integer <- subtract n:integer 1:literal) + (subresult:integer <- factorial x:integer) + (result:integer <- multiply subresult:integer n:integer) + (reply result:integer) ]) ; factorial 0 = 1 (after factorial/more-clauses [ { begin - ((zero? boolean) <- equal (n integer) (0 literal)) - (break-unless (zero? boolean)) - (reply (1 literal)) + (zero?:boolean <- equal n:integer 0:literal) + (break-unless zero?:boolean) + (reply 1:literal) } ]) (function main [ - ((1 integer) <- factorial (5 literal)) - (print-primitive ("result: " literal)) - (print-primitive (1 integer)) - (print-primitive ("\n" literal)) + (1:integer <- factorial 5:literal) + (print-primitive (("result: " literal))) + (print-primitive 1:integer) + (print-primitive (("\n" literal))) ]) diff --git a/tangle.mu b/tangle.mu index 0a7bc05e..7580c328 100644 --- a/tangle.mu +++ b/tangle.mu @@ -4,8 +4,8 @@ ; possibilities. (function factorial [ - ((default-scope scope-address) <- new (scope literal) (30 literal)) - ((n integer) <- next-input) + (default-scope:scope-address <- new scope:literal 30:literal) + (n:integer <- next-input) { begin base-case } @@ -14,22 +14,22 @@ (after base-case [ ; if n=0 return 1 - ((zero? boolean) <- equal (n integer) (0 literal)) - (break-unless (zero? boolean)) - (reply (1 literal)) + (zero?:boolean <- equal n:integer 0:literal) + (break-unless zero?:boolean) + (reply 1:literal) ]) (after recursive-case [ ; return n*factorial(n-1) - ((x integer) <- subtract (n integer) (1 literal)) - ((subresult integer) <- factorial (x integer)) - ((result integer) <- multiply (subresult integer) (n integer)) - (reply (result integer)) + (x:integer <- subtract n:integer 1:literal) + (subresult:integer <- factorial x:integer) + (result:integer <- multiply subresult:integer n:integer) + (reply result:integer) ]) (function main [ - ((1 integer) <- factorial (5 literal)) - (print-primitive ("result: " literal)) - (print-primitive (1 integer)) - (print-primitive ("\n" literal)) + (1:integer <- factorial 5:literal) + (print-primitive (("result: " literal))) + (print-primitive 1:integer) + (print-primitive (("\n" literal))) ]) diff --git a/x.mu b/x.mu index dac4fe1c..873d380f 100644 --- a/x.mu +++ b/x.mu @@ -1,5 +1,5 @@ (function main [ - ((x integer) <- copy (1 literal)) - ((y integer) <- copy (3 literal)) - ((z integer) <- add (x integer) (y integer)) + (x:integer <- copy 1:literal) + (y:integer <- copy 3:literal) + (z:integer <- add x:integer y:integer) ]) |