1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
|
# One liner comments start with # and go till end of line
#.. Multi-line comments start with #.. and
continue until dedent
# Import files like so:
require "lib/core.nom"
# Numbers:
23
4.5
#.. Since this language cross-compiles to lua, integers and floating point numbers are
both represented using the same primitive.
# Strings:
"asdf"
".."|This is a multi-line string
|that starts with ".." and includes each indented line that starts with a "|"
|until the indentation ends
# Lists:
[1,2,3]
[..]
"like multi-line strings, lists have an indented form", "that can use commas too"
"or just newlines to separate items"
5
6,7,8
# Dictionaries (AKA hash maps):
dict [["x", 99], ["y", 101]]
dict [..]
["z", 222]
[383, "howdy"]
# Function calls:
say "Hello world!"
# Variables use the % sign:
%str =: "Hello again"
say %str
# There are +=:, -=:, *=:, /=:, ^=:, and=:, or=:, and mod=: operators for updating variables
%x =: 1
%x +=: 100
say %x
# Conditionals look like this:
if (1 < 10):
say "1 is indeed < 10"
if (1 > 10):
say "this won't print"
..else:
say "this will print"
# For longer conditionals, a "when" branch is the best option
when:
? 1 > 4:
say "this won't print"
? 1 > 3:
say "this won't print"
? 1 > 2:
say "this won't print"
?:
say "this will print"
# When "when" is given an argument, it works like a switch statement
when 3:
== 1:
say "this won't print"
== 2:
say "this won't print"
== 3:
say "this will print"
==:
say "this won't print"
# Loops look like this:
for %x in [1,2,3]:
say ".."|for loop over list #\%x\
# If you want to iterate over a numeric range, you can use some built in functions like this:
for %x in (1 through 3):
say ".."|for loop over number range #\%x\
# While loops:
%x =: 1
repeat while (%x <= 3):
say ".."|repeat while loop #\%x\
%x +=: 1
%x =: 1
repeat until (%x > 3):
say ".."|repeat until loop #\%x\
%x +=: 1
# Infinite loop:
%x =: 1
repeat:
say ".."|repeat loop #\%x\
%x +=: 1
if (%x > 3):
break
# GOTOs:
do:
%x =: 1
-> %again
say ".."|go to loop #\%x\
%x +=: 1
if (%x <= 3):
go to %again
say "finished going to"
# Function definition:
rule [say both %first and also %second] =:
say %first
# Function arguments are accessed just like variables
say %second
# The last line of a function is the return value
rule [add %x and %y] =:
%result =: %x + %y
%result
# Functions can use "return" to return a value early
rule [first fibonacci above %n] =:
%f1 =: 0
%f2 =: 1
repeat:
%tmp =: %f1 + %f2
%f1 =: %f2
%f2 =: %tmp
if (%f2 > %n):
return: %f2
say (first fibonacci above 10)
# Functions can have aliases, which may or may not have the arguments in different order
rule [..]
I hate %worse-things more than %better-things
I think %worse-things are worse than %better-things
I like %better-things more than %worse-things
..=:
say ".."|\%better-things capitalized\ rule and \%worse-things\ drool!
I like "dogs" more than "cats"
I think "chihuahuas" are worse than "corgis"
#.. Function calls can have parts of the function's name spread throughout.
Everything that's not a literal value is treated as part of the function's name
say both "Hello" and also "again!"
# Functions can even have their name at the end:
rule [%what-she-said is what she said] =:
say %what-she-said
say "-- she said"
"Howdy pardner" is what she said
#.. The language only reserves []{}().,:;% as special characters, so functions and variables
can have really funky names!
rule [>> %foo-bar$$$^ --> %@@& _~-^-~_~-^ %1 !] =:
say %foo-bar$$$^
say %@@&
say %1
>> "wow" --> "so flexible!" _~-^-~_~-^ "even numbers can be variables!" !
# Math and logic operations are just treated the same as function calls in the syntax
say (2 + 3)
# So it's easy to define your own operators
rule [%a ++ %b] =:
2 * (%a + %b)
say (2 ++ 3)
#.. Code blocks start with ":" and either continue until the end of the line
or are indented blocks
# One liner:
: say "hi"
# Block version:
:
say "one"
say "two"
#.. So the function definitions above are actually just passing a regular string, like
"say both %first and also %second", and a code block to a function called "rule % %"
that takes two arguments.
# Line continuations work by starting the next line with ".."
say both "Bruce"
..and also "Lee"
# This can be combined with the block forms of literals:
say both ".."
|Four score and seven years ago our fathers brought forth, upon this continent,
|a new nation, conceived in liberty, and dedicated to the proposition that
|"all men are created equal"
..and also "-- Abraham Lincoln"
rule [my favorite number] =: 21 + 2
# Subexpressions are wrapped in parentheses:
say (my favorite number)
# There's a multi-line indented block form for subexpressions too:
say (..)
my favorite
..number
# Block strings can interpolate values by enclosing an expression in a pair of \s
say ".."|My favorite number is \my favorite number\!
say ".."
|My favorite number is still \(..)
my favorite
..number
..\, but this time it uses an indented subexpression!
rule [sing %starting-bottles bottles of beer] =:
for %n in (%starting-bottles down through 0):
say ".."
|\%n if (%n > 0) else "No more"\ \"bottle" if (%n == 1) else "bottles"\ of beer on the wall.
|\"" if (%n == 0) else " Take one down, pass it around..."\
sing 9 bottles of beer
#.. Note that because math and logic operations are just macros, they require a lot
of parentheses to disambiguate. There's no PEMDAS.
say (5 + (4 * (- (1 + (6 + 2)))))
# For convenience, +,*,"and", and "or" have been hand defined to work with up to 4 operands:
1 + 2 + 3 + 4
1 * 2 * 3 * 4
1 and 2 and 3 and 4
1 or 2 or 3 or 4
# Longer lists can use "sum of %", "product of %", "all of %", and "any of %", respectively, or lots of parentheses.
sum of [1,2,3,4,5,6,7]
product of [1,2,3,4,5,6,7]
all of [1,1,1,1,0,1,1]
any of [0,0,0,0,1,0,0]
# And 3-operand chained inequality comparisons have been defined:
1 < 2 <= 3
# Macros:
# The "lua block %" and "lua expr %" macros can be used to write raw lua code:
rule [say the time] =:
lua block ".."
|io.write("The OS time is: ")
|io.write(tostring(os.time()).."\\n")
say the time
say ".."|Math expression result is: \lua expr "(1 + 2*3 + 3*4)^2"\
#.. In the lua environment, "vars" can be used to get local variables/function args, and
"compiler" can be used to access the compiler, function defs, and other things
rule [square root of %n] =:
lua expr "math.sqrt(vars.n)"
say ".."|The square root of 2 is \square root of 2\
# Macros can be defined as functions that take unprocessed syntax trees and return lua code
# "macro block %" is for defining macros that produce blocks of code, not values
macro block [unless %condition %body] =: ".."
|if not (\%condition as lua expr\) then
| \(lua expr "vars.body.value") as lua block\
|end
unless (1 > 10):
say "Macros work!"
say "It looks like a keyword, but there's no magic here!"
# and "macro %" is for defining macros that produce an expression
macro [%value as a boolean] =: ".."
|(not not (\%value as lua expr\))
macro [yep] =: "true"
|