NOTE: ndy means not done, yet
Single statements allways end with a ";".
Statements may contain more statements. These statements are treated differently.
They are either composed from a single statement or are encased in a block-statement.
Block statements are collections of normal statements that begin with "begin" or "{" and end with "end" or "}"
Within this tutorial I will only use "begin" and "end". But you can allways allso use the alternative.
gCode is internally seperated to 4 types of code:
* Statements
* inline-statements
* value setters
* value getters
Rules:
* inline allways referrs to a value getter.
* Statements use value getters and setters and other statements
* value getters use inline statements
* inline statements use value getters and statements
gCode offers multiple ways to insert comments into your code:
// this is a line comment! it ends once this line ends
/begin/this is a multiline comment! it last until it is ended manually
/end/
NOTE: there are multiple synonyms for /begin/ and /end/:
/* ... */ (* ... *) /{/ ... /}/
Everything in gCode is a var (except not loaded modules)
there a 6 ways to assign a var (don't worry knowing 1 is enough)
These assignment methods are considered a statement.
They cannot be performed inline
a = 1;
b := 2;
c <- 3;
d <-- 4;
5 -> e;
6 --> f;
a = 21;
// NOTE: the following actions can be performed inline (they returm the new value of the var being modified)
a += 19; // a is now 40
a -= 20; // a is now 20
a *= 4; // a is now 80
a /= 3; // a is now 26 (this value was truncated because a is not a floating point number)
a ^= 2; // a is now 164
Strings are allways toggled on and off by using "'". In order to write a "'" you just write "''". In order to add special characters, you end the string, write \ and either 'n','r','t' or the hexadecimal code of the char in the current context (Unicode/Ansi).
NOTE: Strings are multi-line structures
Example:
a = 'foobar'; // easy
b = 'foo'\r\n'bar'; // new line inbetween (method 1)
c = 'foo
bar'; // a real new line between (within the code -- method 2)
d = 'Hello, I''m foo.'; // string containing a '
e = \t'hello'; // string starting with a tab
f = 'hello'\t; // string ending with a tab
Please note that when using print to output a string directly, gCode will not try to recreate the sytax (probably) used to write the string, which it will do if the string is nested in a tuple or somthing else!
Deleting vars is simple (the print statement is covered in the next chapter):
a = 5;
print a; // print 5 (expected)
del a; // deletes a
print a; // var not found exception here (for exception: see below)
You can allso delete multiple vars at once:
a,b = 1,5;
del a,b;
print a,b; // the same exception
Anything in gCode can be displayed as a [String].
Because of that and the fact gCode is only designed as a console application,
print is the default interface, to give out text to the console:
print a,b,c,d,e,f;
Anything in gCode can be merged into a single value. This is how a [Method] is able to return multiple values.
Tuples are created more often than you might think:
whenever you have multiple values seperated by ',' (see print statement -- 4.), you are creating a tuple internally.
Tuples work both ways: you can merge values into 1 by having too many inputs and you can expand them by having too many outputs:
a = 1,2; // too many inputs
print a; // this will display as '(1,2)'
b,c = a; // too many outputs
print b; // this will display as '1'
print c; // this will display as '2'
Sometimes it isn't possible to create a tuple even if you need one:
You want a tuple containing another tuple.
This is done by forcing gCode to create a tuple by saying:
a = (1,2),3;
print a; // this will display as '((true 2) 3)'
Using brackets you can force gCode to create tuples
CAUTION: this only works for 2 or more values (for single values this behaves like the normal mathematical brackets):
a = (1),2;
print a; // this will display as '(1 2)'
Allso be aware of the fact, that because of that same rule:
a = 1,2,3; // this does the same
a = (1,2,3); // as this
NOTE: Creating tuples that only contain 1 value is possible though never really needed:
a = Tuple().setLen(1);
a[0] = 21; // this caused a crash in v02 (fixed in v03)
print a; // prints (21)
// working version for v02 and up
function toTuple([a]) return a;
a = toTuple(1);
print a;
Array behave and are created much like tuples. The differences being:
* arrays use '[' and ']' in for their creation.
* arrays cannot be split open by having to many outputs
* arrays don't have a limitation on holding at least 1 item
gCode has a lot more default operators that other languages:
print 2+3; // add
print 2-3; // subtract
print 2*3; // multiply
print 2/3; // divide
print 2^3; // power
print 2:3; // range (see below)
print 2=3; // compare: equal
print 2!=3; // compare: not equal
print 2>=3; // compare: greater,equal
print 2!>=3; // compare: not greater,equal
print 2<=3; // compare: lower,equal
print 2!<=3; // compare: not lower,equal
print 2<>3; // compare: lower,greater
print 2!<>3; // compare: not lower,greater
print 2<=>3; // compare: lower,equal,greater
print 2!<=>3; // compare: not lower,equal,greater
print a++; // increase a by 1 and print it
print a--; // decrease a by 1 and print it
print 0x0F or 0xF0; // binary/logical or (0xFF)
print 0x0F nor 0xF0; // binary/logical or (0x00)
print 0x0F and 0xF0; // binary/logical and (0x00)
print 0x0F nand 0xF0; // binary/logical and (0xFF)
print 0x0F xor 0xF0; // binary/logical xor (0xFF)
print 0x0F nxor 0xF0; // binary/logical xor (0x00)
print 0x0F shl 4; // binary shift left (0xF0)
print 0x0F nshl 4; // inverted binary shift left (0x0F)
print 0xF0 shr 4; // binary shift left (0x0F)
print 0xF0 nshr 4; // inverted binary shift left (0xF0)
print -11; // prefix: range symbol (-11)
print not 11; // prefix: binary invertion (244)
print @a; // pointer to a
print a^; // a being a pointer; src of a
Note about comparint values:
Every line in the upcomming code does the same!
print 1>=2;
print 1=>2;
print 1>>>====2;
print 1===>===2;
print 1=>=>=>>>2;
You see where I'm going with this...
Allright. Lets get this of the table.
This might sound a little bit complex for it being here so soon.
But is you don't understand it (yet), skip this part and come back here for reference.
So here are the standard types:
Typename | Size | Prefix | Pastfix | Range | Description | Can be condition |
---|---|---|---|---|---|---|
[UInt1] | 1 | u1 | 0:1 | allso known as boolean | yes | |
[UInt8] | 1 | u8,b | 0:255 | allso known as byte | yes | |
[UInt16] | 2 | u16,w | 0:65535 | allso known as word | yes | |
[UInt32] | 4 | u32,lw, !new in v02!: c |
0:4294967295 | allso known as longword | yes | |
[UInt64] | 8 | u64 | 0:18446744073709551615 | yes | ||
[SInt8] | 1 | s8,sh | -128:127 | allso known as shortInt | yes | |
[SInt16] | 2 | s16,sm | -32768:32767 | allso known as smallInt | yes | |
[SInt32] | 4 | s32,i,li | -2147483648:2147483647 | allso known as longInt/Integer/Int | yes | |
[SInt64] | 8 | s64 | -9223372036854775808:9223372036854775807 | yes | ||
[Pointer] | 4 | 0x00000000:0xFFFFFFFF | no | |||
[Float] | 4 | f | ... | yes | ||
[Real48] | 6 | r48 | ... | yes | ||
[Currency] | 8 | c | ... | yes | ||
[Double] | 4 | d | ... | yes | ||
[Extended] | 4 | e | ... | yes | ||
[UnicodeString] | 8 | u | a string made up out of unicode characters | no | ||
[AnsiString] | ndy | a | ndy | ndy | ndy | |
[WideString] | ndy | w | ndy | ndy | ndy | |
[ShortString] | ndy | s | ndy | ndy | ndy | |
[Char] | ndy | c | ndy | ndy | ndy | |
[AnsiChar] | ndy | ac | ndy | ndy | ndy | |
[Tuple] | 8 | ( | ) | contains gC-vars | no | |
[Array] | ndy | [ | ] | ndy | ndy | ndy |
NOTE: When not using a prefix/pasfix, gCode will allways choose the smallest possible type for data storage
The if statement is the most basic way to create conditional code:
if condition
then print 'condition is true'
else print 'condition is false';// remember the rules about statement blocks for multi-statement sub-blocks:
if condition then beginprint 'condition is true'; // note how I have to set ';' here
print 'allso this is a 2nd statement in the true-block';end else begin
print 'condition is false'; // ^
print 'allso this is a 2nd statement in the false-block';end;
HINT: you can allso stack multiple if-statements onto each other:
if condition1 then print 1 else
if condition2 then print 2 else
if condition3 then print 3 else
if condition4 then print 4 else
if condition5 then print 5 else
if condition6 then print 6 else
if condition7 then print 7 elseprint 'conditions 1:7 are all false';
NOTE: To see all standart types that can be conditions: see 6.
The If statement is one of the lucky statements that can be used inline
print if condition then 'That is correct' else 'Sorry, thats wrong'; // response to an anser?
print base+(if addvar1 then var1 else 0); // add var1 to base if addvar1 is true
Now we allready know 1 sequence type: Tuple.
But a lot of things can be sequenced (even (un)signed numbers) what these sequences do and how they behave it different for each of them.
To work with sequences, you have 5 different operations:
a = 1,2,3;
print #a,len#a; // length of a sequence (3)
print lo#a,low#a; // lowest valid index of a sequence (0)
print hi#a,high#a; // highest valid index of a sequence (2)
print 2 in a; // is a given object in the sequence? (true)
print a[0]; // item as position 0
print a[n]; // item as position n
// NOTE: if your not into binary: skip this part
a = 0x0F;
print a[0]; // get the 0 bit
a[0] = true; // set the 0 bit
gCode has 2 basic conditional loops:
The while loop:
a = 0;
while a<20 do print 'foo'+(a++);
a = 0;
while a<20 do beginprint a+'. loop';
a++;end;
The repeat loop:
a = 0;
repeat print a++ until a>20;
a = 0;
repeat beginprint 'loop!';
print 'Iteraction',a++;end until a>20;
gCode has 2 non-conditional loop:
the for .. to .. do
for i = 10 to 20 do print i; // prints the numbers 10 to 20
// remember the rules about var assignment -- you don't have to write '='. you can do :=, <-, etc.
for i = 20 to 10 do print i; // prints the numbers 20 to 10 (counting down)
the for .. in .. do
for i in 'foobar' do print i;
Note for .. in .. do uses the seqence mechanics internally
the for .. in .. do statement can allso be used inline.
When used it creates a new tuples composed of all entry of the object it was working with.
This statement is very handy if you want to manipulate some for of sequence and store the manipulated version in a tuple
a = 'foobar';
b = ('_'+c+'_') for c in a;
print b; // b is a tuple composed out of 6 strings: ('_f_','_o_',...)
For all this time up to now you've been using print to display everything.
But did you know that print is just a method (that you could even overwrite and replace with your own method)?
Of course you did. But the way you call print is not the standard way to call a method. print is only there, to make things easier.
By default you call something by writing *object*([*params*]).
print type(21); // this will print UInt8
// ^ type is a default method that return the type-var of every value it is called with
// ^ its return value is passed on to the print method with converts the value to a string
// ^ and outputs it to the console
gCode has uses 2 different method types internally:
* return method
* resultVar method
Example for a return method:
function foo() return 21;
// function foo() begin return 21; end; // remember, that this does the same thing
print foo(); // call my function foo and print its return value (21)
NOTE: return is a statement that behaves and can be used just like print
NOTE2: it allso exits out of the methpd
Example for a result-var method:
function bar(): result begin
result = 21;
print result; // prints 21end;
a = bar();
print a++; // prints 22
NOTE: result is just the name of the return var. You could name it anything. The important thing to keep in mind is the ':' after the ()
NOTE2: gCode has some [standart methods], that will allways be loaded when you start it.
Now you might be wondering how do I create a method that can not only return but allso get values.
Well... heres how you do it:
function sum(a,b,c) return a+b+c;
print sum(1,2,3); // prints 6
Ok. but you talked about methods accepting a vaiable amount of parameters.
Well... heres how you do that:
function sum([params]): result begin
result = 0i; // create result as an integer value
for value in params doresult += value;
end;
print sum(1,2); // prints 3
print sum(3,4,5); // prints 12
print sum(6,7,8,9); // prints 30
You can allso define methods inline by just leaving out the name:
foo,bar =
function() begin print 'foo'; return 1; end,
function(): result begin print 'bar'; result = 2; end;print foo(); // prints 'foo' and 1
print bar(); // prints 'bar' and 2
Anything in gCode can have attributes. Oftenly attributes are helper methods of sub-components.
Attributes are accessed by writing object.attributeName.
HINT: For a list of all attributes of a var, visit the types page in this wiki.
a = 21i; // integer -- 21
print a.asHex(); // asHex returns a string composed out of the hexadecimal representation of a
If you don't like binary, you can skip this part!
gCode supports 5 number systems for In and Output by default
* Binary
* Quad
* Octal
* Decimal
* Hexadecimal
For input you can write:
a = 0b01; // binary
a = 0q0123; // quad
a = 0o01234567; // octal
a = 1234567890; // decimal
a = 0x0123456789ABCDEF; // hexadecimal
For output you can write:
print a.asBin(); // binary
print a.asQuad(); // quad
print a.asOct(); // octal
print a; // decimal (obviously)
print a.asHex(); // hexadecimal
NOTE: even when entered in a custom number system, you can still use pre/pastfixes and gCode will still try to compile the value into smallest available type
A Slice is composed out of 2 vars (left and right).
Systax (allready mentioned above): *left*:*right*
Slice ange useage example:
for i in 1:100 do print i; // prints all values between 1 and 100 (inclusive)
a = 1:100;
s = 1:100;
for I = 0 to 101 doprint str(I).iZFill(4).iLJust(8),I in s;
// ^ check for each value bewteen
// 0:101, if it is within 1:100
print s.left;
// ^ left bound of the slice
print s.right;
// ^ right bound of the slice
r = s.range(); // tuple of all values s represents
for line in r.spread(10) doprint (str(a).iZFill(3)) for a in line;
NOTE: Slices do not cache all the values inbetween. Those are calculated as you request them
NOTE2: In the future Slices will be a to retrieve multiple values from a seqence
Whenever an instance of gCode is started, you will start out with a bunch of default methods. These methods don't have to be imported manually but are included by default.
Though you can overwrite and modify them, that is not recommended, because it may break your code.
For a list and description of all default fields see here [standart methods].
To seperate merge and dynamically use code, gCode comes equipped with a Modules System.
A modules is considered to be a single file located in any on the lib folders (see [libs.ini]).
Modules and parts of modules can be imported at any time using the include statement.
include math; // this includes the math modules. After this it is accessible by typing math.*field*
include pi from math; // this only include the field pi from math. After this is is accessible as pi
include pi from math as myPi; // does the same but pi is now accessible as myPi
include * from math; // includes every field from math. these fields are accessible by typing their original name
For more info on what the * does, visit [formatted string match].
Usage example:
include random from math as rand;
print rand(); // print a random extended in the range 0:1
I won't go over what a Pointer is in here. What I will go over is:
* Binary, custom data interpretation
* Creating a pointer
* Getting the source of a pointer
* Creating custom data structures
* Helper methods
* Risks
You can Interpret anything in gCode in any way on a binary level by calling the type you wan't to
interpret an object as with the object as parameter.
a = -100;
print UInt8(a); // this will interpret the data allocated by a as a UInt8 (prints 156)
Hint: if you want to convert a value to a different type, goto the types page and look through its attributes
Pointers are created by using the '@' operator (see operators above)
b = @a; // b is now a pointer to a
Pointer sources are accessed by the '^' operator (see operators aboce)
c = b^; // c is not an untyped piece of data located at the source of b
NOTE: this is where 18.1. custom data interpretation comes in
a = 21; // a var
b = @a; // a pointer to the var
c = type(a)(b^); // c is a fully typed var (of the same type as a) with the same data address as a
// NOTE: c does know, that it does not own the data it points to, and thereby will not try to do so
Call the type you want to have a structor of without any parameters:
a = SInt8(); // a is now an empty hull for a SInt8
To design your own data structure: see [Record] and the tutorial below
The gCode var-management system (see [under the hood]) is designed to automatically and instantly unload anything thats no longer used anywhere.
Pointers are very natural and are not designed, to fit in with that system.
That can lead to pointers pointing to vars that are no longer loaded.
As a generic rule: Anything, that you can't access by name is not / no longer loaded.
Though this isn't necessarily a problem, you should NEVER create global pointers pointing to local vars!
Just allways keep your pointers in a higher or the same [stack frame] than their destination.
gCode supports direct coding of binary structures. For this you can use the type [Record]. Inspired by pascal records and known as structures in C, this type can define collections of data.
myStruct = Record();
myStruct.x = SInt32; // add a field called x that is a SInt32
myStruct.y = SInt32; // ... called y ...
myStruct.lock();
NOTE: prior to v02, to add a field you would have to use this code:
// this still works, but is deprecated and may be dropped at some point
myStruct.addField('x',SInt32);
The method "lock()" should be called once the record is completely declared. It locks the record definition from being edited again. This should be done to ensure that the record won't change while instances are being used.
After a structure is defined, it can be instanciated like all other types:
inst = myStruct();
// inst is a 16-bit structure build up out of 2 SInt32s
inst.x = 21i; // set the x field to 21
inst.y = 15i; // set the y field to 15
print inst; // prints a big chunk of data containing all information about the structure and instance
Records can not only be used to store data. You can add methods to them:
myStruct2 = Record();
myStruct2.x = SInt32;
myStruct2.y = SInt32;
myStruct2.sum = function(self) return self.x+self.y; // sum adds x and y together
myStruct2.lock();
inst = myStruct2()
inst.x = 9i;
inst.y = 11i;
print inst.sum(); // prints 20
NOTE: prior to v02, to add a method you would have to use this code:
// this still works, but is deprecated and may be dropped at some point
myStruct2.addMethod('sum',function(self) return self.x+self.y);
!new in v02! Using this method system, you can allso overwrite internal events:
myStruct3 = Record();
myStruct3.x = SInt32;
myStruct3.y = SInt32;
myStruct3.__init__ = function(self) print 'myStruct3 instance created';
myStruct3.__del__ = function(self) print 'myStruct3 instance deleted';
myStruct3.lock();
inst = myStruct3(); // __init__ is called in this
del inst; // __del__ is called in this
Here is a list of all events, call conditions, params and expected return values
Method name | call condition | params | expected return value | desc |
---|---|---|---|---|
__init__ | called when an instance is created | (instance) | - | could be used to specify default values a record should be created with or create custom data |
__del__ | called when an instance is deleted | (instance) | - | could be used to drop custom data |
__getItem__ | inst[loc] | (instance,loc) | item at loc | could be used to create a pseudo array |
__setItem__ | inst[loc] = value | (instance,loc,value) | - | could be used to create a pseudo array |
__getSlice__ | inst[loc] | (instance,loc) | slice from loc.left to loc.right | only called, if loc is a slice (__getItem__ is called otherwise) |
__setSlice__ | inst[loc] = value | (instance,loc,value) | - | only called, if loc is a slice (__setItem__ is called otherwise) |
__in__ | value in inst | (instance,value) | boolean | returns if value is in inst |
__hi__ | hi#inst | (instance) | highest array index | should return the highest values that can be used in __getItem__ or __setItem__ |
__lo__ | lo#inst | (instance) | lowest array index | should return the lowest value that can be used in __getItem__ or __setItem__ |
__len__ | #inst | (instance) | amount of array indices | should return the amount of values that can be used in __getItem__ or __setItem__ (usually abs(hi#inst-lo#inst)+1) |
HINT: for a good example use of all the features of records, see "File" in module "fs"