The Scriptol Programming Language

Complete reference manual for the version 3 of Scriptol.

This manual applies to the Scriptol to C++ and to JavaScript compilers.
The manual of Scriptol 2 must be used for the Scriptol PHP compiler. Older versions of the compilers use the Scriptol 1 language.

The version 3 of the language is entirely implemented into the Scriptol to JavaScript compiler but some extensions (promises, async/await) are not for the C++ version.

Home page: https://www.scriptol.com/

Table of Contents

Overview

The Scriptol programming language may be used with interpreters and compilers.
A Windows and Unix version exist for each compilers.
The goal of the Scriptol language is to be simple, natural and thus to reduce risk of errors. Scriptol means to "Scriptwriter Oriented Language". It is an universal language designed to produce dynamic wew pages, scripts and GUI based applications. It may be a good scripting language for tools that produce XML documents.
Scriptol may be embedded inside a html page and is converted to the same page with PHP code, ready for the Net and fully portable.
The language has been defined according to seven rules displayed on the scriptol.com site.

About this manual

Please note that the [ ] symbols included into the syntax of statements are usually not part of the syntax of the language itself and denote an optional item, but for indexing and intervals.

Compiling a Scriptol program to JavaScript

You must install Node.js to run the command line program. It automatically installs after download on Windows. In Linux you have to type this command:

sudo apt-get install nodejs

Or equivalent, depending on the distribution.

To compile the program to JavaScript, the command is:

solj [options] filename 

If the file is already compiled, the JS program is directly launched, else it is compiled first, and if no error is encountered, it is executed.
While the source has errors, the command "solp sourcefile" compiles it again. If the source is a HTML page, it is not executed after compilation.

Options of the compiler:

none:  run a scriptol file, compile it if needed.
 -w:    compile code embedded inside a page and make an HTML file.
 -j:    generate a JavaScript file to be included into HTML. 
 -r:    forces to run. Compile if needed and invoques the interpreter.
 -c:    recompile the file and all included ones. Don't interpret.
 -v:    displays more messages when running a program.
 -q:    no message after compilation.

These letters may be combined in a single option.
Ex: -be is equivalent to -b -e.

Also works in recent versions of Powershell on Windows.

Changing the extension and the runtime

The solj.ini file can set the path of the scriptol.js lib and the extension of HTML generated file. For example:

lib="c:/scriptolj/scriptol.js
htmlext=".php"

My first program

A Scriptol source is just a text file with commands inside, one per line.
Examples:

   print x * 2
   print x + (y / 2)

With the text editor included in the archive, or any other text editor, enter this text:

   print "Hello world"

Save it into the hello.sol file.

Click on the "interpreter" or "interpret" command in the "Tools" menu, the "Hello world" sentence will be displayed.

If you are working in a command line windows (called MS-DOS under Windows or console under Unix), just type:

   si hello                  or
   solp hello


You may also build and run an executable with the commands:

    solc -bre hello                build hello.exe or hello under Unix
    hello                          run hello.exe or hello

You can work both with the editor and a command-line windows.

Scriptol project

No project file is required to build a whole Scriptol application.
Just as Java or PHP, you can compile an entire project just by compiling the main source file.
A Scriptol source must have an "include" statement for each file the content of which it uses. The compiler calculates the dependancies among all levels of embedding and solves cross including.

Scriptol source file

A Scriptol file must have the ".sol" extension, and may be converted into a newer file with either the ".php" or ".cpp" and ".hpp" extensions or binary file with a ".exe" extension under Windows and no extension under Unix.

Sources files may be eithers scripts or applications (or dynamic web pages).

A script source is a list of statements along with definitions of functions or classes...
A script, a source with statements at global level, can't holds a "main" function because for the compilers, the whole script is itself a "main" function.

An application source holds only functions and data declarations. The main file is the source argument of the compilation command, a "main" function must be defined into the main file main() ...starting the program (See below).

Features of the language

The design of the Scriptol language has been made with a rigourous method and not empirically by adding features from time to time, when needed. Seven rules have been defined to lead the design (look at the "seven" page on the site), and nothing has been included into the language that doesn't satisfy all the rules. I decided as first rule that the language must be simple and natural, and the second one is to suppress all causes of errors for the programmer.

Scriptol may be defined as:

Case-sensitivity:

Identifiers:

Numbers:

This depends upon the target language.

Cast:

Object-oriented:

XML oriented:

Reactive programming

Scriptol in HTML page

For Scriptol code embedded inside HTML compiled to PHP, it should be inserted inside the following tags:

<?sol
      ... code scriptol ...
?>

Inside theses markers, the last line of a script must be terminated by a semi colon or an end of line (before the ?> symbol).

The simplest way to use a Scriptol script is to call it from a PHP page, that holds a simple include statement:
Example:

<?php
    include_once("count.php");
    update("manual.dat");
?>

This example calls a PHP counter inside the count.php file, built from the example.sol file with the command:

sol -w example
php count.php > mypage.html

To compile Scriptol code to JavaScript in an HTML page, put it inside these markers:

<scriptol>
   ... scriptol code ...
</scriptol> 

Testing html pages

If you have installed a server as Apache or Xitami or Windows Server on your computer, and configured them to recognize the php extension, your code will be processed as on a the web, once compiled to PHP.
Otherwise you have to redirect the output of the script into a html file, "test.html" for example, with two commands that produce mypage.php, and execute the PHP code:

   solp -w mypage
   php mypage.php > test.html

Statement

A statement is ended by a semi-colon or by the end of the line.
When a statement exceeds the width of a line, the line is concatened with the following one providing that it is ended by a comma, or by an operator. No symbol is required to continue a statement on the next line.
Multiple statements on a same line are separated by a semi-colon. This is provided mostly to leave freedom to programmers, but may be useful if you insert Scriptol code into an html page and the editor concatenates the lines!

Comment

Source comments are destinated to the reader only and are skipped by the interpreter.
A one line comment start with the // symbol, the text is skipped up to the end of the line by the compiler.

   // this is a full line comment
   print x        // this is a comment at end of line
   # this is a persistent comment

A multi-lines comment starts with /* and ends with */. The enclosed text is skipped.
Example:

   /*
     Inside these markers, anything is ignored by the compiler
   */

The // and /* */ comments are not included in the target code, unlike # comment.

Symbols

The Scriptol language does not use a symbol for things that are conceptually different .

+ - * / are arithmetic operators you know.
=       operator of assignment.
<       less than.
>       greater than.
<=      less or equal.
>=      greater or equal.
;       is a end of statement terminator.
,       is a separator. It separates elements of an initializer, or of a tuple.
:       builds an association. It attaches a body to a header, a value
        to a key, a method to an object, and so one...
.       uses an association. It associates a method call to the object.
..      separates the limits of an interval of two numbers.
--      is also an interval symbol, upper limit beeing not included.
()      groups sub-expressions, or parameters of a function.
[]      denotes an index or an interval.
?       terminates a condition in one-line control structures.
!=      not equal
<>      not equal
&       binary and, or intersection of arrays.
|       binary or, or union of arrays.
<<      shift left.
>>      shift right.
and     logical and (on boolean values).
or      logical or.
not     logical negation.
^       xor.
mod     modulo ("%" from C++ is not recognized).
~~      encloses target code to insert directly.
`       encloses template, multi-lines text.
#       copyright comment.
//      one line source comment.
/* */   multi-lines source comment.
@       followed by an external identifier to use it without declaration.

Identifiers and keywords

Identifiers are names of variables, functions or objects. They start with a letter, followed by letters, underscores or digits.
They are not case-sensitive, you can't give same name to two different objects, one in uppercase and the other in lowercase.
Keywords are reserved words of the language and are lowercase.

Variables or primitives

Variables are names associated at memory fields holding scalar values. Primitives are basic variable implemented in the language.

Scriptol's primitives are these:

var        dynamic variable, may be assigned anything.
number     any king of number (up to "double" in C++).
int        a number rounded to the integer part. 32 bits.
natural    64 bits unsigned integer but 0. 
real       a number with decimals. 
bool       the true or false value.
text       a string of characters. 
array      an indexed and dynamic list of objects
dict       an associative list of pairs key:value.
var        generic element of array or value of dict.
react      reactive variable.
file       a file.

Other types have been added to use external C extensions:

byte       external C type.
cstring    used in C++ or Java declarations (converted to char *).

Literals

A text is written: "sometext" or 'sometext'.
In the first case, symbols inside the string as $ or { have special meanings when the target language is PHP.

Literals numbers are written:

123         integer (int)
123n        natural
123.0       real
0.123       real
1.2e10      real
0xf8        hexadecimal
0b011       binary
true/false  boolean

Quotes and escaping

A literal text may be enclosed into simple or double quotes.

  print "abc$xyz"
  print 'abc$xyz'

In the first case, this displays a string of these characters: abc followed by the content of the xyz variable.
In the second case, this displays this string: abc$xyz.

To insert characters that cannot be directly inserted with the keyboard, the special escape code \ is used, followed by a letter:

   \"      inserts a double quote
   \'      inserts a single quote
   \n     inserts a newline.
   \t      inserts a tab.
   \\      inserts the \ character itself.

Multi-lines

A string may be shared on several line when enclosed inside ` markers like in ECMAScript 6.

Example:

x = `
     row 1
     row 2
    `

Line feed may be either direct or escaped:

x = "one\ntwo"            ...valid
x = "one
two"                          ... not valid

x = `one
two`                       ... valid

Variable in string

Inside a double-quoted string some symbols have special meaning at runtime, a $ symbol means for a variable name.

text xyz = "def"
text t = "abc$xyz "

The t variable is assigned the characters a,b,c followed by the content of the variable xyz, and thus, t really holds the string: abcdef. It is called string interpolation.

The {} symbols may have a special meaning for the target language and must be escaped with the \ caracter in a double quotes string.

The recommended syntax is rather:

 text t = "abc" + xyz

A string inside simple quotes and prefixed by $ is not interpreted at all.

text t = 'av$er\n'

is displayed as: av$er\n

Declaration

The declaration of a variable has the form:

type var [ = expression ]

Examples:

int x
text t = "demo"

Declaring several variable at once is allowed in the form:

type name [= value], name [= value], ...

Examples:

int x, y, z
int x = 0, y = 0, z

Assigning a tuple is not allowed (this is allowed only with variables already declared)

int x, y = 1, 2               ... not valid

While the following is supported:

text a = "a"
text b = "b"
text c, d
c, d = [a, b]

Constant

The const modifier defines a variable whose value can't change.
Syntax and example:

const type NAME= value
const int X = 5                   ... you can't assign further to x another value.
const text T = "demo"

Constants declared by users are usually uppercase.
Some predefined constants are keywords of the language:

true        matches an expression that is true.
false       the opposite.
zero        the 0 value.
nil         (Not In List) object that doesn't exist inside a sequence.
null        value of an object while not initialized yet or sign for deletion.

PI is a built-in constant for the pi mathematical value.

Nil and null

Nil means for "not found" or "empty" while null means for "no value" or "declared but not defined".

Nil is not a real value but a contruction of the language instead. In reading, it reflects the fact that an object is not found by a search in a list. In writing it has the effect of removing an element or a range from a list. A variable should not be initialized with nil.

Examples of use:

array a = [1,2,3,4,5]
a[1..3] = nil

Now the content of the array is [1,5].

int i = "demo".find("x")
if i = nil print "Not found"

Since "x" is not in the string "demo", the message "Not found" is displayed.

Here are the values that nil matches for each type...

   bool         false
   int          0
   natural      -1
   real         0
   text         ""
   array        []
   dict         {}
   file         null
   object       null
   var          as each of above according to the type of the content.

When Scriptol generates PHP code, nil is replaced by false for numbers, "" for text.

When JavaScript is generated, nil is replaced by -1 for numbers, "" for text.

Null

The null keyword is converted to "null" in PHP, "NULL" in C++ and "undefined" in JavaScript.
If null is assigned to a variable, the variable can't be referenced, thus is unusable until it is assigned with a value. You can only compare it in a condition with the null keyword.

Example of use:

text a = null

The "a" variable may be assigned but otherwise referenced only to be compared to null, or an error message is displayed.

Assignment

The syntax of a simple assignment is:

identifier = expression

You must assign a variable with a value of same type.

int i = 10
int j = "343"            ... bad

It is possible to convert a type into another with constructors of primitives.

Compound assignment

When a operation performed on a variable, and the result assigned to the same variable, this may simplified in a simple, augmented instruction.

The syntax of such a compound assignment is:

identifier compound-operator expression

For example, to add 10 to x, and put the result into x, rather than write x = x + 10, you can write x + 10.

Compound operators are: + - * / mod << >> | & ^
Example:

a = 1              ... gives a the value 1
a + 1              ... adds 1 to a
x * y              ... replace the content of x by x * y.
a * (x + 2)        ... a is multiplied by the expression
a = a * (x + 2)    ... as above
a & b              ... replace the content of the array a by the intersection of a and b.

Takes not in an expression, x + 10 return the addition of x and 10, with no change in x.

  if x + 1 : ...        x is unchanged.

Destructuring assignment

A tuple of variables may be assigned a tuple of expressions.
Syntax and example:

   name [, name]* = expression [, expression]*

   x, y, z = 1, x2, 8

The number of expressions at right must match the number of targets at left or may be a single value assigned to several variables.
Multiple assignment allows a function to return several values.

Examples:

   x, y, z = 0
   a, b = myfunc()

Unlike multiple declaration, multiple assignment may be operated on variable having different type.
Example:

  int x
  text t
  x, t = 1000, "abc"

Arrays having a dynamic size, the number of expression to assign is not fixed. Example:

  x, y, z = [1, 2, 3, 4]

Is as: x = 1, y = 2, z = 3.

  x, y, z = [1]

Is as: x = 1

You may assign several variables, previously declared , separated by commas from:

In case of array or dict, or a tuple, or a function returning several values, the variables from 1 to n are assigned the items from 1 to n, in the same order.
If the number doesn't match, it is an error.
If the function returns a single value, the same value is assigned to each variable at left.

Swaping the contents of two variables:

var a = "alpha"
var b = "beta"

a,b = [b, a]
print a, b

It will display: beta, alpha.

Operators

Comparison operators are:

=   equal
<   less
>   greater
<=  less or equal
>=  greater equal
!=  different
<>  different

The "in" operator tests the inclusion of an element in a sequence: a string in a text, an object in an array, a value in a range.

   if "a" in line  print "in text"
   if x in 1..10  print "in range"

Binary operators are:

  &  and
  |  or
  ^  exclusive or
  ~  not
  << shift left
  >> shift right

Array operators are:

   &  intersection
   |  union
   ^  complement of intersection

Precedence

Unary operator have precedence over binary ones. Among binary operators, precedence must be denoted by parenthesis.

Expression

An expression is a combination of values and operators. Main kinds of expressions are:

- Arithmetical expressions: Combinations of arithmetical values or function calls with these operators: + - * / mod.
mod is a shortcut for modulo and returns the remainder of a division...
Example:

   print 100 mod 3
   ... should display 1 that is the remainder of 100 divided by 3.

- Conditional expression: Set of two at least expressions linked by relational operators, and returning a boolean value.

- Logical expressions: A combination of boolean values or expressions (relational or logical ones) and logical operators and, or, not.
The "and" expression returns true if the two terms are true, false otherwise.
The "or" expression returns true if one of the two terms is true, false if the two ones are false.
If we add the "not" operator on the whole expression, it negates the final result.

Example:

   bool x = true
   bool y = false
   if x and y print "true"; else print "false"          ... should display false
   not(x or y)          ... is false.
   x and not y          ... is true

- Binary expressions: A set of numbers linked by binary operators.

  |    binary or
  &    binary and
  ^    exclusive or
  ~    binary not
  <<   shift left, that is equivalent to multiply by 2
  >>   shift right, that is equivalent to divide by 2

- Text expressions: Operators on text are:

 = <  >  <=  >=    to compare two texts.
 +                 to concatenate two texts.
 []                indexing, slicing or splicing (see at text chapter).
 in                test if a text is a part or another one.

Example:

   text t = "prefix"
   print t + "suffix"
   ...should display: prefixsuffix

- List expressions: Operators on lists (array, dict) are:

 = < > <= >= <> compare two lists for values.
 +            concatenates two lists (doubloons may result).
 -            removes from a list, element of a second one (but doubloons).
 []           indexing, slicing or splicing (see at array and dict).
 in           tests if an element is inside a list.
 &            intersection, returns element common to two lists.
 |            union, returns elements of two list without doubloons.
 ^            complement of intersection.

Precedence

Some programming languages have instituted precedence rules, so, when parenthesis are missing, we know the terms involved by each operator. Meanwhile precedence has been built inside the Scriptol parser, error message is thrown when parenthesis are missing because they are required for readability.
The sole case where precedence is admitted without parenthesis is for unary operators: not, ~
Unary operator applies always to the term that follows it, and thus to be applied to an expression, the expression must be enclosed between parenthesis.
Examples:

if not a and b
if not (a and b)

In the first case, the not operator is associated to the "a" variable.
The second line negates the whole expression in parenthesis.

In compound assignment the first operator, that is also a equal operator, applies to the whole expression at right.

Function

A function starts with a header and ends with the "return" keyword.
The return type is required, and the type of parameters also. "void" is used if nothing is returned.

Syntax:

  type [,type]* identifier( [parameter [, parameter]*] )
     ... statements ...
  return [expression [, expression]*]

  int myfunc(int x)
  int, bool myfunc(text t, int i)

Example:

  int multiply(int x, int y)
    int z
    z = x * y
  return z

This may be written simply:

  int multiply(int x, int y)
  return x * y

The body is a list of statements, including some "return" if needed. Inside the body of a function you can put any kind of statement, but a high-level declaration (class, enum) or another function. You can put inner return statements.

The ending statement is a return with zero, one, or several values.
Examples:

   return
   return x
   return x, y, 5

If the function return several values, it must have also several return types and the return statement has several parameters (in the same order that the return types).

Example:

  text, int, int coordinate(int num)
    int x = mytable[num].x
    int y = mytable[num].y
  return "coo", x, y

Calling a function:

A call to a function may assign zero, one, or several variables.

   myfunc()
   a = myfunc()
   a,b,c = myfunc()

Alias: Parameters of a function

When a function has objects as parameters, the name of the parameters are aliases of the original objects, and any change inside the function are made in fact on the original objects.

By default, primitives are copy and other arguments are aliases. It is possible, if required, to use also the original of a variable, rather than a copy: thanks to the "alias" keyword, the compiler knows that this is just another name for the original variable.

Example:
void func(number x)
  x + 1
  print x
return

void funcalias(alias number x)
  x + 1
 print x
return

number y = 5
func(y)
print y
... should display 6 then 5

funcalias(y)
print y
...  should display 6 then 6.

Default values

Assigning a default value allows to omit an argument at the function call. The complete syntax for the heading is:

type [,type]* name(type name [= expression] [, type name [= expression]]* )

Example:

  int increment(int x, int y = 1)
    x + y
  return x

  print increment(10, 5)             ... should display:  15
  print increment(10)                 ... should display: 11

The default value 1 has been used to replace the missing parameter.

If the interface of a function has several parameters with a default value, you can't omit one in the call without omitting all following ones. The parameters can't be not recognized by their type.
If what you want if to write a function with different numbers and types of parameters at call, you must use an array or a dict instead.

Example:

  void param(dict parlist)
    size = parlist["size"]
    name = parlist["name"]
    values = parlist["values"]
  return

In this example, the variables "size", "name", "values" are global, and they are just assigned by the content of the dict in argument.

Scope and function

A function opens a new scope for all variables declared inside. If the function is at the global level, all global variables compiled before the function are visible in the function.
Inside a function, a variable can't be declared with same name that a global variable. This rule applies also inside methods of classes.
If the function is a method of a class, all variables declared in the class before the function are visible in the function.
Objects declared in the function are visible in embedded control structures. Identifiers still in use can't be reused inside embedded blocks too.

The "main" function

It is often required to pass arguments to a program from the command line. To do that in Scriptol (as in PHP), use the external $argv PHP variable.
To mimic the way C++ passes arguments to a program, declare a function "main", and call it with $argv (and $argc if needed) as parameter.

  int main(int argnum, array arglist)
    print argnum, "parameters"
    for arg in  arglist
       print arg
    /for
  return 0

  main($argc, $argv)    $argc and $argv are system variables, assigned automatically.

The int return type is mandatory if the source is compiled to binary.

When the program is compiled to C++, the main call is useless.

Print and echo

Echo

Echo displays an expression, or a list of expressions separated by commas, without blank space nor line feed at end (as the print statement does).

Syntax: echo expression [, expression]

Example:

  x = 5
  y = 20
  z = 1
  echo "values", x, y / 2
  echo z

This will be displayed on the screen as this:
values5101

Example:

  echo "demo", 5
  echo "next"

displays: demo5next

Print

In a such case, a better display is performed with the print statement. Print replace the comma by a blank space, and it adds a newline at end.

Syntax: print expression [, expression]

Example:

  print "demo", 5

displays: demo 5

A single print statement, without parameter, sends a line feed.
Example:

  print

Input

To enter a text, or numbers, from the keyboard, use the input command.
A text may be displayed before the input is requested.

Example:

  text name
  input name
  print name

Example:

  input "who are you? ", name

The variable to assign must be declared before the input command, it may be a text or any kind of number.

Control structures

Control structures are:

if
   if else /if.
   one-instruction if.
   composite if.
for
   for /for.
   one-instruction for.

while
   while let.
   while /while.
   while forever.
do
   do until.
   do /do while.
   do case.
switch case
enum
   simple enum.
   dict enum.

For JavaScript only:

to for /to
to while /to
one-line to for

break and continue are two statements used inside controls structures.

A one-instruction control structure has the form:

     keyword expression let statement
or  keyword expression ? statement
or  keyword expression statement-starting-with-a-keyword.

"Let" means for "Last statement, Execute and Terminate". The let element is always the last part of a control structure and may be the sole one. In this case there is no ending but the end of line. The sole statement may be any basic statement and can't be a control structure.
Let is required when the statement is an assignment or a function call, but is optional when a keyword follows it.
The "?" symbol is just a shorter replacement for "let".

A multi-lines control structure has the form:

structure-name expression [:]
   ... statements ...
/structure-name

The colon is optional (but if a statement continues the ligne).

If

One-instruction syntax:

if condition ? statement  : statement

One must read the line as this: condition true? action else another-action

Examples:

if a = 5 ? break
if a = 1 ? print "one" : print "several"

Multi-lines syntax:

if boolean-expression [:]
    ... statements ...
else                            ...optional
    ... statements ...
/if

N.B.: The colon is optional after the condition, as the semi-colon after a statement, but is required to concatenate the lines.

Examples:

if (x + y) > 8
    print "> 8"
    print x
else
    print "<= 8"
/if

if x + y) > 8 : print "> 8" ; print x ; else print "<= 8"; /if

Composite if

The syntax is:

if not-boolean-expression [:]
  operator expression : statements
  operator expression : statements
       ...
else
       ... statements ...
/if

A not-boolean expression, is an ident, a litteral, or any expression that doesn't return a boolean value (true or false).
The structure: "operator expression : statements" is a case group. There are no "break" keyword after a case group. A break will causes exiting from the control structure that would contain the current "if" structure.
Valid operators are:
=, <, >, <=, >=, !=, <>, in, else.
"else" here is equivalent to "default" in the switch case.

Examples:

if a
  = 1: print 1
  = 2: print 2
  > 2: print ">2"
else
      print "<1"
/if

if x
    in [1,2,3]: print "first"
    in [4,5,6]: print "second"
    in [7,8]  : print "third"
    else print "other"
/if

For in

The for control structure scans either a range or a sequence and puts each item into a variable.

Syntax of for range:

 for variable in start..end [step s] [:]
     ... statements ...
 /for

The start, end, step elements are either identifiers or literals.
- step is optional, the default value is 1.
- the end value is included in the range if the range symbol is "..", not is the symbol is "-".
- the end value may be inferior to the start one, providing the step is present and holds a negative value.
The container variable that is assigned each value of the range, may be declared into the heading, in this case, it is local to the control structure.

Syntax of for list:

for variable in list-expression [:]
    ... statements ...
/for

In this case, the content of an expression is scanned and each item
assigned to the variable. The expression must be an array, a text or any expression that returns an array or a text.
Examples:

for i in 1..10
    print i
/for


for w in myarray
    print w
/for


for w in arr1 + (arr2 & arr3[0..5])
    print w
/for

The one-instruction shortened syntax

for ident in list let basic-statement

Examples:

for w in mylist let print w
for x in 10..1 step -1 let print w + 10

Getting the key and the value

The for loop scans an associative array value by value. It is equivalent to for .. of in JavaScript while for .. in in JavaScript scans keys.

for var v in d let print v        // display values

But you may also get the key and the value:

for text k, var v in d let print k, ":", v // display keys and values 

This works also on a simple array:

array a = (10,20,30)
for int index, int val in a
  print index, ")", val
/for

That displays:

1) 10
2) 20
3) 30

While

The while structure is a conditional loop.

One-instruction syntax:

   while expression let instruction

Standard syntaxe:

   while expression [:]
       ... statements ...
   /while

Example:

   int x = 10
   while x <  20
      print x
      x + 1
   /while

A "break" statement exits the loop.
A "continue" statement skips all that follows and starts a new loop.

While let

This syntax is recommended to avoid the risk of infinite loops.
The statement that changes the value of the expression that is the condition of the loop, is moved after the /while marker by the mean of the "let" statement.

   while condition
       ...statements...
   let incrementing

Example:

  while x < 10
     if (x mod 2) = 0 continue
     print x
  let x + 1

The continue statement jump to the let instruction.
There is not corresponding code in C or PHP, because a "continue" statement in C or PHP bypasses following instructions, including "x + 1", and leads to a infinite loop.

Examples of one-statement loops:

   while x < 10 let x + 1
   while x < 10 : print x; let x + 1

Do until

The block of statements enclosed inside the do /do tags, is a new scope, and enclosed statements are perfomed first, before a condition is tested, if a condition is given.

General syntax of do:

do
 ... statements ...
until [ condition ]

The block of statements inside do until is performed while the condition is false, and is exited when the condition is true.

Example of do until:

do
   print x
   x + 1
until x = 10

Do case

Do case is a powerful pattern-matching control structure. It contains one or several case groups followed by an optional default and an optional always. One case group only is processed, the one the condition of which if first matched. Always is always executed. Default only when no condition is matched.

Syntax of do case:

do
case condition : statements
[ case condition : statements ]
[ default statements ]
[ always statements ]
/do [while expression]

Examples:

do
case nom = "pussycat":    print "it is a cat"
case nom = "flipper":        print "it is a dolphin"
case nom = "mobby dick": print "it is a whales"
default
   print "another animal"
/do

int state = ON
do
case state = ON:  counter + 1
case state = OFF: break
always
     state = getState()     ` some function
/do while forever

The automaton loops until the OFF state is encountered (produced by the called function.

Do while

The /do ender may be completed by a condition, while or forever.
Statements while be processes once, and while the condition is true.

Syntax of do while:

do
    ... statements ...
/do while boolean-expression


do
    print x
    x + 1
/do while x < 3

Options

Switch case

Syntax:

swith varname
case int/real/text : case block
... series of cases ...
default: case block
/switch

A variable may be compared to:

Example:

real x = 0.8


switch x
  case 0 : print "0"
  case 0 .. 1 : print "in the range"
  case 1,0.5, 0.8, 1 :  print "in the range"
  defaut:  print "not found"
/switch

It is not an error to compare a variable from a type to a value of a different type, unlike in an assignment. For example, an integer and a real. The target language will decide what is the result of the comparison.

Break and continue

Break is the command to exit a loop.
Example using the "forever" keyword that leads deliberatly into an infinite loop:

int x = 0
while forever
    print x
    if x > 100
        break
    /if
    x + 1
/while

When x reaches the 100 value, the break statement skip instructions beyond /while, and the while structure.

Continue is a command to skip all statements, from the current position, up to the end of the structure, and thus to start a new loop.

int x = -1
while x < 20
    x + 1
    if (x mod 2) = 0 continue
    print x
/while

This example displays only the even values of x, because if an odd value is encountered, the condition x mod 2 is matched and a continue command is performed.
Note than if incrementing the variable tested in the while condition is put after the continue statement, it is skipped also. An infinite loop is prevented thanks to the while ... let syntax.

Enum

Enum allows to assign sequentially values of several types to identifiers.
You can use also equal to assign an integer, for the automatically generated sequence continue, starting from this number.
You can also assign to any identifier, a real or a text, with a colon.

Syntax of enum:

enum
  identifier [ : value | = value ]
  [ identifier ...]*
/enum


enum
     Z, ONE, TWO, THREE
/enum

This assigns 0 to Z, 1 to ONE, and so one and is equivalent to:

const int ZERO = 0
const int ONE = 1
etc...


or:
enum: Z:0, ONE:1, TWO:2 /enum

More complex example assigning various values and restarting a sequence:

enum
    Z : "a0",                      ...  assign a0
    ONE  : "a1",                  ...  assign a1
    THREE,                        ...  assign 0
    FOUR : 3.15,                ...   assign 3.15
    FIVE = 5,                     ...   assign 5 and restart the numbering
    SIX                            ...   assign 6
/enum

Example of the one-line syntax:

 enum ZERO, ONE, TWO, THREE

Indexing

The syntax of an index in a text or array is: [indice].
The indice must be a simple expression without square brackets embedded inside. A simple expression is a literal number, an identifier, a function call, or an arithmetical expression, and must be resolved as an integer value.

Range

The syntax of a range is:

start .. end

It is enclosed between square bracket to subscript a list:

list-name[start .. end]

Start and end are integer expressions.
The end is part of the range unless the "-" operator is used instead.

a[0 -- 100]        is as  a[0 .. 99]
a[x -- y]            is as a[x .. y-1]

Examples of ranges:

0..10
x..y
x * 2 / 4 .. y + 10

You may use range to:
- test if a value is inside a range: if x in 10..100
- scan a range: for x in 1..100
- extract a part of a list: array b = a[x..y]
- change a part of a list: a[x..y] = another-list

Subscripting

The start and end value may be omitted when subscripting a list.

Splitting a list, there are three ways:
   array a = [x0, x1, x2, x3, x4, x5, x6, x7, x8]
   array b = a[..2]
   array c = a[3..5]
   array d = a[6..]

Now we have three arrays, with these contents:
   b:   [x0, x1, x2]
   c:   [x3, x4, x5]
   d:   [x6, x7, x8]

Displaying the arrays:
   b.display()
   c.display()
   d.display()

You should see:
   array (
    [0] => x0
    [1] => x1
    [2] => x2
   )
and so one...

To replace an interval by another list, a simple assignment is required:
a[3..5] = ["a", "b", "c"]
The content becomes:
(x0, x1, x2, "a", "b", "c", x6, x7, x8)

With the same syntax, a sub-list may be replaced either by another list, or by a single value:
a[3..5] = "xyz"
The original list becomes:
(x0, x1, x2, "xyz", x6, x7, x8)
If we want rather to remove a sub-list from the original array, we have to declare it "not in list":
a[3..5] = nil
As we have removed the sub-list 3..5 that is (x3, x4, x5), the content now becomes:
(x0, x1, x2, x6, x7, x8)

We can test is a valuer is in a sub-list.
Example:

  array a = ["one, "two", "three"]
  if "two" in a[2..5] print "inside"

Text

A text is a basic objet with methods, that holds a string of characters. A literal text is a string encloded between simple or double quotes. When a text is the argument of a function, the function uses a copy of the text, not an alias on the original one.
An indice may be negative in slicing or splicing, not in indexing.

Syntax:

text s                 creates a text.
s = "str"              initializes.
s = s[i]               gets a char.
s[i] = s2              replaces a char, s2 should be a one-char text.
s = s[i..j]            gets a sub-string, from i until j included.
s[i..j] = s            replaces a sub string.
s[i..j] = ""           removes a sub string.

A litteral text is a string of character enclosed in simple or double quotes.

The + symbol may be used with texts as with mathematical expression to concatenate strings.
Example:

text b = "prefix"
text a = b + "suffix"

The content of a will be: "prefixsuffix". T

Methods of text

Return   Method          Function

void     cat(text)       concatenates another text.
text     capitalize()    converts the first char to uppercase.
int      compare(text)   compares lexicographically two texts (ignore case).
                         returns -1, 0, 1.
text     dup(int)        returns a text duplicated n times. Ex: "*".dup(10).
void     fill(text, int) fills the text with the text argument n times.
int      find(text t2)   returns the position of text s2 inside the text.
                         returns "nil" if no found.
                         (test for x = nil as x <> nil doesn't work in PHP)
int      identical(text) compares, doesn't ignore case. Return -1, 0, 1
void     insert(int,text)inserts a text at position.
bool     isNumber()      return true if the test is a numeric string.
int      length()        returns the length.
text     lower()         converts to lowercase.
text     lTrim()         removes heading controls/blanks.
void     replace(ft, rt) replaces each occurence of ft by rt.
void     reserve(int)    allocates the size to use the text as a buffer.
text     rTrim()         removes trailing controls/blanks.
array    split(sep)      splits a text into items separated by sep.
void     toFile(text)    save to file with the name in parameter.
int      toInt()         converts to integer.
natural  toNatural()     converts to natural.
real     toReal()        converts to real.
text     toText()        converts a literal string to text (for C++).
text     trim()          removes heading and trailing control codes/blanks.
text     upper()         converts to uppercase.
text     wrap(int size)  wordwraps the text.

Dynamic variables

Are declared with the type "var".
Dynamic variables have the methods of all other types of primitives but not the methods of declared classes (see at "extern").
Once a variable is assigned to a var, a cast is required to assign the content of the var to a typed variable:

Methods on var:

Sequence and list

A sequence is either a static (text) or dynamic, associative list (array or dict).
List and sequence have same operators, but & and | that are proper to lists.
Operations on lists are these:

  []   : index, slice, or splice.
  +    : merges two sequences. Or push a scalar to a dynamic list.
  -    : removes a sequence from another one, or an item from a dynamic list.
  =    : compares two sequences.
  in   : tests if an object is in a sequence.
  &    : intersects two lists (gives common elements).
  |    : union without doubloons of two lists.

Array

Two types of dynamic lists of objects exist in Scriptol:

 array:  keys are integer numbers.
 dict:   (dictionary) keys are texts.

An array is a dymamic and indexed list of object or literals.
Dynamic means the size is not predefined nor limited.
An empty array is symbolized by [].
A literal array is a list of expressions separated by commas and enclosed between square brackets. A variable is a valid element.
The array constructor starts with the keyword "array".

Type a.display() to view the content of the a array, this output is displayed:

 array(
  0 : first
  1 : second
  2 : last
 )

Making an array

The array constructor has the form: array()
An empty initializer is written: array()
A literal array is written: [ ... values ... ] You can define a array by assigning a literal array or the constructor, or a single value.

Syntax:

array a                               creates an array.
array a = []                          creates an empty array
array a = [x, y, ...]                 creates and initializes an array.
array a = [3]                         create an array of one element.

Elements of an array may be any expression *** but boolean ones ***. If you put the true value inside an array PHP will return always true when you use the "in" operator, with any searched value.

An array may be declared without assigning any content, and filled further:

array a
a.push("first")
a.push("second")
a.push("third")

Elements are accessed by their position inside the array. Examples:

a[1] = "a"
a[2] = "b"
for x in a : print x
 ... should print:  a b

Indexing an array

Items inside an array are accessed by an integer number.
Syntax:

   a[n]                      reads the item with at position n.
   a[n] = x                  replaces the item at n by x.
   a[n] = nil                erases the item at n
   a = []                    clears the whole array.
   a[n].upper()              calls a method on the dynamic element n.

An empty index designate the current item:

   a[]                        reads the item with at current position.

The indice may be any kind of expression, but this expression must not include another array.

  a[10 + x / 2]            valid.
  a[10 + b[5]]             not valid.

Since arrays may contains any kind of object, and even other arrays, you need for a dynamic variable to get an element unless you know the type of the item to get:

  array a = [ x, "two", 3 ]
  var x = a[1]                 use var for unknow element at first position
  text t = a[2]
  int i = a[3]

When an element is added outside bound, it is just pushed at last position into the array.
If you assign an element with the statement:

   a[1000] = "x"

In PHP and JavaScript:
  array(
    0 : one
    1 : two
    2 : last one
    1000: x
  )
In C++:
  array(
    0 : one
    1 : two
    2 : last one
    3: x
  )

In PHP, the 1000 indice is just temporary and will differ as soon that a statement has modified the array.
For compatibility issue, use a such statement to replace values in an array, not to add them, this is the way dict only may be filled.

Iterator

An array may be scanned with an iterator.
One points out the first element with begin(), or the last one with end(). The currently pointed out value is accessed by an empty indice: [].

Iterator methods:

   begin()     points out the first element and returns it.
   end()       points out the last element and returns it.
   inc()       moves to the next element.
               Returns the value, or nil, beyond the last element.
   dec()       moves to the previous element. Returns the value or nil.
   index()     returns the index of the pointed out element.
   value()     returns the value of the pointed out element.
   []          empty indice for the current element.
   nil         means for "not in list" and is returned by various functions
               when no value can be returned.

Example of use with the a array:

  a.begin()                 // moves to the first element
  while a[] != nil          // tests if end of list reached
      print a[]             // prints the currently pointed out element
      a.inc()               // moves to next element
  /while

In reverse order:

  a.end()
  while a[] != nil
     print a[]
     a.dec()
  /while

Using array as a stack

Once the array is created, you can perform various list - or stack - processing...

  a.push("item")     ...add an element at end of the list
  a.unshift("item")  ...insert an element at begin of the list
  a.pop()            ...read and remove the last element
  a.shift()          ...read and remove the first element

You can both read and remove the elements of an array by successive such statements:
print a.shift()

Interval in array

An interval is subscripted by a couple of positions.

a[pos..end]           the range between "pos" and "end" included.
a[..end]              from the start to position "end".
a[pos..]              from position "pos" to the end of array.
a[..]                 gets the whole array (useless)
a[pos] = nil          removes an item (keys are renumbered).
a[pos..end] = nil     removes a range of items (here also).
a[pos..end]= b        replaces a range by an array/item

Operators on array

An item, or a group of items, may be added or removed with the + and - operators.

Example:

array a = ["one", "two"]
array b
b = a + ["three", "four"]        b is now ("one", "two", "three", "four").
b = b - ["one", "four"]          b is now ("two", "three").

Only the + and - arithmetical operators are usable on arrays along with the in operator.

The "in" operator

This operator may be used to test if a value is contained inside a list (array, dict or even a text), and to scan the content too.

Syntax and examples:

  if variable in array  ... some statement ...
  for variable in array  ... some statement...

  if x in a  print "inside"
  if x in [1,2,3] print "inside"

  for x in a print x
  for t in ["one", "two", "three"] print t

Binary operators on dynamic lists

You may use for dynamic lists (array or dict) the binary operators:

   &  intersection    returns only elements that are parts of both the two lists
   |  union              merge two list without doubloons.
   ^  complement of intersection

   a = [1,2,3,4] & [3,4,5,6]  assigns (3, 4) to a.
   a = [1,2,3,4] | [3,4,5,6]  assigns (1,2,3,4,5,6) to a.

Applying a function to an array

The map method, which is implemented in JavaScript and PHP allows to successively apply a function to each element of an array and optionally return a new array. example:

int mapfun(int x) return x * 25

b = [1,2,3,4,5]
print b.map(mapfun)

If you want to apply a function to several arrays at once, or dicts, the index is used. Example:

for text k, var v in d1
  d1[k] + d2[k]
/for  

Elements are added one by one, from the contents of the associative array d1 and d2.

Using a function, with two parameters:

array a1 = [1,2,3,4,5]
array a2 = [10, 20, 30, 40, 50]
int mapfun(int x, int y) return x + y
for int i, var x in a1 print mapfun(x, a2[i])

Multi-dimensional array

The number of dimensions is not limited.
For a two-dimensional array, the syntax...
- to access an element is: x = arrayname[i][j]
- to change an element is: arrayname[i][j] = x

To create an element, the syntax is:

  arrayname[i] = []
  arrayname[i][j] = x
  or
  arrayname[i] = [x]

You cannot create directly an element into a not existing sub-array. The i and j indexes suppose that i and j elements already exist.

Comparing two arrays

The language can make comparisons between arrays of numbers with all relational operators. Two arrays of different sizes are different.

For arrays of strings or other objects, you can test only if they are identical or if they are different. For further comparisons, you must define your own algorithm.

Content of PHP array, step by step

We have to know how integer keys of PHP array change, according to all operations we can perform. This is important to understand associatives arrays and to avoid lot of bugs. After each operation, the content is displayed.

  array a = []
  array ()

  a.push("one")
  array
   (
    [0]=> one
   )

  a + ["two", "three", "four"]
  array
   (
    [0]=> one
    [1]=> two
    [2]=> three
    [3]=> four
   )

a.shift()            The first element is removed and the keys are renumbered.
  array
   (
    [0]=> two
    [1]=> three
    [2]=> four
   )

  a[1000] = "thousand"
  array
   (
    [0]=> two
    [1]=> three
    [2]=> four
    [1000]=> thousand
   )

  a.unshift("x")       All keys are renumbered, even the 1000 one.
  array
   (
    [0]=> x
    [1]=> two
    [2]=> three
    [3]=> four
    [4]=> thousand
   )

Creating two new arrays:

  array a = ["one","two"]
  array b = []
  b[1000] = "thousand"
  a + b

Keys are renumbered.
  array
   (
    [0]=> one
    [1]=> two
    [2]=> thousand
   )

If we replace a + b by a.push("thousand") the result will be the same.

Methods of array

Iterators are not implemented in the JavaScript compiler yet, so begin, dec etc... are not supported.

Return  Name              Action

var     begin()           points out the first item.
var     dec()             decrements the pointer and returns the element.
void    display()         displays the array.
var     end()             points out the last item.
bool    empty()           returns true if array empty.
int     find(var)         searches for an item, returns the index or nil.
int     findLast(var      searches for an item from the end.
var     inc()             increments the pointer and returns the element.
int     index()           returns the index of pointed out item.
void    insert(int, var)  inserts a value at the integer position.
text    join(text sep)    converts into text with sep between elements.
bool    load(text name)   loads the file into the array.
var     min()             gets the lowest value.
var     max()             gets the highest value.
array map(function) applies a function to each element and returns a new array. void pack() Makes elements of the array consecutives. var pop() gets and removes the last item. var pop(int) gets and removes the item at the given position. void push(var) adds an item at end. var rand() returns an item at random location. list reverse() returns the list in reverse order. var shift() gets and removes the first item. int size() returns the number of elements. void sort(int) sorts the values in ascending order. See below. void rsort(int) sorts the values in descending order. See below. void store(text name) stores the array into a file. Add false as argument to not add eol. number sum() calculates the sum of items. text toText([text]) converts the array to text with glue string in option. array unique() return the array with not doubloons, first found kept. void unShift(var) inserts an item at the first position.

The sort method requires one optional parameter: 0 for an alphabetical sorting (the default in JavaScript and PHP), 1 for numerical sorting.

Dictionary

A dict is a dymamic list of pairs key and value. Keys are always texts. Values may be any objects. A variable may be used as key or value.
The format for a pair key and value is:

key:value

An empty dict is symbolized by {}.

A literal dict is a list of pairs separated by commas and enclosed in curly braces.

Unlike arrays, a dict is filled by assignments:

d[k] = "b"
d["first"] = "element 1"

Although JavaScript supports digital keys placed in quotation marks, thus considered texts, it produces unpredictable results when mixed with alphabetic keys. Thus mixing these types must be avoided.

Making a dict

A dict may be assigned a constructor or a literal dict.
Syntax:

dict d                             ... creates a dict.
dict d = {x:v, y:w,...}            ... creates and initializes a dict.
dict d = {}                        ... creates an empty dict.

The values stored may be any kind of objects.
The key can be a variable and the value an expression.

Examples:

text k = "a"
text v = "b"
dict d = {k : v}
dict d = {k : v + "x".dup(4) + 20.toText()}

This example puts "bxxxx20" into d with the key "a".

Indexing a dict

Items in an dict are accessed by a textual key.

Syntax:

  d["key"]                 ...gets the first item with the key "key".
  d[key] = var             ...replaces a value or add the couple key, value
                           ...if the key is not already inside the dict.
  d[key] = nil             ...removes an item.
  d = {}                   ...clears the whole dict.

Example:

  dict d
  d["program"] = "what we want to write faster"
  print d["program"]     ... will display the text above

Interval and dictionary

The right way to use a dictionary is by the means of keys or iterator. In some cases, it mays be useful to access a range of items directly.
When adding an element or another dictionary to a dict, by the way of interval, push, unshift, PHP generate a new key for the item. The new key is a number.
- If you replace a range by another dict, some of the items may be lost.
- This also does happen when merging.
- The keys of the replacing dict are not kept in changed dict.

Examples of display:
Should print all keys and values in the dictionary.

dict d = {"a":"alia", "b":"beatrix", "c":"claudia"}     

d.display()                                  

for k,v in d : print k,v; /for                 

Methods of dict

Return  Name              Action

void    display([flat])   displays the dict indented. If flat is false, it is not indented.
bool    empty()           returns true if the dict is empty.
int     hasKey(text)      returns true if the key exists.
int     find(var)         searches for an item, returns the index or nil.
int     findLast(var)     searches from the top.
dict    getById(text)     return a dict with an id property whose value is in parameter.
array   getByName(text)   return an array of all elements having a name attribute whose value is the parameter.
array   getByTag(text)    return an array of all elements whose tag attribute has the parameter as value.
array   keys()            returns the list of keys.
void    kSort()           orders the indices, associations being preserved.
void    load(text name, [xml])   loads the file into the dict.
var     pop()             gets and removes the last item.
var     shift()           gets and removes the first item.
int     size()            returns the number of elements.
void    sort()            sorts the values in ascending order.
void    store(text name)  stores the dict into a file.
text    toXML()           converts the dict to XML in a string.
void    unShift(text, var)inserts a pair key value at the first position.
array   values()          returns the list of values.

Method load: The file is converted from XML to dict if the extension is xml, rss, svg or if the optional argument is 1.

Typed arrays

Typed arrays hold a unique type of objets. They are very more efficient than common arrays because processing directly 32 bits or 64 bits objects or pointers rather than dynamic variables is faster. (This is for binary executables, there is no difference in a PHP target.) Typed arrays are dynamic also, size is not limited, and boundary overflow is controled.

Virtual methods of typed arrays are identical to that of mixed arrays. See above.

Constructor and literal

The constructor of a typed array has the form:

  type(...elements...)

Example:

  int(1, 2, 3)

The number of element is between 0 and n.

When there is only one element, there is no difference between the constructor of typed array and the constructor of a scalar:

  int(1)
  real(10r)

This is not a problem at assignment as we can create an array from a scalar.

Array of integers

The syntax to declare an array of int is:

  int[] i = int(x, y, ....)

Once it is declared, it is used as a common mixed array, but only integer numbers may be added to the array.
At creation stage, a constructor or a literal may be assigned.

If you use a single argument: int(10), for example, this can be assigned either to a variable or to an array of int. In an expression a such constructor is a scalar. You must use a literal for one-element typed array.

Examples:

   int[] x = int(5)
   int[] x = int(1,2)
   int[] x = y + int{5}

Array of real, natural, number

The declarations are:

  real[] r = real(1.0, 2.0, ...)
  natural[] n = natural(1, 2, ...)
  number[] n = number(1, 2.0, ...)

Array of text

The declaration is:

 text[] t = text("one", "two", etc...)

Assignment and conversion

You can not assign a typed array to a mixed array but you can use the arrayval function:

  int[] i = int(...
  array a = arrayval(i)

- You can't, of course, assign a mixed array to a typed array since the values may have different types, unless you push the elements one by one. A literal array without prefix is considered to be a mixed array. Thus you can't assign it to a typed array.

Examples:

    [1,2,3]           ... this is a mixed array even with integer items.
    int[] i = [1,2,3]     ... NOT VALID you must write instead:
    int[] i = int(1,2,3)  ... valid.

- You can't create a mixed array with a constructor of typed array:

   array a = int(1,2)          ... NOT VALID
   array a = [int(1,2)]   ... NOT VALID

Using typed array with var

You can assign a typed array to a var.

   int[] i = int(1,2)
   var d = var(i)

Two new var methods are provided to use a such var:

arrayType()
return the type of the typed array assigned to a var.
toList(int = 0) return a typed array assigned to a var.
The parameter is the type (see below) and is required only if the var hold a classical array we want return as a typed one.

Types currently recognized are:

   $TYPE_INT        array of integers
   $TYPE_REAL
   $TYPE_NATURAL
   $TYPE_NUMBER

Example of use:

   d = var(int(1,2))
   if d.arrayType()
   = $TYPE_INT:
      int[] i = d.toList()
   = $TYPE_REAL:
      rea[] r = d.toList()
   /if

Random assignment

For compatibility with PHP, adding an element to an array outside the boundary, has same effect than pushing it on top of the array.
For example:

   int[] i
   i[10] = 10               ...this is equivalent to:  i.push(10)

Pushing values is the right way to fill an array in fact.

If you want really putting element at fixed position, you have to fill the array with some values...

   for int k in 0 .. 10 let i.push(0)

you can now put an element at the 10 indice.

Limitations and compatibility

- You can't apply a method directly to an element of a typed array.

  i[10].toText()    .. not valid
  int x = i[10]
  x.toText()         .. valid

- The PHP's array_diff function doesn't work with arrays holding objects, so substracting such arrays is not possible.

File

File is virtual object, for processing local or distant files.
For a complete explanation of the file system, see "fopen" in a C manual. A file object is created by an instance declaration. The file itself is created by the "open" command. The open command allows to access a file in different modes, accoding to the second parameter of the "open" method.
The error control structure is used to test if the file has been properly opened or not.

Syntax to create or open a file:

   file fname                 declares a file.
   fname.open(path, mode)     opens the file with the path, and the mode.

Path types:
   http://path                     http distant file.
   ftp://path                      ftp distant file.
   path                      local file.

Modes:
   "r"                        read only.
   "w"                        write only.
   "a"                        append at end of file, write only.
   "r+"                       reads or write at start of file.
   "a+"                       reads at current location, or write at end.

File's methods are:

return     method                   action

int        eof()                    return true, if end of file reached.
int        open(text, text)         create or open a file. Set the error flag.
int        close()                  close the file.
text       read(int)                read a chunk of size in argument, returns a text.
text       readLine()               read the next line from a text file, returns it.
int        seek(int)                go to the position in argument. Return 1 if ok.
int        size()                    return the size of the file.
int        time()                   return the time of last change.
int        write(text)              write the text in argument, return the size written.
void       writeLine(text)         write the text in argument.

Examples:

file myfile                             creates a file object.
myfile.open("myfilename", "r")  opens a real file.
myfile.close()                        closes the file.
bool b = myfile.eof()          returns true if end of the file reached.
myfile.seek(250)                    reads or writes skipping the first 250 bytes.

Distant files are not handled by Scriptol C++ and the interpreter for now.

Read

A file may be read line per line, or by binary blocks.
In the first case, the readLine() method is used, otherwise the read method has the size of the block as parameter.
The end of line code is included in the text and may be removed by the rTrim() text method.
Examples:

text t = fname.readline()           reads a line terminated by a newline code.
text t = fname.read(1000)           reads a block of 1000 bytes from the file.

Write

The write method puts the content of a text variable inside a file. Once the file is open (either in "w" or "a" mode), and thus written either from scratch or at end of the current content, each new call to the write method results in appending a new text at end.
Example:

text filename = "myfile"
file outfile                                       name of the virtual object.
outfile.open(filename, "w")                        opens to write.
error? die("enable to open " + filename)           if error, exits with a message;
for text line in outList                           an array previously filled
   outfile.write(line)                              writes an element
/for
outfile.close()                                      closes the file

XML

Standard XML code can be inserted into a scriptol program. It will be converted into an associative array. Tag within another tag is converted into dict inside another dict.

The textual content of a tag is associated to the data key in the generated associative array.

Example:

<xml id="car" speed=150 name="Spitfire">
<engine id="engine1" power=100 />
<passengers id="pass1" num=4 >
"Clara, Dana, Elisa, Farah"
</passengers>
</xml>

This JavaScript code is generated by the compiler:

var car={
  "_00" : "car",
  "tag" : "xml",
  "speed":150,
  "name":"Spitfire",
  "engine1":{
    "tag": "engine",
    "power":100
  },
  "pass1":{
    "tag": "passengers",
    "num":4,
    "data":"Clara, Dana, Elisa, Farah"
  }
};

Or this PHP code:

$car=[
  "speed"=>150,
  "name"=>"Spitfire",
"engine"=>[ "power"=>100 ],
"passengers"=>[ "num"=>4,
"data"=>"Clara, Dana, Elisa, Farah" ] ];

The associative array may also be converted into an XML document in a text variable that may be saved to a file:

car.toXML().store("file.xml")

The error control structure

After the "open" statement, the control structure "error /error" or one-line "error ?" should be executed to detect when an access error occurs. But the interpreter may stop the program before the construct is processed.
Otherwise the body of the error block is processed when an error occurs.
The syntax is:

xxx.open("filename")
error
     ...statements...
/error
or:
  xxx.open("filename"); error ? action
or:
  xxx.open("filename"); error action

Example:

file myfile
myfile.open("filename", "r")
error? exit()

If the file can't be found or opened, the program exits.

Scopes

Rules of visibility of variable are that of main procedural language, not that of scripting languages.
Scriptol add some safety rules, it doesn't allow a same name to be given to different objects in embedded scopes (for example, the global scope and the one of a function). But names may be reused in successive scopes.

There are four scoping levels: - global, - class, - body of a function, - and body of a control structure.

The scope of a variable is level where it is declared: global, class, function or delimited block of statements (body of if, while, do, case, etc...), and inner levels.
A variable can't be redeclared inside the same scope, but only when the scope is closed, inside other scopes.

The header of the for control structure is a part of the body's scope.

for text t in a              // t is visible only inside the for loop
   t = a.inc()
/for

The scope of the let statement that ends a while control structure is a part of the body of the while structure.
Parameters of a function are inside the scope of the function.
Inside a function, if a variable is referenced before any assignment, it is assumed referencing a global variable if it exists, otherwise this is an error.
Inside a method of a class, if it is referenced before any assignment, it references to a member if this member exists, otherwise this is an error. Global variables are not visible inside classes, but the external ones.

External variables (those of PHP, Apache, etc...) are always in the scope, since there is no control for them (look at the "External variable" section).
Thus, you have to know their name to avoid using a name that will become that of a PHP variable, when the "$" will be added to.
If you use PHP external variables inside a function, you must declare them as "global", as the compiler does not manage them.

External variables, constants and functions

Functions, variables and constants of the PHP or C++ languages or extensions may be used inside the Scriptol code.
Their scope is external, that means they are visible anywhere, in global, local or class scopes.

Variables and constants

PHP variables and constants may be used as scriptol objects, providing they are declared with the extern keywords.
Extern declarations, as include ones, must be put at start of a source file.

The syntax is:

   extern type identifier
   extern const type identifier

No any test is performed on the type and the scope or external, and you must also use a global statement if you use them inside a function.

Example:

  global argv
  array a = $argv

A PHP constant is declared as a variable, with the const modifier.
Example:

   extern const text PHP_VERSION
    ...
   print PHP_VERSION

It is possible also to use a PHP or C++ variable without declaration with the $ prefix followed by an identifier.
It can start with an underscore.

$var_name
$(constant_name)                          

External functions

PHP functions may be used without declaration, this is not the case for C++ functions.
To declare a external function, a extern statement is required.
A default value is denoted by an assignment. The value is used in the C++ target, it is ignored by PHP.

Syntax and example:

  extern type identifier(... parameters...)

  extern text substr(text, int, int = 0)

External classes

To use methods of PHP or C++ classes, you must declare the classes and the members you want to use.

Example:

extern
  class phpClass
     int phpAttribute
     void phpMethod(int parameter)
     ... declarations ...
  /class
/extern

External types

C++ allows to create new types with the typedef and define directives. These types may be integrated into a Scriptol source with the "define" instruction:
Example: define uint
This corresponds to "#define uint unsigned int" in C++.
No any code is generated by the define instruction: the C++ definition must existats inside an included C++ header file.
See at "The define statement" for more on this command.

Inserting native code

If you want to insert JavaScript or C++ code directly into your program, use the ~~ symbols to enclose the code.
The compiler doesn't process it, it is as a comment for the Scriptol compiler, but it is processed by the target interpreter or compiler.

For a simple identifier or keyword, the @ symbol is used. Example:

@await 

You can include code specifically for the PHP interpreter or C++ compiler. If you want to insert some PHP code, use this statement:

require_once("thefile.php") 

This statement is interpreted in PHP, but is ignored by the C++ compiler.

To insert C++ or JavaScript code, use a such statement:

include "thefile.hpp"
include "thefile.js"

Class

A class is a structure which contains variables (attributes) and has functions (methods).
Once a class is defined, it becomes a new type added to the language and unlimited number of instances (objects) may be declared with this new type. We use attributes and methods of the object with a command in the form:

   x = object.attribute
   object.method()

Defining a class

The description of a class begins with the "class" keyword and ends with "/class".

Example of a class declaration:

class car
   ...members...
/class

Example of class with attributes and methods:

class car
      int theSpeed = 50
      int passengers = 4

      void car.speed(int i)
          int x = theSpeed * 2
      return x
   /class

Example of instance and method reference:

car mycar
print mycar.passengers
print mycar.speed()

Constructor and instance

A constructor is a method the name of which being that of the class, and that is called only when creating an instance of the class. The constructor always returns a void type.

Example of constructor:

  class Car
      int speed

      void Car(int p)           ` this method is the constructor
         speed = 0               ` speed is initialized with a default value
      return
  /class

The syntax to create an instance is:
Classname instancename = Classname(parameter [, parameters])
or:
Classname instancename ... for a constructor without parameter.

Example:

  Car mycar = Car(60)           ... create a car with a speed of 60
  Truck mytruck                         ... is equivalent to
  Truck mytruck = Truck()

Static methods and attributes

It is convenient to store all functions relative to a task into a class and declare them "static". You can then refer to these methods directly along with the class name without the need for declaring an instance.

Example:

  node, ext = Dir.splitExt(path)

Static attributes are also allowed . A static attribut is common to all instances of the class and inherited ones. Static methods can use only static attributes, as other ones exist only in instances of the class, Static methods can't reference other methods.
The "static" modifier must preceed the type of the object. An error message is thrown if a static method attemps to use a non-static attribute or to call another method.

Example of static attributes and methods:

  class Car
     static factory = "xxx"
     static void setName(text x)
        factory = x
     return
  /class

  Car.setName("name")
  Car.factory = "name"

Static attributes and methods may be associated to an instance also:

  Car myCar
  myCar.setName("name")
  myCar.factory = "name"

The result will be the same.

Inheritance

A class may inherit from attributes and method of another one, if it is declared as a subclass of it.
The class "name" inherits of attributes and methods of the superclass "othername". This works also for static attributes and methods.

The syntax of inheritance declaring is:

class name is othername

Example:

  class Vehicle
      int fuel
      void Vehicle()
          fuel = 100
      return
  /class

  class Car is Vehicle
      int passengers
      void Car()
         passengers = 3
         fuel = 50
      return
  /class

  class Truck is Vehicle
       int charge
       void Truck()
           fuel = 200
           charge = 1000
       return
   /class

  Truck redbaby
  print redbaby.charge            attribute of the Truck class
  print redbaby.fuel              attribute of the Vehicle superclass
  print redbaby.passengers        bad! passengers is not accessible to Truck!
  Car daisy
  print daisy.passengers          good, passengers is attribute of Car

Overloading

A method may be redefined with different parameters, both inside the same class or into inherited classes. The return type must be the same for any definition of the method.

Example:

  void add(int x, int y)
  void add(real x, natural y)

You have just to call the "add" method with any arguments, the compiler associates the corresponding definition...
The main target language, C++ requires the return type remains the same, and this has been kept also in Scriptol.

Async/await (JavaScript)

Syntax:

async type myfunction(parameters)
  var x = await anotherfunction(arguments)
     ... following instructions...
return

Example:

int fibo(int n) 
   if (n < 2) return n
return fibo(n-2) + fibo(n-1)

async void getFibo(int n) 
  int f = await fibo(n)
  print "fibo=",f
return 

getFibo(20)

In the function declared async, statements following the call declared await are executed only after the call has returned a value, even if it is asynchronous.

However, the instructions following the async function call are executed immediately without waiting.

In order to avoid confusion it is preferable that the async function does not return a value, even if this would nevertheless be correct and accepted by the compiler.

The compiler encapsulates the call of the function following await in a Promise object. If the function called already returns a Promise object, then we will use instead:

@await 

Include, import and require

The syntax to include an external scriptol file is:

include "filename.sol"

Parenthesis are optional. Simple or double quotes are required. If you want to use directly a PHP file, and the compiler not to compile it, use a PHP extension.
Only files having a ".sol" extension are parsed by the scriptol compilers. For other extensions:

Examples.

include "example.php"
include "example.js

The PHP file will be ignored by the JavaScript code and the JS file will be ignored by the PHP code.

When scriptol code is embedded into an HTML page to be compiled to JavaScript, a file to include must be enclosed in <scriptol> and </scriptol> tags (even if there is only scriptol code in the file. The code generated for an HTML page may be different.

Using a module (JavaScript)

External modules included by npm can be declared as a dictionary or as an object.

In the first case, the module is declared as follows:

const net = require("net")

In the second case, the module must be included to the global scope with the import command:

import MyModule = require("MyModule")

And in the second case, it must be used by an instance:

MyModule module1

In all cases the Scriptol compiler does not check the attributes, methods and arguments. This is delegated to the JavaScript virtual machine.

Using a function as variable

You can use a function as argument of another function by defining this function as a type. This works only at the global level and can't be used inside a class. Once a type is defined, you can't redefine it.

1) define a function:
Example:

  int compare(int a, int b)
    bool b = (a < b)
  return b

2) use the function type to uses this function as argument:

  void myfunc(function a, int x, int y)
    print a(x,y)
  return

3) use the generic function:
The argument may be the original function or another function with same arguments and return type.

  myfunc(compare2, 10, 8)

Define

The syntax is :

define NEWTYPE
define NEWTYPE as

Create a new type you can use in arguments of external functions.
The "as" modifier prevents the new type to be used as a pointer. Use as if the type is a primitive, as uint or gint for example.

Useful functions

These scriptol functions are common to JavaScript, PHP, and C++.

The full list is in the fun.hpp header file.

void die(text)                Displays a message and exits the program.
void exit()                   Exits the program.
number min(num, num)          Returns the lowest of two arguments.
number max(num, num)          Returns the greatest of two arguments.
const cstring plural(int)     Returns "s" if the integer is greater than 1.
array range(int, int)         Generates an array of integers from x to y.
cstring str(number)           Converts a number into a string of chars.
void swap(var, var)           Exchanges the content of two variables.
text pad(text t, len l , text c[, int o])
   Pads a text with blank space or the given string of chars.
   t: text to pad. l: length to reach. c: char to add, default blank space.
   o: options STR_PAD_LEFT, STR_PAD_BOTH, default at right.

Casting

text chr(number)               Returns the character for an ASCII value, ex "A" for 65.
int ord(text)                  Gets the ASCII value of a character. 
int intval(any)
int realval(any)
natural naturalval(any) 
text strval(any)               Convert a number to a text. 
char *str(any)                 Convert a number to a C string. 
bool boolval(int) 
array arrayval(tarray)         Convert a typed array to an array of dynamic variables.

File functions (see also at File type methods):

void exec(text)                Passes a command to the operating system.
bool file_exists(text)         Test if the file whose name is in argument, exists.
number filesize(text)          Return the size.
number filetime(text)          Return the time (use date function to display).
text filetype(text)            Return "file" or "dir".
text fileToText(text)          Load a file in a text.
bool rename(text, text)        Renames a file.  Returns false if impossible.
void system(text)              Passes a command to the operating system.
bool unlink(text)              Deletes a file. Returns true if deleted.
var require(text)              Declare an external module (JavaScript only).

Directory functions:

bool chdir(text)              Changes the current directory. Returns false if unsuccessful.
bool mkdir(text)              Creates a sub-directory, returns true if created.
bool rmdir(text)              Deletes a sub-directory. Returns true if deleted.
text getcwd()                                      Returns the path of the current directory.

Math functions:

number abs(number)           	Returns the absolute value of a number.
real acos(real)
real asin(real)
real atan(real)
number ceil(number)          	Returns the rounded up integer.
real cos(real)
real exp(real)
number floor(number)         	Returns the rounded down integer.
number fmod(number, number)  	Return the modulus of two numbers.
real log(real)
number pow(number, number)   	Returns the n power of a number.
int rand()                     Returns a random number.
void randomize()               Starts a sequence of random numbers.
real round(real)               Round at nearest of floor or ceil.
real sin(real)
number sqrt(number)            Returns the square root of a number.
real tan(real)

Time functions:

int time()             		Time in milliseconds since January 1, 1970.
dict localtime()         		Current time and date at call into a dictionary, see below.

Keys of the dict returned by localtime:

tm_sec  	Seconds after the minute [0,61]
tm_min  	Minutes after the hour   [0,59]
tm_hour 	Hours after midnight     [0,23]
tm_mday 	Day of the month         [1,31]
tm_mon  	Months since January     [0,11]
tm_year 	Years since 1900
tm_wday 	Days since Sunday        [0,6]
tm_yday 	Days since January 1	 [0,365]
tm_isdst	Daylight Savings Time flag

Exceptions handling

Exception processing requires an external definition. Syntax:

  extern
    class exception
       string what()
    /class
  /extern


  try
     ... some statements ...
  catch(exception e)
     print e.what()
  /try

JavaScript Extensions

When compiled to JavaScript, the Scriptol langage offers more features, they are described on the site.

Appendix: Keywords

Word may be reserved for the target language but are not part of the Scriptol language.

alias always and array await as async
bool bool break byte
case catch char class const continue
define dict do
echo else enum error exception
false file finally float for forever from function
global
if import in include int integer is
let long
mod
nan natural new nil not null number
or
print private protected public
react real require return
script scriptol sol static step super switch
text this to true try
undefined until
var void
while
yield
zero


© 2001-2021 Denis Sureau.