68 | 68 |
(Mostly this is useful for debugging. In the following, `world` is
|
69 | 69 |
repeated because it is both printed, and the result of the evaluation.)
|
70 | 70 |
|
71 | |
| main = $.print(hello) & $.print(world).
|
|
71 |
| main = print hello & print world.
|
72 | 72 |
+ ahoshoshohspohdphs
|
73 | 73 |
= hello
|
74 | 74 |
= world
|
|
146 | 146 |
Note that `print` and `return` never fail. Thus, code like the following
|
147 | 147 |
is "useless":
|
148 | 148 |
|
149 | |
| main = foo & $.print(hi) | return useless.
|
150 | |
| foo = return bar | $.print(useless).
|
|
149 |
| main = foo & print hi | return useless.
|
|
150 |
| foo = return bar | print useless.
|
151 | 151 |
= hi
|
152 | 152 |
= hi
|
153 | 153 |
|
154 | 154 |
Note that `return` does not exit the production immediately — although
|
155 | 155 |
this behaviour may be re-considered...
|
156 | 156 |
|
157 | |
| main = return hello & $.print(not_useless).
|
|
157 |
| main = return hello & print not_useless.
|
158 | 158 |
= not_useless
|
159 | 159 |
= not_useless
|
160 | 160 |
|
161 | 161 |
Alternatives can select code to be executed, based on the input.
|
162 | 162 |
|
163 | |
| print(X) = $.print(X).
|
164 | |
| main = aorb & print(aorb) | cord & print(cord) & return ok.
|
165 | |
| aorb = "a" & print(ay) | "b" & print(bee).
|
166 | |
| cord = "c" & print(see) | eorf & print(eorf).
|
167 | |
| eorf = "e" & print(ee) | f & print(eff).
|
|
163 |
| main = aorb & print aorb | cord & print cord & return ok.
|
|
164 |
| aorb = "a" & print ay | "b" & print bee.
|
|
165 |
| cord = "c" & print see | eorf & print eorf.
|
|
166 |
| eorf = "e" & print ee | f & print eff.
|
168 | 167 |
+ e
|
169 | 168 |
= ee
|
170 | 169 |
= eorf
|
|
442 | 441 |
and it is always in scope.
|
443 | 442 |
|
444 | 443 |
The module `$` contains a number of built-in productions which would not
|
445 | |
be possible or practical to implement in Tamsin. Among them:
|
446 | |
|
447 | |
* `$.any`, which matches any token
|
448 | |
* `$.eof`, which matches the end of the input
|
449 | |
* `$.char`, the character scanner (more on scanner productions below)
|
450 | |
* `$.tamsin`, the tamsin scanner (more on scanner productions below)
|
|
444 |
be possible or practical to implement in Tamsin. See Appendix B for a list.
|
451 | 445 |
|
452 | 446 |
Advanced Parsing
|
453 | 447 |
----------------
|
454 | 448 |
|
455 | |
### $.EOF ###
|
|
449 |
### eof ###
|
456 | 450 |
|
457 | 451 |
If there is more input available than what we wrote the program to consume,
|
458 | 452 |
the program still succeeds.
|
|
461 | 455 |
+ apparently
|
462 | 456 |
= p
|
463 | 457 |
|
464 | |
The built-in production `$.eof` may be used to match against the end of the
|
|
458 |
The built-in production `eof` may be used to match against the end of the
|
465 | 459 |
input (colloquially called "EOF".)
|
466 | 460 |
|
467 | |
| main = "a" & "p" & $.eof.
|
|
461 |
| main = "a" & "p" & eof.
|
468 | 462 |
+ ap
|
469 | 463 |
= EOF
|
470 | 464 |
|
471 | 465 |
This is how you can make it error out if there is extra input remaining.
|
472 | 466 |
|
473 | |
| main = "a" & "p" & $.eof.
|
|
467 |
| main = "a" & "p" & eof.
|
474 | 468 |
+ apt
|
475 | 469 |
? expected EOF found 't'
|
476 | 470 |
|
477 | 471 |
The end of the input is a virtual infinite stream of EOF's. You can match
|
478 | 472 |
against them until the cows come home. The cows never come home.
|
479 | 473 |
|
480 | |
| main = "a" & "p" & $.eof & $.eof & $.eof.
|
|
474 |
| main = "a" & "p" & eof & eof & eof.
|
481 | 475 |
+ ap
|
482 | 476 |
= EOF
|
483 | 477 |
|
484 | |
### $.any ###
|
485 | |
|
486 | |
The built-in production `$.any` matches any token defined by the scanner
|
|
478 |
### any ###
|
|
479 |
|
|
480 |
The built-in production `any` matches any token defined by the scanner
|
487 | 481 |
except for EOF. (Remember that for now "token defined by the scanner"
|
488 | 482 |
means "character", but that that can be changed, as you'll see below.)
|
489 | 483 |
|
490 | |
| main = $.any & $.any & $.any.
|
|
484 |
| main = any & any & any.
|
491 | 485 |
+ (@)
|
492 | 486 |
= )
|
493 | 487 |
|
494 | |
| main = $.any & $.any.
|
|
488 |
| main = any & any.
|
495 | 489 |
+ a
|
496 | 490 |
? expected any token, found EOF
|
497 | 491 |
|
|
545 | 539 |
+ 0000
|
546 | 540 |
= zero(zero(zero(zero(nil))))
|
547 | 541 |
|
548 | |
### $.fail ###
|
549 | |
|
550 | |
The built-in production `$.fail` always fails. This lets you establish
|
|
542 |
### fail ###
|
|
543 |
|
|
544 |
The built-in production `fail` always fails. This lets you establish
|
551 | 545 |
global flags, of a sort. It takes a term, which it uses as the failure message.
|
552 | |
Note that the term must be in parentheses — more on that in a minute.
|
553 | 546 |
|
554 | 547 |
| debug = return ok.
|
555 | 548 |
| main = (debug & return walla | "0").
|
556 | 549 |
+ 0
|
557 | 550 |
= walla
|
558 | 551 |
|
559 | |
| debug = $.fail(notdebugging).
|
|
552 |
| debug = fail notdebugging.
|
560 | 553 |
| main = (debug & return walla | "0").
|
561 | 554 |
+ 0
|
562 | 555 |
= 0
|
563 | 556 |
|
564 | |
| main = set E = 'Goodbye, world!' & $.fail(E).
|
|
557 |
| main = set E = 'Goodbye, world!' & fail E.
|
565 | 558 |
+ hsihdsihdsih
|
566 | 559 |
? Goodbye, world!
|
567 | 560 |
|
|
678 | 671 |
returns an atom, which the client will treat as a token.
|
679 | 672 |
|
680 | 673 |
| main = scanner using $.char.
|
681 | |
| scanner = {scan → A & $.print(A)} & ".".
|
|
674 |
| scanner = {scan → A & print A} & ".".
|
682 | 675 |
| scan = {" "} & ("-" & ">" & return '->' | "(" | ")" | "," | ";" | word).
|
683 | 676 |
| word = letter → L & {letter → M & set L = L + M}.
|
684 | 677 |
| letter = "a" | "b" | "c" | "d" | "e" | "f" | "g".
|
|
800 | 793 |
|
801 | 794 |
| main = program using scanner.
|
802 | 795 |
| scanner = scan using $.char.
|
803 | |
| print(X) = $.print(X).
|
804 | 796 |
| scan = (
|
805 | 797 |
| "c" & "a" & "t" & return cat | "d" & "o" & "g" & return dog
|
806 | 798 |
| ).
|
807 | |
| program = "cat" & print(1) &
|
808 | |
| ("cat" & print(2) | "dog" & print(3)) &
|
809 | |
| "dog" & print(4) & return ok.
|
|
799 |
| program = "cat" & print 1 &
|
|
800 |
| ("cat" & print 2 | "dog" & print 3) &
|
|
801 |
| "dog" & print 4 & return ok.
|
810 | 802 |
+ catcatdog
|
811 | 803 |
= 1
|
812 | 804 |
= 2
|
|
815 | 807 |
|
816 | 808 |
| main = program using scanner.
|
817 | 809 |
| scanner = scan using $.char.
|
818 | |
| print(X) = $.print(X).
|
819 | 810 |
| scan = (
|
820 | 811 |
| "c" & "a" & "t" & return cat | "d" & "o" & "g" & return dog
|
821 | 812 |
| ).
|
822 | |
| program = "cat" & print(1) &
|
823 | |
| ("cat" & print(2) | "dog" & print(3)) &
|
824 | |
| "dog" & print(4) & return ok.
|
|
813 |
| program = "cat" & print 1 &
|
|
814 |
| ("cat" & print 2 | "dog" & print 3) &
|
|
815 |
| "dog" & print 4 & return ok.
|
825 | 816 |
+ catdogdog
|
826 | 817 |
= 1
|
827 | 818 |
= 3
|
|
1070 | 1061 |
the production's rule.
|
1071 | 1062 |
|
1072 | 1063 |
| main = donkey(world).
|
1073 | |
| donkey[$.any → E] = return hello(E).
|
|
1064 |
| donkey[any → E] = return hello(E).
|
1074 | 1065 |
= hello(w)
|
1075 | 1066 |
|
1076 | 1067 |
| main = donkey(world).
|
1077 | |
| donkey[$.any → E using $.tamsin] = return hello(E).
|
|
1068 |
| donkey[any → E using $.tamsin] = return hello(E).
|
1078 | 1069 |
= hello(world)
|
1079 | 1070 |
|
1080 | 1071 |
No variables from the caller leak into the called production.
|
1081 | 1072 |
|
1082 | 1073 |
| main = set F = whatever & donkey(world).
|
1083 | |
| donkey[$.any → E] = return hello(F).
|
|
1074 |
| donkey[any → E] = return hello(F).
|
1084 | 1075 |
? KeyError
|
1085 | 1076 |
|
1086 | 1077 |
Terms are stringified before being matched.
|
|
1178 | 1169 |
* `$.eof` -- succeeds on eof and returns eof, otherwise fails
|
1179 | 1170 |
* `$.any` -- fails on eof, succeeds and returns token on any other token
|
1180 | 1171 |
* `$.print(X)` -- prints X to output as a side-effect, returns X
|
|
1172 |
* `$.fail(X)` -- always fails, giving X as the error message
|
1181 | 1173 |
|
1182 | 1174 |
Appendix C. Notes
|
1183 | 1175 |
-----------------
|