about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2021-06-23 10:06:42 -0700
committerKartik K. Agaram <vc@akkartik.com>2021-06-23 10:06:57 -0700
commit6a65f6f23385b98f3f79a9b0258a7f349a84d7eb (patch)
tree867f29ba4093b609a4e0531e97cb938b0649de34
parentba0c41673b7cb024544c5e1ec1638cf2fb1f3725 (diff)
downloadmu-6a65f6f23385b98f3f79a9b0258a7f349a84d7eb.tar.gz
one more bug, and documentation for infix
One error message gets a bit worse.
-rw-r--r--shell/README.md59
-rw-r--r--shell/infix.mu3
-rw-r--r--shell/sandbox.mu6
-rw-r--r--shell/tokenize.mu39
4 files changed, 80 insertions, 27 deletions
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 {