Syntax and Basic Semantics - Paramecium13/LSN GitHub Wiki
The syntactic elements of LSN can be divided into two categories. The first category, executable syntax elements, can, after being reified and loaded, be executed by the interpreter. The second category, declarative syntax elements, define types and functions that can be used in other parts of the code.
LSN contains three main categories of executable syntax elements. Expressions are evaluated and return a value. They often contain other expressions. Expressions cannot be placed alone in a script or function body. Statements tell the interpreter to do something, such as assign a value to a variable or display a message. Most of them contain at least one expression. Control structures contain statements, other control structures (statements and control structures are collectively referred to as components) and often a set number of expressions. Control structures consist of two parts, the head, which contains the keyword(s) that identify it and often one or more expressions, and the body, which contains the components that are executed, depending on the results of the expression(s) in the head.
LSN is a strongly typed language, all expressions have a type that is know at reification time.
Constant expressions consist of a constant value. Some types, such as strings and numbers, can be written directly in the source code, others, such as struct and record values, are only produced by reifier optimizations (namely Constant Folding). See the page on built in types (not yet added) for their syntax.
Variable expressions refer to the value of a specific variable. They are written simply as the name of the variable they refer to.
LSN has all the arithmetic expressions that C# does, as well as the exponentiation expression, which uses the '^' symbol. The operator precedence and associativity follows standard practice (the associativity needs to be tested). Arithmetic expressions are of the form
⌈expression0⌋ ⌈operator⌋ ⌈expression1⌋
where the expressions have a return type of int or double (they do not have to match). Arithmetic expressions between two ints return an int and arithmetic expressions that have at least one double return a double.
⌈expression0⌋ ⌈operator⌋ ⌈expression1⌋
Operator is '&&' or '||'...
!⌈expression⌋
⌈expression0⌋ ⌈comparison⌋ ⌈expression1⌋
Comparison can be: '<', '>', '>=', '<=', '==', or '!='...
LSN supports string concatenation using the '+' operator with two expressions with a return type of string. LSN also has string multiplication using the '*' operator with an expression that returns a string on the left and one that returns an int on the right. String multiplication returns the string on the left concatenated with itself the value of the int times. Bad things may happen if the int is negative.
Syntax
⌈expression for container⌋.⌈field name⌋
⌈expression for collection⌋[⌈expression for index⌋]
Syntax
⌈function name⌋(⌈expression for param 0⌋, ..., ⌈expression for param n⌋)
⌈function name⌋(⌈name of param i⌋ : ⌈expression for param i⌋, ...,⌈name of param j⌋ : ⌈expression for param j⌋)
Syntax
⌈expression for object⌋.⌈method name⌋(⌈expression for param 0⌋, ..., ⌈expression for param n⌋)
⌈expression for object⌋.⌈method name⌋(⌈name of param i⌋ : ⌈expression for param i⌋, ...,⌈name of param j⌋ : ⌈expression for param j⌋)
Syntax
new ⌈type name⌋ (⌈field i name⌋ : ⌈expression for field i⌋, ..., ⌈field j name⌋ : ⌈expression for field j⌋)
new ⌈type name⌋ (⌈expression for field 1⌋, ...,⌈expression for field n⌋)
Syntax
new List<⌈type name⌋>()
Assignment statements assign the result of an expression to a new variable and optionally declare if the variable is mutable (if it can be assigned a different value later on). Syntax
let (mut) ⌈variable name⌋ = ⌈expression⌋;
If the key word 'mut' is present, it indicates that the variable is mutable. The type of the variable is inferred from the expression.
Reassignment statements assign the result of an expression to an existing variable. The variable of a reassignment statement must already exist and be mutable. Additionally, the type of the expression must match the type of the variable.
Reassignment statements can also change the value of a field in a script class or a struct.
Syntax
⌈variable name⌋ = ⌈expression⌋;
LSN currently does not support the syntactic shortcuts '+=', '-=', etc.
The goto statement changes the location of the player, or an other character on the current map or a different map.
Syntax
(actor) goto ⌈destination⌋;
There are currently five different possibilities for the destination parameters.
⌈map⌋
⌈map⌋ ` ⌈label⌋
⌈map⌋ ` ⌈x⌋ ` ⌈y⌋
⌈label⌋
⌈x⌋ ` ⌈y⌋
⌈map⌋ is an expression that returns the name of the map to go to.
⌈label⌋ is an expression that returns the name of the label to go to (on the current map or a different map). I plan to add the ability to place labels at points on maps.
⌈x⌋ is an expression that returns the x coordinate.
⌈y⌋ is an expression that returns the y coordinate.
Syntax
return ⌈value⌋;
If the return statement is in a function or event that returns a value, then it must have a value. Additionally, the type of the value must match the return type specified by the function or method.
The break statement exits the innermost loop. It must not be used outside of a loop.
Syntax
break;
The next statement causes the innermost loop to go directly to its next iteration (, not pass go, and not collect $200). It must not be used outside of a loop.
Syntax
next;
The Set State Statement can only be used in a method or event listener inside a script object or one of its states. It changes the current state of its containing script object. For more information on script objects and states, see the 'Script Objects' page on this wiki.
Syntax
SetState ⌈state⌋;
where 'state' is the name of the state to which the script object is set.
Syntax
if(⌈condition⌋) {
⌈body⌋
}
else if (⌈condition⌋){
⌈body⌋
}
else {
⌈body⌋
}
It can have any number of 'else if' blocks but can only have one 'else' block, which must be after all the 'else if' blocks.
Syntax
for(⌈assignment⌋ ` ⌈condition⌋ ` ⌈reassignment⌋) {
⌈body⌋
}
I will be switching to the following syntax soon.
for ⌈variable name⌋ in ⌈collection or range⌋
{
⌈body⌋
}
Where 'collection' is an expression that returns a collection (vector or list) and range is a range expression, as shown below
⌈int expression 1⌋..⌈int expression 2⌋
Or, maybe also
⌈int expression 1⌋ to ⌈int expression 2⌋
Syntax
while(⌈condition⌋){
⌈body⌋
}
Syntax
choice {
⌈string expression⌋ -> {
⌈body⌋
}
...
⌈condition (optional)⌋ : ⌈string expression⌋ -> {
⌈body⌋
}
}
A branch consists of an optional condition (an expression that returns a bool), a prompt (an expression that returns a string), and a body (LSN code). A choice structure can have any number of branches.
Semantics
When executed, the choice structure displays the prompts for all branches whose condition evaluates to true or that lack a condition to the player. When the player selects a prompt, the corresponding body will be executed.
Not yet implemented...
Not yet implemented...
LSN currently supports five top level types of declarations: structs, records, functions, host interfaces, and script objects. Other declarations, such as enums and quests (maybe...) are planned. Host interface and script object declarations both include sub-declarations. Host interface declarations can contain two different sub-declarations: method definition declarations and event definition declarations. Script object declarations can contain five different types of sub-declarations: properties, fields, methods, event listeners, and states, which can contain methods and event listeners.
Syntax
struct ⌈name⌋ {
⌈Field_0 Name⌋ : ⌈Field_0 Type⌋,
...,
⌈Field_n Name⌋ : ⌈Field_n Type⌋
}
Syntax
record ⌈name⌋ {
⌈Field_0 Name⌋ : ⌈Field_0 Type⌋,
...,
⌈Field_n Name⌋ : ⌈Field_n Type⌋
}
Syntax
fn ⌈name⌋(⌈param_0_name⌋ : ⌈param_0 type⌋, ..., ⌈param_n name⌋ : ⌈param_n type⌋) -> ⌈return type⌋ {
⌈Function Body⌋
}
The body of the function consists of the control structures and/or statements that are executed when it is called.
Syntax
HostInterface ⌈name⌋ {
⌈body⌋
}
The body of a host interface consists of its method definitions and/or event definitions. For information on the meaning and use of host interfaces, see the associated page(s) on this wiki.
Syntax
fn ⌈name⌋(⌈param_0 name⌋ : ⌈param_0 type⌋, ..., ⌈param_n name⌋ : ⌈param_n type⌋) -> ⌈return type⌋;
Syntax
event ⌈name⌋(⌈param_0 name⌋ : ⌈param_0 type⌋, ..., ⌈param_n name⌋ : ⌈param_n type⌋);
Syntax
ScriptObject ⌈name⌋ < ⌈HostInterface⌋ {
⌈body⌋
}
For information on the meaning and use of script objects, see the associated page(s) on this wiki.
Syntax
property ⌈name⌋ : ⌈type⌋;
Syntax
mut ⌈name⌋ : ⌈type⌋;
Syntax
fn ⌈name⌋(⌈param_0 name⌋ : ⌈param_0 type⌋, ..., ⌈param_n name⌋ : ⌈param_n type⌋) -> ⌈return type⌋{
⌈body⌋
}
Syntax
on ⌈name⌋(⌈param_0 name⌋ : ⌈param_0 type⌋, ..., ⌈param_n name⌋ : ⌈param_n type⌋){
⌈body⌋
}
Syntax
state ⌈name⌋{
⌈body⌋
}