one more bug, and documentation for infix

One error message gets a bit worse.
This commit is contained in:
Kartik K. Agaram 2021-06-23 10:06:42 -07:00
parent ba0c41673b
commit 6a65f6f233
4 changed files with 80 additions and 27 deletions

View File

@ -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.

View File

@ -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
#

View File

@ -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 {

View File

@ -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 {