Skip to main content

4. Statements

Like previously mentioned, LiteScript simplifies the statement model into a fixed-form model that allows for its parsing and evaluation to be simple and straight forward, so it is important to be aware of what can and cannot be done.

4.1 Assigners and Expressions

Just like assembly, for assignment statements where we either declare a variable or reassign its value, we derive the assembly movement instruction into the following fixed form:

[variable] [assigner] [expression]

A variable is declared when it is first mentioned in an assignment statement, and recurring mentions simply just reassign its value.

First declared
x [assigner] expression1
Value reassigned
x [assigner] expression2

When it comes to value reassignments, since LiteScript is a dynamically typed programming language, a variable's type can be changed during runtime from one type to another. So if expression1 evaluates to an integer, x is declared as an integer type, and if expression2 evaluates to a string, then x has its value reassigned and its type changed to a string.

In LiteScript there are only three basic assigners:

  • Equality assigner (=): Simply sets the variable's value and type to whatever the expression evaluates to. Compatible with every primitive data type and containers.

  • Incremental assigner (+=): Equivalent to x = x + expression. Evaluates the expression, and performs the addition of the expression's corresponding type with the same variable, therefore, the variable needs to have been declared prior to this. Compatible with every primitive data.

  • Decremental assigner (-=): Equivalent to x = x - expression. Evaluates the expression, and performs the subtraction of the expression's corresponding type with the same variable, therefore, the variable needs to have been declared prior to this. Compatible only with integers and reals.

4.1.1 Expressions and Operators

In LiteScript, expressions are evaluated rather unconventionally. Instead of evaluating a parsed AST, the expression instead gets converted to postfix and evaluated using the Shunting Yard Algorithm, so any rules and evaluation orders applied to these will be applied to every LiteScript expression.

Unlike C, there is no lazy evaluation, so expressions that are supposed to represent boolean values are evaluated in its entirety.

In the following table, we describe every operator that can be used in an expression, including what it evaluates (expressed either in C like pseudocode, or text), the precedence value (lower values indicate lesser precedence) and if it is unary, binary or both; for every primitive data type and ordered by ascending precedence.

OperatorSymbolPrecedenceUnary/BinaryIntegerRealStringEvaluates to
Logical OR||1Binary(a != 0 || b != 0) ? 1 : 0--Integer
Logical AND&&2Binary(a != 0 && b != 0) ? 1 : 0--Integer
Bitwise OR|3Binarya | b--Integer
Bitwise XOR^4Binarya ^ b--Integer
Bitwise AND&5Binarya & b--Integer
Equals==6Binary(a == b) ? 1 : 0(a == b) ? 1 : 0(a == b) ? 1 : 0Integer
Not equals!=6Binary(a != b) ? 1 : 0(a != b) ? 1 : 0(a != b) ? 1 : 0Integer
Less than<7Binary(a < b) ? 1 : 0(a < b) ? 1 : 0(a < b) ? 1 : 0Integer
Less or equal than<=7Binary(a <= b) ? 1 : 0(a <= b) ? 1 : 0(a <= b) ? 1 : 0Integer
Greater than>7Binary(a > b) ? 1 : 0(a > b) ? 1 : 0(a > b) ? 1 : 0Integer
Greater or equal than>=7Binary(a >= b) ? 1 : 0(a >= b) ? 1 : 0(a >= b) ? 1 : 0Integer
Bitwise Left Shift<<8Binarya << b--Integer
Bitwise Right Shift (signed)>>8Binarya >> b--Integer
Addition+9BinaryInteger additionFloating point addition (if at least one is a real)ConcatenationInteger/Real/String
Subtraction-9BothInteger subtractionFloating point subtraction (if at least one is a real)-Integer/Real
Multiplication*10BinaryInteger multiplicationFloating point multiplication (if at least one is a real)-Integer/Real
Division/10BinaryInteger multiplicationFloating point multiplication (if at least one is a real)-Integer/Real
Modulus%10BinaryRemainder of an integer division--Integer
Exponentiation**11Binary-a to the power of b (if at least one is a real)-Real
Logical NOT!12Unary(a == 0) ? 1 : 0--Integer
Logarithmation~12Unary-log base 2 of a-Real

Parentheses can be used to clearly indicate the order in which operations should precede past others defined by the language's precedence table.

For expressions that are meant to represent boolean values, integers by default represent them the best and all logical operators evaluate to integer types, however, reals and strings can represent them too. For reals, 0.0 is false and everything else is true, and for strings, an empty string "" is false and anything else is true.

4.2 Control Flow

The language offers the abstraction of control flow by providing the two basic necessary keywords for conditional and iterative logic, inspired by the control flow statements available in UML.

  • The "opt" keyword

opt [expression]
...

LiteScript's version of the "if" statement. Just like in assembly, if the expression evaluates to true the program enters the next indented scope, which ends until we return to a prior scope; otherwise skip all the statements of the indented scope until reaching the next statement within the same scope.

The opt keyword is the main method for writing conditional statements, with no abstractions for else-if, else and switch statements, we consider that this is enough and all that is ever going to be needed.

  • The "loop" keyword

loop [expression]
...

LiteScript's version of the "while" statement. If the expression evaluates to true, then run just like an opt statement, execute the code in the following indented scopes, however when the scope ends, return to the loop statement to reevaluate the expression and see what it now evaluates. If it evaluates, skip the following indented scopes just like the opt statements.

The loop keyword is therefore the sole method for writing iterative statements, only abstracting the jump to label behavior from assembly, with no abstractions for other loops like "for" and foreach loops.

Thus, with these control flow keywords, we guarantee that LiteScript can simulate a Turing machine, therefore proving the language's turing completeness, meaning that the language can perform any theoretical mathematical computation.

  • The "conditional" keyword (deprecated)

conditional [expression]
...

This used to be the only keyword for conditional statements up until LiteScript 0.8.2, where it was replaced by the opt keyword because it was to verbose and tedious to write continuously. It is still supported for backwards compatibility, but its use is discouraged.

4.3 Miscellaneous Keywords

There are still a couple of keywords missing that provide extra behavior to the language, most notably global variables which is what mainly transforms LiteScript from being a functional programming language to a procedural one.

  • The "global" keyword

global [variable]

Since the global scope in LiteScript doesn't exist, we need a way to create variables/symbols that are accessible throughout the entire runtime. So the language offers a keyword that creates a global reference during runtime like Python, but unlike Python this is the only exclusive way to do this.

All it does is bind a symbol/name of a variable of any type, including primitive and containers, (that has to be declared later) to a global reference that can be referenced anytime after its creation by any scope. All following modifications to a global variable will have their changes visible globally at a per line granularity, so after the statement has finished executing. These global variables are also shared between threads, which is the only method of inter-thread communication that is natively supported.

It is important to then declare the variable with a value after declaring the global reference, as its value is completely undefined at initialization and cannot be used.

global x
x = 0
y = 1 + x
global x
y = 1 + x

The global keyword can also be used for making local variables global during runtime, in this case the value will be correctly initialized with the current value it is holding.

x = 3
global x

  • The "exit" keyword

exit [integer]

LiteScript provides a built-in keyword for exiting the program, with an optional integer parameter that specifies the exit code. If the parameter is not provided, then the program exits with a default code of 0.

When calling exit, all imported modules running and their implicit data structures and objects are automatically cleaned up during exiting, so there is no need for manual cleanup.