From 6a65f6f23385b98f3f79a9b0258a7f349a84d7eb Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 23 Jun 2021 10:06:42 -0700 Subject: one more bug, and documentation for infix One error message gets a bit worse. --- shell/README.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ shell/infix.mu | 3 ++- shell/sandbox.mu | 6 +++--- shell/tokenize.mu | 39 +++++++++++++++--------------------- 4 files changed, 80 insertions(+), 27 deletions(-) (limited to 'shell') diff --git a/shell/README.md b/shell/README.md index a9d8ea7b..3f536bef 100644 --- a/shell/README.md +++ b/shell/README.md @@ -118,6 +118,65 @@ if (= 1 (% x 2)) 'even ``` +### Infix + +The Mu shell supports infix operators: +``` +3 + 1 +=> 4 +``` + +You don't need spaces around infix ops: +``` +3+1 +=> 4 +``` + +Operator precedence is not hardcoded. Instead, there is just one rule: +operators surrounded by whitespace have lower precedence than operators that +are not. + +To see how an expression is parsed, quote it: +``` +'3+1 +=> (+ 3 1) +``` + +You can create your own infix ops: +``` +def (a <> b) + (not (a = b)) +``` + +To permit arbitrary infix operators, the Mu shell partitions the space of +graphemes between operators and regular symbols. As a result, you can't define +symbols mixing the two. +``` +'*global* +=> ((* global) . *) # probably not what you want + +'uppercase-char-p +=> (- (- uppercase char) p) # probably not what you want + +'(char> a p) +=> ((char . >) a p) # probably not what you want +``` + +Infix operators also work in prefix position: +``` +(+ 3 1) +=> 4 +``` + +To pass infix operators to higher-order functions, wrap them in parens. A +silly example: +``` +def (+++ x) # silly name + x+1 +(map1 (+++) '(1 2 3)) +=> (2 3 4) +``` + ### Known issues * No mouse support. diff --git a/shell/infix.mu b/shell/infix.mu index 2164eb5c..ba96a81e 100644 --- a/shell/infix.mu +++ b/shell/infix.mu @@ -392,6 +392,7 @@ fn test-infix { check-infix "(+a)", "((+ a))", "F - test-infix/unary-operator-3" check-infix "-a", "(- a)", "F - test-infix/unary-operator-4" check-infix "a+b", "(+ a b)", "F - test-infix/no-spaces" + check-infix "3+1", "(+ 3 1)", "F - test-infix/no-spaces-starting-with-digit" check-infix "',a+b", "',(+ a b)", "F - test-infix/no-spaces-with-nested-quotes" check-infix "$a+b", "(+ $a b)", "F - test-infix/no-spaces-2" check-infix "-a+b", "(+ (- a) b)", "F - test-infix/unary-over-binary" @@ -584,7 +585,7 @@ fn check-infix actual: (addr array byte), expected: (addr array byte), message: var actual-tree-ah/esi: (addr handle cell) <- address actual-tree-h read-cell actual-buffer, actual-tree-ah, trace #? dump-trace-with-label trace, "infix" -#? dump-cell-from-cursor-over-full-screen actual-tree-ah, 7/fg 0/bg + dump-cell-from-cursor-over-full-screen actual-tree-ah, 7/fg 0/bg var _actual-tree/eax: (addr cell) <- lookup *actual-tree-ah var actual-tree/esi: (addr cell) <- copy _actual-tree # diff --git a/shell/sandbox.mu b/shell/sandbox.mu index 5115eca2..6a6180fa 100644 --- a/shell/sandbox.mu +++ b/shell/sandbox.mu @@ -684,9 +684,9 @@ fn test-run-error-invalid-integer { # render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height, 1/show-cursor # skip one line of padding - check-screen-row screen, 1/y, " 1a ", "F - test-run-error-invalid-integer/0" - check-screen-row screen, 2/y, " ... ", "F - test-run-error-invalid-integer/1" - check-screen-row-in-color screen, 0xc/fg=error, 3/y, " invalid number ", "F - test-run-error-invalid-integer/2" + check-screen-row screen, 1/y, " 1a ", "F - test-run-error-invalid-integer/0" + check-screen-row screen, 2/y, " ... ", "F - test-run-error-invalid-integer/1" + check-screen-row-in-color screen, 0xc/fg=error, 3/y, " unbound symbol: 1a ", "F - test-run-error-invalid-integer/2" } fn test-run-error-unknown-symbol { diff --git a/shell/tokenize.mu b/shell/tokenize.mu index 2d7ea041..6ebf5e46 100644 --- a/shell/tokenize.mu +++ b/shell/tokenize.mu @@ -419,27 +419,6 @@ fn next-token in: (addr gap-buffer), out: (addr token), start-of-line?: boolean, next-stream-token in, out, trace break $next-token:case } - # special-case: '-' - { - compare g, 0x2d/minus - break-if-!= - var dummy/eax: grapheme <- read-from-gap-buffer in # skip '-' - var g2/eax: grapheme <- peek-from-gap-buffer in - put-back-from-gap-buffer in - var digit?/eax: boolean <- decimal-digit? g2 - compare digit?, 0/false - break-if-= - next-number-token in, out, trace - break $next-token:case - } - # digit - { - var digit?/eax: boolean <- decimal-digit? g - compare digit?, 0/false - break-if-= - next-number-token in, out, trace - break $next-token:case - } # other symbol char { var symbol?/eax: boolean <- symbol-grapheme? g @@ -878,8 +857,22 @@ fn number-token? _self: (addr token) -> _/eax: boolean { break-if-!= g <- read-grapheme in-data } - var result/eax: boolean <- decimal-digit? g - return result + { + { + var result/eax: boolean <- decimal-digit? g + compare result, 0/false + break-if-!= + return 0/false + } + { + var done?/eax: boolean <- stream-empty? in-data + compare done?, 0/false + } + break-if-!= + g <- read-grapheme in-data + loop + } + return 1/true } fn bracket-token? _self: (addr token) -> _/eax: boolean { -- cgit 1.4.1-2-gfad0