-
-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathoverview.nelua
1286 lines (1085 loc) · 32 KB
/
overview.nelua
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
require 'span'
require 'string'
require 'math'
require 'memory'
require 'iterators'
require 'allocators.default'
require 'allocators.general'
do print '## Hello world'
print 'Hello world!'
end
do print '## Comments'
-- one line comment
--[[
multi-line comment
]]
--[=[
multi line comment, `=` can be placed multiple times
in case if you have `[[` `]]` tokens inside, it will
always match it's corresponding token
]=]
end
do print '## Variables'
local b = false -- of deduced type 'boolean', initialized to false
local s = 'test' -- of deduced type 'string', initialized to 'test'
local one = 1 -- of type 'integer', initialized to 1
local pi: number = 3.14 -- of type 'number', initialized to 3.14
print(b,s,one,pi) -- outputs: false test 1 3.14
end
do print '### Type deduction'
local a -- type will be deduced and scope end
a = 1
a = 2
print(a) -- outputs: 2
-- end of scope, compiler deduced 'a' to be of type 'integer'
end
do print '### Zero initialization'
local b: boolean -- variable of type 'boolean', initialized to 'false'
local i: integer -- variable of type 'integer', initialized to 0
print(b, i) -- outputs: false 0
end
do print '### Auto variables'
local a: auto = 1 -- a is deduced to be of type 'integer'
-- uncommenting the following will trigger the compile error:
-- constant value `1.0` is fractional which is invalid for the type 'int64'
--a = 1.0
print(a) -- outputs: 1
end
do print '### Compile-time variables'
local a <comptime> = 1 + 2 -- constant variable of value '3' evaluated and known at compile-time
print(a) -- outputs: 3
end
do print '## Const variables'
local x <const> = 1
local a <const> = x
print(a) -- outputs: 1
-- uncommenting the following will trigger the compile error:
-- error: cannot assign a constant variable
--a = 2
end
do print '## To-be-closed variables'
local AbstractFile = @record{
name: string
}
function AbstractFile.open(name: string): AbstractFile
local file = AbstractFile{name=name}
print('opened', file.name)
return file
end
function AbstractFile:__close() -- define __close metamethod
print('closed', self.name)
end
do
local file: AbstractFile <close> = AbstractFile.open('dummy') -- prints 'opened dummy'
-- when scope ends, AbstractFile:__close() is called and prints 'closed dummy'
end
end
do print '### Multiple variables assignment'
local a, b = 1, 2
print(a, b) -- outputs: 1 2
b, a = a, b -- swap values
print(a, b) -- outputs: 2 1
end
do print '### Local symbol'
do
local a = 1
do
print(a) -- outputs: 1
end
end
-- uncommenting this would trigger a compiler error because `a` is not visible:
-- a = 1
end
print '### Global symbol'
global global_a = 1
global function global_f()
return 'f'
end
-- require 'globals'
print(global_a) -- outputs: 1
print(global_f()) -- outputs: f
do print '### Symbols with special characters'
-- local π = 3.14
-- print(π) -- outputs 3.14
end
do print '### If'
local a = 1 -- change this to 2 or 3 to trigger other ifs
if a == 1 then
print 'is one'
elseif a == 2 then
print 'is two'
else
print('not one or two')
end
end
do print '### Switch'
local a = 1 -- change this to 2 or 3 to trigger other ifs
switch a do
case 1 then
print 'is 1'
case 2, 3 then
print 'is 2 or 3'
else
print 'else'
end
end
do print '### Do'
do
local a = 0
print(a) -- outputs: 0
end
do
local a = 1 -- can declare variable named a again
print(a) -- outputs: 1
end
end
do print '### Defer'
do
defer
print 'world'
end
print 'hello'
end
-- outputs 'hello' then 'world'
end
do print '### Goto'
local haserr = true
if haserr then
goto getout -- get out of the loop
end
print 'success'
::getout::
print 'fail'
-- outputs only 'fail'
end
do print '### While'
local a = 1
while a <= 5 do
print(a) -- outputs 1 2 3 4 5
a = a + 1
end
end
do print '### Repeat'
local a = 0
repeat
a = a + 1
print(a) -- outputs 1 2 3 4 5
local stop = a == 5
until stop
end
do print '### Numeric For'
for i=0,5 do
-- i is deduced to 'integer'
print(i) -- outputs 0 1 2 3 4 5
end
end
do print '#### Exclusive For'
for i=0,<5 do
print(i) -- outputs 0 1 2 3 4
end
end
do print '#### Stepped For'
for i=5,0,-1 do
print(i) -- outputs 5 4 3 2 1 0
end
end
do print '### For In'
local a: [4]string = {"a","b","c","d"}
for i,v in ipairs(a) do
print(i,v) -- outputs: 0 a, 1 b, 2 c, 3 d
end
end
do print '### Continue'
for i=1,10 do
if i<=5 then
continue
end
print(i) -- outputs: 6 7 8 9 10
end
end
do print '### Fallthrough'
local a = 1
switch a do
case 1 then
print '1'
fallthrough -- next case block will be executed
case 2 then
print '2'
end
-- outputs '1' followed by '2'
end
do print '### Break'
for i=1,10 do
if i>5 then
break
end
print(i) -- outputs: 1 2 3 4 5
end
end
do print '### Do expression'
local i = 2
local s = (do
local res: string
if i == 1 then
res = 'one'
elseif i == 2 then
res = 'two'
else
res = 'other'
end
in res -- injects final expression result
end)
print(s) -- outputs: two
end
do print '### Boolean'
local a: boolean -- variable of type 'boolean' initialized to 'false'
local b = false
local c = true
print(a,b,c) -- outputs: false false true
end
do print '### Number'
local dec = 1234 -- variable of type 'integer'
local bin = 0b1010 -- variable of type 'uint8', set from binary number
local hex = 0xff -- variable of type 'integer', set from hexadecimal number
local char = 'A'_u8 -- variable of type 'uint8' set from ASCII character
local exp = 1.2e-100 -- variable of type 'number' set using scientific notation
local frac = 1.41 -- variable of type 'number'
print(dec,bin,hex,char,exp,frac)
local pi = 0x1.921FB54442D18p+1 -- hexadecimal with fractional and exponent
print(pi) -- outputs: 3.1415926535898
local a = 1234_u32 -- variable of type 'int32'
local b = 1_f32 -- variable of type 'float32'
local c = -1_isize -- variable of type `isize`
print(a,b,c) --outputs: 1234 1.0 -1
end
do print '### String'
local str1: string -- empty string
local str2 = "string 2" -- variable of type 'string'
local str3: string = 'string 3' -- also a 'string'
local str4 = [[
multi
line
string
]]
print(str1, str2, str3) -- outputs: "" "string 2" "string 3"
print(str4) -- outputs the multi line string
end
do print '#### String escape sequence'
local ctr = "\n\t\r\a\b\v\f" -- escape control characters
local utf = "\u{03C0}" -- escape UTF-8 code
local hex = "\x41" -- escape hexadecimal byte
local dec = "\65" -- escape decimal byte
local multiline1 = "my\z
text1" -- trim spaces and newlines after '\z'
local multiline2 = "my\
text2" -- escape new lines after '\' to '\n'
print(utf, hex, dec, multiline1) -- outputs: π A A mytext1
print(multiline2) -- outputs "my" and "text2" on a new line
end
do print '### Array'
local a: [4]integer = {1,2,3,4}
print(a[0], a[1], a[2], a[3]) -- outputs: 1 2 3 4
local b: [4]integer
print(b[0], b[1], b[2], b[3]) -- outputs: 0 0 0 0
local len = #b -- get the length of the array, should be 4
print(len) -- outputs: 4
end
do print '#### Array with inferred size'
local a: []integer = {1,2,3,4} -- array size will be 4
print(#a) -- outputs: 4
end
do print '#### Multidimensional Array'
local m: [2][2]number = {
{1.0, 2.0},
{3.0, 4.0}
}
print(m[0][0], m[0][1]) -- outputs: 1.0 2.0
print(m[1][0], m[1][1]) -- outputs: 3.0 4.0
end
do print '### Enum'
local Weeks = @enum{
Sunday = 0,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
print(Weeks.Sunday) -- outputs: 0
local a: Weeks = Weeks.Monday
print(a) -- outputs: 1
end
do print '### Record'
local Person = @record{
name: string,
age: integer
}
-- typed initialization
local a: Person = {name = "Mark", age = 20}
print(a.name, a.age)
-- casting initialization
local b = (@Person){name = "Paul", age = 21}
print(b.name, b.age)
-- ordered fields initialization
local c = (@Person){"Eric", 21}
print(c.name, c.age)
-- late initialization
local d: Person
d.name = "John"
d.age = 22
print(d.name, d.age)
end
do print '### Union'
local IntOrFloat = @union{
i: int64,
f: float64,
}
local u: IntOrFloat = {i=1}
print(u.i) -- outputs: 1
u.f = 1
print(u.f) -- outputs: 1.0
print(u.i) -- outputs some garbage integer
end
do print '### Pointer'
local n = nilptr -- a generic pointer, initialized to nilptr
local p: pointer --a generic pointer to anything, initialized to nilptr
local i: *integer -- pointer to an integer
end
do print '#### Unbounded Array'
local a: [4]integer = {1,2,3,4}
-- unbounded array only makes sense when used with pointer
local a_ptr: *[0]integer
a_ptr = &a -- takes the reference of 'a'
print(a_ptr[1])
end
do print '### Function type'
local function add_impl(x: integer, y: integer): integer
return x + y
end
local function double_add_impl(x: integer, y: integer): integer
return 2*(x + y)
end
local add: function(x: integer, y: integer): integer
add = add_impl
print(add(1,2)) -- outputs 3
add = double_add_impl
print(add(1,2)) -- outputs 6
end
do print '### Span'
local arr = (@[4]integer) {1,2,3,4}
local s: span(integer) = &arr
print(s[0], s[1]) -- outputs: 1 2
print(#s) -- outputs 4
end
do print '### Niltype'
local n: niltype = nil
end
do print '### Void'
local function myprint(): void
print 'hello'
end
myprint() -- outputs: hello
end
do print '### The "type" type'
local MyInt: type = @integer -- a symbol of type 'type' holding the type 'integer'
local a: MyInt -- variable of type 'MyInt' (actually an 'integer')
print(a) -- outputs: 0
end
do print '#### Size of a type'
local Vec2 = @record{x: int32, y: int32}
print(#Vec2) -- outputs: 8
end
do print '### Implicit type conversion'
local i: integer = 1
local u: uinteger = i
print(u) -- outputs: 1
end
do print '### Explicit type conversion'
local i = 1
local f = (@number)(i) -- convert 'i' to the type 'number'
print(i, f) -- outputs: 1 1.0
local MyNumber = @number
local i = 1
local f = MyNumber(i) -- convert 'i' to the type 'number'
print(i, f) -- outputs: 1 1.0
local ni: integer = -1
-- the following would crash with "narrow casting from int64 to uint64 failed"
--local nu: uinteger = ni
local nu: uinteger = (@uinteger)(ni) -- explicit cast works, no checks are done
print(nu) -- outputs: 18446744073709551615
end
do print '## Operators'
print(2 ^ 2) -- pow, outputs: 4.0
print(5 // 2) -- integer division, outputs: 2
print(5 / 2) -- float division, outputs: 2.5
end
do print '## Functions'
local function add(a: integer, b: integer): integer
return a + b
end
print(add(1, 2)) -- outputs 3
end
do print '## Return type inference'
local function add(a: integer, b: integer)
return a + b -- return is of deduced type 'integer'
end
print(add(1, 2)) -- outputs 3
end
do print '### Recursive calls'
local function fib(n: integer): integer
if n < 2 then return n end
return fib(n - 2) + fib(n - 1)
end
print(fib(10)) -- outputs: 55
end
do print '### Multiple returns'
local function get_multiple()
return false, 1
end
local a, b = get_multiple()
-- a is of type 'boolean' with value 'false'
-- b is of type 'integer' with value '1'
print(a,b)
local function get_multiple(): (boolean, integer)
return false, 1
end
local a, b = get_multiple()
print(a,b) -- outputs: false 1
end
do print '### Anonymous functions'
local function g(x: integer, f: function(x: integer): integer)
return f(x)
end
local y = g(1, function(x: integer): integer
return 2*x
end)
print(y) -- outputs: 2
end
do print '### Nested functions'
local function f()
local function g()
return 'hello from g'
end
return g()
end
print(f()) -- outputs: hello from g
end
--do print '### Top scope closures'
local counter = 1 -- 'a' lives in the heap because it's on the top scope
local function increment() -- a top scope closure
-- counter is an upvalue for this function, we can access and modify it
counter = counter + 1
end
print(counter) -- outputs 1
increment()
print(counter) -- outputs 2
--end
do print '### Variable number of arguments'
local function f(...: varargs)
print(...)
end
f(1, true) -- outputs: 1 true
local function sum(...: varargs)
local s: integer
## for i=1,select('#', ...) do -- iterate over all arguments
s = s + #[select(i, ...)]# -- select argument at index `i`
## end
return s
end
print(sum(1, 2, 3)) -- outputs: 6
end
do print '### Polymorphic functions'
local function add(a: auto, b: auto)
return a + b
end
local a = add(1,2)
-- call to 'add', a function 'add(a: integer, b: integer): integer' is defined
print(a) -- outputs: 3
local b = add(1.0, 2.0)
-- call to 'add' with different types, function 'add(a: number, b: number): number' is defined
print(b) -- outputs: 3.0
end
do print '### Record functions'
local Vec2 = @record{x: number, y: number}
function Vec2.create(x: integer, y: integer): Vec2
return (@Vec2){x, y}
end
local v = Vec2.create(1,2)
print(v.x, v.y) -- outputs: 1.0 2.0
end
do print '### Record methods'
local Rect = @record{x: number, y: number, w: number, h: number}
function Rect:translate(x: number, y: number)
-- 'self' here is of the type '*Rect'
self.x = self.x + x
self.y = self.y + y
end
function Rect:area()
-- 'self' here is of the type '*Rect'
return self.w * self.h
end
local v = Rect{0,0,2,3}
v:translate(2,2)
print(v.x, v.y) -- outputs: 2.0 2.0
print(v:area()) -- outputs: 6.0
end
do print '### Record metamethods'
local Vec2 = @record{x: number, y: number}
-- Called on the binary operator '+'
function Vec2.__add(a: Vec2, b: Vec2)
return (@Vec2){a.x+b.x, a.y+b.y}
end
-- Called on the unary operator '#'
function Vec2:__len()
return math.sqrt(self.x*self.x + self.y*self.y)
end
local a: Vec2 = {1, 2}
local b: Vec2 = {3, 4}
local c = a + b -- calls the __add metamethod
print(c.x, c.y) -- outputs: 4.0 6.0
local len = #c -- calls the __len metamethod
print(len) -- outputs: 7.211102550928
end
print '### Record globals'
global Globals = @record{} -- record used just for name spacing
global Globals.AppName: string
Globals.AppName = "My App"
print(Globals.AppName) -- outputs: My App
do print '### Calls with nested records'
local WindowConfig = @record{
title: string,
pos: record{
x: integer,
y: integer
},
size: record{
x: integer,
y: integer
}
}
local function create_window(config: WindowConfig)
print(config.title, config.pos.x, config.pos.y)
end
-- the compiler knows that the argument should be parsed as WindowConfig
-- notice that 'size' field is not set, so its initialized to zeros
create_window({title="hi", pos={x=1, y=2}})
end
do print '## Memory management'
local str = tostring(1) -- tostring needs to allocates a new string
print(str) -- outputs: 1
## if pragmas.nogc then -- the GC is disabled, must manually deallocate memory
str:destroy() -- deallocates the string
## end
print(str) -- the string was destroyed and is now empty, outputs nothing
end
do print '### Allocating memory'
local Person = @record{name: string, age: integer}
local p: *Person = default_allocator:new(@Person)
p.name = "John"
p.age = 20
print(p.name, p.age)
p = nilptr
-- we don't need to deallocate, the GC will do this on its own when needed!
end
do print '### Allocating memory manually'
local Person = @record{name: string, age: integer}
local p: *Person = general_allocator:new(@Person) -- allocate the appropriate size for Person
p.name = tostring("John") -- another allocation here
p.age = 20
print(p.name, p.age)
p.name:destroy() -- free the string allocation
general_allocator:delete(p) -- free the Person allocation
p = nilptr
end
do print '### Dereferencing and referencing'
local a = 1
local ap = &a -- ap is a pointer to a
$ap = 2
print(a) -- outputs: 2
a = 3
print($ap) -- outputs: 3
print(ap) -- outputs memory address of a
end
do print '### Automatic referencing and dereferencing'
local Person = @record{name: string, age: integer}
local function print_info_byref(p: *Person)
print(p.name, p.age)
end
local function print_info_bycopy(p: Person)
print(p.name, p.age)
end
local p: Person = {"John", 20}
print_info_byref(p) -- the referencing with `&` is implicit here
local pref: *Person = &p
print_info_bycopy(pref) -- the dereferencing with `$` is implicit here
local Person = @record{name: string, age: integer}
local function print_info_byref(p: *Person)
print(p.name, p.age)
end
local function print_info_bycopy(p: Person)
print(p.name, p.age)
end
local p: Person = {"John", 20}
print_info_byref(&p)
local pref: *Person = &p
print_info_bycopy($pref)
local Person = @record{name: string, age: integer}
-- note that this function only accept pointers
function Person.print_info(self: *Person)
print(self.name, self.age)
end
local p: Person = {"John", 20}
p:print_info() -- perform auto referencing of 'p' when calling here
Person.print_info(p) -- equivalent, also performs auto referencing
end
do print '### Preprocessor'
local a = 0
## for i = 1,4 do
a = a + 1 -- unroll this line 4 times
## end
print(a) -- outputs 4
##[[
local something = false
if something then
]]
print('hello') -- prints hello when compiling with "something" defined
##[[ end ]]
end
do print '### Emitting AST nodes (statements)'
##[[
-- create a macro that injects a custom node when called
local function print_macro(str)
local node = aster.Call{{aster.String{"hello"}}, aster.Id{"print"}}
-- inject the node where this macro is being called from
inject_statement(node)
end
]]
## print_macro('hello')
end
do print '### Emitting AST nodes (expressions)'
local a = #[aster.Number{1}]#
print(a) -- outputs: 1
end
do print '### Expression replacement'
local deg2rad = #[math.pi/180.0]#
local hello = #['hello' .. 'world']#
local mybool = #[false]#
print(deg2rad, hello, mybool) -- outputs: 0.017453 helloworld false
end
do print '### Name replacement'
local #|'my' .. 'var'|# = 1
print(myvar) -- outputs: 1
local function foo1() print 'foo' end
#|'foo' .. 1|#() -- outputs: foo
local Weekends = @enum{ Friday=0, Saturday, Sunday }
print(Weekends.#|'S'..string.lower('UNDAY')|#)
end
do print '### Preprocessor templated macros'
## function increment(a, amount)
-- 'a' in the preprocessor context is a symbol, we need to use its name
-- 'amount' in the preprocessor context is a lua number
#|a.name|# = #|a.name|# + #[amount]#
## end
local x = 0
## increment(x, 4)
print(x)
end
do print '### Statement replacement macros'
## local function mul(res, a, b)
#[res]# = #[a]# * #[b]#
## end
local a, b = 2, 3
local res = 0
#[mul]#(res, a, b)
print(res) -- outputs: 6
end
do print '### Expression replacement macros'
## local function mul(a, b)
in #[a]# * #[b]#
## end
local a, b = 2, 3
local res = #[mul]#(a, b)
print(res) -- outputs: 6
end
do print '### Preprocessor macros emitting AST nodes'
##[[
-- Create a fixed array initializing to 1,2,3,4...n
local function create_sequence(attr_or_type, n)
local type
if traits.is_type(attr_or_type) then -- already a type
type = attr_or_type
elseif traits.is_attr(attr_or_type) then -- get a type from a symbol
type = attr_or_type.value
end
-- check if the inputs are valid, in case of wrong input
static_assert(traits.is_type(type), 'expected a type or a symbol to a type')
static_assert(traits.is_number(n) and n > 0, 'expected n > 0')
-- create the InitList ASTNode, it's used for any braces {} expression
local initlist = aster.InitList{pattr = {
-- hint the compiler what type this braces should be evaluated
desiredtype = types.ArrayType(type, n)}
}
-- fill expressions
for i=1,n do
-- convert any Lua value to the proper ASTNode
initlist[i] = aster.value(i)
end
return initlist
end
]]
local a = #[create_sequence(integer, 10)]#
end
do print '### Code blocks as arguments to preprocessor functions'
##[[
function unroll(count, block)
for i=1,count do
block()
end
end
]]
local counter = 1
## unroll(4, function()
print(counter) -- outputs: 1 2 3 4
counter = counter + 1
## end)
end
do print '### Generic code via the preprocessor'
## function Point(PointT, T)
local #|PointT|# = @record{x: #|T|#, y: #|T|#}
function #|PointT|#:squaredlength()
return self.x*self.x + self.y*self.y
end
## end
## Point('PointFloat', 'float64')
## Point('PointInt', 'int64')
local pa: PointFloat = {x=1,y=2}
print(pa:squaredlength()) -- outputs: 5.0
local pb: PointInt = {x=1,y=2}
print(pb:squaredlength()) -- outputs: 5
end
do print '### Preprocessing on the fly'
local Weekends = @enum{ Friday=0, Saturday, Sunda }
## for i,field in ipairs(Weekends.value.fields) do
print(#[field.name .. ' ' .. tostring(field.value)]#)
## end
local Person = @record{name: string}
## Person.value:add_field('age', primtypes.integer) -- add field 'age' to 'Person'
local p: Person = {name='Joe', age=21}
print(p.age) -- outputs '21'
end
do print '### Preprocessing polymorphic functions'
local function pow(x: auto, n: integer)
## static_assert(x.type.is_scalar, 'cannot pow variable of type "%s"', x.type)
## if x.type.is_integral then
-- x is an integral type (any unsigned/signed integer)
local r: #[x.type]# = 1
for i=1,n do
r = r * x
end
return r
## elseif x.type.is_float then
-- x is a floating point type
return x ^ n
## end
end
local a = pow(2, 2) -- use specialized implementation for integers
local b = pow(2.0, 2) -- use pow implementation for floats
print(a,b) -- outputs: 4 4.0
-- uncommenting the following will trigger the compile error:
-- error: cannot pow variable of type "string"
--pow('a', 2)
end
do print '## Generics'
-- Define a generic type for creating a specialized FixedStackArray
## local make_FixedStackArrayT = generalize(function(T, maxsize)
-- alias compile-time parameters visible in the preprocessor to local symbols
local T = #[T]#
local MaxSize <comptime> = #[maxsize]#
-- Define a record using T and MaxSize compile-time parameters.
local FixedStackArrayT = @record{
data: [MaxSize]T,
size: isize
}
-- Push a value into the stack array.
function FixedStackArrayT:push(v: T)
if self.size >= MaxSize then error('stack overflow') end
self.data[self.size] = v
self.size = self.size + 1
end
-- Pop a value from the stack array.
function FixedStackArrayT:pop(): T
if self.size == 0 then error('stack underflow') end
self.size = self.size - 1
return self.data[self.size]
end
-- Return the length of the stack array.
function FixedStackArrayT:__len(): isize
return self.size
end
-- return the new defined type to the compiler
## return FixedStackArrayT
## end)
-- define FixedStackArray generic type in the scope
local FixedStackArray: type = #[make_FixedStackArrayT]#
do -- test with 'integer' type
local v: FixedStackArray(integer, 3)
-- push elements
v:push(1)
v:push(2)
v:push(3)
-- uncommenting would trigger a stack overflow error:
-- v:push(4)
-- check the stack array length
assert(#v == 3)
-- pop elements checking the values
assert(v:pop() == 3)
assert(v:pop() == 2)
assert(v:pop() == 1)
-- uncommenting would trigger a stack underflow error:
-- v:pop()
end
do -- test with 'number' type
local v: FixedStackArray(number, 3)