forked from ckknight/gorillascript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1503 lines (1136 loc) · 62.7 KB
/
index.html
File metadata and controls
1503 lines (1136 loc) · 62.7 KB
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
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title>GorillaScript</title>
<link rel="stylesheet" href="extras/style.css" />
</head>
<body>
<nav id="top-nav">
<ul>
<li><a href="#try" id="try-link">Try it out</a>
<li><a href="#toc">Table of contents</a>
<li class="right"><a href="http://github.com/ckknight/gorillascript">Fork on Github</a>
</ul>
</nav>
<nav id="toc">
<ul>
<li><a href="#why-not-js">Why not use JavaScript?</a>
<li><a href="#strict-equality">Strict vs unstrict equality</a>
<li><a href="#addition">The <code>+</code> operator (and <code>+=</code>)</a>
<li><a href="#strict-mode-by-default">Strict mode by default</a>
<li><a href="#type-safety-of-operators">Type safety of operators</a>
<li><a href="#immutable-by-default">Immutable by default</a>
<li><a href="#indentation">Indentation to mark code blocks</a>
<li><a href="#changed-operators">Changed operators</a>
<li><a href="#function-syntax">Slightly nicer function syntax</a>
<li><a href="#string-interpolation">String interpolation</a>
<li><a href="#optional-parameters">Optional parameters</a>
<li><a href="#spread-parameters">Spread parameters</a>
<li><a href="#dashed-identifiers">Dashed-identifiers</a>
<li><a href="#numbers">Nicer number syntax</a>
<li><a href="#strings">Some new string syntaxes</a>
<li><a href="#objects-and-arrays">Nicer syntaxes for objects and arrays</a>
<li><a href="#maps-and-sets">First-class support for Maps and Sets</a>
<li><a href="#unless">Unless statement</a>
<li><a href="#loops">Loops</a>
<li><a href="#lexical-scope">Lexical scoping in loops</a>
<li><a href="#array-slicing">Array slicing</a>
<li><a href="#array-negative-index">Array negative indexing</a>
<li><a href="#expressions">Everything is an expression (mostly)</a>
<li><a href="#existential">Existential operator</a>
<li><a href="#in"><code>in</code> operator</a>
<li><a href="#haskey-ownskey"><code>haskey</code> and <code>ownskey</code></a>
<li><a href="#ownership">Access with ownership</a>
<li><a href="#apply">Apply syntax</a>
<li><a href="#bind">Binding access</a>
<li><a href="#classes">Classes</a>
<li><a href="#destructuring">Destructuring</a>
<li><a href="#switch">Switch</a>
<li><a href="#try-catch">Try-catch-else-finally</a>
<li><a href="#regexes">Regular Expressions</a>
<li><a href="#custom-interpolation">Custom interpolation strings</a>
<li><a href="#iterators">Iterators</a>
<li><a href="#async">Async</a>
<li><a href="#typing">Optional typing</a>
<li><a href="#operators-as-functions">Operators, accesses, and method calls as functions</a>
<li><a href="#properties">Getters and setters</a>
<li><a href="#labels">Labels and <code>break</code>/<code>continue</code></a>
<li><a href="#global">The <code>GLOBAL</code> identifier</a>
<li><a href="#curry">Curried functions</a>
<li><a href="#generic">Generics</a>
<li><a href="#gnome">GNOME bindings</a>
</ul>
</nav>
<div id="try">
<textarea id="try-input">alert "Hello, GorillaScript!"</textarea>
<textarea id="try-output" readonly></textarea>
</div>
<div id="container">
<h1>GorillaScript</h1>
<p>GorillaScript is a compile-to-JavaScript language designed to empower the user while attempting to prevent some common errors.</p>
<section id="why-not-js">
<h2>Why not use JavaScript?</h2>
<p>JavaScript has a lot of warts in the language and while the ECMAScript community is doing a good job with its upcoming revisions, it’s still left with a lot of the old cruft. Also, for those who want to code for older browsers, all the shiny new features that the newer versions of ECMAScript provide are for all intents and purposes unreachable.</p>
</section>
<section id="strict-equality">
<h2>Strict vs unstrict equality</h2>
<p><code>==</code> and <code>!=</code> perform type coercion behind the scenes and can be the cause of some subtle bugs.</p>
<pre class="js-code"><code>// JavaScript, all the following are true
1 == "1"
0 != ""
3 == "03"
[] == ""
[] == 0
[] == ![]
[] == false
null != false
null == undefined
</code></pre>
<p>These could all be fixed by adding an extra equal sign, but GorillaScript makes <code>==</code> and <code>!=</code> strict by default. If one really wants the unstrict equality operators, one can use <code>~=</code> and <code>!~=</code>, but it is not recommended except for comparing against null or undefined, which has the nice postfix operator <code>?</code>.</p>
</section>
<section id="addition">
<h2>The <code>+</code> operator (and <code>+=</code>)</h2>
<p><code>+</code> can mean one of two things in JavaScript, addition or string concatenation. There is no way to know at compile-time what the consequences of using <code>+</code> is unless one is 100% certain what each type is.</p>
<pre class="js-code"><code>x + y
</code></pre>
<p>Is addition unless both <code>x</code> and <code>y</code> are numbers, booleans, undefined, or null, with any mixed variation. If either is not one of those, at which point it performs string concatenation.</p>
<pre class="js-code"><code>// JavaScript
1 + 2 === 3 // as expected
"hello, " + "world" === "hello, world" // as expected
"hello, " + 123 === "hello, 123" // sure, I can accept this
"1" + 2 === "12"
1 + "2" === "12"
// and for some oddities
false + false === 0
false + true === 1
true + true === 2
null + null === 0
isNaN(undefined + undefined)
[] + [] === ""
{} + {} === "[object Object][object Object]"
true + [] === "true"
new Date() + 1 === "Tue Jan 29 2013 20:25:58 GMT-0800 (PST)1" // or something like it
new Date() - 1 === 1359519958072 // or some other number
var foo = {
toString: function () { return 5; }
valueOf: function () { return "foo"; }
};
foo.toString() + 1 === 6
foo + 1 === "foo1"
</code></pre>
<p>GorillaScript solves this by splitting the operator into two: <code>+</code> for addition and <code>&</code> for string concatenation.</p>
<pre class="gs-code no-convert"><code>// GorillaScript
1 + 2 == 3
"hello, " & "world" == "hello, world"
"hello, " & 123 == "hello, 123" // concatenation with numbers still works perfectly fine
1 & 2 == "12" // despite both being numbers, & always makes a string.
1 + "2" // TypeError
"1" + 2 // TypeError
"1" + "2" // TypeError
false + false // TypeError
null + null // TypeError
void + void // TypeError
[] + [] // TypeError
{} + {} // TypeError
new Date() + 1 // TypeError
new Date().getTime() + 1 == 1359519958072 // or some other number
</code></pre>
<p>As can be seen, the operators which don’t fit the proper types exactly fail immediately, allowing one to catch bugs as early as possible rather than allowing them to permeate through one’s programs.</p>
<p>Don’t be worried about losing the bitwise and operator, that is now called <code>bitand</code>.</p>
</section>
<section id="strict-mode-by-default">
<h2>Strict mode by default</h2>
<p>All GorillaScript code is wrapped in an immediately-invoked function expression (IIFE) which has the declaration of <code>"use strict"</code>. This ensures that on the engines that support it, strict semantics will be followed, meaning less bugs in the long run.</p>
</section>
<section id="type-safety-of-operators">
<h2>Type safety of operators</h2>
<p>All operators check the types of their operands to assure that there will be no improper inputs and that any errors that do occur are caught as early as possible.</p>
<ul>
<li><code>==</code> and <code>!=</code> do not check the types, since they are already strict by default (in GorillaScript).</li>
<li><code><</code>, <code>></code>, <code><=</code>, <code>>=</code> are restricted to primitive <code>String</code>s and <code>Number</code>s, but never mixing the two.</li>
<li><code>+</code> only works on primitive <code>Number</code>s.</li>
<li><code>&</code>, the new string concatenation operator, works on primitive <code>String</code>s and <code>Number</code>s.</li>
<li><code>-</code>, <code>*</code>, <code>/</code>, <code>\</code> (floor division), <code>%</code>, <code>%%</code> (divisible-by), <code>^</code> (exponentiation, not bitwise xor), <code>bitand</code> (instead of <code>&</code>), <code>bitor</code> (instead of <code>|</code>), <code>bitxor</code> (instead of <code>^</code>), <code>bitnot</code> (instead of <code>~</code>), <code>bitlshift</code> (instead of <code><<</code>), <code>bitrshift</code> (instead of <code>>></code>), <code>biturshift</code> (instead of <code>>>></code>), <code>-</code> (unary negate), <code>+</code> (unary coerce-to-number), and all their respective assignment operators (<code>-=</code>, <code>+=</code>, etc.) all only work on primitive <code>Number</code>s.</li>
</ul>
<p>No other operators’ types are checked.</p>
<p>If one really wishes to work in an environment where the operands’ types are not checked, one can always prepend the operator with <code>~</code>, so there is a <code>~*</code> operator which performs multiplication without checking. It is recommended to instead parse input data into conforming types before performing operations on them.</p>
<p>Thankfully, GorillaScript is able to tell which types most values are, so in the general case, there should be little to no runtime type checking occurring.</p>
</section>
<section id="immutable-by-default">
<h2>Immutable by default</h2>
<p>GorillaScript uses two separate tokens for declaration as compared to assignment. Also, instead of JavaScript’s <code>var</code> keyword, GorillaScript uses <code>let</code>. Unless one specifies <code>let mutable</code>, the local constant cannot be reset to any other value. The object in the value can still be mutated (assuming it is mutable). This can prevent some errors and often helps with the clarity of one’s code.</p>
<p>Also, no undeclared variables can be altered, preventing unexpected global pollution (and typos).</p>
<pre class="gs-code no-convert"><code>let x = 5
x := 6 // Error
let mutable y = 5
y := 6 // perfectly fine
z := 6 // never declared, this is an error
</code></pre>
<p>As you may have noticed, there are two different operators for declaration <code>=</code> as compared to assignment <code>:=</code>. This is to clarify the difference. In an ideal program, having as little mutable state as possible is best, so if <code>:=</code> jumps out, that’s a good thing.</p>
</section>
<section id="indentation">
<h2>Indentation to mark code blocks</h2>
<p>Instead of using braces to dictate code blocks, GorillaScript opts for whitespace indentation as a way to mark blocks. Although this may be jarring at first and one may be skeptical, any good programmer properly indents his or her code to have a consistent whitespace anyway. GorillaScript does not dictate how many spaces or tabs are used, as long as it is consistent within any given block.</p>
<pre class="gs-code"><code>if hello
if loudly
"HELLO!"
else
"hi"
else
"Goodbye."
</code></pre>
<p>You may have also noticed the lack of semicolons. The parser is able to tell when the end of a statement is without them, so they are unnecessary.</p>
</section>
<section id="changed-operators">
<h2>Changed operators</h2>
<p>Many of the operators have changed to provide more clarity or to free up the usage of certain symbols.</p>
<ul>
<li><code>===</code> - <code>==</code></li>
<li><code>!==</code> - <code>!=</code></li>
<li><code>==</code> - <code>~=</code></li>
<li><code>!=</code> - <code>!~=</code></li>
<li><code>!x</code> - <code>not x</code></li>
<li><code>+</code> - <code>+</code> for addition, <code>&</code> for string concatenation, type-checked</li>
<li><code>&</code> - <code>bitand</code>, type-checked</li>
<li><code>|</code> - <code>bitor</code>, type-checked</li>
<li><code>^</code> - <code>bitxor</code>, type-checked</li>
<li><code>~x</code> - <code>bitnot x</code>, type-checked</li>
<li><code><<</code> - <code>bitlshift</code>, type-checked</li>
<li><code>>></code> - <code>bitrshift</code>, type-checked</li>
<li><code>>>></code> - <code>biturshift</code>, type-checked</li>
<li><code>--x</code> - <code>x -= 1</code>, type-checked</li>
<li><code>++x</code> - <code>x += 1</code>, type-checked</li>
<li><code>x--</code> - <code>post-dec! x</code>, not recommended except for advanced cases</li>
<li><code>x++</code> - <code>post-inc! x</code>, not recommended except for advanced cases</li>
<li><code>&&</code> - <code>and</code></li>
<li><code>||</code> - <code>or</code>, can no longer be used with <code>and</code> unless one group is in parentheses.</li>
<li><code>x ? y : z</code> - <code>if x then y else z</code></li>
<li><code>key in obj</code> - <code>obj haskey key</code>, reversed arguments. Can use <code>not haskey</code></li>
<li><code>obj instanceof constructor</code> - Can also use <code>not instanceof</code></li>
<li><code>delete x.y</code> - Returns the value of <code>x.y</code> as well as deleting. Does not work on global variables anymore, use <code>delete GLOBAL.x</code></li>
</ul>
<p>Kept the same:</p>
<ul>
<li><code><</code> - type-checked</li>
<li><code><=</code> - type-checked</li>
<li><code>></code> - type-checked</li>
<li><code>>=</code> - type-checked</li>
<li><code>-</code> - type-checked</li>
<li><code>*</code> - type-checked</li>
<li><code>/</code> - type-checked</li>
<li><code>%</code> - type-checked</li>
<li><code>-x</code> - type-checked</li>
<li><code>+x</code> - type-checked</li>
<li><code>x[y]</code></li>
<li><code>typeof x</code></li>
<li><code>throw x</code> - Can now be used as an expression</li>
</ul>
<p>Added:</p>
<ul>
<li><code>typeof! x</code> - displays the constructor name of the object, <code>typeof! {} == "Object"</code>, <code>typeof! [] == "Array"</code></li>
<li><code>throw? x</code> - Only throws <code>x</code> if <code>x</code> is not null or undefined.</li>
<li><code>x ^ y</code> - Same as <code>Math.pow(x, y)</code></li>
<li><code>x \ y</code> - Same as <code>Math.floor(x / y)</code></li>
<li><code>xor</code> - For logical completeness with <code>and</code> and <code>or</code></li>
<li><code>x and= y</code> - Same as <code>if x then x := y</code></li>
<li><code>x or= y</code> - Same as <code>if not x then x := y</code></li>
<li><code>x in y</code> - Does <code>x</code> exist in array <code>y</code>. Can use <code>not in</code>. Highly efficient if <code>y</code> is a literal array.</li>
<li><code>x ownskey y</code> - Does <code>x</code> own the property named <code>y</code>. Can use <code>not ownskey</code></li>
<li><code>x <=> y</code> - if x == y, 0. if x < y, -1. otherwise, 1.</li>
<li><code>x %% y</code> - Is x divisible by <code>y</code>? Same as <code>x % y == 0</code>.</li>
<li><code>x min y</code> - Choose the lower number or lexicographically lesser string</li>
<li><code>x min= y</code> - If <code>y</code> is less than <code>x</code>, set <code>x</code> to <code>y</code>.</li>
<li><code>x max y</code> - Choose the higher number or lexicographically greater string</li>
<li><code>x max= y</code> - If <code>y</code> is greater than <code>x</code>, set <code>x</code> to <code>y</code>.</li>
<li><code>x?</code> - Is <code>x</code> <code>null</code> or <code>undefined</code>?</li>
<li><code>x ? y</code> - If <code>x</code> is <code>null</code> or <code>undefined</code>, then <code>y</code>, otherwise keep the value of <code>x</code>. <code>y</code> may not be executed.</li>
<li><code>x ?= y</code> - If <code>x</code> is <code>null</code> or <code>undefined</code>, then set <code>x</code> to <code>y</code>. <code>y</code> may not be executed.</li>
<li><code>is-array! x</code> - True if <code>x</code> is an Array (and not just an Array-like object). Works on arrays from a different context.</li>
<li><code>is-object! x</code> - True if <code>x</code> is an Object and not null. Works on objects from a different context.</li>
<li><code>x to y</code> - Create an array from <code>x</code> to inclusive <code>y</code>.</li>
<li><code>x til y</code> - Create an array from <code>x</code> until exclusive <code>y</code>.</li>
<li><code>array by step</code> - Take every <code>step</code>th value from the array. If <code>step</code> is less than 0, go in reverse.</li>
<li><code>x to y by step</code> - Create an array from <code>x</code> to inclusive <code>y</code>, stepping by <code>step</code>.</li>
<li><code>x til y by step</code> - Create an array from <code>x</code> until exclusive <code>y</code>, stepping by <code>step</code>.</li>
<li><code>x instanceofsome y</code> - Iterate over array and check with <code>instanceof</code>. Highly efficient if <code>y</code> is a literal array.</li>
<li><code>x is y</code> - Works like the ECMAScript6 Object.is, which is like GorillaScript’s <code>==</code>, but differentiating between <code>0</code> and <code>-0</code> and properly comparing <code>NaN is NaN</code>. Not recommended to use unless you know you’re working with numbers.</li>
<li><code>x isnt y</code> - Same as <code>not (x is y)</code></li>
<li><code>x << y</code> - Compose <code>x</code> and <code>y</code>, like <code>#(...args) -> x(y(...args))</code></li>
<li><code>x >> y</code> - Compose <code>y</code> and <code>x</code>, like <code>#(...args) -> y(x(...args))</code></li>
<li><code>x |> f</code> - Pipe <code>x</code> into <code>f</code>, like <code>f(x)</code></li>
<li><code>f <| x</code> - Pipe <code>x</code> into <code>f</code>, like <code>f(x)</code></li>
<li><code>x <<< y</code> - Import all properties from <code>y</code> into <code>x</code>, like <code>for k, v of y; x[k] := v</code></li>
<li><code>x >>> y</code> - Import all properties from <code>x</code> into <code>y</code>, like <code>for k, v of x; y[k] := v</code></li>
</ul>
</section>
<section id="function-syntax">
<h2>Slightly nicer function syntax</h2>
<p>There are two ways to specify functions, one directly using <code>let</code>, and one as an anonymous function. Also, unlike JavaScript, the last expression is automatically returned (unless tagging the function with <code>!</code>). Functions can be called optionally without parentheses, as long as it is unambiguous.</p>
<pre class="gs-code"><code>let increment(x)
x + 1
assert increment(0) == 1
assert (increment 1) == 2
assert 3 == increment 2
let run(callback)
callback()
assert run(#-> "hello") == "hello"
assert (run #-> "there") == "there"
assert run(#
"you") == "you"
assert run(#
let x = "guys"
"good " & x) == "good guys"
// this syntax also works
let f() -> Math.random()
console.log f()
</code></pre>
<p>The outer <code>this</code> can also be captured be appending <code>@</code> to the head of the function declaration, creating a “bound” function. This is similar to ECMAScript 5’s <code>Function.prototype.bind</code>, but more efficient since a hidden <code>_this</code> variable is used rather than an extra function call.</p>
<pre class="gs-code"><code>let func()
let inner()@
this
assert func() == this
</code></pre>
</section>
<section id="string-interpolation">
<h2>String interpolation</h2>
<p>Inside double-quoted strings <code>("like this")</code>, not single-quoted strings <code>('like this')</code>, one can specify string interpolations using the <code>$</code> symbol, followed by an identifier or a parenthetical expression.</p>
<pre class="gs-code"><code>let hello(name)
"Hello, $name"
assert hello("World") == "Hello, World"
assert hello("Universe") == "Hello, Universe"
// or
let greet(names)
"Hello, $(names.join ', ')"
assert greet(["World", "Universe"]) == "Hello, World, Universe"
</code></pre>
</section>
<section id="optional-parameters">
<h2>Optional parameters</h2>
<p>To specify an optional parameter, one simply need to specify <code>= value</code> in the function parameter list.</p>
<pre class="gs-code"><code>let hello(name = "World")
"Hello, $name"
assert hello() == "Hello, World"
assert hello("Universe") == "Hello, Universe"
</code></pre>
<p>If a value is passed in that is null or undefined, it will be automatically turned into the default value.</p>
</section>
<section id="spread-parameters">
<h2>Spread parameters</h2>
<p>Instead of using JavaScript’s atrociously broken <code>arguments</code> special, one can specify a spread parameter by prefixing <code>...</code>. Only one can occur in a function parameter list, but it can be at any position.</p>
<pre class="gs-code"><code>let hello(...names)
if names.length == 0
"No one is here"
else
"Hello, $(names.join ', ')"
hello() == "No one is here"
hello("World") == "Hello, World"
hello("World", "Universe") == "Hello, World, Universe"
</code></pre>
<p>And so that callers don’t feel bad about themselves, you can call with spread as well.</p>
<pre class="gs-code"><code>let f(a, b, c) -> [a, b, c]
let items = [1, 2]
f(0, ...f(...items, 3), 4)
</code></pre>
</section>
<section id="dashed-identifiers">
<h2>Dashed-identifiers</h2>
<p>Although completely optional to use if you prefer using <code>camelScript</code>-style identifiers, one can now specify identifiers with dashes, such as <code>my-name</code> or <code>gorillas-are-awesome</code>. They are turned into <code>myName</code> and <code>gorillasAreAwesome</code>, respectively.</p>
<pre class="gs-code"><code>let gorillas-are-awesome = "Yes, they are."
</code></pre>
</section>
<section id="numbers">
<h2>Nicer number syntax</h2>
<p>All numbers can have arbitrary underscores in the middle of them, which can be used for thousands separators or bitwise n-bit separators. (<code>1_234_567</code> or <code>0x1234_5678_90ab_cdef</code>)</p>
<p>Decimal numbers can have inline-comments appended to them after an underscore. (<code>1000_ms</code>)</p>
<p>Octals use the format <code>0o12345670</code> instead of <code>01234567</code>, to help with clarity.</p>
<p>Binary numbers are available with the format <code>0b10101010</code>.</p>
<p>Arbitrary-radix numbers are available by specifying a decimal number between 2 and 36, <code>r</code>, and the number. (<code>4r01230123</code>, <code>36rjdhremn</code>)</p>
<pre class="gs-code"><code>let time = 10_000_ms
let hex = 0x1234_5678
let octal = 0o070
let binary = 0b1010010101
let radix = 36rNFfdH45
let float = 123_456.789_012
</code></pre>
<p>Non-decimals do support floating point unlike JavaScript, though that is a lesser-used feature.</p>
</section>
<section id="strings">
<h2>Some new string syntaxes</h2>
<p>Aside from the already-seen string interpolation, there are also triple-quoted strings, which allow for multi-line and are indentation-friendly.</p>
<pre class="gs-code"><code>let name = "Jimmy"
let string = """
Hello there.
I have a story to tell you, $name.
I can't think of it right now, though.
"""
</code></pre>
<p>The indentation is stripped (but not line 2’s, since that's deliberate), and interpolation is done for <code>$name</code>, and the first and last newlines are removed. This all occurs at compile-time, so your result code will be as fast as possible.</p>
<p>There are also string like <code>'''this'''</code> which do not have interpolation, if you wish to use it.</p>
<p>There is also a short syntax for single-word strings that also convert <code>dashed-names</code> to <code>camelCase</code> just as normal identifiers do.</p>
<pre class="gs-code"><code>assert "Jimmy" == \Jimmy
assert object.some-key == object[\some-key]
assert "someKey" == \some-key
</code></pre>
<p>GorillaScript includes all the escape sequences you may be familiar with in JavaScript, such as <code>\0</code>, <code>\t</code>, <code>\v</code>, and many more. You needn’t worry about some non-standard escape codes such as <code>\v</code>, as GorillaScript compiles to the lowest common denominator.</p>
<p>It also includes the <code>\u</code> unicode escape sequence which takes 4 hex characters trailing it and <code>\x</code> which takes 2 hex characters trailing it.</p>
<p>Unlike JavaScript, GorillaScript can properly handle unicode code points greater than <code>0xFFFF</code>, by having the <code>\u{}</code> syntax. Inside the braces, one can put between 1 and 6 hex characters as long as the representation doesn't exceed <code>0x10FFFF</code>. This will be split up into two UTF-16 code points if exceeding <code>0xFFFF</code>.</p>
<pre class="gs-code"><code>let escapes = "\b\f\r\n\t\v\0\1\2\3\4\5\6\7"
let hex = "\xe9"
let unicode = "\u1d25"
let large-unicode = "\u{20bb7}"
</code></pre>
</section>
<section id="objects-and-arrays">
<h2>Nicer syntaxes for objects and arrays</h2>
<p>Although the standard JavaScript-style syntaxes work, there are a few other ways to specify objects and arrays.</p>
<pre class="gs-code"><code>let list = [1, 2, 3]
let other-list = [...list, 4, 5, 6] // now contains [1, 2, 3, 4, 5, 6]
// another way to specify an array
let items =
* "Apples"
* "Bananas"
* "Cherries"
let obj = {
list // same as list: list
sum: 6
f() -> "result" // same as f: #() -> "result"
}
let great-apes =
bonobos:
awesomeness: "pretty cool"
population: 40_000
humans:
awesomeness: "let's not say anything bad about these guys"
population: 7_000_000_000
gorillas:
awesomeness: "clearly the best"
population: 100_000
let special = {
[1 + 2]: "three"
"key$i": "interpolated key"
class: "JavaScript would fail on the 'class' key."
}
</code></pre>
<p>To specify the prototype of an object:</p>
<pre class="gs-code"><code>let parent = { hello: \there }
let child = { extends parent
value: 1
}
assert child.hello == \there
assert child.value == 1
</code></pre>
</section>
<section id="maps-and-sets">
<h2>First-class support for Maps and Sets</h2>
<p><code>Map</code> and <code>Set</code> are available in the upcoming ECMAScript 6 and in some existing JavaScript engines. There are also shims to provide support in engines that do not support it out-of-the-box.</p>
<p>GorillaScript will automatically provide a shim if used, but it is recommended to use either a native implementation or a more-efficient shim.</p>
<p><code>Map</code> is similar to <code>Object</code>, except its keys are not required to be <code>String</code>s, but can be any type. Also, access and assignment is done through method calls rather than raw dot-access.</p>
<p><code>Set</code> is a collection of unique values, similar to a <code>Map</code> where all values are <code>true</code>.</p>
<p>GorillaScript has syntax for declaring both of these as literals, just as one can do with <code>Array</code>s or <code>Object</code>s.</p>
<pre class="gs-code"><code>let obj = {}
let other = {}
let map = %{
[obj]: 1
[other]: "hello"
}
assert map.get(obj) == 1
assert map.get(other) == "hello"
map.delete other
assert map.has obj
assert not map.has other
map.set other, "there"
assert map.has other
assert map.get(other) == "there"
let set = %[obj, other]
assert set.has(obj)
assert set.has(other)
set.delete(other)
assert not set.has(other)
set.add other
assert set.has(other)
set.add other // does nothing, already in the set.
</code></pre>
</section>
<section id="unless">
<h2>Unless statement</h2>
<p>To correlate with the <code>if</code> statement, there is also an <code>unless</code> statement which works as its exact opposite.</p>
<pre class="gs-code"><code>if hates-bananas
"You monster."
else unless loves-gorillas
"How could you?"
else if likes-the-gorillaz
"Fire comes out of the monkey's head."
else
"Well, at least you love gorillas and don't hate bananas."
</code></pre>
</section>
<section id="loops">
<h2>Loops</h2>
<p>GorillaScript provides many different looping constructs, all fitted for their own purposes.</p>
<p>Normal while loop, same as JavaScript:</p>
<pre class="gs-code"><code>let mutable i = 0
while i < 10
console.log i
i += 1
</code></pre>
<p>Opposite of a while loop, <code>until</code>:</p>
<pre class="gs-code"><code>let mutable i = 0
until i >= 10
console.log i
i += 1
</code></pre>
<p>Better version of the above, acts like JavaScript’s for(;;)</p>
<pre class="gs-code"><code>let mutable i = 0
while i < 10, i += 1
console.log i
</code></pre>
<p>Even better version:</p>
<pre class="gs-code"><code>for i in 0 til 10
console.log i
</code></pre>
<p>Or if you want to go in reverse,</p>
<pre class="gs-code"><code>for i in 9 to 0 by -1
console.log i
</code></pre>
<p>Or by twos:</p>
<pre class="gs-code"><code>for i in 0 til 10 by 2
console.log i
</code></pre>
<p>You don’t have to use literal numbers, they can be any expression in GorillaScript. You can also use <code>to</code>, <code>til</code>, and <code>by</code> to make arrays outside of loops.</p>
<p>The difference between <code>til</code> and <code>to</code> is that <code>til</code> goes up until it hits the end, but <code>to</code> includes the end.</p>
<p>To iterate over an array,</p>
<pre class="gs-code"><code>for food in ["Apples", "Bananas", "Cherries"]
console.log food
</code></pre>
<p>If you want its index,</p>
<pre class="gs-code"><code>for food, index in ["Apples", "Bananas", "Cherries"]
console.log "$index: $food"
</code></pre>
<p>You can also get the total length of the array, if you need it:</p>
<pre class="gs-code"><code>for value, index, length in some-array
f()
</code></pre>
<p>To iterate an array in reverse (slightly more efficient):</p>
<pre class="gs-code"><code>for value, index in some-array by -1
// index goes from some-array.length - 1 down to 0.
console.log value
</code></pre>
<p>To iterate only a part of the array:</p>
<pre class="gs-code"><code>for value in some-array[2 to 5]
console.log value
</code></pre>
<p>It works similarly to some-array.slice(2, 6). You can slice outside of loops as well.</p>
<p>To iterate over objects, you can use <code>of</code> instead of <code>in</code>:</p>
<pre class="gs-code"><code>for key, value of some-object
console.log key, value
</code></pre>
<p>GorillaScript automatically runs an Object.prototype.hasOwnProperty check on the key. To avoid this, use:</p>
<pre class="gs-code"><code>for key, value ofall some-object
console.log key, value
</code></pre>
<p>Any loop can be an expression simply by returning it or assigning it to a variable. This will create an array.</p>
<pre class="gs-code"><code>let squares = for value in 0 to 10
value ^ 2
// squares now contains [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
</code></pre>
<p>Single-line loops can be specified as so:</p>
<pre class="gs-code"><code>let squares = for value in 0 to 10; value ^ 2
</code></pre>
<p>There are also reducing loops which work by placing one of the reducers (<code>first</code>, <code>every</code>, <code>some</code>, <code>filter</code>, <code>reduce</code>) on the <code>for</code> or <code>while</code> loop.</p>
<pre class="gs-code"><code>let all-good = for every item in array; item.is-good()
let has-bad = for some item in array; item.is-bad()
let best-value = for first item in array
if item.is-best()
item.value
let only-good = for filter item in array; item.is-good()
let sum = for reduce value in [0, 1, 2, 3, 4], current = 0
current + value
</code></pre>
<p>These work on any <code>for</code> or <code>while</code> loop.</p>
</section>
<section id="lexical-scope">
<h2>Lexical scoping in loops</h2>
<p>A common bug in JavaScript is when one creates a function inside a loop that refers to the current index or value or some other variable that changes each loop iteration. GorillaScript solves this problem by wrapping any for loop that creates a function in another function, so the following works by seemingly lexically-scoping the inside of the for loop rather than abiding by JavaScript’s normal function scoping.</p>
<pre class="gs-code"><code>let funcs = []
for i in 0 til 10
funcs.push #-> i
funcs[0]() == 0
funcs[5]() == 5
</code></pre>
<p>With no extra work on the developer’s part.</p>
</section>
<section id="array-slicing">
<h2>Array slicing</h2>
<p>As mentioned briefly earlier, one can use the <code>to</code>, <code>til</code>, and <code>by</code> syntaxes to slice on arrays.</p>
<pre class="gs-code"><code>let array = [\a, \b, \c, \d, \e]
assert-arr array[1 to 3], [\a, \b, \c]
assert-arr array[1 to 5 by 2], [\a, \c, \e]
assert-arr array[5 to 1 by -2], [\e, \c, \a]
assert-arr array by -1, [\e, \d, \c, \b, \a]
assert-arr array[0 to -1], [\a, \b, \c, \d, \e]
assert-arr array[0 to Infinity], [\a, \b, \c, \d, \e]
</code></pre>
<p>The negative values work just as they do in <code>.slice</code>, unlike normal accessing</p>
</section>
<section id="array-negative-index">
<h2>Array negative indexing</h2>
<p>GorillaScript can’t wrap every single access in a check to see if the child is a negative value (as Python or some other languages do), due to efficiency, but it does provide a nice syntax to make it easier.</p>
<pre class="gs-code"><code>let array = [\a, \b, \c, \d, \e]
assert array[* - 1] == \e
assert array[* - 2] == \d
assert array[* \ 2] == \c // halfway point in the array
</code></pre>
<p>When a standalone <code>*</code> is encountered in an index, it is converted to the current array’s <code>.length</code>.</p>
</section>
<section id="expressions">
<h2>Everything is an expression (mostly)</h2>
<p>Unlike JavaScript, <code>for</code> loops, <code>while</code> loops, <code>try</code> blocks, and <code>if</code> constructs can be used as expressions.</p>
<pre class="gs-code"><code>let array = for i in 0 to 10; i
let trial = try
throw Error()
catch e
"Caught something"
assert trial == "Caught something"
let check = if youre-amazing
"It's true"
else
"Not amazing."
</code></pre>
</section>
<section id="existential">
<h2>Existential operator</h2>
<p>If one wishes to check a value against null or undefined, the existential operator (<code>?</code>) can be used.</p>
<pre class="gs-code"><code>let exists = value?
</code></pre>
<p>It can also be used for access soaking</p>
<pre class="gs-code"><code>let inner = value?.which.might?.not.exist
</code></pre>
<p>Turns into</p>
<pre class="gs-code"><code>let inner = if value?
let _ref = value.which.might
if _ref?
_ref.not.exist
</code></pre>
<p>It can also be used for function checking</p>
<pre class="gs-code"><code>let result = f?()
</code></pre>
<p>Turns into</p>
<pre class="gs-code"><code>let result = if typeof f == \function
f()
</code></pre>
</section>
<section id="in">
<h2><code>in</code> operator</h2>
<p>To correlate with array iteration, <code>in</code> checks if a value is in an array, in a similar way to <code>array.indexOf(value) != -1</code> would.</p>
<pre class="gs-code"><code>assert \hello in [\hi, \there, \hello]
</code></pre>
<p>To check if an object contains a key, see the <code>haskey</code> operator.</p>
</section>
<section id="haskey-ownskey">
<h2><code>haskey</code> and <code>ownskey</code></h2>
<p>Instead of using JavaScript’s <code>in</code>, <code>haskey</code> is used to verify a key’s existence on an object. Also, <code>ownskey</code> is also available to check if a key exists on an object without prototype-checking.</p>
<pre class="gs-code"><code>let parent = { alpha: \bravo }
let child = { extends parent, charlie: \delta }
assert parent haskey \alpha
assert parent ownskey \alpha
assert parent not haskey \charlie
assert parent not ownskey \charlie
assert child haskey \alpha
assert child not ownskey \alpha
assert child haskey \charlie
assert child ownskey \charlie
</code></pre>
</section>
<section id="ownership">
<h2>Access with ownership</h2>
<p>Sometimes you may have an object where you want to access its key but only in the case of the object owning the key as a property.</p>
<pre class="gs-code"><code>assert if parent ownskey key
parent[key]
// functionally equivalent to
assert parent![key]
</code></pre>
<p>Or, for a known key:</p>
<pre class="gs-code"><code>assert if parent ownskey \key
parent.key
assert parent!.key
</code></pre>
</section>
<section id="apply">
<h2>Apply syntax</h2>
<p>In JavaScript, if you wish to specify the <code>this</code> argument passed to a function, one must use either <code>.call</code> or <code>.apply</code>. GorillaScript provides the <code>@</code> syntax:</p>
<pre class="gs-code"><code>let f() -> this
let obj = {}
assert obj == f@ obj
assert obj == f@(obj)
Array.prototype.slice@ arguments, 1
</code></pre>
<p>It transparently converts to <code>.call</code> or <code>.apply</code> (whichever is more appropriate), using the first argument as its <code>this</code>.</p>
</section>
<section id="bind">
<h2>Binding access</h2>
<p>ECMAScript 5 supplies <code>Function.prototype.bind</code> as a way to bind functions to a specific this (and specify arguments). To do a similar binding in GorillaScript, one need only use the familiar <code>@</code> syntax with access.</p>
<pre class="gs-code"><code>let obj = {
f: # -> this
}
let bound = obj@.f
assert bound() == obj
let unbound = obj.f
assert unbound() == window
</code></pre>
</section>
<section id="classes">
<h2>Classes</h2>
<p>GorillaScript provides a way to make classical-style classes. JavaScript does not have classes normally, so GorillaScript’s creation is slightly hackish, but works for the general case.</p>
<pre class="gs-code"><code>class Animal
def constructor(@name) ->
def eat() -> "$(@name) eats"
class GreatApe extends Animal
// no constructor, Animal's is automatically called
def eat(food="fruit") -> super.eat() & " a " & food
class Gorilla extends GreatApe
def constructor(@name, @favorite-food)
// important to call the super constructor.
super(@name)
def eat() -> super.eat(@favorite-food)
class Chimp extends GreatApe
def eat() -> super.eat("banana")
let bobo = Chimp("Bobo") // new is not required on GorillaScript-made classes
assert bobo.eat() == "Bobo eats a banana"
let toko = Gorilla("Toko", "cherry")
assert toko.eat() == "Toko eats a cherry"
// set a method on the Gorilla constructor
Gorilla::barrel := # -> @name & " throws a barrel!"
assert toko.barrel() == "Toko throws a barrel!"
</code></pre>
<p>Classes can <code>extend</code> other classes and call into their superclass with <code>super</code>. The constructor functions automatically check the <code>this</code> argument and if it is not the current class’s type (such as when called without <code>new</code>), it will create a new one on-the-fly.</p>
</section>
<section id="destructuring">
<h2>Destructuring</h2>
<p>GorillaScript, like ECMAScript 6, provides a destructuring declaration.</p>
<pre class="gs-code"><code>let [x, y] = [1, 2]
assert x == 1
assert y == 2
let {a, b: c} = {a: 3, b: 4}
assert a == 3
assert c == 4
</code></pre>
<p>These can be nested like so:</p>
<pre class="gs-code"><code>let [a, {b, c: [d]}] = get-data()
</code></pre>
<p>And the spread operator (<code>...</code>) can be used once per array destructure:</p>
<pre class="gs-code"><code>let [value, ...rest] = array
</code></pre>
</section>
<section id="switch">
<h2>Switch</h2>
<p>Like JavaScript, GorillaScript provides <code>switch</code>. The only major exception is that JavaScript is fallthrough-by-default, and GorillaScript is break-by-default. GorillaScript can also specify multiple values to check at once instead of having multiple cases. <code>switch</code> can also be used as an expression.</p>
<pre class="gs-code"><code>switch value
case 0, 1, 2
"small"
case 3, 4, 5
fallthrough // in the last position of the case, causes the case to fall through to the next case.
case 6, 7, 8
"large"
default
"unknown"
</code></pre>
<p>Unlike JavaScript, GorillaScript provides a topicless <code>switch</code>, which works by checking if each case is truthy rather than comparing against a value. <code>fallthrough</code> works the same way as a normal switch statement. This does not generate a JavaScript <code>switch</code> statement, as it is extremely inefficient to use <code>switch</code> in JavaScript without constant <code>case</code> checks.</p>
<pre class="gs-code"><code>switch
case is-good()
"good"
case is-bad()
"bad"
default
"neutral"
</code></pre>
</section>
<section id="try-catch">
<h2>Try-catch-else-finally</h2>
<p>Try-catch also works similarly to JavaScript, except that catches can have type-checks and the notable exception of the <code>else</code> statement, for when no error was caught, but occurs before the <code>finally</code> statement.</p>
<pre class="gs-code"><code>try
something-dangerous()
catch e as SpecificError
handle-error(e)
catch e
uh-oh()
else
whew()
finally
cleanup()
</code></pre>
<p>At least one of <code>catch</code>, <code>else</code>, or <code>finally</code> must be used, but so can all three.</p>
</section>
<section id="regexes">
<h2>Regular Expressions</h2>