forked from meircif/lumi-lang
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample.mr
More file actions
774 lines (616 loc) · 24 KB
/
example.mr
File metadata and controls
774 lines (616 loc) · 24 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
(## Module documentation - must be first line of the file
This is MR programming language example.
This syntax is temporary and will probably change in the near future.
#)
# Documentation
################
(## <-- multi-line documentation start
Can use markup language in the documentation.
Must be directly above the documented item - without empty lines.
multi-line documentation end --> #)
func f-documented-function()
return
## single line documentation, strict exactly one space after ##
## can be more then one line...
func f-documented-function()
return
# comments
###########
func f-comment-example()
(# <-- multi-line comment start
multi-line comment end --> #)
# single line comment, strict exactly one space after #
f-some-code() # line end comment, strict 2 spaces before #
f-some-code( (# mid-code comment (strict whitespacing?) #) )
(#
(#
allow nested comments?
#)
#)
# object creation
##################
func f-variables-example()
# stack variable objects are created using "var"
var Int int-var
var String{128} string-var
# dynamically allocated object are created using "new"
owner String{Uint8b} some-string(new{String{32}}(""))
# references
#############
func f-references-example()
(# managing references
References should be managed correctly to reach goal #1,
and to reach goal #2 - it should be done as efficiently as possible.
This is done with 3 layers of managing - allowing easy trade-of between
flexibility and performance by the user:
1. No performance overhead - compile time only reference managing
2. More flexible reference managing - with a small performance cost
3. Maximum flexibility - but with performance issues
Below is a first suggestion to implement this, but it will probably be
developed further over time, and maybe even changed completely.
(# 1. No performance overhead - compile time only reference managing
MR will allow performance free reference managing that will be done only in
compile time.
Every reference has a single "owner" entity - which is another object
or a stack block.
When an owner is destroyed it automatically destroys the referenced object,
unless the ownership was passed to another entity.
Owners can give the reference to multiple "user" entities - other entities
that are deeper in the stack than the owner.
Users are free to modify the referenced object freely - but cannot destroy it.
Variables ca also give references as owners - but cannot pass their ownership.
#)
owner String{32} some-string(new{String{32}}(""))
f-user-func(user some-string) # give reference to a user
f-owning-func(owner some-string) # pass ownership, cannot be used anymore
(# 2. More flexible reference managing - with a small performance cost
MR will allow more complex and flexible reference managing that come with a
small and predictable performance cost
Same as 1. with the addition of weak references.
To allow this the owner should be declared as "managed". It will work the
same way as a regular owner, plus the it can now give "weak" references to any
other entity without limitations. Weak references will automatically test that
the reference is still valid before accessing it.
There are several ways to implement this - but all need some extra memory to
manage the weak references, plus the extra check if the weak reference is valid.
Depends on the implementation of the compiler the extra overhead is small
and predictable.
* It is also possible to support "strong" reference counting - but this is not
added because it can cause memory leaks because of reference loops.
#)
managed String{32} some-string(new{String{32}}(""))
f-user-func(user some-string) # give reference to a user
f-weak-func(weak some-string) # give weak reference
f-owning-func(managed some-string) # pass ownership
(# 3. Maximum flexibility - but with performance issues
MR will allow declaring a reference as garbage-collected, which will allow
passing references freely without limitation. The memory will only be cleared
when all "strong" references are destroyed. The garbage-collector must check and
remove reference loops to avoid memory leaks.
To allow this a reference should be declared as "shared". This reference can
then be passed to other "shared", "user" or "weak" references.
Implementing a garbage-collector has a significant and unpredicted performance
cost, but some MR users may be willing to pay it in some sections of their
project where performance is less important.
#)
shared String{32} some-string(new{String{32}}(""))
f-shared-func(shared some-string) # copy strong reference
f-user-func(user some-string) # give reference to a user
f-weak-func(weak some-string) # give weak reference
# empty references (nil/null/none)
(#
As default, (non-weak) references always point to a legal object.
To allow empty references a references must be declared as "conditional" using
the "?" sign. Empty value can be set using "_".
#)
user String{Uint8b}? cond-str # initialized as empty
cond-str := some-string # now not empty
cond-str := _ # now is empty again
if cond-str? # check if empty
# ...
cond-str?.clear() # raise error if empty
f-with-cond(user _) # send empty to function
# primitive types
##################
func f-primitive-types-example()
# integers
# the basic integer type is "Int{min:max}" (inclusive), where max >= min
var Int{-12:47} limited-int(34)
var Int{0:255} integer(0)
# useful aliases
var Uint8b unsigned-8bit(0) # same as Int{0:255}
var Uint16b unsigned-16bit(0) # same as Int{0:65535}
var Uint32b unsigned-32bit(0) # same as Int{0:4294967295}
var Uint64b unsigned-64bit(0) # same as Int{0:18446744073709551615}
var Uint-size unsigned-size(0) # same as Int{0:MAX-UINT-IN-MACHINE}
var Sint8b signed-8bit(0) # same as Int{0:255}
var Sint16b signed-16bit(0) # same as Int{-32766:32767}
var Sint32b signed-32bit(0) # same as Int{-2147483646:2147483647}
var Sint64b signed-64bit(0)
# same as Int{-9223372036854775806:9223372036854775807}
var Sint-size signed-size(0)
# same as Int{MIN-INT-IN-MACHINE:MAX-INT-IN-MACHINE}
# in C code generation each int will be implemented with the smallest int type
# that can contain its range,
# "Uint-size" and "Sint-size" sizes are as size_t and ssize_t respectfully
# compile time constant integer
const Int CONTS-INT(42) # in this case the type is same as Int{42:42}
const Int BYTE-SIZE(8) # in this case the type is same as Int{8:8}
# dynamic ranged int - for dynamic array indices
var Int{some-array} array_index(0) # actual range is {0:array-length - 1}
# Dynamically allocated infinite integer (same as Python's "long")
var Iint infinite-dynamic-signed-integer(347563948756923876592347856659238659)
# assignment
var Int{6:12} int-small(10)
var Int{0:100} int-large(0)
int-large := int-small # is OK - range is inclusive
# range cast
int-small := clamp int-large # clamp if smaller or larger
int-small := check int-large # raise error if smaller or larger
int-small := min int-large # clamp if smaller, raise error if larger
int-small := max int-large # raise error if smaller, clamp if larger
# integer operators, the return value range depends on the operation
int-large + int-small # return type is Int{6:112}
int-large - int-small # return type is Int{-12:94}
int-large * int-small # return type is Int{0:1200}
int-large div int-small # return type is Int{0:16}
int-large mod int-small # return type is Int{0:11}
# range cast
int-small := int-large + clamp int-small # cast to assigned type
int-small := check int-large + clamp{0:100} int-small # cast to explicit type
# cast to given variable's type
int-small := check int-large + clamp{int-large} int-small
# boolean
var Bool bool # has 2 possible values: "true" or "false"
const Bool MR-IS-GOOD(true)
const Bool LIFE-IS-EASY(false)
# cast to other
var Int{0:1} flag(1 if bool else 0)
# cast from other
bool := integer = 3
# other operators
bool := not bool
bool := integer > 3
bool := integer < 3
bool := integer <= 3
bool := integer >= 3
bool := integer != 3
bool := bool and LIFE-IS-EASY
bool := bool or LIFE-IS-EASY
bool := bool xor LIFE-IS-EASY
bool := bool and not LIFE-IS-EASY
bool := not bool and LIFE-IS-EASY
bool := not (bool and LIFE-IS-EASY)
bool := not bool and not LIFE-IS-EASY
# character
var Char char # only accept characters as 'single-letter'
var Uchar unicode-char # only accept characters as u'single-letter'
const Char ZERO('0')
const Uchar UNICODE-ZERO(u'0')
# cast to integer
number := ord(char)
# cast from integer
char := chr(number)
# allow implicit cast?
# byte
var Byte byte # only accept characters as b'byte-hex'
const Byte BYTE-ZERO(b'00')
# decode
number := decode byte
number := decode{Int} byte # explicit decoding
number := decode{number} byte # decode to given variable's type
int-small := clamp decode byte
bool := decode byte
char := decode byte
# encode
byte := encode number
byte := encode{Int} number
byte := encode{number} number
byte := encode bool
byte := encode char
# real numbers (floating-point)
Real real-number # same as "float" in C
Reald double-real-number # same as "double" in C
Realdl large-real-number # same as "long double" in C
# built-in complex types
#######################
func f-complex-types-example()
# arrays
# compile time constant size array is "Array{length:type}", where length >= 0,
# length is not stored
var Array{128:Bool} bit-map(false) # all items initialized with "false"
var Array{4:Int{0,20}} int-array(3, 4, 5, 12) # unique item initialization
user Array{4:Bool} partial-bit-map(bit-map[4:8]) # partial reference
# dynamic sized array is "Array{length-int-type:type}",
# "length-int-type" must be an integer with range minimum >= 0,
# length is stored alongside the array reference
user Array{Uint32b:Bool} dynamic-bit-map(bit-map)
dynamic-bit-map := bit-map[3:8] # partial reference [start:upper-bound]
# compile time constant array
const Array{Int} CONST_ARRAY(3, 5, 4, 2, 2, 5)
# in this case the type is same as Array{6:Int{2:5}}
# assignment
bit-map[5] := true
bool := bit-map[12]
# range casting
var Int{10:20} smaller(12)
var Int{0:300} larger(12)
bit-map[smaller] := true # no casting needed
bit-map[clamp larger] := true # casting needed, expects Int{0:127}
bit-map[check larger] := true
bit-map[min larger] := true
bit-map[max larger] := true
# dynamic array range
var Int{dynamic-bit-map} dynamic-index(0)
dynamic-bit-map[dynamic-index] := true
# copying with slicing (as in python)
var Array{128:Bool} another-bit-map(true)
another-bit-map[:] := bit-map[:] # copy all
another-bit-map[0:4] := bit-map[3:7] # sliced copy
another-bit-map[1:] := bit-map[:-1]
another-bit-map[0:4] := bit-map[0:8:2]
# buffers behave like arrays of "Byte" with extra functionality
var Buffer{128} const-sized-buffer
var Buffer{Uint32b} dynamic-sized-buffer
# in this case the type is same as Buffer{8}
const Buffer COMPILER-CONSTANT-BUFFER(b"4500a320-34ff348f")
# encoding and decoding
unsigned-32bit := decode const-sized-buffer[4:8]
const-sized-buffer[8:12] := encode unsigned-32bit
# strings
# compile time constant maximum length string is "String{max-length}",
# where max-length >= 0,
# actual length is stored as Int{0:max-length},
# actual array is stored the same as Array{max-length:Char}
var String{128} some-string
# dynamic maximum length string is "String{length-int-type}",
# "length-int-type" must be an integer with range minimum >= 0,
# actual maximum length is stored as length-int-type,
# actual array is stored the same as Array{length-int-type:Char}
user String{Uint32b} dynamic-sized-string(some-string)
# compile time constant string
const String NAME("MR language")
# in this case the the type is same as String{11}
# unicode is same as string replacing "String" with "Unicode"
# and "Char" with "Uchar"
var Unicode{128} unicode-string
var Unicode{Uint32b} dynamic-sized-unicode-string
const Unicode UNICODE-NAME(u"משהו בעברית")
# in this case the the type is same as Unicode{11}
# emoji support?
# structures
#############
func f-structures-example()
# if else
if bool
f-call-some-func()
else
f-call-other-func()
# loops
(# main loops and functions rules:
1. limited loop is one that contains at least one "for" statement
2. all loops must be limited, except main loops
3. main loops and main functions can only be used inside main functions
4. main loops and main function cannot be called inside main loops
#)
# "for" and "while" statements can appear multiple times anywhere in the loop,
# but not under "if" or "else".
# The first one to end will break the loop immediately.
Int{6:12} number
do
for number # loop number from 6 to 12
for Int{5:8} index # loop index from 5 to 8 (inclusive)
for Int{5:24} index in -2 # loop index from 24 to 5 with step of 2
for Int{1:3} # loop 3 times (another way?)
while bool # loop while bool is true
while not bool # loop until bool is true
for Int num in int-array
if bool
continue
else
break
# All loops must be limited, except main loops. Limited loops are loops that
# contain at least one "for" statement.
# main loop:
do main # infinite loop
f-call-some-func()
# switch
switch number # any primitive type
case 34 # compile time constant
f-call-some-func()
case 23
f-call-some-func()
fallthrough # this is not the default
case 45, 67, 26, 56, 67, 89, 56, 87
f-call-other-func()
default # must be the last only if not all values are taken care of
return
var Int{2:4} number(2)
switch number
case 4
f-call-some-func()
case 2
f-call-other-func()
case 3
return
# functions
############
(# arg:
copy : read-only value copy
user : read-only ref
owner : moved owner ref
ref : ref can be changed
out copy : must be set a value
out user : must be sta a ref
out owner : an owner ref must be moved to it
#)
# declaring a function
func f-func-name(copy Uint32b input-value):(copy Int{0:9} return-value)
# function body...
return input-value mod 10 # return value
func f-no-params-func()
# function body...
func f-complex-func(
copy Uint32b input-by-value, # "copy" only works for primitive types
user String{Uint8b} user-reference,
owner String{Uint8b} owner-reference, # takes ownership of the reference
weak String{Uint8b} weak-reference,
managed String{Uint8b} managed-reference, # takes ownership
shared String{Uint8b} shared-reference)
):( # supports multiple return values
copy Uint32b return-value,
weak String{Uint8b} weak-reference-return-value, # or any other type
var String{36} stack-variable) # must be initialized in the func
)
# function body...
var stack-variable("init string")
return input-by-value div 5, managed-reference, stack-variable
# calling a function
func f-calling-example()
owner String{36} simple-string(new{String{36}}(""))
managed String{36} managed-string(new{String{36}}(""))
shared String{36} shared-string(new{String{36}}(""))
var Uint32b some-int := f-func-name(345)
var Uint32b out-int,
weak String{Uint8b} out-string,
var String{36} new-string := f-complex-func(
copy some-int,
user simple-string,
owner simple-string, # pass ownership
weak managed-string,
managed managed-string, # pass ownership
shared shared-string)
f-no-params-func()
# function reference
var Func f-func-ref(copy Uint32b input-value):(copy Int{0:9} return-value)
f-func-ref := f-func-name
# calling native external code
###############################
# MR allows calling external code from the native language that the code is
# generated to (C).
# This should be used with caution because MR cannot enforce its safety
# standards over other languages.
# to call a native function it must be declared in MR way using "native",
# only "out", "copy" and "user" parameters can be used
native func n-external-func-name(copy Int{0:255} in-param):
(Int{0:255} out-param,)
# in C this will call a function declared as:
# Returncode external_func_name(Uint* out_param, Uint in_param)
# "Returncode", "Uint" and others are typedefs declared in "mr-c-api.h"
# Sometimes we wish to receive and store a reference to some native
# data-structure that can be used in other native functions.
# Unknown native types declaration:
native type Some-native-type
# we can the use this types in MR code as reference:
native func n-get-reference(out Some-native-type ref)
native func n-work-with-reference(
user Some-native-type ref,
copy Int{0:255} param)
native func n-delete-reference(owner Some-native-type ref)
# this is the only case an "owner" parameter can be used
# in C, native types are treated as "void*"
# error handling
#################
func f-error-raising()
raise
# TODO
# Type system
##############
(#
Dynamic Interface
Static Structure
Interface + Structure = Class
* Var: var structure
* Ref: ref structure
* Interface: ref interface
* Generic Duck: ref interface, ref object
* Class Duck: ref interface, ref structure
* Embed: ref interface, var structure
* Embed Ref: ref (ref interface, var structure)
Class Example
var Example example
#)
static Struct(Object)
# ...
dynamic Interface(Object)
# ...
class Class(Object)
# ...
func f-oop-example()
# structure
var Struct structure-only
var Class class-structure-only
# reference
user Struct structure-reference
user Class.static class-structure-reference
# interface
user Interface interface-and-object-refernece
user Class.interface class-interface-and-object-refernece
user Interface.dynamic interface-only
user Class.dynamic class-interface-only
# binding
user Bind{Struct:Interface} interface-and-structure-reference
user Class class-interface-and-structure-reference
# embed
var Embed{Struct:Interface} interface-and-structure
var Embed{Example} class-interface-and-structure
user Embed{Struct:Interface} reference-to-interface-and-structure
user Embed{Example} class-reference-to-interface-and-structure
(#
Object type is:
1. "interface" if has no instance variables, else "class"
2. "abstract" if has abstract members, else "dynamic" if has dynamic members,
else "static"
Full table:
\ has or inherit|instance |abstract | dynamic |
class type \ |variables| members | members |
------------------+---------+---------+---------+---
static interface | X | X | X | "generic"
------------------+---------+---------+---------+---
abstract interface| X | V | X/V | "interface"
------------------+---------+---------+---------+---
dynamic interface| X | X | V | "dynamic"
------------------+---------+---------+---------+---
static class | V | X | X | "structure"
------------------+---------+---------+---------+---
abstract class | V | V | X/V | "abstract"
------------------+---------+---------+---------+---
dynamic class | V | X | V | "class"
Everyone can have: instance functions, global members
#)
# Object type deceleration:
# "Object" is the base type of all object types
static interface Object(Object)
inst func ref():(copy Uint-size obj-ref)
inst func equal(user Object other):(copy Bool is-equal)
# Each object type must have a base type
static class Class-name(Object)
# members declaration
inst var Int{0:99} int-member
inst var Char char-member
inst var String{60} string-member
inst owner String{Uint8b} string-reference-member
# methods declaration, use "self" to access instance members
inst func m-get-int():(copy Int{0:99} int-res)
int-res := self.int-member
inst func m-set-int(copy Int{0:99} int-arg)
if self.m-get-int() != int-arg
self.int-member := int-arg
# class global definitions
class const Int CLASS-CONST(3)
static class var Int class-global-variable
# use "self-class" to access global members
static class func m-inv(copy Int{0:99} int-arg):(copy Int{0:99} int-res)
int-res := clamp int-arg + self-class.CLASS-CONST +
self-class.class-global-variable
# static class inheritance
static class Deriver-class(Class-name)
# additional members
inst var Int{0:99} another-int
# override function, use "base" for base class instance members
inst func m-set-int(copy Int{0:99} int-arg)
base.m-set-int(copy int-arg)
self.int-member := int-arg
# override class global definitions
# use "base-class" for base class global members
class const Int CLASS-CONST(base-class.CLASS-CONST + 1)
static class var Int class-global-variable
static class func m-inv(copy Int{0:99} int-arg):(copy Int{0:99} int-res)
int-res := clamp int-arg + self-class.CLASS-CONST +
self-class.class-global-variable + base-class.class-global-variable
# declare interfaces
abstract interface Interface-name(Object)
abstract class var Int{0:255} polymorphic-int
abstract inst func m-polymorphic-meth(copy Int{0:255} int-arg)
abstract class func m-polymorphic-func(copy Int{0:255} int-arg)
# interface with default implementation
dynamic interface Implemented-interface(Interface-name)
dynamic class var Int{0:255} polymorphic-int(3)
dynamic inst func m-polymorphic-meth(copy Int{0:255} int-arg)
self.m-polymorphic-func(int-arg)
dynamic class func m-polymorphic-func(copy Int{0:255} int-arg)
self-class.polymorphic-int := int-arg / 3
# Polymorphic classes:
abstract class Abstract-class(Interface-name)
inst var Int{0:255} int-member
inst func m-some-meth(copy Int{0:255} int-arg):
self.int-member := int-arg / self.polymorphic-int
dynamic class Implemented-class(Abstract-class)
dynamic class var Int{0:255} polymorphic-int(3)
dynamic inst func m-polymorphic-meth(copy Int{0:255} int-arg)
self.int-member := int-arg / 3
dynamic class func m-polymorphic-func(copy Int{0:255} int-arg)
self-class.polymorphic-int := int-arg / 3
# single base classs with multiple interfaces
abstract interface First-interface(Object)
abstract inst func m-first-func()
abstract interface Second-interface(Object)
abstract inst func m-second-func()
dynamic class Multiple(Class-name): First-interface, Second-interface
dynamic inst func m-first-func()
self.m-set-int(self.m-get-int())
dynamic inst func m-second-func()
self.int-member := self.m-get-int()
# TODO construction
# TODO destruction
# TODO using classes
# generics
static class My-generic{Any-type}(Object)
inst var Int count
inst user My-generic{Generic} next
inst owner Any-type item
inst func m-set(owner Any-type item)
self.item := item
inst func m-get():(user Any-type item)
item := self.item
func f-generic-example()
new Class-name item
var My-generic{Class-name} generic
generic.m-set(owner item)
item := generic.m-get()
func f-generic{Any-type}(user Any-type param):(user Any-type output)
output := param
static class My-generic{Class-name-type{Class-name}:
Abstract-class-type{Abstract-class}}(Object)
owner Class-name-type class-name-item
owner Abstract-class-type abstract-class-item
# Others
#########
# String formatting
func f-str-getter(copy Int x, user String text, copy Int y)
# ...
func f-format-example()
var String{256} s1("")
user String sa("AAA")
user String sb("BBB")
user String sc("CCC")
s1.concat(* ("a={}, b={}, c={}", sa, sb, sc))
f-str-getter(copy 3, * ("a={}, b={}, c={}", sa, sb, sc), copy 7)
do
for part in "a={}, b={}, c={}", sa, sb, sc
for n in 6
sys.print(user part)
s1.concat(user part)
f-str-getter(copy 0, user part, copy n)
# Type variable
func f-type-var-example()
var Type{Abstract-class} abstract-type(Implemented-class)
abstract-type := Implemented-class
var As{abstract-type} abstract-var
new As{abstract-type} abstract-ref
# aliases
alias NEW-CONST-INT for CONTS-INT
alias m-new-func-name for m-func-name
alias New-int-name for Int{20:40}
alias New-string-name for String{Uint8b}
alias New-array-name for Array{Int{0:60}:String{Uint8b}}
alias New-class-name for Class-name
# unit tests
#############
mock f-mocked-function(copy Uint8b x):(copy Uint8b y)
assert x > 3
y := 3
mock Sys.write(user String{Uint16b} text)
return
test f-test-func()
assert f-tested-func(copy 12) = 13