2019-06-27 06:29:09 +00:00
|
|
|
### Top-level elements
|
2019-06-22 02:02:59 +00:00
|
|
|
* #include
|
|
|
|
* #pragma
|
|
|
|
* class
|
|
|
|
* interface
|
|
|
|
* pooldic
|
|
|
|
|
2019-06-27 06:29:09 +00:00
|
|
|
### Comments
|
2019-06-22 02:02:59 +00:00
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
#! comment text
|
|
|
|
// comment text
|
|
|
|
/* comment text */
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
|
|
|
|
### Literal notations
|
2019-06-22 02:02:59 +00:00
|
|
|
* 200 decimal integer
|
|
|
|
* 2r1100 binary integer
|
|
|
|
* 16rFF00 hexadecimal integer
|
|
|
|
* 20p9999.99 fixed-point decimal where 20 is the number of digits after the point
|
|
|
|
* 999.9 fixed-point decimal
|
|
|
|
|
|
|
|
* $X character
|
|
|
|
* C'X' -> charcter??
|
|
|
|
* C"X" -> character??
|
|
|
|
|
2019-06-27 07:43:17 +00:00
|
|
|
* 'XXXX' string literal
|
|
|
|
* "XXXX" string litearl with escaping
|
2019-06-22 02:02:59 +00:00
|
|
|
|
2019-06-27 07:43:17 +00:00
|
|
|
* B'XXXXXX' -> byte array literal
|
|
|
|
* B"XXXXX" -> byte array literal with escaping
|
2019-06-22 02:02:59 +00:00
|
|
|
|
|
|
|
* #XXXX symbol
|
|
|
|
* #'XXXX' quoted symbol
|
|
|
|
* #"XXXX" quoted symbol with escaping
|
|
|
|
|
2019-06-27 07:43:17 +00:00
|
|
|
* #\e123 Error literal
|
|
|
|
* #\pB8000000 SmallPointer(smptr) literal
|
2019-06-22 02:02:59 +00:00
|
|
|
|
2019-06-28 06:13:09 +00:00
|
|
|
* #() Array. Comma as element delimiter is optional
|
2019-10-29 14:21:14 +00:00
|
|
|
* #[] ByteArray. Comma as element delimiter is optional #[ 16r10, 16r20, 16r30 ] #[ "\x10\x20", "\x30" ]
|
2019-06-27 07:43:17 +00:00
|
|
|
* #{} Dictionary - not supported yet
|
2019-06-22 02:02:59 +00:00
|
|
|
|
2019-10-29 14:21:14 +00:00
|
|
|
|
2019-08-02 16:12:12 +00:00
|
|
|
The followings are not literals. The followings forms expressions.
|
2019-06-22 02:02:59 +00:00
|
|
|
|
2019-06-28 06:13:09 +00:00
|
|
|
* ##() Array expression. Comma required to delimit elements
|
|
|
|
* ##[] ByteArray expression. Comma required to delimit elements
|
|
|
|
* ##{} Dictionary expression. Comma required to delimit elements
|
2019-06-22 02:02:59 +00:00
|
|
|
|
2019-08-02 16:12:12 +00:00
|
|
|
The followings are not implemented. but can i do something like these?
|
|
|
|
* S#[] String literal with each character specified. S%{A B C '\n'}
|
|
|
|
* S#{} String with dynamic expression
|
|
|
|
* S#{ 65 asCharacter, 64 asCharacter }
|
2019-06-27 06:29:09 +00:00
|
|
|
|
|
|
|
### Class
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
class MyClass(Object)
|
|
|
|
{
|
|
|
|
method show: this
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
|
2019-09-05 15:55:39 +00:00
|
|
|
Class attributes
|
|
|
|
|
|
|
|
The word class can be followed by attribute list enclosed in parenthesis. e.g.) class(#limited,#immutable)
|
|
|
|
|
|
|
|
* #limited - not instantiable with new.
|
|
|
|
* #immutable - instantiated object to be read-only.
|
|
|
|
* #final - disallow subclasses.
|
2019-09-22 15:59:09 +00:00
|
|
|
* #uncopyable - instantiated object not to be copied.
|
2019-09-05 15:55:39 +00:00
|
|
|
* #byte, #character, #halfword, #word, #liword, #pointer -
|
|
|
|
specify the type of a non-pointer object. a non-pointer type can have an additional size
|
|
|
|
enclosed in parenthesis. e.g.) #character(2)
|
|
|
|
a non-pointer object is not allowed to have named instanced variables.
|
|
|
|
a non-pointer object is always variable indexed.
|
|
|
|
* #pointer - specify a pointer variable indexed object. an instantiate object can have extra
|
|
|
|
object pointers in additon to named instance variables.
|
|
|
|
|
|
|
|
```
|
|
|
|
class(#word(2)) X(Object) { }
|
|
|
|
X new -> create an object with 2 words.
|
|
|
|
X new: 4 -> create an object with 6 words.
|
|
|
|
```
|
|
|
|
|
2019-09-22 16:26:30 +00:00
|
|
|
if an object is asked to instantiate with trailer in the class defintion, it becomes
|
|
|
|
uncopyable, without the #uncopyable attribute.
|
|
|
|
|
|
|
|
```
|
|
|
|
class Shader(Object) from 'shader'
|
|
|
|
{
|
|
|
|
// if the shaer module calls moo_setclasstrsize(), an instance of Shader is uncopyable
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2019-10-01 09:19:25 +00:00
|
|
|
### Pool dictionary
|
2019-10-02 09:36:44 +00:00
|
|
|
```
|
2019-10-01 09:19:25 +00:00
|
|
|
pooldic MyData
|
|
|
|
{
|
|
|
|
A := 20,
|
|
|
|
B := 30,
|
|
|
|
C := 40
|
|
|
|
}
|
|
|
|
|
2019-10-02 09:34:43 +00:00
|
|
|
class MyClass(Object)
|
2019-10-01 09:19:25 +00:00
|
|
|
{
|
|
|
|
import MyData.
|
|
|
|
|
|
|
|
method x ()
|
|
|
|
{
|
|
|
|
MyData.A dump.
|
|
|
|
C dump. // if imported, it doesn't require prefixing with MyData.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-02 09:34:43 +00:00
|
|
|
class MyClass2(Object)
|
2019-10-01 09:19:25 +00:00
|
|
|
{
|
|
|
|
pooldic Const
|
|
|
|
{
|
2019-10-02 09:34:43 +00:00
|
|
|
A := 20,
|
|
|
|
B := 30
|
2019-10-01 09:19:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
method x()
|
|
|
|
{
|
|
|
|
A dump. // the nested pooldic is auto-imported.
|
|
|
|
Const.A dump.
|
|
|
|
self.Const dump.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-02 09:34:43 +00:00
|
|
|
class MyClass3(MyClass2)
|
|
|
|
{
|
|
|
|
pooldic Const
|
|
|
|
{
|
|
|
|
A := MyClass2.Const.A // pooldic is not inherited. need redefinition for auto-import
|
|
|
|
B := MyClass2.Const.B
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MyClass4(MyClass2)
|
|
|
|
{
|
|
|
|
import MyClass2.Const. // similar to redefinition inside the class. it won't be available MyClass4.Const as such is not available.
|
|
|
|
|
|
|
|
|
|
|
|
method x
|
|
|
|
{
|
|
|
|
MyClass2.Const at: #XXX put: 'QQQQQQQQQQQQQQ'. // you can add a new item dynamically,
|
|
|
|
(MyClass2.Const at: #XXX) dump. // and can access it.
|
|
|
|
|
|
|
|
// the compiler doesn't recognize the dynamically added item as MyClass2.Const.XXX
|
|
|
|
}
|
|
|
|
}
|
2019-10-02 09:36:44 +00:00
|
|
|
```
|
2019-10-02 09:34:43 +00:00
|
|
|
|
2019-06-27 06:29:09 +00:00
|
|
|
### Flow Control
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
k := if (i < 20) { 30 } else { 40 }.
|
2019-07-13 03:06:07 +00:00
|
|
|
|
|
|
|
if (a < 10) { ... }
|
2019-07-26 04:40:33 +00:00
|
|
|
elif (a < 20) { ... }
|
|
|
|
else { ... }.
|
|
|
|
|
2019-08-02 16:12:12 +00:00
|
|
|
ifnot (i < 20) { 30 } else { 40 }. /* TODO: ifnot or nif? elifnot or elnif? */
|
2019-07-26 04:40:33 +00:00
|
|
|
|
|
|
|
if (a < 10) { .. }
|
|
|
|
elifnot (a > 20) { ... }
|
2019-07-13 03:06:07 +00:00
|
|
|
else { ... }.
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
|
|
|
|
}.
|
2019-07-13 03:06:07 +00:00
|
|
|
|
|
|
|
until (a > b)
|
|
|
|
{
|
|
|
|
}.
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
} while (a > b).
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
} until (a > b).
|
|
|
|
|
|
|
|
[a > b] whileTrue: [ ... ].
|
|
|
|
[a > b] whileFalse: [ ... ].
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
1 to: 20 do: [:count | ... ].
|
2019-07-13 03:06:07 +00:00
|
|
|
1 to: 10 by: 3 do: [:count | ... ].
|
|
|
|
30 timesRepeat: [ ... ].
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-06-27 06:29:09 +00:00
|
|
|
|
2019-07-12 07:24:37 +00:00
|
|
|
|
|
|
|
### Exception handling
|
|
|
|
Exception signal.
|
|
|
|
Exception signal: "message".
|
|
|
|
|
|
|
|
[ ... ] on: Exception do: [:ex | ... ].
|
|
|
|
|
|
|
|
ex retry.
|
|
|
|
ex resume.
|
|
|
|
ex resume: value.
|
|
|
|
ex return: value.
|
2019-07-13 03:06:07 +00:00
|
|
|
|
2019-08-06 10:01:54 +00:00
|
|
|
### return from context(method/block)
|
|
|
|
|
|
|
|
explicit return operators
|
|
|
|
```
|
|
|
|
^ return_stacktop
|
|
|
|
^^ local_return
|
|
|
|
```
|
|
|
|
|
|
|
|
implicit return when the end of the context is reached
|
|
|
|
* a method context returns the receiver.
|
|
|
|
* a block context returns the last evaluated value. if nothing has been evaluated, nil is returned.
|
|
|
|
|
2019-07-14 16:46:08 +00:00
|
|
|
### goto
|
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-07-14 16:46:08 +00:00
|
|
|
goto jump_label.
|
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
jump_label:
|
2019-08-06 10:01:54 +00:00
|
|
|
a + b.
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-07-14 16:46:08 +00:00
|
|
|
|
2019-08-06 10:01:54 +00:00
|
|
|
goto inside a block context.
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-08-06 10:01:54 +00:00
|
|
|
[ 1 + 2. goto r. 3 + 4. r: 99 ]
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-07-14 16:46:08 +00:00
|
|
|
|
|
|
|
goto must not cross the boundary of the block context.
|
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-07-14 16:46:08 +00:00
|
|
|
this is invalid. cannot jump into a block from outside
|
|
|
|
and vice versa.
|
|
|
|
goto x.
|
2019-08-02 16:12:12 +00:00
|
|
|
[ x:
|
2019-07-14 16:46:08 +00:00
|
|
|
1 + 2 ].
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-07-14 16:46:08 +00:00
|
|
|
|
|
|
|
|
2019-07-13 03:06:07 +00:00
|
|
|
### Type checking
|
|
|
|
|
|
|
|
Type checking not implemented yet.
|
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-07-13 03:06:07 +00:00
|
|
|
class SampleClass(Object)
|
|
|
|
{
|
|
|
|
method run => Integer
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
method execute((Integer)a,(Integer)b) => Integer
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
method handle: (Object)this with: (a Integer)care => Integer
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-07-13 03:06:07 +00:00
|
|
|
|
|
|
|
TODO: How to specify return type of a block? or How to specify parameter type to a block?
|
|
|
|
How to evaluate a block type-safely?
|
2019-07-30 06:07:24 +00:00
|
|
|
|
|
|
|
```
|
2019-07-14 16:46:08 +00:00
|
|
|
[ :(Integer)a :(Integer)b => Integer |
|
2019-07-13 03:06:07 +00:00
|
|
|
| (Integer)c (Integer)d }
|
|
|
|
a + b
|
|
|
|
] with: 20 with: 10
|
2019-07-14 16:46:08 +00:00
|
|
|
|
|
|
|
the method value is a variadic method. and it is a primitive.
|
|
|
|
[ :a :b | a + b ](1, 20) <---- syntax sugar for [:a :b | a + b] value(1, 20).
|
|
|
|
|
|
|
|
[:(Integer)a :(Integer)b => Integer | a + b ] value("kkkk", 20)
|
|
|
|
-> the first argument violates the expected type.
|
|
|
|
-> argument types to a method is defined in the method signature.
|
|
|
|
-> but the block argument types are specified in the block itself.
|
|
|
|
-> so it doesn't seem natural to achieve type safety without treating 'value' specially.
|
|
|
|
-> create a shorthand expression for 'value' [:(Integer)a :(Integer)b => (Integer) | a + b ](1, 2)
|
|
|
|
-> ] followed by ( ===> shorthand expression for value.
|
|
|
|
-> it looks more sensible to treat this () specially
|
|
|
|
|
|
|
|
what looks better as a shorthand expression for block value?
|
|
|
|
[ :a :b | a + b ](10, 20)
|
|
|
|
[ 10 + 20 ]() // no arguments
|
|
|
|
[ :a :b | a + b ]->(10, 20). // -> cannot form a valid binary selector. must exclude it from binary selector patterns
|
|
|
|
[ 10 + 20 ]->() // if no arugments are required.
|
|
|
|
|
|
|
|
continuation?
|
|
|
|
| a |
|
|
|
|
a->()? block value?
|
|
|
|
|
|
|
|
| (Block)a |
|
|
|
|
a->()? block value?
|
|
|
|
|
2019-07-30 06:07:24 +00:00
|
|
|
```
|
2019-08-10 04:08:49 +00:00
|
|
|
|
|
|
|
### FFI
|
|
|
|
|
|
|
|
```
|
|
|
|
ffi := FFI new: 'libc.so.6'.
|
2019-08-16 15:29:36 +00:00
|
|
|
[
|
|
|
|
(ffi call: #printf signature: 's|sl>i' arguments: #("[%s ffi test %ld]\n" "sloppy" 12345678)) dump.
|
|
|
|
(ffi call: #printf signature: 's>i' arguments: #("[%% ffi test %%]\n")) dump.
|
|
|
|
(ffi call: #puts signature: 's>i' arguments: #("this is ffi test")) dump.
|
|
|
|
(ffi call: #time signature: 'p>l' arguments: #(#\p0)) dump.
|
|
|
|
]
|
|
|
|
ensure: [
|
|
|
|
ffi close.
|
|
|
|
].
|
2019-08-10 04:08:49 +00:00
|
|
|
```
|
2019-08-16 15:29:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Command line options
|
|
|
|
|
|
|
|
```
|
|
|
|
moo --log /dev/stderr ../kernel/test-001.moo
|
|
|
|
moo --log /dev/stderr,warn+ ../kernel/test-001.moo
|
|
|
|
```
|
|
|
|
|