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
|
# One liner comments start with # and go till end of line
#.. Multi-line comments start with #.. and
continue until dedent
# Import files like so:
run file "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
# Dicts:
dict [["x", 99], ["y", 101]]
dict [..]
["z", 222]
[383, "howdy"]
# Function calls:
say "Hello world!"
# Function definition:
rule "say both %first and also %second":
# Variables use the "%" sign:
say %first
say %second
rule "get x from %dict":
#.. Functions can return values explicitly, but if not, the last line in the function
is the return value.
return (%dict's "x")
# 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!" !
# Though literals can't be used in function names
# 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 either ending a line with ".." and continuing with an indented block:
say..
both "Tom" and
also
"Sawyer"
# Or by starting the next line with ".."
say both "Bruce"
..and also "Lee"
# This can be mixed and matched:
say both..
"Rick"
..and also..
"Moranis"
# And 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": return 23
# 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!
#.. There's a few macros in the language for things like conditional branches and logic/math
operations, but they can be thought of as basically the same as functions.
There are no keywords in the language!
if (1 < 10):
say "One is less than ten"
..else:
say "One is not less than ten"
#.. Breakdown of the above:
Function call (actually a macro) to "if % % else %"
First argument is a subexpression that is a function call (also a macro) to "% < %"
that performs a comparison on its arguments, 1 and 10
Second argument is a block of code that includes a function call to "say %", the "if" body
Third argument is a block of code that includes a different function call to "say %", the "else" body
# Line continuations can be used for "elseif"
if (1 > 10):
say "First condition"
..else: if (1 > 5):
say "Second condition"
..else:
say "Last condition"
# ^that's the same as:
if (1 > 10):
say "First condition"
..else:
if (1 > 5):
say "Second condition"
..else:
say "Last condition"
# Variables are modified with a macro, "let % = %"
let "numbers" = [5,6,7]
# Looping:
say ".."|Looping over \%numbers\:
for "number" in %numbers:
say (%number + 100)
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":
return (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.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"
|