Add Prolog/Erlang style list sugar. All tests pass.
--HG-- rename : mains/tamsin-grammar.tamsin => mains/grammar.tamsin
This commit is contained in:
parent
e617bada09
commit
281ab6dc36
8 changed files with 81 additions and 8 deletions
8
bin/wrap
8
bin/wrap
|
@ -2,11 +2,13 @@
|
|||
|
||||
import sys
|
||||
|
||||
WIDTH=120
|
||||
|
||||
for line in sys.stdin:
|
||||
line = line.rstrip('\n')
|
||||
while len(line) > 72:
|
||||
print line[:72]
|
||||
line = line[72:]
|
||||
while len(line) > WIDTH:
|
||||
print line[:WIDTH]
|
||||
line = line[WIDTH:]
|
||||
print line
|
||||
|
||||
# 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
TODO
|
||||
----
|
||||
|
||||
* PROLOG/ERLANG'S LIST SUGAR. would be really really nice.
|
||||
* `using` production x: x's scanner defaults to utf8, not x
|
||||
* find different way to match variables in libtamsin, so that
|
||||
struct term's can be const all the way down — then share terms
|
||||
* don't consume stdin until asked to scan. demand_buffer. per-line loop.
|
||||
or rather, per-inputconsumechunk
|
||||
|
||||
### testing ###
|
||||
|
||||
|
@ -12,6 +13,7 @@ TODO
|
|||
* tests that `'V'` is not a variable
|
||||
* tests for failing when utf8 scanner hits badly-encoded utf8
|
||||
* tests for invalid escape codes
|
||||
* test for mismatched # of formals in prod branches
|
||||
|
||||
### support for simulating machines and vms ###
|
||||
|
||||
|
@ -63,8 +65,6 @@ TODO
|
|||
* `Table ← {} & fields → F@fields(H,T) & Table[H] ← T`
|
||||
* on that topic — production values and/or lambda productions...
|
||||
* pretty-print AST for error messages
|
||||
* don't consume stdin until asked to scan. demand_buffer. per-line loop.
|
||||
or rather, per-inputconsumechunk
|
||||
|
||||
### symbol fun ###
|
||||
|
||||
|
@ -91,6 +91,7 @@ TODO
|
|||
(implement Bakerloo in Tamsin)
|
||||
* analysis: always_succeeds(Rule)
|
||||
* analysis: may_backtrack(Rule)
|
||||
* analysis: may_consume_input(Rule)
|
||||
* regex-like shortcuts: `\w` for "word", `\s` for "whitespace", etc.
|
||||
* EOF and nil are the same? it would make sense... call it `end`?
|
||||
* productions with names with arbitrary characters in them.
|
||||
|
|
|
@ -509,6 +509,31 @@ Note also that you can print a constructor.
|
|||
= hi(there(I'm(a(constructor))))
|
||||
= hi(there(I'm(a(constructor))))
|
||||
|
||||
### List sugar ###
|
||||
|
||||
In a term context, `[]` is sugar for a list structure.
|
||||
|
||||
| main = return [a, b, c].
|
||||
= list(a, list(b, list(c, nil)))
|
||||
|
||||
The tail of the list default to the atom `nil`, but an "improper" list can
|
||||
be given using the `|` syntax, like Prolog or Erlang.
|
||||
|
||||
| main = return [a, b | c].
|
||||
= list(a, list(b, c))
|
||||
|
||||
An empty list is just `nil`.
|
||||
|
||||
| main = return [].
|
||||
= nil
|
||||
|
||||
Only one term may appear after the `|`.
|
||||
|
||||
| main = return [a, b | c, d].
|
||||
? expected
|
||||
|
||||
The list sugar syntax may also be used in match patterns (see far below.)
|
||||
|
||||
### Examples using Terms ###
|
||||
|
||||
This program accepts a pair of bits and evaluates to a term, a constructor
|
||||
|
@ -1383,6 +1408,17 @@ parentheses.
|
|||
| what() = "2".
|
||||
? expected
|
||||
|
||||
Note that the list sugar syntax can also be used in patterns.
|
||||
|
||||
| main = expr([a, b, c]) & 'ok'.
|
||||
| expr([]) = print 'end'.
|
||||
| expr([H|T]) = print H & expr(T).
|
||||
= a
|
||||
= b
|
||||
= c
|
||||
= end
|
||||
= ok
|
||||
|
||||
Advanced Scanning
|
||||
-----------------
|
||||
|
||||
|
|
3
eg/list-sugar2.tamsin
Normal file
3
eg/list-sugar2.tamsin
Normal file
|
@ -0,0 +1,3 @@
|
|||
main = expr([1,2|3]).
|
||||
expr([1,2|3]) = "f".
|
||||
|
|
@ -81,6 +81,14 @@ tamsin_parser {
|
|||
texpr = term → T & {"+" & term → S & T ← concat(T, S)} & T.
|
||||
term = term0.
|
||||
term0 = variable
|
||||
| "[" & L ← atom(nil) &
|
||||
[term → T & L ← constructor(list, list(T, list(L, nil))) &
|
||||
{"," & term → T & L ← constructor(list, list(T, list(L, nil)))}] &
|
||||
Tail ← atom(nil) &
|
||||
["|" & term → Tail] &
|
||||
"]" &
|
||||
reverse_c(L, Tail) → L &
|
||||
return L
|
||||
| atom → A & L ← nil & ["(" &
|
||||
term0 → T & L ← list(T, L) &
|
||||
{"," & term0 → T & L ← list(T, L)} &
|
||||
|
@ -134,4 +142,8 @@ tamsin_parser {
|
|||
find_production_global(MN, PN, P) =
|
||||
find_module(MN, P) → M & find_production(PN, M).
|
||||
|
||||
reverse_c(constructor(list, list(Fst, list(Snd, nil))), Acc) =
|
||||
Acc ← constructor(list, list(Fst, list(Acc, nil))) &
|
||||
reverse_c(Snd, Acc).
|
||||
reverse_c(Other, Acc) = Acc.
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ expr5 = "(" & expr0 & ")"
|
|||
| prodref & ["(" & texpr & {"," & texpr} & ")"].
|
||||
texpr = term & {"+" & term}.
|
||||
term = atom & ["(" & [term & {"," & term}] & ")"]
|
||||
| "[" & [term & {"," & term}] & ["|" & term] & "]"
|
||||
| variable.
|
||||
atom = word | sq_string.
|
||||
terminal = dq_string
|
|
@ -251,7 +251,25 @@ class Parser(EventProducer):
|
|||
return self.term1()
|
||||
|
||||
def term1(self):
|
||||
if self.peek()[0].isupper():
|
||||
if self.consume('['):
|
||||
t = AtomNode('nil')
|
||||
if self.consume(']'):
|
||||
return t
|
||||
term = self.term()
|
||||
t = ConstructorNode('list', [term, t])
|
||||
while self.consume(","):
|
||||
term = self.term()
|
||||
t = ConstructorNode('list', [term, t])
|
||||
new = AtomNode('nil')
|
||||
if self.consume('|'):
|
||||
new = self.term()
|
||||
self.expect(']')
|
||||
# reverse, with specified tail
|
||||
while isinstance(t, ConstructorNode):
|
||||
new = ConstructorNode('list', [t.contents[0], new])
|
||||
t = t.contents[1]
|
||||
return new
|
||||
elif self.peek()[0].isupper():
|
||||
return self.variable()
|
||||
elif (self.peek()[0].isalnum() or
|
||||
self.peek()[0] == "'"):
|
||||
|
|
2
test.sh
2
test.sh
|
@ -117,7 +117,7 @@ elif [ x$1 = xinterpreter -o x$1 = xi ]; then
|
|||
echo "*** Testing Python interpreter..."
|
||||
falderal $VERBOSE --substring-error fixture/tamsin.py.markdown $FILES
|
||||
elif [ x$1 = xgrammar ]; then
|
||||
test_it $MODE "mains/tamsin-grammar.tamsin" \
|
||||
test_it $MODE "mains/grammar.tamsin" \
|
||||
"lib/tamsin_scanner.tamsin" \
|
||||
"ok" \
|
||||
"bin/tamsin-grammar"
|
||||
|
|
Loading…
Add table
Reference in a new issue