Merge pull request 'docs: Finally get the tour to start from the real helloworld' (#23) from hw_tour into main
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Also improves the testing situation for the features to date. Resolves #17. Reviewed-on: #23
This commit is contained in:
commit
380177b274
151
tests/basic.spt
151
tests/basic.spt
@ -16,15 +16,21 @@ Title: A whirlwind tour of fostr
|
||||
|
||||
## Whirlwind tour
|
||||
|
||||
fostr is just in its infancy, so it's not yet even ready for
|
||||
Hello, World. The best we can offer now is this little snippet
|
||||
that writes the sum of the ASCII codes for 'H', 'W', and '!' to standard output:
|
||||
There seems only to be one way to start a tour like this. So here goes:
|
||||
```fostr
|
||||
**/
|
||||
|
||||
/** md */ test emit_sum [[
|
||||
stream << 72 + 87 + 33
|
||||
/** md */ test hello_world [[
|
||||
<<< 'Hello, world!'
|
||||
]] /* **/
|
||||
parse to TopLevel(DefGets(LitString("'Hello, world!'")))
|
||||
/** writes
|
||||
Hello, world!**/
|
||||
|
||||
// Prior proto-hello-world, no longer in the tour.
|
||||
test emit_sum [[
|
||||
stream << 72 + 87 + 33
|
||||
]]
|
||||
parse to TopLevel(Gets(Stream(), Sum(Sum(Int("72"), Int("87")), Int("33"))))
|
||||
/** writes
|
||||
192**/
|
||||
@ -33,7 +39,7 @@ parse to TopLevel(Gets(Stream(), Sum(Sum(Int("72"), Int("87")), Int("33"))))
|
||||
```
|
||||
|
||||
At the moment, there are only two ways to run a file containing fostr code
|
||||
(you can find the above in `tests/emit_sum.fos`). They both start by
|
||||
(you can find the above in `tests/hw.fos`). They both start by
|
||||
cloning this fostr project. Then, either:
|
||||
|
||||
1. Open the project in Eclipse and build it, visit your program file,
|
||||
@ -46,30 +52,70 @@ cloning this fostr project. Then, either:
|
||||
|
||||
For example, this snippet generates the following Python:
|
||||
```python
|
||||
{! ../tests/emit_sum.py extract:
|
||||
{! ../tests/hw.py extract:
|
||||
start: 'Stdio\s='
|
||||
!}
|
||||
```
|
||||
(which writes "192" to standard output); it also generates identical code in
|
||||
this simple example for
|
||||
Javascript, although it generates a different preamble defining Stdio in each
|
||||
case. (Haskell code generation is also currently supported.)
|
||||
It generates nearly identical code in
|
||||
this simple example for Javascript (just with `"Hello, world!"`
|
||||
in place of `r'Hello, world!'`), although it generates a different
|
||||
preamble defining Stdio for each language. (Currently, Haskell code
|
||||
generation is also supported.)
|
||||
|
||||
There's not much to break down in such a tiny program as this, but let's do
|
||||
it. The prefix operator `<<<` could be read as "the default stream receives...",
|
||||
and unsurprisingly in a main program the default stream is standard input and
|
||||
output. And `'Hello, world!'` is a literal string constant; what you see is
|
||||
what you get. The only detail to know is that such constants must occur
|
||||
within a single line of your source file. So depending on how you
|
||||
ran the program and how closely you looked at its output,
|
||||
you may have noticed this program does not write a newline at the end
|
||||
of its message. Nothing is ever implicitly sent to a stream. So if you want
|
||||
newlines, you should switch to a (double-quoted) string that allows
|
||||
the usual array of escape sequences:
|
||||
|
||||
```fostr
|
||||
**/
|
||||
|
||||
/** md */ test hello_esc_world [[
|
||||
<<< "Hello,\t\tworld!\n\n"
|
||||
]] /* **/
|
||||
parse to TopLevel(DefGets(EscString("\"Hello,\t\tworld!\n\n\"")))
|
||||
/** writes
|
||||
Hello, world!
|
||||
|
||||
**/
|
||||
|
||||
/** md
|
||||
```
|
||||
(We threw in two of each so you could clearly see them in the output if
|
||||
you run this program.)
|
||||
|
||||
### Everything has a value
|
||||
|
||||
As mentioned in the [Introduction](../README.md), everything in a fostr
|
||||
program (including the entire program itself) is an expression and has
|
||||
a value. So what's the value of that expression above? Well, appropriately
|
||||
enough, `stream` is our
|
||||
first example of a stream, and for convenience, the value of a stream
|
||||
receiving an item is (usually) just the stream back again. The `<<` operator
|
||||
is also left-associative, so that way we can chain insertions into a stream:
|
||||
a value. So what's the value of that expression above? Well, for convenience,
|
||||
the value of a stream receiving an item is (generally) just the stream back
|
||||
again. That way we can use the general (left-associative)
|
||||
`_stream_ << _value_` operator to chain insertions into a stream:
|
||||
```fostr
|
||||
**/
|
||||
|
||||
/** md */ test emit_twice [[
|
||||
stream << 72 + 87 + 33 << 291
|
||||
/** md */ test state_obvious [[
|
||||
<<< 'Two and ' << 2 << ' make ' << 2+2 << ".\n"
|
||||
]] /* **/
|
||||
parse to TopLevel(
|
||||
Gets(Gets(Gets(Gets(DefGets(LitString("'Two and '")),Int("2")),
|
||||
LitString("' make '")),Sum(Int("2"),Int("2"))),
|
||||
EscString("\"./n\"")))
|
||||
/** writes
|
||||
Two and 2 make 4.
|
||||
**/
|
||||
|
||||
test emit_twice [[
|
||||
stream << 72 + 87 + 33 << 291
|
||||
]]
|
||||
parse to TopLevel(
|
||||
Gets(Gets(Stream(), Sum(Sum(Int("72"), Int("87")), Int("33"))), Int("291")))
|
||||
/** writes
|
||||
@ -77,24 +123,28 @@ parse to TopLevel(
|
||||
|
||||
/** md
|
||||
```
|
||||
Running this program produces a nice palindromic output: "192291".
|
||||
|
||||
And because sometimes you want to emphasize the value and propagate that
|
||||
instead of the stream, you can also write these expressions "the other way"
|
||||
with `>>`; both forms return the first argument, so the following writes "824":
|
||||
with `>>>` for sending to the default stream or `>>` in general; these forms
|
||||
(generally) return the value sent, so the following writes "824":
|
||||
```fostr
|
||||
**/
|
||||
|
||||
/** md */ test enters_twice [[
|
||||
(7 + 8 >> stream + 9) >> stream
|
||||
(7 + 8 >> stream + 9) >>>
|
||||
]] /* **/
|
||||
parse to TopLevel(
|
||||
To(Sum(Sum(Int("7"), To(Int("8"), Stream())), Int("9")), Stream()))
|
||||
DefTo(Sum(Sum(Int("7"), To(Int("8"), Stream())), Int("9"))))
|
||||
/** writes
|
||||
824**/
|
||||
|
||||
/** md
|
||||
```
|
||||
Two things are worth noting here: the default stream can always be referred to
|
||||
directly via the identifier `stream`, and the precedences of `<<` and `>>` are
|
||||
different so that generally full expressions go to a stream with `<<` but
|
||||
just individual terms are sent with `>>`.
|
||||
|
||||
### Layout in fostr
|
||||
|
||||
@ -104,13 +154,13 @@ lines are indented from the start of the initial line:
|
||||
**/
|
||||
|
||||
/** md */ test receive_enter_break [[
|
||||
stream <<
|
||||
<<<
|
||||
7
|
||||
+ 8 >> stream
|
||||
+ 8 >>>
|
||||
+ 9
|
||||
]] /* **/
|
||||
parse to TopLevel(
|
||||
Gets(Stream(), Sum(Sum(Int("7"), To(Int("8"), Stream())), Int("9"))))
|
||||
DefGets(Sum(Sum(Int("7"), DefTo(Int("8"))), Int("9"))))
|
||||
/** writes
|
||||
824**/
|
||||
|
||||
@ -121,8 +171,8 @@ parse to TopLevel(
|
||||
**/
|
||||
|
||||
/** md */ test enter_receive_bad_continuation [[
|
||||
(7 + 8 >> stream + 9)
|
||||
>> (stream << 9 + 2)
|
||||
(7 + 8 >>> + 9)
|
||||
>> (<<< 9 + 2)
|
||||
]] /* **/
|
||||
parse fails
|
||||
|
||||
@ -145,16 +195,17 @@ lines are evaluated in sequence. For example, the program
|
||||
**/
|
||||
|
||||
/** md */ test emit_thrice [[
|
||||
stream << 72 + 87
|
||||
stream << 88
|
||||
<<< 72 + 87
|
||||
<<< 88
|
||||
+ 96
|
||||
99 + 12 >>
|
||||
stream
|
||||
99 + 12
|
||||
>>>
|
||||
|
||||
]] /* **/
|
||||
parse to TopLevel(Sequence([
|
||||
Gets(Stream(), Sum(Int("72"), Int("87"))),
|
||||
Gets(Stream(), Sum(Int("88"), Int("96"))),
|
||||
Sum(Int("99"), To(Int("12"), Stream()))
|
||||
DefGets(Sum(Int("72"), Int("87"))),
|
||||
DefGets(Sum(Int("88"), Int("96"))),
|
||||
Sum(Int("99"), DefTo(Int("12")))
|
||||
]))
|
||||
/** writes
|
||||
15918412**/
|
||||
@ -169,10 +220,10 @@ in sequence align at the left; e.g., the following fails to parse:
|
||||
**/
|
||||
|
||||
/** md */ test emit_thrice_bad_alignment [[
|
||||
stream << 72 + 87
|
||||
stream << 88
|
||||
<<< 72 + 87
|
||||
<<< 88
|
||||
+ 96
|
||||
99 + 12 >> stream
|
||||
99 + 12 >>>
|
||||
]] /* **/
|
||||
parse fails
|
||||
|
||||
@ -187,23 +238,23 @@ are so terminated. So the following is OK:
|
||||
**/
|
||||
|
||||
/** md */ test emit_several [[
|
||||
stream << 1 + 2; 3 >> stream
|
||||
(4 + 5) >> stream; stream << 6;
|
||||
stream << 7
|
||||
stream << 8
|
||||
<<< 1 + 2; 3 >>>
|
||||
(4 + 5) >>>; stream << 6;
|
||||
<<< 7
|
||||
<<< 8
|
||||
+ (9+10);
|
||||
11 + 12 >> stream; 13 >> stream
|
||||
>> stream
|
||||
11 + 12 >>>; 13 >>>
|
||||
>>>
|
||||
]] /* **/
|
||||
parse to TopLevel(Sequence([
|
||||
ISequence(Prior([Terminate(Gets(Stream(), Sum(Int("1"), Int("2"))))]),
|
||||
To(Int("3"), Stream())),
|
||||
ISequence(Prior([Terminate(To(Sum(Int("4"), Int("5")), Stream()))]),
|
||||
ISequence(Prior([Terminate(DefGets(Sum(Int("1"), Int("2"))))]),
|
||||
DefTo(Int("3"))),
|
||||
ISequence(Prior([Terminate(DefTo(Sum(Int("4"), Int("5"))))]),
|
||||
Terminate(Gets(Stream(), Int("6")))),
|
||||
Gets(Stream(), Int("7")),
|
||||
Terminate(Gets(Stream(), Sum(Int("8"), Sum(Int("9"), Int("10"))))),
|
||||
ISequence(Prior([Terminate(Sum(Int("11"), To(Int("12"), Stream())))]),
|
||||
To(To(Int("13"), Stream()), Stream()))
|
||||
DefGets(Int("7")),
|
||||
Terminate(DefGets(Sum(Int("8"), Sum(Int("9"), Int("10"))))),
|
||||
ISequence(Prior([Terminate(Sum(Int("11"), DefTo(Int("12"))))]),
|
||||
DefTo(DefTo(Int("13"))))
|
||||
]))
|
||||
/** writes
|
||||
3396727121313**/
|
||||
|
Loading…
Reference in New Issue
Block a user