fostr/tests/basic.spt

164 lines
4.1 KiB
Cheetah

module basic
language fostr
/** md
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:
```fostr
**/
/** md */ test emit_sum [[
stream << 72 + 87 + 33
]]/* **/ parse to TopLevel(Gets(Stream(),
Sum(Sum(Int("72"), Int("87")), Int("33"))))
/** writes
192**/
/** md
```
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
cloning this fostr project. Then, either:
1. Open the project in Eclipse and build it, visit your program file,
generate code from it in your preferred target language (among
the options available in the "Spoofax > Generate" menu), and execute the
resulting code.
1. Use the `bin/fosgen` bash script to generate code in a target language,
and execute the resulting code.
For example, this snippet generates the following Python:
```python
{! ../tests/emit_sum.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.)
### 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:
```fostr
**/
/** md */ 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
192291**/
/** 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":
```fostr
**/
/** md */ test enters_twice [[
(7 + 8 >> stream + 9) >> stream
]]/* **/ parse to TopLevel(
To(Sum(Sum(Int("7"), To(Int("8"), Stream())), Int("9")), Stream()))
/** writes
824**/
/** md
```
### Layout in fostr
Expressions may be laid out onto multiple lines, as long as all continuation
lines are indented from the start of the initial line:
```fostr
**/
/** md */ test receive_enter_break [[
stream <<
7
+ 8 >> stream
+ 9
]]/* **/ parse to TopLevel(
Gets(Stream(), Sum(Sum(Int("7"), To(Int("8"), Stream())), Int("9"))))
/** writes
824**/
/** md
```
(So for example you will get a parse error with something like this:)
```fostr
**/
/** md */ test enter_receive_bad_break [[
(7 + 8 >> stream + 9)
>> (stream << 9 + 2)
]] /* **/ parse fails
/* Extra tests not in the tour */
test enter_receive [[
(7 + 8 >> stream + 9) >> (stream << 9 + 2)
]]/* **/ parse to TopLevel(
To(Sum(Sum(Int("7"),To(Int("8"),Stream())),Int("9")),
Gets(Stream(),Sum(Int("9"),Int("2")))))
/** writes
81124**/
/** md
```
Of course, fostr programs are not limited to one line; expressions on successive
lines are evaluated in sequence. For example, the program
```fostr
**/
/** md */ test emit_thrice [[
stream << 72 + 87
stream << 88
+ 96
99 + 12 >>
stream
]] /* **/ 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()))]))
/** writes
15918412**/
/** md
```
will write 15918412. fostr enforces that successive expressions in sequence
must line up at the left, i.e., the following will not parse:
```fostr
**/
/** md */ test emit_thrice_bad_alignment [[
stream << 72 + 87
stream << 88
+ 96
99 + 12 >> stream
]] /* **/ parse fails
/** md
```
**/