aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2022-07-18 07:45:58 +0100
committerJuan J. Martinez <jjm@usebox.net>2022-07-18 07:45:58 +0100
commit8bb321f8b032dfaeffbe3d1b8dfeb215c12d3642 (patch)
treec53977d1284347bb1d5963ddb4dc7723c40c6e55 /docs
downloadmicro-lang-8bb321f8b032dfaeffbe3d1b8dfeb215c12d3642.tar.gz
micro-lang-8bb321f8b032dfaeffbe3d1b8dfeb215c12d3642.zip
First public release
Diffstat (limited to 'docs')
-rw-r--r--docs/tour.md488
1 files changed, 488 insertions, 0 deletions
diff --git a/docs/tour.md b/docs/tour.md
new file mode 100644
index 0000000..27c7e14
--- /dev/null
+++ b/docs/tour.md
@@ -0,0 +1,488 @@
+# A tour of Micro
+
+Micro is a small statically typed toy programming language.
+
+## Syntax
+
+Micro statements are:
+
+* Variable declarations and expressions, delimited by semicolons.
+* Function and structure definitions.
+
+### Comments
+
+Only line comments, starting with `//` and ending at the end of the line.
+
+```micro
+// This is a comment
+```
+
+### Reserved words
+
+These are the reserved words in micro:
+
+> var const def func bool true false return if else for in break continue
+
+See also the built-in functions.
+
+### Identifiers
+
+Identifiers can be any string starting with a later (upper or lower case) or underscore (`_`), followed by the same type of character or a numeric value.
+
+An identifier can't be a reserved word.
+
+### Blocks and scope
+
+Micro has series of statements in blocks delimited with `{` and `}`, and a block defines a lexical scope.
+
+A variable declaration can shadow another from a parent scope.
+
+```micro
+var a number = 1;
+println(a);
+
+{
+ // block, new scope
+ var a string = "one";
+ println(a);
+}
+
+println(a);
+
+// output:
+// 1
+// one
+// 1
+```
+
+### Operators
+
+Micro uses the same operators and almost the same operator precedence as C, from more to less priority:
+
+```micro
+? ! - ~
+/ * %
+&
+- +
+<< >> | ^
+> >= < <=
+|| &&
+!= ==
+=
+```
+
+Arithmetic operators only apply to integers.
+
+Comparison operators only apply to integers, with the exception of `==` and `!=` that also apply to other types (if both operands are of the same type).
+
+Logic operators apply to booleans and to the following:
+
+* An empty string is false, true otherwise.
+* A numeric value of 0 is false, true otherwise.
+* A function reference is always true.
+
+The result of these operators is a boolean and they are lazy operators (e.g. in `a && b`, `b` won't be evaluated if `a` is false).
+
+## Values
+
+| Type | Keyword | Sample |
+| --- | --- | --- |
+| Boolean | `bool` | `true; false; ` |
+| Number | `number` (int64) | `123;` |
+| String | `string` | `"example";` |
+
+There is also a "none" type referred when a function doesn't return a value. It is not a available to use but it will appear in error reporting.
+
+For example, the interpreter running this code:
+```micro
+def fn() { }
+
+var a number = fn();
+// error: type mismatch expected number found none
+```
+
+See functions for more information about the "func" type.
+
+Number supports the following formats:
+
+ * 0 decimal
+ * 0x00 hexadecimal
+ * 0b00 binary
+ * 'x' for "ASCII character"
+
+## Variables
+
+Variables are declared with `var`.
+
+If they are not initialized, a default value is assigned; with the exception of functions, that can't be used until they have a value (or there will be a runtime error).
+
+```micro
+var a number = 123;
+var b number; // initialises default to 0
+var c string; // empty string
+var d bool; // false
+
+// e was not declared: error
+e = 123;
+
+var fn func ();
+fn();
+// error: value is not callable
+```
+
+### Constants
+
+Constants are immutable values.
+
+Constants can be literals or expressions that get evaluated at compilation time.
+
+```micro
+const K number = 10;
+
+var a number = K;
+
+K = 0;
+// error: value cannot be assigned to constant K
+```
+
+## Conditionals and flow control
+
+### If-else
+
+```micro
+var a number;
+
+if a > 0 {
+ println("it is true");
+} else {
+ println("it is false");
+}
+
+// output:
+// it is false
+```
+
+### For and for-in
+
+The block will loop while the expression evaluates to true.
+
+```micro
+var i number = 4;
+
+for i > 0 {
+ println(i);
+ i = i - 1;
+}
+
+// output:
+// 4
+// 3
+// 2
+// 1
+```
+
+Loop flow can be altered with:
+
+- `continue` to jump to next iteration.
+- `break` to exit the loop.
+
+The expression is optional (infinite loop).
+
+```micro
+var i number = 4;
+
+for {
+ println(i);
+ i = i - 1;
+ if i == 0 {
+ break;
+ }
+}
+```
+
+`for ... in` can be used to Iterate over arrays.
+
+```micro
+var arr [3]string = ["one", "two", "three"];
+for i in arr {
+ // i is of type string
+ println(i);
+}
+// output:
+// one
+// two
+// three
+```
+
+## Functions
+
+Functions can be defined using `def` and they are assigned a "func" type describing parameters and return type.
+
+Recursion is supported and recursive tail calls will be optimized.
+
+```micro
+// recursive factorial
+// (the tail call will be optimized)
+def fact(n number, acc number) number {
+ if n == 1 {
+ return acc;
+ } else {
+ return fact(n - 1, acc * n);
+ }
+}
+// type of fact is: func (number, number) number
+
+println(fact(20, 1));
+// output:
+// 2432902008176640000
+
+def fn(a number, b number) {
+ // implicit return with no value
+ // it is an error if a value is expected
+}
+```
+
+Functions are higher-order.
+
+```micro
+// b is a function that takes one number and returns a number
+def fn(a number, b func (number) number) number {
+ return b(a);
+}
+```
+
+Closures are supported.
+
+```micro
+def makeCounter() func (number) number {
+ // defaults to 0
+ var c number;
+ def count() number {
+ c = c + 1;
+ return c;
+ }
+ return count;
+}
+
+var c func = makeCounter();
+
+println(c()); // 1
+println(c()); // 2
+println(c()); // 3
+```
+
+Arrays and structures are always passed as reference.
+
+```micro
+var arr [5]number;
+
+def fn(a [5]number) {
+ a[0] = 10;
+}
+fn(arr);
+
+arr[0]; // 10
+```
+
+Local arrays and "struct" can't be returned from a function.
+
+```micro
+def fn() [5]number {
+ var local [5]number;
+ return local;
+}
+// error: returning a local value of type array [5]number
+```
+
+But references to variables in scope are allowed.
+
+```micro
+var g [5]number;
+def fn() [5]number {
+ // local is a reference to a non-local variable
+ var local [5]number = g;
+ return local;
+}
+// error: returning a local value of type array [5]number
+```
+
+### Returning error
+
+For cases when the return value can't be used to inform of an error, a function can tag a return value as "error" using `!?`. That tag can be tested with the `?` unary operator.
+
+Even if a return value is tagged, it must be a valid return value for the function definition.
+
+```micro
+def safeDiv(a number, b number) number {
+ // a / 0 would result on a runtime error!
+ if b == 0 {
+ return !? 0;
+ }
+ return a / b;
+}
+
+var result number;
+
+// checks if the error tag is set while keeping the return value
+if ? (result = safeDiv(1, 0)) {
+ println("safeDiv returned error");
+}
+
+// it can also be used with functions returning no values
+def fn() {
+ return !?;
+}
+
+if ? fn() {
+ println("fn always fails!");
+}
+```
+
+`?` (test error) operator resets the error flag before evaluating the right expression.
+
+```micro
+// our previous "always fails" function
+fn();
+// error is not set
+if ? true {
+ println("Not run");
+}
+```
+
+## Arrays
+
+Arrays are zero based and are supported for all types.
+
+Array size is a numeric literal or a constant expression (must be known at compilation type).
+
+Arrays can be initialised to literals with:
+
+* `[` and `]` providing a list of values.
+* A literal string using double quotes for arrays of unit8; the array size must be at least the length of the string plus 1 (a zero terminating the string).
+
+```micro
+// array of 5 numbers; the size is only needed
+// when no initializing values are provided
+var arr [5]number;
+
+// initialized to specific values
+var arr2 [5]bool = [true, false, true, false, true];
+
+arr[0]; // 0
+arr2[0]; // true
+
+// iterate over members
+for i in arr {
+ println(i);
+}
+
+len(arr); // 5
+
+var i number;
+// arrays indexes are zero based
+for i < len(arr) {
+ println(arr[i]);
+ i = i + 1;
+}
+
+```
+
+Arrays can be constants.
+
+```micro
+const arr [10]number;
+
+arr[0] = 10;
+// error: can't modify a constant variable
+
+// but can change references
+const ref [10]number = arr;
+const arr2 [10]number;
+
+ref = arr2;
+```
+
+Arrays are passed by reference to functions.
+
+## Structures
+
+Structures allow grouping data and functions.
+
+In a structure definition only variable declarations, and definitions of functions and other structures are allowed.
+
+```micro
+// declare struct A
+def A {
+ var n number;
+
+ def fn() number {
+ // n is in scope
+ n = n + 1;
+ return n;
+ }
+}
+
+// memory is allocated for obj
+var obj A;
+
+// obj2 is a reference to obj
+var obj2 A = obj;
+
+prinln(obj2.n);
+// output: 0
+
+println(obj.fn());
+// output: 1
+
+prinln(obj2.n);
+// output: 1
+
+def B { var n bool; }
+
+var b B = obj;
+// error: type mismatch: expected struct B found struct A
+
+// recursive structures are not supported (micro doesn't have pointers)
+def B {
+ var next B;
+ // error: recursive definition of struct B
+}
+
+def C {
+ println("error");
+ // error: expected definition in a struct block
+}
+```
+
+## Directives
+
+TODO
+
+Include a file in current source and it will interpreted / compiled.
+
+```micro
+include "file.micro"
+```
+
+Include a binary file as an expression list to initialize an array.
+
+```micro
+var arr [64]number = incbin "file.micro";
+```
+
+## Interpreter built-in functions
+
+These are available on the interpreter.
+
+| Function | Description | Example |
+| --- | --- | --- |
+| `len` | returns the size in elements of a variable of type array | `len(arr);` |
+| `panic` | ends execution with a message and a runtime error | `panic("message");` |
+| `println` | writes to standard output a variable list of expressions, followed by an end of line; returns number of bytes written | `println("value: ", a);` |
+| `str` | used with arrays of uint8 to convert them as a printable string | `println(str(arr));` |
+
+
+## To do
+
+See [TODO](todo.md) for features that are planned but not yet implemented.
+