The language
println( "Hello, world!" );
SGScript is a dynamic, procedural language, similar in syntax to many other programming languages, including C and JavaScript. It consists of various operations and structures that can be combined to specify operations and data that they use.
- The basics - quickly covers the basics but doesn't get into much detail
- Data types - handling all kinds of data
- Flow control - how to run a part of the code, at specific moments
- Advanced concepts - not the first necessary things, helpful nonetheless
The basics
- Functions are reusable blocks of code. To call a function means to do what's specified in the function.
function printText()
{
println( "text" );
}
printText();
- Basic function definitions have the following syntax:
function <name> ( <argument-list> ) { <code> }
- Argument list is a comma-separated list of names or nothing.
- Names, also called "identifiers", can have the folowing symbols: a-z, A-Z, _, 0-9, but they cannot start with a digit, because only numbers can start with a digit.
- User-defined names cannot collide with so-called keywords - special names, like
function
y = 15.51;
x = 3 * y + 10;
x * y;
- Each expression statement ends with ";".
- Useful expression statements include an assignment operator or a function call, or both.
- All expression statements presented so far - except the last one - are useful.
- The assignment operator is "=". It simply assigns the value on the right side to the item on the left side.
- Numbers use the point (".") as decimal digit separator.
- There are arithmetic operators available that take two items at each side (called "binary operators").
- The operators used in the example are those of addition ("+") and multiplication ("*").
include "math";
function sinc( x )
{
xpi = x * M_PI;
return sin( xpi ) / xpi;
}
sinc3 = sinc( 3 );
- Functions may return with or without data. When they do return data, that data can be retrieved from the call.
- A basic function call has the syntax
<name> <subexpression>
- A subexpression has the syntax
( <expression-list> )
- Expression list is a comma-separated list of expressions or nothing.
- The
include
statement loads a library or a code file.
math
is one of the few built-in libraries. In this example, it defines the function sin
and the constant M_PI
x = 1; y = 2;
x += y;
++x;
--y;
- Shortcuts exist for common operations: combined assignment operators and increment/decrement operators.
- Most non-assignment binary operators have their assignment counterparts. The difference is that they assign the calculated value to the left side of the expression.
- Increment/decrement operators are shortcuts for
x += 1
and x -= 1
, respectively.
- There are alternative versions of these operators that will be covered later.
x = 5; y = 3;
x *= y * ( y + x );
y -= x + x * y;
y += 5 * y += y;
printvar( y );
println( dumpvar( x ) );
- There's very few limits on how the expressions can be combined so it's up to you to write them in a way the meaning is clear both to you and the compiler.
- A very useful tool for finding out the contents of a variable are the
printvar
/ dumpvar
functions.
println
is a function that prints the given variables to standard output and moves write cursor to the next line.
- Order of arithmetic operations is mathematically correct: sub-expressions
( .. )
are evaluated first, then multiplication *
/ division /
/ modulo (remainder) %
, and then - addition +
and subtraction -
.
x = 5;
global y = 6;
function z()
{
a = 7;
global b = 8;
function c(){}
}
- Variables are the currency of this language.
- There are 4 types of variable storage, two of which are covered in the example: local and global variables.
- In the example, variables x, a, c are local and y, z, b are global.
- All new variables are local by default.
- The keyword
global
specifies a list of variables that are global and allows to assign their values.
- A function definition creates a global function variable outside other functions, local otherwise.
// testing the assignment operator
a = 5;
/* this ----------
-- should print --
------------- 5 */
println( a ); ////
- Code can contain comments. They can be used to communicate between various users and maybe even compilers of the code.
- The SGScript compiler completely ignores comments.
- There are two types of comments: single-line comments
// ...
and multiline comments / ... /
Data types
a = null;
b = true;
c = 123;
d = 123.456;
e = "text";
- There's a total of 9 data types in SGScript: null, boolean, integer, real number, string, function, C function, object and pointer.
null
is the 'no value' type. There is only one value for the type.
- Boolean is a
true
/false
type.
- Integers and real numbers are two ways to represent numbers in the language. Both have their uses, however generally they're interchangable.
- The
string
type stores an array of bytes, generally meant to store text but can be used for any data.
f = function(){ return 4; };
g = println;
h = io_file(); // returns a file object
i = toptr(100);
- Functions and C functions are not as much data types as they are code types. One represents a function defined in SGScript code and another represents a function defined in C/C++ code.
- As with numbers, both function types are generally interchangable but have some major differences.
- Objects are universal, yet somewhat heavy types with a variable number of subtypes. They can represent data structures as well as interfaces and even act like functions.
- Pointers are basically integers that have restricted manipulation capabilities and a separate processing chain, useful for passing handles and memory addresses in a safe way.
arr = [ 1, 3, 5, 7 ];
println( arr[2] ); // prints 5
println( arr[4] ); // warning: index out of bounds
println( arr.size ); // prints 4
- Array is a complex data type, a subtype of object. It contains a list of other variables.
- Sub-variables can be accessed with index
[ .. ]
and property .
operators.
- Be aware that not all sub-variables can be read and not all of them can be written. Systems will often report the same warnings for variables that don't exist and those that don't support the required operation.
- The array's
size
property returns the length of the array, the number of variables in it.
arr = [];
arr.push( 5 );
x = arr.pop();
arr.unshift( 4 );
y = arr.shift();
- Objects can have methods. Methods can be called through property access, this compiles to a special call where the object is passed through a special channel.
- Other sub-variable accessors don't support the method call, however it is possible to invoke in other ways, to be described in further sections.
- Array methods shown in the example are the stack/queue interface of the array. Push/pop deals with the end of the array, shift/unshift works on the beginning.
- More info on array and its methods can be found in the documentation: array [object]
dct = { x = 5 };
dct[ "key" ] = "value";
println( dct ); // {x=5,key=value}
fnmap = map();
fnmap[ print ] = "print";
- Objects can have non-numeric indices. All variable types are allowed for keys but not all maintain their value in all objects.
- Objects of
dict
type (generated by the dict literal {}
or function dict()
) store string keys. Documentation: dict [object]
- Objects of
map
type (generated by the map
function) store literally all kinds of keys. Documentation: map [object]
dict
object is expected to be the building block of most data stored because it is most accessible.
myObj = { x = 5, y = 7 };
function myObj.moveLeft(){ --this.x; }
myObj.moveLeft(); // method call
function myObj_moveRight(){ ++this.x; }
myObj!myObj_moveRight(); // compatible call
- There are many ways to make and two ways to call functions that work on objects.
- Making:
- 1. Create a method by specifying
<variable-name> . <property-name>
for the name.
- 2. Create a plain function.
- 3. Create an anonymous method by using the following syntax:
<variable-name> . <property-name> = function ( ) <code>
or assigning any callable to a property.
- Either way,
this
can be used inside the function to access the associated object.
- Calling:
- Method call:
<data-source> . <property-name> ( <argument-list> )
.
- Compatible call:
<data-source> . <callable-source> ( <argument-list> )
.
Flow control
if( a > 5 )
{
println( "'a' is greater than 5" );
if( a < 10 )
println( "...but less than 10" );
}
else
println( "'a' is not greater than 5" );
- It is possible to only run code if a certain condition is true, using the
if
statement.
- If/else statement has the following syntax:
if ( <expression> ) <statement>
, optionally followed by else <statement>
{ .. }
is a block statement, it can be used anywhere a statement can be used
>
("greater than") is one of 8 comparison operators. The others are:
<
- "less than"
>=
- "greater or equal"
<=
- "less or equal"
==
- "equal"
!=
- "not equal"
===
- "strict equality" (not only value must be equal, types must also be same)
!==
- "strict inequality" (inverse of strict equality)
- These operators are not limited to
if
and other such statements, they can be used as any other operator.
- These operators return the type
bool
, it has only two values - true
and false
while( a > 5 )
{
println( a );
--a;
}
for( i = 0; i < 5; ++i )
println( i );
- There are 6 kinds of loops in SGScript:
- The 'while' loop:
while ( <expression> ) <statement>
- The 'for' loop:
for ( <expression-list> ; <expression> ; <expression-list> ) <statement>
- It is a shortcut for a while loop where first expression/list is run before the loop, second - as the condition, third - before each jumpback.
- The 'do-while' loop:
do <statement> while ( <expression> )
- The 'foreach-value' loop:
foreach ( <nvalue-ame> : <expression> ) <statement>
- The 'foreach-key' loop:
foreach ( <key-name> , : <expression> ) <statement>
- The 'foreach-key-value' loop:
foreach ( <key-name> , <value-name> : <expression> )
foreach( name : [ "one", "two", "three" ] )
println( name ); // prints one, two, three
foreach( key , : _G )
println( key ); // prints names of all global variables
foreach( key, value : myObject )
{
if( string_part( key, 0, 2 ) == "!_" )
println( value ); // print all values for keys beginning with "!_"
}
foreach
loops give read-only values (they can be written to but source will not be updated).
foreach( value : data )
{
if( value === false )
continue;
if( value )
break;
}
- It is possible to stop loop execution with
break
or jump to the next iteration with continue
.
break
will skip to code right after the loop.
continue
will skip to right before the end of the loop.
- It is also possible to specify the loop number (within the function/global scope, counting from innermost, starting at 1) to go to.
Advanced concepts
Bitwise operations
hex = 0x12400;
bin = 0b10011010;
b_or = hex | bin ^ hex & bin;
- There are constant formats and bitwise operations for dealing with integers on the bit level.
- The following integer constant formats are available:
- Binary (base 2): begins with "0b", followed by some binary digits (0,1)
- Octal (base 8): begins with "0o", followed by some octal digits (0-7)
- Decimal (base 10): contains only decimal digits (0-9)
- Hexadecimal (base 16): begins with "0x", followed by some hexadecimal digits (0-9,a-f,A-F)
- These operators are available for doing bitwise operations:
- binary AND / AND-assign:
&, &=
- returns 1 if both sides are 1
- binary OR / OR-assign:
|, |=
- returns 1 if any side is 1
- binary XOR / XOR-assign:
^, ^=
- returns 1 if either side is 1, but not both
- unary NOT:
~
- inverts bits
- left shift / left shift-assign:
<<, <<=
- move all bits to the left (more significant positions)
- right shift / right shift-assign:
>>, >>=
- move all bits to the right (less significant positions)
The main difference from other languages is that the integer type by default is 64 bits long. Left/right shift rules are equal to those of the C language. Thus, it is safe to use only shift distances between 0 and 63.
Truth tables for AND/OR/XOR operations
AND | 0 | 1 | | OR | 0 | 1 | | XOR | 0 | 1 |
0 | 0 | 0 | | 0 | 0 | 1 | | 0 | 0 | 1 |
1 | 0 | 1 | | 1 | 1 | 1 | | 1 | 1 | 0 |
Building with SGScript
This section describes all supported ways to compile SGScript and integrate it into your project.
Downloading SGScript
There are two kinds of downloads - source and binaries. All downloads are available in the download page. Source files are hosted on Github.
Even though master
branch is supposed to be the 'stable' branch, it is highly suggested that apidev
branch is tried first since it is the most up-to-date branch, it is expected that generally less bugs are there. master
branch is more thoroughly tested at the time of release and apidev
may contain recent changes that subtly break the build.
Building with GNU Make
Required software
Building
- Open a terminal (
cmd
on Windows, sh
on Linux/Mac) window in SGScript source root directory.
- Run
make
(mingw32-make
on Windows), optionally specifying targets and options.
- The syntax is
make <target|option>[, <target|option> ...]
- To build only the library, just write
make
;
- To build all tools (VM, compiler, plug-in modules), write
make tools
.
- On Windows, a batch file can be used to enable the usage of
make
(create a file make.bat
in C:\MinGW\bin
directory or equivalent, add the directory to PATH if it's not there):
@ECHO OFF
mingw32-make %*
Build options
Targets:
- libraries & tools
- testing
- other
- clean: clean all generated files
- clean_obj: clean only intermediate build files
- clean_objbin: clean intermediate build files and binaries
Options:
- arch=[32|64] - target architecture (x86/x64), default depends on compiler
- mode=[debug|release] - whether it's a debug or a release build (default=debug)
- static=[1|0] - whether to build a static library or a dynamic one (default=0: dynamic)
Additional build options & platforms
- To build on Android, modify the makefile according to the comment in the beginning of that file.
Building with IDEs
All IDE-related build data is under the build
directory.
Supported IDEs
- Code::Blocks (
build/codeblocks
)
- Visual Studio 2010 (and newer versions) (
build/vc10
)
IDEs with necessary files but without support
Building with other tools
CMake
There is a file CMakeLists.txt
in the root directory of the project. It only builds the dynamic library at the moment.
File integration
The code is made to support various compilers and compile under C and C++ so it is quite safe to just drag & drop it into your project.
Including SGScript into your project
There are generally two ways to include SGScript: link the library or include the files directly.
Note: Including the files isn't an option if SGScript modules are to be used.
For simplified inclusion of files, add src/
and ext/
to the include paths.
- The main SGScript API is defined in the file
src/sgscript.h
.
- Requires the SGScript library to be linked to the project or have the files (
src/*
) compiled in.
- Utility library is available in
src/sgs_util.h
.
- Requires the SGScript library to be linked to the project or have the files (
src/*
) compiled in.
- eXtended Game Math library can be found in
ext/sgsxgmath.h
.
- Requires the eXtended Game Math library to be linked to the project or have the files (
ext/sgsxgmath.c
) compiled in.