KScript Scripts and Tags

A KScript source file is a document that contains a series of <% and %> tags that contain KScript content between them. Content that is outside these tags is ignored and passed straight through into the "result" (or "output") of the KScript, which is a series of characters that have some externally defined meaning (usually some kind of XML or HTML).

The content within the KScript tags is one or more KScript elements. The content can either be a block element, which controls how the processor iterates between the different blocks (conditional constructs, looping, and exception handling constructs), or statement elements, which are evaluated sequentially, and may be control constructs such as conditionals, loops, and exception handling instructions, or assignments or expressions. All expressions produce a value; if the value is not assigned to a variable, the string representation of the value is appended to the current output.

Whitespace is not significant in KScript (except for one case documented below). Any kind or amount of whitespace can be substituted for any other whitespace. You can include any kind of whitespace (including end of lines such as \r or \n) in a string literal. One of the consequences of the KScript syntax is that it's a little clumsy to control the whitespace generated in output from the script; this is by design, as the language is intended for generating XML and HTML where whitespace doesn't matter.

Though the language is loosely typed, everything in KScript is an object with a type. There is a single type called "Simple" for strings, intergers, floating point numbers and booleans. Objects other than Simple types may be created by the syntax 'new X(...)' where X is the name of a predefined type (see the KScript API documentation). The parameters of the method are those defined in the constructor for the object. If there is no object, the object cannot be created directly. Objects are reference counted internally to KScript - you never need to perform any form of garbage collection.

Note that comparison is done with '='. Assignment to variables is done by ':='. '==' means case insensitive comparison.

Expressions

An expression is a series of references to functions, variables, object properties or string literals, linked together by a series of operations. Object Properties are referred to using the standard dot notation, i.e. s.length.

This table summarizes the expression operators available in KScript.

Token Description
+ Addition: append for strings, plus (mathematical add) for numbers
& append even if numbers
++ mathematical addition. AN exception will be raised if the operands are not numbers
- Standard mathematical subtraction, or try to delete substrings
* Standard mathematical Multiplication
\ Standard mathematical division
div Standard mathematical integer devision (fractions are truncated)
mod Standard mathematical modulus
| Collect (Collections are described below)
.. Span. Operands must be numerical - this builds a collection of all values between and including the two operands
= Equality
< Less than. Works with strings (a < b, case sensitive)
> Less than. Works with strings (b > a, case sensitive)
== String insensitive equals
!= Not equals
!== String insensitive not equals
<= Less than or equals
>= Greater than or equals
in collection membership - is operand1 in operand2. Also works with strings
like Regex. Does operand1 conform to the regular expression operand1
and Logical and
or Logical Or
xor Logical Xor

This table summarises operator precedence:

|, ..
*, /, div, mod
+, &, ++, -
=, --, !=, !==, <, <=, >=, >, in, like
and, or, xor

All operations on the same level are processed left to right. When this order is in appropriate, alternative orders can be specified using parentheses. Boolean evaluation is always shortened.

Assignments and Variables

KScript supports variables. Variables do not need to be predeclared; they are created as required. All variables are local to the entire script, and global within the entire script. Variables can have any type. The assignment operator is ":=". Variable names can consist of any combination of letters ['a'..'z'] and digits ['0'..'9']. Names are not case sensitive and must include at least one letter (to differentiate from numerical constants)

KScript supports out parameters on function calls for COM compatibility. Out parameters must be variables, and must be created prior to the call by assigning a value to the variable.

Collections

KScript supports collections. To create a collection, use Collect(). The Collect() function can take any number of parameters of any type. All the parameters will be added to the collection. You can also create a collection using the .. and | operators.

You can manipulate collections by adding or removing items from them, or performing operations such as union or intersection. See TCollection for further information. The operations do not change the existing collection; instead they return a new collection.

<% c := Collect(); c := c.Add("1"); c := c.Add("2"); %> <%c := 1..2 | "M"%>

You can iterate collections using a for loop. This iterates through the items of the collection in order.

<% for v : c { v; } endfor; %> <%c := 1..2 | "M"%> <%for v : c%> <%v%> <%endfor%>

Finally, you can test for collection membership

<%if "M" in c%>"M" is in c<%endif%>

Block Syntax

KScript syntax is divided into two main parts, the statement syntax and the block syntax. The block syntax relates the control flow across different KScript tags, and the statement syntax relates to control flow within a single KScript tag.

If..Else

<%if test%>
[document content & kscript tags]
<%else%>
[document content & kscript tags]
<%endif%>

The test (a KScript expression) will be evaluated. If it is true, then the first lot of document content and kscript tags will be evaluated, otherwise the second lot will be. If..Else blocks can be nested to any desired depth.

Note the issue in differentiating between the If..Else block syntax and the If..Then..Else statement syntax below

 

Loop

<%loop optional test%>
[document content & kscript tags]
<%endloop optional test%>

The document content and KScript tags will repeat as long as the loop repeats. The loop will repeat as long as the test on the loop is not present or true, and the test on the endloop is not there or false. There needs to be a test on either the start or end of the loop, or the loop will never terminate.

There is an upper limit of 65536 iterations to protect the system from a errant loop termination test.

 

Try..Except

<%try%>
[document content & kscript tags]
<%except%>
[document content & kscript tags]
<%endtry%>

If any exceptions are raised in the kscript tags between the try and the except tags, the content between the except and the endtry will be executed. There is an implicit variable "errmsg" defined between the except and endtry tags which has the exception details.

Note that any document content and kscript tags that are processed before the exception is raised will appear in the final document content.

 

Try..Finally

<%try%>
[document content & kscript tags]
<%finally%>
[document content & kscript tags]
<%endtry%>

Whether any exceptions are raised in the kscript tags between the try and the finally tags, the content between the finally and the endtry will be executed.

The try finally statement is not very useful - it can be used to clean up resources, but there is currently no internal resources that need cleaning up. It may be useful for external resource recovery (such as hold flags in databases).

 

Comment

<%//

(stuff)

%>

if the first two non-whitespace characters of the KScript tag are //, the entire tag will be ignored.

You can ignore a set of tags and document content easily by putting <%if false%> and <%endif%> around them.

 

Statement Syntax

The syntax in this section applies within a KScript tag - between the <% and %> markers, which are not shown in this section.

Comment

//.. stuff....

// comments the rest of the line and it is ignored

 

If .. Then .. Else

  if (i = 2 or a = b) and c=4 then
    {
    if statements...
    }
  else
    {
    else statements...
    };

If the condition is met, then the statements before the else will be executed otherwise the statements after the else will be executed. The condition can have any number of comparisons linked by ands and ors. KScript does not do short boolean evaluation - all the conditions will be checked. Conditions can be grouped with () parentheses. The following comparison types are defined:

= equal-case sensitive comparison
== equal-non case sensitive comparison
!=, <> not equal
<, <=, =>, > less than, etc

If integer or float comparisons are possible they will be performed, otherwise string comparison will be done.

There's an ambiguity in the language to do with the if syntax. A KScript tag that starts with <%if could either be the start of an If..Else block from above, or one of these if..then..else statements. This is resolved by saying that if a tag starts with "if" (no preceding whitespace) it is an if..else block, and if there is whitespace, it's an if..then..else statement.

 

Loop .. EndLoop

  i := 1;
  loop (i < 20) {
    doSomething(i);
    i := I + 1;
  } endloop (i > total)

Loops have either entry conditions, or exit conditions, or both. You can only enter a loop if there is no entry condition or if the entry condition is true. At the end of the loop you can only go through the loop again if there is not exit condition or if the exit condition is false and also if the start conditions are met.

There is an arbitrary limit of 65536 cycles through the loop after which it will terminate with an exception.

 

Try .. Except

  try {
    statements....
  } except
    {"error: "+errmsg}

If any exception is raised in the statements section, program flow will immediately jump to the except section. An exception is an error condition; if an error condition is encountered, normal program execution is suspended and resumes at the next except (also at "finally"), program execution will continue from the except block. In the except block a variable "errmsg" is defined which contains information about the error.

You can raise your own exceptions using the RaiseError Statement. If no exception handers are found in the KScript, the exception will be handled by HL7Connect.

 

Try .. Finally

  try {
    statements....
  } finally
    Clean Up statements...}

If any exception is raised in the statements section, program execution will look for the next except handler, but will execute any code contained in finally blocks along the way. Whatever happens between the try and the finally, the content in the finally section will execute anyway.

The try finally statement is not very useful - it can be used to clean up resources, but there is currently no internal resources that need cleaning up. It may be useful for external resource recovery (such as hold flags in databases).

 

Case .. EndCase

  Case (i-k) of
    1: ("value is 1")
    2: ("there is twice as many")
   "test": ("Testing")
    23-j: (raiseerror("This is an error"))
   "":(raiseerror("i was not defined"))
  default : (raiseerror("i value is unknown"))
  endcase;

The value of i-k will be obtained, and the compared against all the values in the list (left hand side of ":"). On the first match, the paired statement (right hand side of ":") will be executed. The default statement is executed if nothing else matches.

 

Switch .. EndSwitch

  Switch (i-k)
    1: ("value is 1")
    2: ("there is twice as many")
   "test": ("Testing")
    23-j: (raiseerror("This is an error"))
   "":(raiseerror("i was not defined"))
  endswitch

The switch statement is the same as the case statement but any matching statements will be executed, not just the first.

 

 

Notes:
  1. In a condition, if no second statement is specified, the result will be false if the value of the first statement is "", "F", "f", "0", "false" or "FALSE"
  2. + means try integer, then float addition otherwise append. ++ means force integer or float addition, & means force append. - means try integer or float subtraction otherwise try deleting substrings the other operators only do integer then float. "," and ".." are collector operations, where "," is a single collect, and ".." collects everything between the 2 operands (requiring integers at each end)
  3. In a try ... except block, the blocklist after the except will only run if an exception occurred between the try and the except
    In a try ... finally block, the blocklist after the finally will always run no matter what happens between the try and the finally
  4. In a case block, the result of the first statement will be compared to the list of options until a match is found. Once a match is found, the statement exits
  5. A switch block is the same as a case block except that all statements will be checked

Reserved Words

The following tokens are reserved words and cannot be used as variable names, statement names, or parameter names.

Note: some of these reserved words are for possible future features

Formal Syntax

This is the formal syntax definition for the KScript langauge. It is intended to be authoritative

BlockList = Block {block}
Block = :IfBlock::LoopBlock::StatementList::TryBlock::CaseBlock::SwitchBlock::Assignment:
StatementList = :(statementList)::statement: {linkOP :(statementList)::statement:}
Statement1 = :Name {parameter}::StringLiteral:
StringLiteral = :"[Content]"::Number4::Variable5,6:
Parameter = name= :StringLiteral::(StatementList):
IfBlock = if CondList then (blockList) [else (blocklist)]
LoopBlock = loop [(condlist)] blocklist endloop [{condlist}]
TryBlock7 = try blocklist :except::finally: (blocklist)
CaseBlock8 = case (StatementList) of {StatementList:(BlockList)} endcase
SwitchBlock9 = switch (StatementList) {StatementList:(BlockList)} endswitch
Assignment10 = Variable := StatementList
CondList = :Condition::(CondList): {LogOp :Condition::(CondList):}
Condition2 = [NOT] statement11 [CompOP statement]
LogOp = :AND::OR::XOR:
CompOp = :=::==::!=::<>::<=::>=::>::<::like::in:
LinkOp3 = :+::++::&::-::*::/::div::mod::|::..:

Legend:

[ ] Content is optional
{ } Content can be repeated as many times as required (including 0 times)
:x::y: Content can be either x or y


© Kestral Computing P/L 2000-2010.
Keywords: KScript, Syntax, Try, For, Case, If, Operators, Assignment, Loop