/
jerboa_intro.html
373 lines (282 loc) · 15.3 KB
/
jerboa_intro.html
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>A Whirlwind Introduction to Jerboa</title>
<link rel="stylesheet" href="stylesheets/styles.css">
<link rel="stylesheet" href="stylesheets/pygment_trac.css">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header>
<h1>A Whirlwind Introduction to Jerboa</h1>
<p class="view"><a href="/">back to index</a></p>
</header>
<section>
<h1>The Very Basics</h1>
<p>Integers are a thing. <code>2</code>, <code>3</code>, <code>4</code>, <code>5</code>. Integers are -2^31 to 2^31-1 and wrap.</p>
<p>Floats! <code>2.0</code>, <code>3.0</code>, <code>4.</code>, etc. 32-bit IEEE floats, the regular.</p>
<p>Bools have two values, <code>true</code> and <code>false</code>.</p>
<p>The value <code>null</code> exists. It is the default value.</p>
<p>Comments are done as in C: <code>/*</code> and <code>*/</code> mark a multiline comment, <code>//</code> marks the rest of the line as a comment.</p>
<p>Math is done by infix operators. The operator precedence is:</p>
<table>
<thead>
<tr>
<th>precedence</th>
<th>operator</th>
<th>meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>||</td>
<td>short-circuit or</td>
</tr>
<tr>
<td>1</td>
<td>&&</td>
<td>short-circuit and</td>
</tr>
<tr>
<td>2</td>
<td>< > <= >= == !=</td>
<td>comparisons</td>
</tr>
<tr>
<td>3</td>
<td>+ -</td>
<td>addition, subtraction</td>
</tr>
<tr>
<td>4</td>
<td>* / %</td>
<td>multiplication, division, modulo</td>
</tr>
<tr>
<td>5</td>
<td>|</td>
<td>arithmetic or</td>
</tr>
<tr>
<td>6</td>
<td>&</td>
<td>arithmetic and</td>
</tr>
</tbody>
</table>
<p>Postfix works, prefix doesn't. TODO. Also <code>a += b</code> is the same exactly as <code>a = a + b</code>.</p>
<p>Precedence can be enforced with parens, ie. <code>(2 + 3) * 4</code>. Evaluation is left to right.</p>
<p>Functions are expressions. A function is called with <code>fun(param1, param2, param3)</code>.
This has higher precedence than any infix operation.</p>
<p>Strings are defined using quote marks: <code>"Hello World"</code> or <code>'Hello World'</code>.</p>
<p>The equality operation <code>==</code> may be overloaded - for instance, <code>2 == 2.0</code>, and arrays are equal if all their elements
are equal. For identity comparison, which yields true if two objects are <em>identical</em>, that is the same object,
use the <code>is</code> operator: <code>a is b</code> is true iff <code>a</code> and <code>b</code> are the same object. So for instance, <code>[2] is [2]</code> is false,
because those are two different array objects.</p>
<p>Note: ints, floats and bools with the same value are always the same object.</p>
<h2>Statements</h2>
<p>A Jerboa file consists of a list of statements.</p>
<p>Expressions are statements. When an expression is to be interpreted as a statement, it must be terminated by a semicolon.</p>
<p>A list of statements enclosed in brackets is a statement: <code>{ statement1; statement2; }</code></p>
<p>Branching is done via the <code>if</code> statement, as in</p>
<pre><code>if (condition) statement;
</code></pre>
<p>Optionally, an <code>else</code> branch can be added.</p>
<pre><code>if (condition) statement; else statement;
</code></pre>
<p>While loops and for loops work as in C, analogously.</p>
<pre><code>while (condition) statement;
for (var i = 0; i < 10; i++) {
}
</code></pre>
<p>Loops may be marked using a label:</p>
<pre><code>label:while (condition) statement;
</code></pre>
<p>When marked as such, <code>break</code> and <code>continue</code> can specify the loop to be broken using <code>break label</code> and <code>continue label</code>.</p>
<h2>Truth</h2>
<p>When evaluating a condition, we test a property called "truthiness" to disambiguate it from the boolean <code>true</code> and <code>false</code> values.</p>
<table>
<thead>
<tr>
<th>type</th>
<th>truthiness</th>
</tr>
</thead>
<tbody>
<tr>
<td>null</td>
<td>always false</td>
</tr>
<tr>
<td>bool</td>
<td>true if true, false if false</td>
</tr>
<tr>
<td>int</td>
<td>true if not zero</td>
</tr>
<tr>
<td>float</td>
<td>true if not zero</td>
</tr>
<tr>
<td>object</td>
<td>always true</td>
</tr>
</tbody>
</table>
<p>The "Boolean" operators in Jerboa are a bit unusual. They're short-circuiting, but operate on values, not bools.</p>
<p><code>a || b</code> has the value of <code>a</code> if <code>a</code> is truthy, else <code>b</code>. If <code>a</code> is truthy, <code>b</code> is not evaluated.</p>
<p><code>a && b</code> has the value of <code>b</code> if <code>a</code> is truthy, else <code>a</code>. If <code>a</code> is falsy, <code>b</code> is not evaluated.</p>
<p>Boolean logic falls out of this as a special case.</p>
<h1>Variables</h1>
<p>Variables must be declared before they can be used. To declare a variable, simply write <code>var identifier;</code>.
The variable will start out with the value <code>null</code>. To initialize the variable, write <code>var identifier = value;</code>.
To assign a value to a variable later, write <code>identifier = value;</code>. You can declare multiple variables at once
by separating them with commas: <code>var a = 2, b = 3;</code>. Variables are scoped to the current block.</p>
<p>If you declare a variable with <code>const identifier</code> instead of <code>var identifier</code>, its immediate value cannot be changed.</p>
<p>Variable lookup proceeds lexically.</p>
<p><strong>Note</strong>: Variable declarations are expressions. That means they can be used like this:</p>
<pre><code>if (var foo = someFunction()) { print(foo); }
</code></pre>
<h1>Objects</h1>
<p>An object is something that contains a bunch of name-value pairs, called "properties", with each name being unique, as well as a "prototype" or "parent"
which is another object, which may have its own prototype and so on until you reach an object whose prototype is <code>null</code>.</p>
<p>An object is made using an "object literal":</p>
<pre><code>var object = {
a = 5;
b = 6;
};
</code></pre>
<p>Note the use of "=" as opposed to ":" in Javascript.</p>
<p>The values of the properties can be accessed with <code>object.a</code>. If a property is not found, the object's prototype will
be searched, and then its prototype and so on. Accessing a missing property is an error. To check if a property can be
accessed, you can use <code>"a" in object</code>, which will be true if <code>object.a</code> succeeds. Accessing a property this way is called
"access as object".</p>
<p>To define a new object whose prototype is another object, use <code>new</code>:</p>
<pre><code>var child = new object {
c = 5;
}
print(child.a); // still works and prints 5 because a is in prototype
child.a = 8;
</code></pre>
<p>When you do not want to set any further properties, this works as a shortcut: <code>var child = new object;</code>.</p>
<p><strong>Important</strong>: assigning a value to a property will always set it in the <em>actual object</em>, even
if the value exists in a prototype.</p>
<p><strong>Also important</strong>: assigning a property that is not in the object yet at all, is an <strong>error</strong>. Defining new properties should
only be done by defining a new object with the old one as prototype. In case this cannot done, you can use the index operator.</p>
<p>An array is formed by using the an array literal:</p>
<pre><code>var array = [2, 25, 254, 2573];
</code></pre>
<p>Array values are accessed via the index operator: <code>array[2] == 254</code>, <code>array[3] = -7</code>. Indexes are 0-based. Accessing past the
end of the array is an error.</p>
<p>Properties can <em>also</em> be accessed via the index operator: <code>object["a"]</code>. This syntax allows you to use properties that cannot
be identifiers. It works otherwise exactly the same as object access. The difference lies in assignment: while <code>object.a</code> will
error if the identifier is not yet in the prototype hierarchy, <code>object["a"] = 5;</code> will happily define <code>a</code> as a property of <code>object</code>.
This is called "access as array".</p>
<h1>Functions</h1>
<p>Functions are expressions with the following syntax: <code>function(parameterlist) statement;</code>.</p>
<p>When assigned to a variable, like <code>var fn = function(a) { };</code>, the following equivalent syntax should be used:</p>
<pre><code>function fn(a) { }
</code></pre>
<p>The variable will be constant. A terminating semicolon is not required.</p>
<p>When <code>method</code> is used instead of <code>function</code> (as in, <code>method(a) { }</code>), the object that the method is called on is passed in
as an implicit parameter called <code>this</code>. That is, if the method is called like <code>object.method(5)</code>, then <code>this</code> is set to <code>object</code> inside
the method.</p>
<p>Code inside a function may access variables declared outside it, even if the surrounding function has already returned. These variables
will have the values that they had when their containing block ended.</p>
<h1>Type constraints</h1>
<p>Variables and object properties can be "[proto]type constrained" using the following syntax:</p>
<pre><code>var a: int = 5
var obj = {
a: int = 6;
};
</code></pre>
<p>When constrained, assigning a value with a different prototype to the variable will cause a runtime error.</p>
<h1>Other stuff</h1>
<p>Since every value is an object, the infix math shown earlier are simply properties of the "int" prototype. That is, <code>2*3+4</code>
is the same as <code>2["*"](3)["+"](4)</code>.</p>
<p>Use <code>instanceof</code> to check if an object has another object as a prototype. To check types of values, simply use
<code>val instanceof int</code>, <code>float</code> or <code>bool</code>.</p>
<p>Most operations will error if their arguments are missing. To avoid if-heavy code,
use the "conditional access" operators: <code>a?.b</code>, which is null if <code>a</code> is null or <code>b</code> is not in it, <code>a?[b]</code> likewise, and <code>a?()</code>, which
is null if <code>a</code> is null and calls it otherwise. When a condition fails, the rest of the "property expression" - ie. any chain
of <code>a.b</code>, <code>a[b]</code> and <code>a(b)</code> - is not evaluated.</p>
<p>Objects may be marked as "frozen" using <code>Object.freeze(object)</code>. In this state, values of keys in the object may no
longer be modified through any means.</p>
<p>Objects may be marked as "closed" using <code>Object.close(object)</code>. In this state,
no new keys may be added to the object.</p>
<p>These states are occasionally useful for optimization. For instance, accesses to a const frozen object
may be replaced with their values.</p>
<p>Fun trivia: Ints aren't <em>really</em> objects internally, but they act like closed frozen objects for all intents and purposes.</p>
<h1>Source file management</h1>
<p>To import other files, use the function <code>require(filename)</code>. <code>require(filename)</code> executes the given file,
using a search path of <code>/usr/share/jerboa</code>, <code>$HOME/.local/share/jerboa</code> (more specifically,
<a href="https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">following the XDG spec</a>),
and then the current directory; it then returns all variables defined in the toplevel as an object.
Multiple calls to <code>require</code> for the same file will result in the same object being returned.</p>
<p><strong>Note</strong>: when importing libraries, such as <code>var gl = require('c/opengl.jb')</code>, it is strongly recommended to make the
module variable <code>const</code>, as in <code>const gl = require('c/opengl.jb')</code>. Doing so allows calls to imported functions
to be more effectively optimized.</p>
<h1>Standard Functions and Objects</h1>
<ul>
<li><code>int</code>: prototype of integer values, used for instanceof tests and constraints
<ul>
<li><code>int.parse()</code> parse string as int</li>
</ul></li>
<li><code>float</code>: prototype of floating point values
<ul>
<li><code>float.toInt()</code> to cast to int</li>
</ul></li>
<li><code>bool</code>: prototype of boolean values</li>
<li><code>function</code>: prototype of function expressions
<ul>
<li><code>function.apply(this, array)</code>: call a function, with <code>array</code> used for arguments</li>
<li><code>function.call(this, arg, arg, arg)</code>: call a function, with <code>arg</code> used for arguments</li>
</ul></li>
<li><code>string</code>
<ul>
<li>prototype of strings</li>
<li><code>string["+"]</code>: string concatenation is implemented with the addition operator</li>
<li><code>string.startsWith(fragment)</code>: returns the rest of the string if it starts with <code>fragment</code>, null otherwise</li>
<li><code>string.endsWith(fragment)</code>: returns the front of the string if it ends with <code>fragment</code>, null otherwise</li>
<li><code>string.slice(from, to)</code>: return a substring from <code>from</code> to <code>to</code>, 0-based</li>
<li><code>string.find(marker)</code>: return the offset into the string where <code>marker</code> was found, or <code>-1</code> otherwise</li>
<li><code>string.replace(marker, replacement)</code>: replace <code>marker</code> with <code>replacement</code> in string</li>
</ul></li>
<li><code>require(filename)</code>: execute <code>filename</code>, then return the defined variables as an object.</li>
<li><code>print(arg, arg, arg)</code>: print given values to stdout in an appropriate format. Useful for debugging.</li>
<li><code>assert(condition, message)</code>: aborts with <code>message</code> if <code>condition</code> is falsy.</li>
<li><code>Math</code>: maths functions
<ul>
<li><code>Math.sin(x)</code>: sine function, domain of 0..2π</li>
<li><code>Math.cos(x)</code>: cosine function, domain of 0..2π</li>
<li><code>Math.tan(x)</code>: tangent function, domain of -π/2..π/2</li>
<li><code>Math.log(x)</code>: natural logarithm</li>
<li><code>Math.sqrt(x)</code>: square root</li>
<li><code>Math.pow(base, exp)</code>: exponentiation function</li>
<li><code>Math.max(arg, ...)</code>: the maximum of its arguments</li>
<li><code>Math.min(arg, ...)</code>: the minimum of its arguments</li>
</ul></li>
<li><code>Object</code>: <strong>Not</strong> the prototype of all objects; merely a collection of useful object-management functions
<ul>
<li><code>Object.keys(obj)</code>: returns an array of all (string) keys in the object. Array keys are not returned.</li>
<li><code>Object.freeze(obj)</code>: <em>freezes</em> the object, preventing all future changes of defined values</li>
<li><code>Object.close(obj)</code>: <em>closes</em> the object, preventing all future definitions of new values</li>
</ul></li>
</ul>
</section>
<footer>
<p><small>Hosted on GitHub Pages — Theme by <a href="https://github.com/orderedlist">orderedlist</a></small></p>
</footer>
</div>
<script src="javascripts/scale.fix.js"></script>
</body>
</html>