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
|
## Whirlwind tour
|
||||||
|
|
||||||
fostr is just in its infancy, so it's not yet even ready for
|
There seems only to be one way to start a tour like this. So here goes:
|
||||||
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:
|
|
||||||
```fostr
|
```fostr
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test emit_sum [[
|
/** md */ test hello_world [[
|
||||||
stream << 72 + 87 + 33
|
<<< '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"))))
|
parse to TopLevel(Gets(Stream(), Sum(Sum(Int("72"), Int("87")), Int("33"))))
|
||||||
/** writes
|
/** writes
|
||||||
192**/
|
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
|
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:
|
cloning this fostr project. Then, either:
|
||||||
|
|
||||||
1. Open the project in Eclipse and build it, visit your program file,
|
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:
|
For example, this snippet generates the following Python:
|
||||||
```python
|
```python
|
||||||
{! ../tests/emit_sum.py extract:
|
{! ../tests/hw.py extract:
|
||||||
start: 'Stdio\s='
|
start: 'Stdio\s='
|
||||||
!}
|
!}
|
||||||
```
|
```
|
||||||
(which writes "192" to standard output); it also generates identical code in
|
It generates nearly identical code in
|
||||||
this simple example for
|
this simple example for Javascript (just with `"Hello, world!"`
|
||||||
Javascript, although it generates a different preamble defining Stdio in each
|
in place of `r'Hello, world!'`), although it generates a different
|
||||||
case. (Haskell code generation is also currently supported.)
|
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
|
### Everything has a value
|
||||||
|
|
||||||
As mentioned in the [Introduction](../README.md), everything in a fostr
|
As mentioned in the [Introduction](../README.md), everything in a fostr
|
||||||
program (including the entire program itself) is an expression and has
|
program (including the entire program itself) is an expression and has
|
||||||
a value. So what's the value of that expression above? Well, appropriately
|
a value. So what's the value of that expression above? Well, for convenience,
|
||||||
enough, `stream` is our
|
the value of a stream receiving an item is (generally) just the stream back
|
||||||
first example of a stream, and for convenience, the value of a stream
|
again. That way we can use the general (left-associative)
|
||||||
receiving an item is (usually) just the stream back again. The `<<` operator
|
`_stream_ << _value_` operator to chain insertions into a stream:
|
||||||
is also left-associative, so that way we can chain insertions into a stream:
|
|
||||||
```fostr
|
```fostr
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test emit_twice [[
|
/** md */ test state_obvious [[
|
||||||
stream << 72 + 87 + 33 << 291
|
<<< '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(
|
parse to TopLevel(
|
||||||
Gets(Gets(Stream(), Sum(Sum(Int("72"), Int("87")), Int("33"))), Int("291")))
|
Gets(Gets(Stream(), Sum(Sum(Int("72"), Int("87")), Int("33"))), Int("291")))
|
||||||
/** writes
|
/** writes
|
||||||
@ -77,24 +123,28 @@ parse to TopLevel(
|
|||||||
|
|
||||||
/** md
|
/** md
|
||||||
```
|
```
|
||||||
Running this program produces a nice palindromic output: "192291".
|
|
||||||
|
|
||||||
And because sometimes you want to emphasize the value and propagate that
|
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"
|
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
|
```fostr
|
||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test enters_twice [[
|
/** md */ test enters_twice [[
|
||||||
(7 + 8 >> stream + 9) >> stream
|
(7 + 8 >> stream + 9) >>>
|
||||||
]] /* **/
|
]] /* **/
|
||||||
parse to TopLevel(
|
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
|
/** writes
|
||||||
824**/
|
824**/
|
||||||
|
|
||||||
/** md
|
/** 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
|
### Layout in fostr
|
||||||
|
|
||||||
@ -104,13 +154,13 @@ lines are indented from the start of the initial line:
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test receive_enter_break [[
|
/** md */ test receive_enter_break [[
|
||||||
stream <<
|
<<<
|
||||||
7
|
7
|
||||||
+ 8 >> stream
|
+ 8 >>>
|
||||||
+ 9
|
+ 9
|
||||||
]] /* **/
|
]] /* **/
|
||||||
parse to TopLevel(
|
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
|
/** writes
|
||||||
824**/
|
824**/
|
||||||
|
|
||||||
@ -121,8 +171,8 @@ parse to TopLevel(
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test enter_receive_bad_continuation [[
|
/** md */ test enter_receive_bad_continuation [[
|
||||||
(7 + 8 >> stream + 9)
|
(7 + 8 >>> + 9)
|
||||||
>> (stream << 9 + 2)
|
>> (<<< 9 + 2)
|
||||||
]] /* **/
|
]] /* **/
|
||||||
parse fails
|
parse fails
|
||||||
|
|
||||||
@ -145,16 +195,17 @@ lines are evaluated in sequence. For example, the program
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test emit_thrice [[
|
/** md */ test emit_thrice [[
|
||||||
stream << 72 + 87
|
<<< 72 + 87
|
||||||
stream << 88
|
<<< 88
|
||||||
+ 96
|
+ 96
|
||||||
99 + 12 >>
|
99 + 12
|
||||||
stream
|
>>>
|
||||||
|
|
||||||
]] /* **/
|
]] /* **/
|
||||||
parse to TopLevel(Sequence([
|
parse to TopLevel(Sequence([
|
||||||
Gets(Stream(), Sum(Int("72"), Int("87"))),
|
DefGets(Sum(Int("72"), Int("87"))),
|
||||||
Gets(Stream(), Sum(Int("88"), Int("96"))),
|
DefGets(Sum(Int("88"), Int("96"))),
|
||||||
Sum(Int("99"), To(Int("12"), Stream()))
|
Sum(Int("99"), DefTo(Int("12")))
|
||||||
]))
|
]))
|
||||||
/** writes
|
/** writes
|
||||||
15918412**/
|
15918412**/
|
||||||
@ -169,10 +220,10 @@ in sequence align at the left; e.g., the following fails to parse:
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test emit_thrice_bad_alignment [[
|
/** md */ test emit_thrice_bad_alignment [[
|
||||||
stream << 72 + 87
|
<<< 72 + 87
|
||||||
stream << 88
|
<<< 88
|
||||||
+ 96
|
+ 96
|
||||||
99 + 12 >> stream
|
99 + 12 >>>
|
||||||
]] /* **/
|
]] /* **/
|
||||||
parse fails
|
parse fails
|
||||||
|
|
||||||
@ -187,23 +238,23 @@ are so terminated. So the following is OK:
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
/** md */ test emit_several [[
|
/** md */ test emit_several [[
|
||||||
stream << 1 + 2; 3 >> stream
|
<<< 1 + 2; 3 >>>
|
||||||
(4 + 5) >> stream; stream << 6;
|
(4 + 5) >>>; stream << 6;
|
||||||
stream << 7
|
<<< 7
|
||||||
stream << 8
|
<<< 8
|
||||||
+ (9+10);
|
+ (9+10);
|
||||||
11 + 12 >> stream; 13 >> stream
|
11 + 12 >>>; 13 >>>
|
||||||
>> stream
|
>>>
|
||||||
]] /* **/
|
]] /* **/
|
||||||
parse to TopLevel(Sequence([
|
parse to TopLevel(Sequence([
|
||||||
ISequence(Prior([Terminate(Gets(Stream(), Sum(Int("1"), Int("2"))))]),
|
ISequence(Prior([Terminate(DefGets(Sum(Int("1"), Int("2"))))]),
|
||||||
To(Int("3"), Stream())),
|
DefTo(Int("3"))),
|
||||||
ISequence(Prior([Terminate(To(Sum(Int("4"), Int("5")), Stream()))]),
|
ISequence(Prior([Terminate(DefTo(Sum(Int("4"), Int("5"))))]),
|
||||||
Terminate(Gets(Stream(), Int("6")))),
|
Terminate(Gets(Stream(), Int("6")))),
|
||||||
Gets(Stream(), Int("7")),
|
DefGets(Int("7")),
|
||||||
Terminate(Gets(Stream(), Sum(Int("8"), Sum(Int("9"), Int("10"))))),
|
Terminate(DefGets(Sum(Int("8"), Sum(Int("9"), Int("10"))))),
|
||||||
ISequence(Prior([Terminate(Sum(Int("11"), To(Int("12"), Stream())))]),
|
ISequence(Prior([Terminate(Sum(Int("11"), DefTo(Int("12"))))]),
|
||||||
To(To(Int("13"), Stream()), Stream()))
|
DefTo(DefTo(Int("13"))))
|
||||||
]))
|
]))
|
||||||
/** writes
|
/** writes
|
||||||
3396727121313**/
|
3396727121313**/
|
||||||
|
Loading…
Reference in New Issue
Block a user