From 4de96970f192bc2226250e52d1366e985db90ab5 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Sun, 18 Sep 2016 09:06:34 -0700 Subject: 3400 Undo commit 3340. Let's standardize names of non-core files to only have dashes. That's also consistent with the edit/ and sandbox/ apps. Mu programmers will tend to pervasively use dashes, just like Lisp programmers. Scripts will continue to use underscores.. --- exuberant-ctags-rc | 10 - exuberant_ctags_rc | 10 + immutable-error.mu | 13 ++ immutable_error.mu | 13 -- lambda-to-mu.mu | 584 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lambda_to_mu.mu | 584 ----------------------------------------------------- real-files.mu | 18 ++ real_files.mu | 18 -- static-dispatch.mu | 21 ++ static_dispatch.mu | 21 -- 10 files changed, 646 insertions(+), 646 deletions(-) delete mode 100644 exuberant-ctags-rc create mode 100644 exuberant_ctags_rc create mode 100644 immutable-error.mu delete mode 100644 immutable_error.mu create mode 100644 lambda-to-mu.mu delete mode 100644 lambda_to_mu.mu create mode 100644 real-files.mu delete mode 100644 real_files.mu create mode 100644 static-dispatch.mu delete mode 100644 static_dispatch.mu diff --git a/exuberant-ctags-rc b/exuberant-ctags-rc deleted file mode 100644 index 120d339e..00000000 --- a/exuberant-ctags-rc +++ /dev/null @@ -1,10 +0,0 @@ ---langdef=mu ---langmap=mu:.mu ---regex-mu=/^def[ \t]+([^ \t]*)/\1/d,definition/ ---regex-mu=/^def![ \t]+([^ \t]*)/\1/d,definition/ ---regex-mu=/^recipe[ \t]+([^ \t]*)/\1/d,definition/ ---regex-mu=/^recipe![ \t]+([^ \t]*)/\1/d,definition/ ---regex-mu=/^before[ \t]+([^ \t]*)/\1/d,definition/ ---regex-mu=/^after[ \t]+([^ \t]*)/\1/d,definition/ ---regex-mu=/^container[ \t]+([^ \t]*)/\1/s,struct/ ---regex-mu=/^exclusive-container[ \t]+([^ \t]*)/\1/u,union/ diff --git a/exuberant_ctags_rc b/exuberant_ctags_rc new file mode 100644 index 00000000..120d339e --- /dev/null +++ b/exuberant_ctags_rc @@ -0,0 +1,10 @@ +--langdef=mu +--langmap=mu:.mu +--regex-mu=/^def[ \t]+([^ \t]*)/\1/d,definition/ +--regex-mu=/^def![ \t]+([^ \t]*)/\1/d,definition/ +--regex-mu=/^recipe[ \t]+([^ \t]*)/\1/d,definition/ +--regex-mu=/^recipe![ \t]+([^ \t]*)/\1/d,definition/ +--regex-mu=/^before[ \t]+([^ \t]*)/\1/d,definition/ +--regex-mu=/^after[ \t]+([^ \t]*)/\1/d,definition/ +--regex-mu=/^container[ \t]+([^ \t]*)/\1/s,struct/ +--regex-mu=/^exclusive-container[ \t]+([^ \t]*)/\1/u,union/ diff --git a/immutable-error.mu b/immutable-error.mu new file mode 100644 index 00000000..2d25d56e --- /dev/null +++ b/immutable-error.mu @@ -0,0 +1,13 @@ +# compare mutable.mu + +def main [ + local-scope + x:&:num <- new number:type + foo x +] + +def foo x:&:num [ + local-scope + load-ingredients + *x <- copy 34 # will cause an error because x is immutable in this function +] diff --git a/immutable_error.mu b/immutable_error.mu deleted file mode 100644 index 2d25d56e..00000000 --- a/immutable_error.mu +++ /dev/null @@ -1,13 +0,0 @@ -# compare mutable.mu - -def main [ - local-scope - x:&:num <- new number:type - foo x -] - -def foo x:&:num [ - local-scope - load-ingredients - *x <- copy 34 # will cause an error because x is immutable in this function -] diff --git a/lambda-to-mu.mu b/lambda-to-mu.mu new file mode 100644 index 00000000..0bdeb43f --- /dev/null +++ b/lambda-to-mu.mu @@ -0,0 +1,584 @@ +## experimental compiler to translate programs written in a generic +## expression-oriented language called 'lambda' into mu + +scenario convert-lambda [ + run [ + local-scope + 1:text/raw <- lambda-to-mu [(add a (multiply b c))] + 2:@:char/raw <- copy *1:text/raw + ] + memory-should-contain [ + 2:@:char <- [t1 <- multiply b c +result <- add a t1] + ] +] + +def lambda-to-mu in:text -> out:text [ + local-scope + load-ingredients + out <- copy 0 + cells:&:cell <- parse in + out <- to-mu cells +] + +# 'parse' will turn lambda expressions into trees made of cells +exclusive-container cell [ + atom:text + pair:pair +] + +# printed below as < first | rest > +container pair [ + first:&:cell + rest:&:cell +] + +def new-atom name:text -> result:&:cell [ + local-scope + load-ingredients + result <- new cell:type + *result <- merge 0/tag:atom, name +] + +def new-pair a:&:cell, b:&:cell -> result:&:cell [ + local-scope + load-ingredients + result <- new cell:type + *result <- merge 1/tag:pair, a/first, b/rest +] + +def is-atom? x:&:cell -> result:boolean [ + local-scope + load-ingredients + reply-unless x, 0/false + _, result <- maybe-convert *x, atom:variant +] + +def is-pair? x:&:cell -> result:boolean [ + local-scope + load-ingredients + reply-unless x, 0/false + _, result <- maybe-convert *x, pair:variant +] + +scenario atom-is-not-pair [ + local-scope + s:text <- new [a] + x:&:cell <- new-atom s + 10:boolean/raw <- is-atom? x + 11:boolean/raw <- is-pair? x + memory-should-contain [ + 10 <- 1 + 11 <- 0 + ] +] + +scenario pair-is-not-atom [ + local-scope + # construct (a . nil) + s:text <- new [a] + x:&:cell <- new-atom s + y:&:cell <- new-pair x, 0/nil + 10:boolean/raw <- is-atom? y + 11:boolean/raw <- is-pair? y + memory-should-contain [ + 10 <- 0 + 11 <- 1 + ] +] + +def atom-match? x:&:cell, pat:text -> result:boolean [ + local-scope + load-ingredients + s:text, is-atom?:boolean <- maybe-convert *x, atom:variant + reply-unless is-atom?, 0/false + result <- equal pat, s +] + +scenario atom-match [ + local-scope + x:&:cell <- new-atom [abc] + 10:boolean/raw <- atom-match? x, [abc] + memory-should-contain [ + 10 <- 1 + ] +] + +def first x:&:cell -> result:&:cell [ + local-scope + load-ingredients + pair:pair, pair?:boolean <- maybe-convert *x, pair:variant + reply-unless pair?, 0/nil + result <- get pair, first:offset +] + +def rest x:&:cell -> result:&:cell [ + local-scope + load-ingredients + pair:pair, pair?:boolean <- maybe-convert *x, pair:variant + reply-unless pair?, 0/nil + result <- get pair, rest:offset +] + +def set-first base:&:cell, new-first:&:cell -> base:&:cell [ + local-scope + load-ingredients + pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant + reply-unless is-pair? + pair <- put pair, first:offset, new-first + *base <- merge 1/pair, pair +] + +def set-rest base:&:cell, new-rest:&:cell -> base:&:cell [ + local-scope + load-ingredients + pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant + reply-unless is-pair? + pair <- put pair, rest:offset, new-rest + *base <- merge 1/pair, pair +] + +scenario cell-operations-on-atom [ + local-scope + s:text <- new [a] + x:&:cell <- new-atom s + 10:&:cell/raw <- first x + 11:&:cell/raw <- rest x + memory-should-contain [ + 10 <- 0 # first is nil + 11 <- 0 # rest is nil + ] +] + +scenario cell-operations-on-pair [ + local-scope + # construct (a . nil) + s:text <- new [a] + x:&:cell <- new-atom s + y:&:cell <- new-pair x, 0/nil + x2:&:cell <- first y + 10:boolean/raw <- equal x, x2 + 11:&:cell/raw <- rest y + memory-should-contain [ + 10 <- 1 # first is correct + 11 <- 0 # rest is nil + ] +] + +## convert lambda text to a tree of cells + +def parse in:text -> out:&:cell [ + local-scope + load-ingredients + s:&:stream:char <- new-stream in + out, s <- parse s + trace 2, [app/parse], out +] + +def parse in:&:stream:char -> out:&:cell, in:&:stream:char [ + local-scope + load-ingredients + # skip whitespace + in <- skip-whitespace in + c:char, eof?:boolean <- peek in + reply-if eof?, 0/nil + pair?:boolean <- equal c, 40/open-paren + { + break-if pair? + # atom + b:&:buffer <- new-buffer 30 + { + done?:boolean <- end-of-stream? in + break-if done? + # stop before close paren or space + c:char <- peek in + done? <- equal c, 41/close-paren + break-if done? + done? <- space? c + break-if done? + c <- read in + b <- append b, c + loop + } + s:text <- buffer-to-array b + out <- new-atom s + } + { + break-unless pair? + # pair + read in # skip the open-paren + out <- new cell:type # start out with nil + # read in first element of pair + { + end?:boolean <- end-of-stream? in + not-end?:boolean <- not end? + assert not-end?, [unbalanced '(' in expression] + c <- peek in + close-paren?:boolean <- equal c, 41/close-paren + break-if close-paren? + first:&:cell, in <- parse in + *out <- merge 1/pair, first, 0/nil + } + # read in any remaining elements + curr:&:cell <- copy out + { + in <- skip-whitespace in + end?:boolean <- end-of-stream? in + not-end?:boolean <- not end? + assert not-end?, [unbalanced '(' in expression] + # termination check: ')' + c <- peek in + { + close-paren?:boolean <- equal c, 41/close-paren + break-unless close-paren? + read in # skip ')' + break +end-pair:label + } + # still here? read next element of pair + next:&:cell, in <- parse in + is-dot?:boolean <- atom-match? next, [.] + { + break-if is-dot? + next-curr:&:cell <- new-pair next, 0/nil + curr <- set-rest curr, next-curr + curr <- rest curr + } + { + break-unless is-dot? + # deal with dotted pair + in <- skip-whitespace in + c <- peek in + not-close-paren?:boolean <- not-equal c, 41/close-paren + assert not-close-paren?, [')' cannot immediately follow '.'] + final:&:cell <- parse in + curr <- set-rest curr, final + # we're not gonna update curr, so better make sure the next iteration + # is going to end the pair + in <- skip-whitespace in + c <- peek in + close-paren?:boolean <- equal c, 41/close-paren + assert close-paren?, ['.' must be followed by exactly one expression before ')'] + } + loop + } + +end-pair + } +] + +def skip-whitespace in:&:stream:char -> in:&:stream:char [ + local-scope + load-ingredients + { + done?:boolean <- end-of-stream? in + reply-if done?, 0/null + c:char <- peek in + space?:boolean <- space? c + break-unless space? + read in # skip + loop + } +] + +def to-text x:&:cell -> out:text [ + local-scope + load-ingredients + buf:&:buffer <- new-buffer 30 + buf <- to-buffer x, buf + out <- buffer-to-array buf +] + +def to-buffer x:&:cell, buf:&:buffer -> buf:&:buffer [ + local-scope + load-ingredients + # base case: empty cell + { + break-if x + buf <- append buf, [<>] + reply + } + # base case: atom + { + s:text, atom?:boolean <- maybe-convert *x, atom:variant + break-unless atom? + buf <- append buf, s + reply + } + # recursive case: pair + buf <- append buf, [< ] + first:&:cell <- first x + buf <- to-buffer first, buf + buf <- append buf, [ | ] + rest:&:cell <- rest x + buf <- to-buffer rest, buf + buf <- append buf, [ >] +] + +scenario parse-single-letter-atom [ + local-scope + s:text <- new [a] + x:&:cell <- parse s + s2:text, 10:boolean/raw <- maybe-convert *x, atom:variant + 11:@:char/raw <- copy *s2 + memory-should-contain [ + 10 <- 1 # parse result is an atom + 11:@:char <- [a] + ] +] + +scenario parse-atom [ + local-scope + s:text <- new [abc] + x:&:cell <- parse s + s2:text, 10:boolean/raw <- maybe-convert *x, atom:variant + 11:@:char/raw <- copy *s2 + memory-should-contain [ + 10 <- 1 # parse result is an atom + 11:@:char <- [abc] + ] +] + +scenario parse-list-of-two-atoms [ + local-scope + s:text <- new [(abc def)] + x:&:cell <- parse s + trace-should-contain [ + app/parse: < abc | < def | <> > > + ] + 10:boolean/raw <- is-pair? x + x1:&:cell <- first x + x2:&:cell <- rest x + s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant + 12:boolean/raw <- is-pair? x2 + x3:&:cell <- first x2 + s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant + 14:&:cell/raw <- rest x2 + 20:@:char/raw <- copy *s1 + 30:@:char/raw <- copy *s2 + memory-should-contain [ + 10 <- 1 # parse result is a pair + 11 <- 1 # result.first is an atom + 12 <- 1 # result.rest is a pair + 13 <- 1 # result.rest.first is an atom + 14 <- 0 # result.rest.rest is nil + 20:@:char <- [abc] # result.first + 30:@:char <- [def] # result.rest.first + ] +] + +scenario parse-list-with-extra-spaces [ + local-scope + s:text <- new [ ( abc def ) ] # extra spaces + x:&:cell <- parse s + trace-should-contain [ + app/parse: < abc | < def | <> > > + ] + 10:boolean/raw <- is-pair? x + x1:&:cell <- first x + x2:&:cell <- rest x + s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant + 12:boolean/raw <- is-pair? x2 + x3:&:cell <- first x2 + s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant + 14:&:cell/raw <- rest x2 + 20:@:char/raw <- copy *s1 + 30:@:char/raw <- copy *s2 + memory-should-contain [ + 10 <- 1 # parse result is a pair + 11 <- 1 # result.first is an atom + 12 <- 1 # result.rest is a pair + 13 <- 1 # result.rest.first is an atom + 14 <- 0 # result.rest.rest is nil + 20:@:char <- [abc] # result.first + 30:@:char <- [def] # result.rest.first + ] +] + +scenario parse-list-of-more-than-two-atoms [ + local-scope + s:text <- new [(abc def ghi)] + x:&:cell <- parse s + trace-should-contain [ + app/parse: < abc | < def | < ghi | <> > > > + ] + 10:boolean/raw <- is-pair? x + x1:&:cell <- first x + x2:&:cell <- rest x + s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant + 12:boolean/raw <- is-pair? x2 + x3:&:cell <- first x2 + s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant + x4:&:cell <- rest x2 + 14:boolean/raw <- is-pair? x4 + x5:&:cell <- first x4 + s3:text, 15:boolean/raw <- maybe-convert *x5, atom:variant + 16:&:cell/raw <- rest x4 + 20:@:char/raw <- copy *s1 + 30:@:char/raw <- copy *s2 + 40:@:char/raw <- copy *s3 + memory-should-contain [ + 10 <- 1 # parse result is a pair + 11 <- 1 # result.first is an atom + 12 <- 1 # result.rest is a pair + 13 <- 1 # result.rest.first is an atom + 14 <- 1 # result.rest.rest is a pair + 15 <- 1 # result.rest.rest.first is an atom + 16 <- 0 # result.rest.rest.rest is nil + 20:@:char <- [abc] # result.first + 30:@:char <- [def] # result.rest.first + 40:@:char <- [ghi] # result.rest.rest + ] +] + +scenario parse-nested-list [ + local-scope + s:text <- new [((abc))] + x:&:cell <- parse s + trace-should-contain [ + app/parse: < < abc | <> > | <> > + ] + 10:boolean/raw <- is-pair? x + x1:&:cell <- first x + 11:boolean/raw <- is-pair? x + x2:&:cell <- first x1 + s1:text, 12:boolean/raw <- maybe-convert *x2, atom:variant + 13:&:cell/raw <- rest x1 + 14:&:cell/raw <- rest x + 20:@:char/raw <- copy *s1 + memory-should-contain [ + 10 <- 1 # parse result is a pair + 11 <- 1 # result.first is a pair + 12 <- 1 # result.first.first is an atom + 13 <- 0 # result.first.rest is nil + 14 <- 0 # result.rest is nil + 20:@:char <- [abc] # result.first.first + ] +] + +scenario parse-nested-list-2 [ + local-scope + s:text <- new [((abc) def)] + x:&:cell <- parse s + trace-should-contain [ + app/parse: < < abc | <> > | < def | <> > > + ] + 10:boolean/raw <- is-pair? x + x1:&:cell <- first x + 11:boolean/raw <- is-pair? x + x2:&:cell <- first x1 + s1:text, 12:boolean/raw <- maybe-convert *x2, atom:variant + 13:&:cell/raw <- rest x1 + x3:&:cell <- rest x + x4:&:cell <- first x3 + s2:text, 14:boolean/raw <- maybe-convert *x4, atom:variant + 15:&:cell/raw <- rest x3 + 20:@:char/raw <- copy *s1 + 30:@:char/raw <- copy *s2 + memory-should-contain [ + 10 <- 1 # parse result is a pair + 11 <- 1 # result.first is a pair + 12 <- 1 # result.first.first is an atom + 13 <- 0 # result.first.rest is nil + 14 <- 1 # result.rest.first is an atom + 15 <- 0 # result.rest.rest is nil + 20:@:char <- [abc] # result.first.first + 30:@:char <- [def] # result.rest.first + ] +] + +# todo: uncomment these tests after we figure out how to continue tests after +# assertion failures +#? scenario parse-error [ +#? local-scope +#? s:text <- new [(] +#? #? hide-errors +#? x:&:cell <- parse s +#? #? show-errors +#? trace-should-contain [ +#? error: unbalanced '(' in expression +#? ] +#? ] +#? +#? scenario parse-error-after-element [ +#? local-scope +#? s:text <- new [(abc] +#? #? hide-errors +#? x:&:cell <- parse s +#? #? show-errors +#? trace-should-contain [ +#? error: unbalanced '(' in expression +#? ] +#? ] + +scenario parse-dotted-list-of-two-atoms [ + local-scope + s:text <- new [(abc . def)] + x:&:cell <- parse s + trace-should-contain [ + app/parse: < abc | def > + ] + 10:boolean/raw <- is-pair? x + x1:&:cell <- first x + x2:&:cell <- rest x + s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant + s2:text, 12:boolean/raw <- maybe-convert *x2, atom:variant + 20:@:char/raw <- copy *s1 + 30:@:char/raw <- copy *s2 + memory-should-contain [ + # parses to < abc | def > + 10 <- 1 # parse result is a pair + 11 <- 1 # result.first is an atom + 12 <- 1 # result.rest is an atom + 20:@:char <- [abc] # result.first + 30:@:char <- [def] # result.rest + ] +] + +scenario parse-dotted-list-of-more-than-two-atoms [ + local-scope + s:text <- new [(abc def . ghi)] + x:&:cell <- parse s + trace-should-contain [ + app/parse: < abc | < def | ghi > > + ] + 10:boolean/raw <- is-pair? x + x1:&:cell <- first x + x2:&:cell <- rest x + s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant + 12:boolean/raw <- is-pair? x2 + x3:&:cell <- first x2 + s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant + x4:&:cell <- rest x2 + s3:text, 14:boolean/raw <- maybe-convert *x4, atom:variant + 20:@:char/raw <- copy *s1 + 30:@:char/raw <- copy *s2 + 40:@:char/raw <- copy *s3 + memory-should-contain [ + 10 <- 1 # parse result is a pair + 11 <- 1 # result.first is an atom + 12 <- 1 # result.rest is a pair + 13 <- 1 # result.rest.first is an atom + 14 <- 1 # result.rest.rest is an atom + 20:@:char <- [abc] # result.first + 30:@:char <- [def] # result.rest.first + 40:@:char <- [ghi] # result.rest.rest + ] +] + +## convert tree of cells to mu text + +def to-mu in:&:cell -> out:text [ + local-scope + load-ingredients + buf:&:buffer <- new-buffer 30 + buf <- to-mu in, buf + out <- buffer-to-array buf +] + +def to-mu in:&:cell, buf:&:buffer -> buf:&:buffer, result-name:text [ + local-scope + load-ingredients + # null cell? no change. + # pair with all atoms? gensym a new variable + # pair containing other pairs? recurse + result-name <- copy 0 +] diff --git a/lambda_to_mu.mu b/lambda_to_mu.mu deleted file mode 100644 index 0bdeb43f..00000000 --- a/lambda_to_mu.mu +++ /dev/null @@ -1,584 +0,0 @@ -## experimental compiler to translate programs written in a generic -## expression-oriented language called 'lambda' into mu - -scenario convert-lambda [ - run [ - local-scope - 1:text/raw <- lambda-to-mu [(add a (multiply b c))] - 2:@:char/raw <- copy *1:text/raw - ] - memory-should-contain [ - 2:@:char <- [t1 <- multiply b c -result <- add a t1] - ] -] - -def lambda-to-mu in:text -> out:text [ - local-scope - load-ingredients - out <- copy 0 - cells:&:cell <- parse in - out <- to-mu cells -] - -# 'parse' will turn lambda expressions into trees made of cells -exclusive-container cell [ - atom:text - pair:pair -] - -# printed below as < first | rest > -container pair [ - first:&:cell - rest:&:cell -] - -def new-atom name:text -> result:&:cell [ - local-scope - load-ingredients - result <- new cell:type - *result <- merge 0/tag:atom, name -] - -def new-pair a:&:cell, b:&:cell -> result:&:cell [ - local-scope - load-ingredients - result <- new cell:type - *result <- merge 1/tag:pair, a/first, b/rest -] - -def is-atom? x:&:cell -> result:boolean [ - local-scope - load-ingredients - reply-unless x, 0/false - _, result <- maybe-convert *x, atom:variant -] - -def is-pair? x:&:cell -> result:boolean [ - local-scope - load-ingredients - reply-unless x, 0/false - _, result <- maybe-convert *x, pair:variant -] - -scenario atom-is-not-pair [ - local-scope - s:text <- new [a] - x:&:cell <- new-atom s - 10:boolean/raw <- is-atom? x - 11:boolean/raw <- is-pair? x - memory-should-contain [ - 10 <- 1 - 11 <- 0 - ] -] - -scenario pair-is-not-atom [ - local-scope - # construct (a . nil) - s:text <- new [a] - x:&:cell <- new-atom s - y:&:cell <- new-pair x, 0/nil - 10:boolean/raw <- is-atom? y - 11:boolean/raw <- is-pair? y - memory-should-contain [ - 10 <- 0 - 11 <- 1 - ] -] - -def atom-match? x:&:cell, pat:text -> result:boolean [ - local-scope - load-ingredients - s:text, is-atom?:boolean <- maybe-convert *x, atom:variant - reply-unless is-atom?, 0/false - result <- equal pat, s -] - -scenario atom-match [ - local-scope - x:&:cell <- new-atom [abc] - 10:boolean/raw <- atom-match? x, [abc] - memory-should-contain [ - 10 <- 1 - ] -] - -def first x:&:cell -> result:&:cell [ - local-scope - load-ingredients - pair:pair, pair?:boolean <- maybe-convert *x, pair:variant - reply-unless pair?, 0/nil - result <- get pair, first:offset -] - -def rest x:&:cell -> result:&:cell [ - local-scope - load-ingredients - pair:pair, pair?:boolean <- maybe-convert *x, pair:variant - reply-unless pair?, 0/nil - result <- get pair, rest:offset -] - -def set-first base:&:cell, new-first:&:cell -> base:&:cell [ - local-scope - load-ingredients - pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant - reply-unless is-pair? - pair <- put pair, first:offset, new-first - *base <- merge 1/pair, pair -] - -def set-rest base:&:cell, new-rest:&:cell -> base:&:cell [ - local-scope - load-ingredients - pair:pair, is-pair?:boolean <- maybe-convert *base, pair:variant - reply-unless is-pair? - pair <- put pair, rest:offset, new-rest - *base <- merge 1/pair, pair -] - -scenario cell-operations-on-atom [ - local-scope - s:text <- new [a] - x:&:cell <- new-atom s - 10:&:cell/raw <- first x - 11:&:cell/raw <- rest x - memory-should-contain [ - 10 <- 0 # first is nil - 11 <- 0 # rest is nil - ] -] - -scenario cell-operations-on-pair [ - local-scope - # construct (a . nil) - s:text <- new [a] - x:&:cell <- new-atom s - y:&:cell <- new-pair x, 0/nil - x2:&:cell <- first y - 10:boolean/raw <- equal x, x2 - 11:&:cell/raw <- rest y - memory-should-contain [ - 10 <- 1 # first is correct - 11 <- 0 # rest is nil - ] -] - -## convert lambda text to a tree of cells - -def parse in:text -> out:&:cell [ - local-scope - load-ingredients - s:&:stream:char <- new-stream in - out, s <- parse s - trace 2, [app/parse], out -] - -def parse in:&:stream:char -> out:&:cell, in:&:stream:char [ - local-scope - load-ingredients - # skip whitespace - in <- skip-whitespace in - c:char, eof?:boolean <- peek in - reply-if eof?, 0/nil - pair?:boolean <- equal c, 40/open-paren - { - break-if pair? - # atom - b:&:buffer <- new-buffer 30 - { - done?:boolean <- end-of-stream? in - break-if done? - # stop before close paren or space - c:char <- peek in - done? <- equal c, 41/close-paren - break-if done? - done? <- space? c - break-if done? - c <- read in - b <- append b, c - loop - } - s:text <- buffer-to-array b - out <- new-atom s - } - { - break-unless pair? - # pair - read in # skip the open-paren - out <- new cell:type # start out with nil - # read in first element of pair - { - end?:boolean <- end-of-stream? in - not-end?:boolean <- not end? - assert not-end?, [unbalanced '(' in expression] - c <- peek in - close-paren?:boolean <- equal c, 41/close-paren - break-if close-paren? - first:&:cell, in <- parse in - *out <- merge 1/pair, first, 0/nil - } - # read in any remaining elements - curr:&:cell <- copy out - { - in <- skip-whitespace in - end?:boolean <- end-of-stream? in - not-end?:boolean <- not end? - assert not-end?, [unbalanced '(' in expression] - # termination check: ')' - c <- peek in - { - close-paren?:boolean <- equal c, 41/close-paren - break-unless close-paren? - read in # skip ')' - break +end-pair:label - } - # still here? read next element of pair - next:&:cell, in <- parse in - is-dot?:boolean <- atom-match? next, [.] - { - break-if is-dot? - next-curr:&:cell <- new-pair next, 0/nil - curr <- set-rest curr, next-curr - curr <- rest curr - } - { - break-unless is-dot? - # deal with dotted pair - in <- skip-whitespace in - c <- peek in - not-close-paren?:boolean <- not-equal c, 41/close-paren - assert not-close-paren?, [')' cannot immediately follow '.'] - final:&:cell <- parse in - curr <- set-rest curr, final - # we're not gonna update curr, so better make sure the next iteration - # is going to end the pair - in <- skip-whitespace in - c <- peek in - close-paren?:boolean <- equal c, 41/close-paren - assert close-paren?, ['.' must be followed by exactly one expression before ')'] - } - loop - } - +end-pair - } -] - -def skip-whitespace in:&:stream:char -> in:&:stream:char [ - local-scope - load-ingredients - { - done?:boolean <- end-of-stream? in - reply-if done?, 0/null - c:char <- peek in - space?:boolean <- space? c - break-unless space? - read in # skip - loop - } -] - -def to-text x:&:cell -> out:text [ - local-scope - load-ingredients - buf:&:buffer <- new-buffer 30 - buf <- to-buffer x, buf - out <- buffer-to-array buf -] - -def to-buffer x:&:cell, buf:&:buffer -> buf:&:buffer [ - local-scope - load-ingredients - # base case: empty cell - { - break-if x - buf <- append buf, [<>] - reply - } - # base case: atom - { - s:text, atom?:boolean <- maybe-convert *x, atom:variant - break-unless atom? - buf <- append buf, s - reply - } - # recursive case: pair - buf <- append buf, [< ] - first:&:cell <- first x - buf <- to-buffer first, buf - buf <- append buf, [ | ] - rest:&:cell <- rest x - buf <- to-buffer rest, buf - buf <- append buf, [ >] -] - -scenario parse-single-letter-atom [ - local-scope - s:text <- new [a] - x:&:cell <- parse s - s2:text, 10:boolean/raw <- maybe-convert *x, atom:variant - 11:@:char/raw <- copy *s2 - memory-should-contain [ - 10 <- 1 # parse result is an atom - 11:@:char <- [a] - ] -] - -scenario parse-atom [ - local-scope - s:text <- new [abc] - x:&:cell <- parse s - s2:text, 10:boolean/raw <- maybe-convert *x, atom:variant - 11:@:char/raw <- copy *s2 - memory-should-contain [ - 10 <- 1 # parse result is an atom - 11:@:char <- [abc] - ] -] - -scenario parse-list-of-two-atoms [ - local-scope - s:text <- new [(abc def)] - x:&:cell <- parse s - trace-should-contain [ - app/parse: < abc | < def | <> > > - ] - 10:boolean/raw <- is-pair? x - x1:&:cell <- first x - x2:&:cell <- rest x - s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant - 12:boolean/raw <- is-pair? x2 - x3:&:cell <- first x2 - s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant - 14:&:cell/raw <- rest x2 - 20:@:char/raw <- copy *s1 - 30:@:char/raw <- copy *s2 - memory-should-contain [ - 10 <- 1 # parse result is a pair - 11 <- 1 # result.first is an atom - 12 <- 1 # result.rest is a pair - 13 <- 1 # result.rest.first is an atom - 14 <- 0 # result.rest.rest is nil - 20:@:char <- [abc] # result.first - 30:@:char <- [def] # result.rest.first - ] -] - -scenario parse-list-with-extra-spaces [ - local-scope - s:text <- new [ ( abc def ) ] # extra spaces - x:&:cell <- parse s - trace-should-contain [ - app/parse: < abc | < def | <> > > - ] - 10:boolean/raw <- is-pair? x - x1:&:cell <- first x - x2:&:cell <- rest x - s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant - 12:boolean/raw <- is-pair? x2 - x3:&:cell <- first x2 - s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant - 14:&:cell/raw <- rest x2 - 20:@:char/raw <- copy *s1 - 30:@:char/raw <- copy *s2 - memory-should-contain [ - 10 <- 1 # parse result is a pair - 11 <- 1 # result.first is an atom - 12 <- 1 # result.rest is a pair - 13 <- 1 # result.rest.first is an atom - 14 <- 0 # result.rest.rest is nil - 20:@:char <- [abc] # result.first - 30:@:char <- [def] # result.rest.first - ] -] - -scenario parse-list-of-more-than-two-atoms [ - local-scope - s:text <- new [(abc def ghi)] - x:&:cell <- parse s - trace-should-contain [ - app/parse: < abc | < def | < ghi | <> > > > - ] - 10:boolean/raw <- is-pair? x - x1:&:cell <- first x - x2:&:cell <- rest x - s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant - 12:boolean/raw <- is-pair? x2 - x3:&:cell <- first x2 - s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant - x4:&:cell <- rest x2 - 14:boolean/raw <- is-pair? x4 - x5:&:cell <- first x4 - s3:text, 15:boolean/raw <- maybe-convert *x5, atom:variant - 16:&:cell/raw <- rest x4 - 20:@:char/raw <- copy *s1 - 30:@:char/raw <- copy *s2 - 40:@:char/raw <- copy *s3 - memory-should-contain [ - 10 <- 1 # parse result is a pair - 11 <- 1 # result.first is an atom - 12 <- 1 # result.rest is a pair - 13 <- 1 # result.rest.first is an atom - 14 <- 1 # result.rest.rest is a pair - 15 <- 1 # result.rest.rest.first is an atom - 16 <- 0 # result.rest.rest.rest is nil - 20:@:char <- [abc] # result.first - 30:@:char <- [def] # result.rest.first - 40:@:char <- [ghi] # result.rest.rest - ] -] - -scenario parse-nested-list [ - local-scope - s:text <- new [((abc))] - x:&:cell <- parse s - trace-should-contain [ - app/parse: < < abc | <> > | <> > - ] - 10:boolean/raw <- is-pair? x - x1:&:cell <- first x - 11:boolean/raw <- is-pair? x - x2:&:cell <- first x1 - s1:text, 12:boolean/raw <- maybe-convert *x2, atom:variant - 13:&:cell/raw <- rest x1 - 14:&:cell/raw <- rest x - 20:@:char/raw <- copy *s1 - memory-should-contain [ - 10 <- 1 # parse result is a pair - 11 <- 1 # result.first is a pair - 12 <- 1 # result.first.first is an atom - 13 <- 0 # result.first.rest is nil - 14 <- 0 # result.rest is nil - 20:@:char <- [abc] # result.first.first - ] -] - -scenario parse-nested-list-2 [ - local-scope - s:text <- new [((abc) def)] - x:&:cell <- parse s - trace-should-contain [ - app/parse: < < abc | <> > | < def | <> > > - ] - 10:boolean/raw <- is-pair? x - x1:&:cell <- first x - 11:boolean/raw <- is-pair? x - x2:&:cell <- first x1 - s1:text, 12:boolean/raw <- maybe-convert *x2, atom:variant - 13:&:cell/raw <- rest x1 - x3:&:cell <- rest x - x4:&:cell <- first x3 - s2:text, 14:boolean/raw <- maybe-convert *x4, atom:variant - 15:&:cell/raw <- rest x3 - 20:@:char/raw <- copy *s1 - 30:@:char/raw <- copy *s2 - memory-should-contain [ - 10 <- 1 # parse result is a pair - 11 <- 1 # result.first is a pair - 12 <- 1 # result.first.first is an atom - 13 <- 0 # result.first.rest is nil - 14 <- 1 # result.rest.first is an atom - 15 <- 0 # result.rest.rest is nil - 20:@:char <- [abc] # result.first.first - 30:@:char <- [def] # result.rest.first - ] -] - -# todo: uncomment these tests after we figure out how to continue tests after -# assertion failures -#? scenario parse-error [ -#? local-scope -#? s:text <- new [(] -#? #? hide-errors -#? x:&:cell <- parse s -#? #? show-errors -#? trace-should-contain [ -#? error: unbalanced '(' in expression -#? ] -#? ] -#? -#? scenario parse-error-after-element [ -#? local-scope -#? s:text <- new [(abc] -#? #? hide-errors -#? x:&:cell <- parse s -#? #? show-errors -#? trace-should-contain [ -#? error: unbalanced '(' in expression -#? ] -#? ] - -scenario parse-dotted-list-of-two-atoms [ - local-scope - s:text <- new [(abc . def)] - x:&:cell <- parse s - trace-should-contain [ - app/parse: < abc | def > - ] - 10:boolean/raw <- is-pair? x - x1:&:cell <- first x - x2:&:cell <- rest x - s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant - s2:text, 12:boolean/raw <- maybe-convert *x2, atom:variant - 20:@:char/raw <- copy *s1 - 30:@:char/raw <- copy *s2 - memory-should-contain [ - # parses to < abc | def > - 10 <- 1 # parse result is a pair - 11 <- 1 # result.first is an atom - 12 <- 1 # result.rest is an atom - 20:@:char <- [abc] # result.first - 30:@:char <- [def] # result.rest - ] -] - -scenario parse-dotted-list-of-more-than-two-atoms [ - local-scope - s:text <- new [(abc def . ghi)] - x:&:cell <- parse s - trace-should-contain [ - app/parse: < abc | < def | ghi > > - ] - 10:boolean/raw <- is-pair? x - x1:&:cell <- first x - x2:&:cell <- rest x - s1:text, 11:boolean/raw <- maybe-convert *x1, atom:variant - 12:boolean/raw <- is-pair? x2 - x3:&:cell <- first x2 - s2:text, 13:boolean/raw <- maybe-convert *x3, atom:variant - x4:&:cell <- rest x2 - s3:text, 14:boolean/raw <- maybe-convert *x4, atom:variant - 20:@:char/raw <- copy *s1 - 30:@:char/raw <- copy *s2 - 40:@:char/raw <- copy *s3 - memory-should-contain [ - 10 <- 1 # parse result is a pair - 11 <- 1 # result.first is an atom - 12 <- 1 # result.rest is a pair - 13 <- 1 # result.rest.first is an atom - 14 <- 1 # result.rest.rest is an atom - 20:@:char <- [abc] # result.first - 30:@:char <- [def] # result.rest.first - 40:@:char <- [ghi] # result.rest.rest - ] -] - -## convert tree of cells to mu text - -def to-mu in:&:cell -> out:text [ - local-scope - load-ingredients - buf:&:buffer <- new-buffer 30 - buf <- to-mu in, buf - out <- buffer-to-array buf -] - -def to-mu in:&:cell, buf:&:buffer -> buf:&:buffer, result-name:text [ - local-scope - load-ingredients - # null cell? no change. - # pair with all atoms? gensym a new variable - # pair containing other pairs? recurse - result-name <- copy 0 -] diff --git a/real-files.mu b/real-files.mu new file mode 100644 index 00000000..78108fbe --- /dev/null +++ b/real-files.mu @@ -0,0 +1,18 @@ +# example program: read a character from one file and write it to another +# BEWARE: this will modify your file system +# before running it, put a character into /tmp/mu-x +# after running it, check /tmp/mu-y + +def main [ + local-scope + f:num/file <- $open-file-for-reading [/tmp/mu-x] + $print [file to read from: ], f, 10/newline + c:char, eof?:boolean <- $read-from-file f + $print [copying ], c, 10/newline + f <- $close-file f + $print [file after closing: ], f, 10/newline + f <- $open-file-for-writing [/tmp/mu-y] + $print [file to write to: ], f, 10/newline + $write-to-file f, c + f <- $close-file f +] diff --git a/real_files.mu b/real_files.mu deleted file mode 100644 index 78108fbe..00000000 --- a/real_files.mu +++ /dev/null @@ -1,18 +0,0 @@ -# example program: read a character from one file and write it to another -# BEWARE: this will modify your file system -# before running it, put a character into /tmp/mu-x -# after running it, check /tmp/mu-y - -def main [ - local-scope - f:num/file <- $open-file-for-reading [/tmp/mu-x] - $print [file to read from: ], f, 10/newline - c:char, eof?:boolean <- $read-from-file f - $print [copying ], c, 10/newline - f <- $close-file f - $print [file after closing: ], f, 10/newline - f <- $open-file-for-writing [/tmp/mu-y] - $print [file to write to: ], f, 10/newline - $write-to-file f, c - f <- $close-file f -] diff --git a/static-dispatch.mu b/static-dispatch.mu new file mode 100644 index 00000000..7aec6fa1 --- /dev/null +++ b/static-dispatch.mu @@ -0,0 +1,21 @@ +def test a:num -> b:num [ + local-scope + load-ingredients + b <- add a, 1 +] + +def test a:num, b:num -> c:num [ + local-scope + load-ingredients + c <- add a, b +] + +def main [ + local-scope + a:num <- test 3 # selects single-ingredient version + $print a, 10/newline + b:num <- test 3, 4 # selects double-ingredient version + $print b, 10/newline + c:num <- test 3, 4, 5 # prefers double- to single-ingredient version + $print c, 10/newline +] diff --git a/static_dispatch.mu b/static_dispatch.mu deleted file mode 100644 index 7aec6fa1..00000000 --- a/static_dispatch.mu +++ /dev/null @@ -1,21 +0,0 @@ -def test a:num -> b:num [ - local-scope - load-ingredients - b <- add a, 1 -] - -def test a:num, b:num -> c:num [ - local-scope - load-ingredients - c <- add a, b -] - -def main [ - local-scope - a:num <- test 3 # selects single-ingredient version - $print a, 10/newline - b:num <- test 3, 4 # selects double-ingredient version - $print b, 10/newline - c:num <- test 3, 4, 5 # prefers double- to single-ingredient version - $print c, 10/newline -] -- cgit 1.4.1-2-gfad0