// //------------------ DOK FILE -------------------------------------------------- +Header languageLib =pkg bios =title Language =short keywords and exceptions =desc This section is about the keywords of Minimacy, such as if, then, else, call, match, ... All of them are explained in the tutorial, so we just give some short explanation on each. Exceptions are also part of this section. // // //------------------ PROTO ----------------------------------------------------- equals +Proto equals =type fun a1 a1 -> Bool =mode function =pkg bios =impl native =link =desc This function is exactly the same than the operator ==. Its only interest is to use it as a lambda function: > #equals >-> fun a1 a1 -> Bool: #2 [ > 0: > Str: "equals" > 1: > Int: 8 (0x8) >] > #== >Compiler: function not found ('==') >> #==;; >> ^ // +arg p =type a1 =desc An element of any type // +arg q =type a1 =desc An element of the same type // +arg result =type Bool =desc A boolean // // //------------------ PROTO ----------------------------------------------------- Exception +Proto Error =type Error =mode sum =pkg bios =impl native =link =desc The type Error is a sum type defined by the VM. It is the only type of data you may use with [[setError]] and retrieve with [[lastError]]. As this is a sum type, you can extend it with your own errors beyond [[msgError]]. // // //------------------ PROTO ----------------------------------------------------- msgException +Proto msgError =type fun Str -> Error =mode constructor =pkg bios =impl mcy =link =desc This is a kind of error with a single string argument. > setError (msgError "foobar") // // //------------------ PROTO ----------------------------------------------------- var +Proto var =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword to define a global variable. The name of the variable must start with uppercase. > var Foo=123 >-> a1: VAR Foo > Type: Int > Int: 123 (0x7b) > Foo >-> Int: 123 (0x7b) > set Foo=456 >-> Int: 456 (0x1c8) // // //------------------ PROTO ----------------------------------------------------- const +Proto const =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword to define a constant. The name of the constant must start with uppercase. > const Foo=123 >-> a1: CONST Foo > Type: Int > Int: 123 (0x7b) > Foo >-> Int: 123 (0x7b) > set Foo=456 > >Compiler: constant 'Foo' cannot be modified // // //------------------ PROTO ----------------------------------------------------- call +Proto call =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword to evaluate a lambda function. It is expected to be followed with one lambda function then a variable number of parameters. It returns the result of the lambda function. > call #fullDate (time) >-> Str: "Sun, 15 May 2022 13:13:21 UTC" > call (lambda (x, y)= x+y) (1, 2) >-> Int: 3 (0x3) // // //------------------ PROTO ----------------------------------------------------- nil +Proto nil =type - =mode keyword =pkg language =impl keyword =link =desc This is the "nothing" value, for any types. // // //------------------ PROTO ----------------------------------------------------- while +Proto while =type - =mode keyword =pkg language =impl keyword =link explicit =desc This is a way to implement loops: while condition do expression Condition is a boolean. The expression loops as long as the condition is true. When you have a while, it means you have a side-effect. Just be aware of that! The result of the while is the value of the expression at the last loop, or nil when no loop occurs (condition already false before the first loop). // // //------------------ PROTO ----------------------------------------------------- repeat +Proto repeat =type - =mode keyword =pkg language =impl keyword =link =desc This is a way to implement loops: repeat expression until condition Condition is a boolean. The expression loops as long as the condition is not true. When you have a repeat, it means you have a side-effect. Just be aware of that! The result of the repeat is the value of the expression at the last loop. // // //------------------ PROTO ----------------------------------------------------- until +Proto until =type - =mode keyword =pkg language =impl keyword =link =desc Keyword. See [[repeat]] // // //------------------ PROTO ----------------------------------------------------- for +Proto for =type - =mode keyword =pkg language =impl keyword =link explicit =desc This is a way to implement loops, based on an iterator. for iterator_definition; condition; next_iterator_value do expression There are different kind of iterators: - integer - elements from a list - elements from an array - any other type With an integer, you define the name of the iterator, the condition and the increment. for i=0 ; i<20 ; i*2+1 do dump i The scope of iterator i is only in the expression after the do. Observe that the increment part is 'i*2+1' and not the C-like 'i=i*2+1'. This is simply the next value of the iterator. When the increment is +1, it can be skipped. In the following example, the loop will run for i=0, i=1, ..., i=19. for i=0 ; i<20 do dump i With a list: for p in 1::2::3::nil do dump p In this example, p is not really an iterator, the real iterator is the list itself. It is possible to get an iterator of the loop: for p,q in 1::2::3::nil do dump q >-> list: > Int: 1 (0x1) > Int: 2 (0x2) > Int: 3 (0x3) >-> list: > Int: 2 (0x2) > Int: 3 (0x3) >-> list: > Int: 3 (0x3) >-> list Int: > Int: 3 (0x3) In the first loop q is the full list, then the full list minus the first element, then... If you are only interested into this iterator q, there is the following example: for q=1::2::3::nil; q<>nil ; tail (q) do dump q With an array: for p of {4, 3, 6} do dump p In this example, p is not really an iterator, the real iterator is the index in the array, starting from 0. It is possible to get an iterator of the loop: for p,index of {4, 3, 6} do dump index With anything: We already saw this example: for q=1::2::3::nil; q<>nil ; tail (q) do dump q We may have a more complex iterator structure: for [x, y]=[0, 10]; x 1+if true then 2 else 3 -> Int: 3 (0x3) When else is omitted, it is considered as 'else nil'. It is possible to chain 'if' constructions by replacing 'else if' with 'elif'. // // //------------------ PROTO ----------------------------------------------------- then +Proto then =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[if]] // // //------------------ PROTO ----------------------------------------------------- elif +Proto elif =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[if]] // // //------------------ PROTO ----------------------------------------------------- else +Proto else =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[if]] // // //------------------ PROTO ----------------------------------------------------- do +Proto do =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[while]] and [[for]] // // //------------------ PROTO ----------------------------------------------------- fun +Proto fun =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword for function declaration. // // //------------------ PROTO ----------------------------------------------------- lambda +Proto lambda =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword for lambda function instanciation. // // //------------------ PROTO ----------------------------------------------------- match +Proto match =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword for pattern matching. match expression with value_A -> expression_A, value_B -> expression_B, value_C -> expression_C, _ -> expression_default The VM evaluates 'expression' then check the value with value_A, value_B, ... in this order. When one of these values matches, for example value_B, then expression_B is evaluated and the result is also the result of the match. When no value matches, the match returns expression_default. When no expression_default is defined, the match returns nil. When expression has a sum type, match is used to extract the constructor and its parameter, and evaluate a specific expression. sum Test= intT _, vec2T _ _, zeroT;; ... match v with intT val -> val, vec2T x y -> x+y, zeroT -> 0;; // // //------------------ PROTO ----------------------------------------------------- with +Proto with =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[match]] and [[extend]]. // // //------------------ PROTO ----------------------------------------------------- try +Proto try =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword allows to work with [[abort]]. try mainExpression When the mainExpression evaluates a 'abort' the evaluation is aborted immediately and the try returns nil. It is possible to define an expression to evaluate when the mainExpression evaluation is aborted: try mainExpression else elseExpression When the mainExpression evaluates a 'abort' the evaluation is aborted immediately and the elseExpression is evaluated. Both expressions must have the same type. // // //------------------ PROTO ----------------------------------------------------- throw +Proto abort =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword allows to work with [[try]]. try if bitTest (time(), 1) then abort else echoLn "timestamp is even" else echoLn "timestamp is odd";; When abort is evaluated, the VM search in the callstack if the evaluation is currently in a [[try]] main expression: - if yes, the evaluation is aborted and continues with the elseExpression of the [[try]] - if no, the 'abort' is processed as a '[[return]] nil' // // //------------------ PROTO ----------------------------------------------------- return +Proto return =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword shortens a function evaluation by providing the result immediately. It is usually a sign of side-effects, and may be useful in loops such as while ... do and for ... do. for i=0; i<20 do if i==j then return i; // // //------------------ PROTO ----------------------------------------------------- break +Proto break =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword breaks a loop by providing the result immediately. It is usually a sign of side-effects, and may be useful in loops such as while ... do and for ... do. for i=0; i< 20 do if i==j then break i; // // //------------------ PROTO ----------------------------------------------------- in +Proto in =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[let]] and [[for]] // // //------------------ PROTO ----------------------------------------------------- of +Proto of =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[for]] // // //------------------ PROTO ----------------------------------------------------- set +Proto set =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword is used to update a variable value. set x=1 The 'set' returns the new value. > let 0->x in dump set x=1 >-> Int: 1 (0x1) // // //------------------ PROTO ----------------------------------------------------- let +Proto let =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword allows to define local variables. let expression -> local variables in expression This follows the order of the computation: first we compute something, then we store it in a new local variable, then we may use it in an expression. let 3 -> x in let x+5 -> y in y*y It is possible to create more local variables in a single _let let 1::2::3::nil -> a::b::_ in ... let [123, 456, 789] -> [a, _, b] in ... // // //------------------ PROTO ----------------------------------------------------- extend +Proto extend =type - =mode keyword =pkg language =impl keyword =link explicit =desc Keyword. See [[sum]]. // // //------------------ PROTO ----------------------------------------------------- enum +Proto enum =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword allows to declare integer constants enum A, B, C;; then: A=0, B=1, C=2 // // //------------------ PROTO ----------------------------------------------------- sum +Proto sum =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword if for sum type declaration. sum Test= intT _, vec2T _ _, zeroT;; See [[extend]] to declare more constructors to an existing sum type. // // //------------------ PROTO ----------------------------------------------------- struct +Proto struct =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword if for structure type declaration. sum Test= [xT, yT, nameT];; It is possible to declare a derived structure with more fields. sum SubTest= Test + [zT];; // // //------------------ PROTO ----------------------------------------------------- include +Proto include =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword is followed by a package name, which is derived from the package name which declares the include. For example, bios.mcy contains: include bios._file;; It may only include files starting with "bios._" It is not a new package, it is just a way to split a long package into smaller source code files. See [[use]]. // // //------------------ PROTO ----------------------------------------------------- use +Proto use =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword is followed by a package name and accept an alias declaration. use core.util.json;; use core.util.xml as Xml;; Packages to use cannot contain the substring "._". Else they are considered a packages to include. See [[include]]; // // //------------------ PROTO ----------------------------------------------------- \float +Proto \float =type - =mode keyword =pkg language =impl keyword =link =desc This construction simplifies the syntax of float expressions. For example if you want to compute 1+pi, the regular syntax is the following: > 1.+.pi >-> Float: 4.14159 It is required to use "1." instead of "1", because "1" is an integer. It is also required to use "+." instead of "+", because we perform an addition of floats. \\float is followed by an expression. In this expression any number or operation will be considered as float number or operation. The following example is equivalent to the example above. > \float 1+pi >-> Float: 4.14159 // // //------------------ PROTO ----------------------------------------------------- \modBarrett +Proto \modBarrett =type - =mode keyword =pkg language =impl keyword =link =desc This construction simplifies the syntax of big numbers expressions with a modulus and the Barret optimisation. For example if you want to compute 10/20 mod 7 with big numbers, the regular syntax is the following: > bigDivModBarrett (bigFromInt (10), bigFromInt (20), bigFromInt (7), bigBarrett (bigFromInt (7))) >-> BigNum: 00000004 This may be painful with larger expressions. \\modBarrett is followed by the modulus, then the Barrett factor, then an expression. In this expression any number or operation will be considered as big number or operation over big numbers with modulus and Barrett optimisation. The following example is equivalent to the example above. > \modBarrett (7, bigBarrett (7)) { 10/20 } >-> BigNum: 00000004 The modulus expression and the Barret factor are considered as operating on big numbers, as in \\bigNum{...} > \modBarrett (7+2, bigBarrett (7+2)) { 10+20 } >-> BigNum: 00000003 The Barret optimisation is interesting only when you have multiple operations to perform with the same modulus. This optimisation applies on multiplication, division, power and simple modulus. // // //------------------ PROTO ----------------------------------------------------- \mod +Proto \mod =type - =mode keyword =pkg language =impl keyword =link =desc This construction simplifies the syntax of big numbers expressions with a modulus. For example if you want to compute 10+20 mod 7 with big numbers, the regular syntax is the following: > bigAddMod (bigFromInt (10), bigFromInt (20), bigFromInt (7)) >-> BigNum: 00000002 This may be painful with larger expressions. \\mod is followed by the modulus then an expression. In this expression any number or operation will be considered as big number or operation over big numbers with modulus. The following example is equivalent to the example above. > \mod (7) 10+20 >-> BigNum: 00000002 The modulus expression is considered as operating on big numbers, as in \\bigNum ... > \mod (7+2) 10+20 >-> BigNum: 00000003 > \mod (\bigNum 7+2) 10+20 >-> BigNum: 00000003 // // //------------------ PROTO ----------------------------------------------------- \bigNum +Proto \bigNum =type - =mode keyword =pkg language =impl keyword =link =desc This construction simplifies the syntax of big numbers expressions. For example if you want to compute 1+2 with big numbers, the regular syntax is the following: > bigAdd (bigFromInt (1), bigFromInt (2)) >-> BigNum: 00000003 This may be painful with larger expressions. \\bigNum is followed by an expression. In this expression any number or operation will be considered as big number or operation over big numbers. The following example is equivalent to the example above. > \bigNum 1+2 >-> BigNum: 00000003 If you need modulus operations on big numbers, consider using \\mod or \\modBarret. // // //------------------ PROTO ----------------------------------------------------- \integer +Proto \integer =type - =mode keyword =pkg language =impl keyword =link =desc When using "\\float expression" construction, it happens that you need also to deal with integers inside the expression. This is when you may user \\integer ... to use the regular syntax on integers. > \float 1+ floatFromInt (\integer 2+3) >-> Float: 6 This is equivalent to: > 1.+.floatFromInt 2+3 >-> Float: 6 // // //------------------ PROTO ----------------------------------------------------- proto +Proto proto =type - =mode keyword =pkg language =impl keyword =link explicit =desc This keyword may be seen only in compiler outputs when an compiling error occurs. The compiler stops at the first error. At this point some functions are already compiled, some other not. The later will be seen as "proto" instead of "fun". For example, create a file with the following program: fun f (x)= x+1;; fun g (x)= x+pi;; fun h (x)= x*2;; Start the program, the compiler will stop on g, because pi is a float and + is an addition on integers. The result of the compiler is: >> fun f : fun Int -> Int >> proto fun g : fun Int -> a1 >> proto fun h : fun a1 -> a2 The meaning of "proto" is: f is already fully compiled with success, g and h aren't yet. // // //------------------ PROTO ----------------------------------------------------- export +Proto export =type - =mode keyword =pkg language =impl keyword =link explicit =desc // // //------------------ PROTO ----------------------------------------------------- run +Proto main =type fun -> a1 =mode keyword =pkg bios =impl mcy =link explicit =desc Defining a function main in a package makes it "runable". If this package is started (for example by double-clicking on a mcy file), the VM compiles it and call its function main. Alternately, a call to the [[start]] function of the bios will have the same effect: compiling the package and call its function main. // +arg result =type a1 =desc Any result // // //------------------ PROTO ----------------------------------------------------- ifdef +Proto #ifdef =type - =mode keyword =pkg language =impl keyword =link =desc This declaration allows to compile or ignore a set of declarations. In this sample, the declarations will be compiled only if the XXXX is a defined label #ifdef XXXX { ... declarations ... } It is possible to write an else statement: #ifdef XXXX { ... } else { ... } // // //------------------ PROTO ----------------------------------------------------- as +Proto as =type - =mode keyword =pkg language =impl keyword =link =desc Keyword. See [[use]] // // //------------------ PROTO ----------------------------------------------------- ifndef +Proto #ifndef =type - =mode keyword =pkg language =impl keyword =link =desc This declaration allows to compile or ignore a set of declarations. In this sample, the declarations will be compiled only if the XXXX is not a defined label #ifndef XXXX { ... declarations ... } It is possible to write an else statement: #ifdef XXXX { ... } else { ... } // // //------------------ PROTO ----------------------------------------------------- elifdef +Proto #elifdef =type a1 =mode keyword =pkg language =impl keyword =link =desc // // //------------------ PROTO ----------------------------------------------------- elifndef +Proto #elifndef =type a1 =mode keyword =pkg language =impl keyword =link =desc // // //------------------ PROTO ----------------------------------------------------- endif +Proto #endif =type a1 =mode keyword =pkg language =impl keyword =link =desc // // //------------------ PROTO ----------------------------------------------------- hide +Proto hide =type a1 =mode keyword =pkg language =impl keyword =link =desc // // //------------------ PROTO ----------------------------------------------------- void +Proto void =type fun a1 -> a2 =mode keyword =pkg language =impl keyword =link =desc This function is used to simplify the code when using imperative programming: it evaluates the expression yet always returns [[nil]]. void expression is equivalent to: (expression; nil) It is useful when using 'if ... then ... else ...' or 'match ... with ...' when you don't care about the result and when the different branches do not return the same type. It is clear sign that you are using side-effects. For example, the following example will fail because the 'then' expression returns a string and the 'else' expression returns an integer: if my_test then echoLn "Then case" else echoLn time; You may fix it with: if my_test then (echoLn "Then case"; nil) else echoLn time; Or more softly with: if my_test then void echoLn "Then case" else echoLn time; Another solution is to insert void before if or match: void if my_test then echoLn "Then case" else echoLn time; Then the if expression always returns nil. // +arg expression =type a1 =desc any expression // +arg result =type a2 =desc always [[nil]]