Candle Query Reference

Version : Candle 0.13
Published date : Jun 13, 2013

1. Introduction

Like many programming languages, Candle language constructs can be divided into 4 levels:
Here are some of the general syntax rules of Candle script:

2. Script Processing Model

The static and dynamic evaluation contexts, the processing model and error handling of Candle are closely based on that of XQuery, so they are not repeated here.

Important concepts like document order, atomization and effective boolean value, are closely based on that of XQuery, so they are not repeated here.

3. Expressions

3.1 Primary Expressions

[Definition: Primary expressions are the basic primitives of the language. They include literals, variable references, context item expressions, constructors, and function calls. A primary expression may also be created by enclosing any expression in parentheses, which is sometimes helpful in controlling the precedence of operators.] 

primary-expr    :=    literal | literal-qname | var-ref | tunneled-var-ref | ParenthesizedExpr | ContextItemExpr | ExprFunctionCall | AnonymousRoutine | OrderedExpr | UnorderedExpr | Constructor;

3.1.1 Literals

Each atomic types of Candle has a unique syntax representation for it. The details of the syntax of the Candle atomic types are specified in Candle Markup Reference.

All markup literals can be used directly in Candle script, except literal qname. Literal qname used in Candle script needs to be prefixed with value::, as a qname in Candle script is treated as variable reference.
literal-qname    :=    "value::", qname;

3.1.2 Variable References

var-ref    :=    qname;
Unlike XQuery, variable name in Candle script does not use the $ prefix.

3.1.3 Tunneled Variable References

tunneled-var-ref    :=    "context", "::", qname;

The tunneled variable in Candle works like tunneled parameter in XSLT. A tunneled variable is a value pushed on the runtime stack by the put statement with a Qname. To retrieve the value of a tunneled variable, you use context::, followed by the Qname of the variable.

3.1.3 Parenthesized Expressions

ParenthesizedExpr    :=    "(", expr?, ")";

3.1.4 Context Item Expression

ContextItemExpr    :=    ".";

3.1.5 Function Calls

ExprFunctionCall := FunctionCall;
FunctionCall    :=    qname, "(", (expr, (",", expr)*)?, ")";

Only functions can be called at expression level. Methods are not allowed to be called at expression level. This is a feature of the separation-of-side-effects mechanism in Candle.

3.1.6 Anonynous Routines

anonymous-routine    :=    anonymous-expr-function | anonymous-stam-function | anonymous-method;
anonymous-expr-function    := "function", "(", ParamList?, ")", ReturnType, "{", expr, "}";
anonymous-stam-function    := "function", "(", ParamList?, ")", StamFuncBody;
anonymous-method    := "method", "(", ParamList?, ")", ReturnType?, MethodBody;

You can define anonymous routines at expression level. The details of routine declaration are defined in Section 5.

Anonymous method can be defined at expression level, but it can only be called in a procedural statement.

3.2 Constructors

constructor    :=    direct-constructor | computed-constructor;
direct-constructor    :=    dir-elem-constructor | dir-obj-constructor | comment-node;
dir-elem-constructor    :=    "<", qname, dir-attr-list, ("/>" | (">", block-content, "</", qname, g:s?, ">"));
dir-obj-constructor := qname, "{", dir-attr-list, block-content, "}";
block-content    :=    (functional-statement | dir-elem-constructor | dir-obj-constructor
       |
text-nodecdata-nodecomment-nodedata-node)*;
dir-attr-list    :=    (qname, "=", (attr-value | enclosed-expr))*;
enclosed-expr := "{", expr, "}";
attr-value := literal-value | literal-seq | literal-array | element | object;
literal-seq := "(", attr-value, (",", attr-value)*, ")";
literal-seq := "[", attr-value, (",", attr-value)*, "]";
literal-value = empty | boolean | double | percentage | measure | color | float | integer
       | string | binary | uri | datetime | lit-qname;
text-node = "&dq;", text-contents, "&dq;";
text-contents = ((char - ("&dq" | "&amp;"))* | Entity)*;
cdata-node = "<<<", cdata-contents, ">>>";
cdata-contents = char* - ((char*, ">") | (char*, ">>>", char*));
comment-node = "<!--", comment-contents, "-->";
comment-contents = ((char - '-') | ('-', (char - '-')))*;
data-node := literal-value;

Candle node constructors are different from XQuery in several ways:

3.2.1 Computed Constructors

ComputedConstructor    :=    CompDocConstructor | CompElmtConstructor | CompAttrConstructor
| CompTextConstructor |
CompDataConstructor | CompCommentConstructor;
CompDocConstructor := "document", "(", ")", "{", block-content, "}";
CompElmtConstructor := "element", "(", expr, ")", "{", block-content, "}";
CompAttrConstructor := "attribute", "(", expr, ")", "{", expr, "}";
CompTextConstructor := ("text", "(", expr, ")") | ("cdata", "(", expr, ")");
CompDataConstructor := "data", "(", expr, ")";
CompCommentConstructor := "comment", "(", expr, ")";

For element constructor, the first expr should evaluates to a Qname that is then used as the name of the constructed element.

For attribute constructor, the first expr should evaluates to a Qname that is then used as the name of the constructed attribute. The second expr is used as the value of the attribute.

3.3 Postfix Expressions

PostfixExpr    ::=    PrimaryExpr (Predicate | ArgumentList)*

3.3.1 Filter Expressions

PostfixExpr    ::=    PrimaryExpr (predicate | ArgumentList)*
predicate    ::=    "[" Expr "]"

3.3.2 Dynamic Function Invocation

PostfixExpr    ::=    PrimaryExpr (predicate | ArgumentList)*
ArgumentList    ::=    "(" (Argument ("," Argument)*)? ")"
Argument    ::=    ExprSingle | ArgumentPlaceholder;
ArgumentPlaceholder    ::=    "?"

[Definition: A dynamic function invocation consists of a PrimaryExpr that returns the function item and a parenthesized list of zero or more arguments (argument expressions or ArgumentPlaceholders).]

If the PrimaryExpr does not return a sequence consisting of a single function item with the same arity as the number of specified arguments, a type error is raised.

Here's an example of defining an anonymous function, then invoking it dynamically:

let add-func = function(a, b) as integer { a + b }
    return add-func(1, 2)

3.4 Path Expressions

PathExpr    :=    ("/", RelativePathExpr?) | ("//", RelativePathExpr) | RelativePathExpr;
RelativePathExpr    :=    step-expr, (("/" | "//"), step-expr)*;

3.4.1 Steps

step-expr    :=    postfix-expr | axis-step;
axis-step    :=    (reverse-stepforward-step), predicate*;
forward-step    :=    (forward-axis, node-test) | abbrev-forward-step;
reverse-step    :=    (reverse-axisnode-test) | abbrev-reverse-step;
forward-axis :=  ("child", "::")
| ("descendant", "::")
| ("attribute", "::")
| ("self", "::")
| ("descendant-or-self", "::")
| ("following-sibling", "::")
| ("following", "::");
reverse-axis :=  ("parent", "::")
| ("ancestor", "::")
| ("preceding-sibling", "::")
| ("preceding", "::")
| ("ancestor-or-self", "::");
node-test := kind-test | name-test;
name-test := qname | wildcard;
wildcard := "*" | (qname, ":", "*") | ("*", ":", name);
kind-test := comment-node-test | text-node-test | data-node-test | any-node-test;
comment-node-test := "comment", "(", ")";
text-node-test := "text", "(", ")";
data-node-test := "data", "(", ")";
any-node-test := "node", "(", ")";
abbrev-forward-step := "@"?, name-test;
abbrev-reverse-step := "..";

3.4.2 Predicates

predicate    :=    FilterPredicate | FieldPredicate;
FilterPredicate  := "[", Expr, "]";
FieldPredicate  := "?", Qname;
AttributePredicate  := "@", Qname;

Candle supports field predicates:

3.5 Sequence Expressions

Candle supports operators to construct, filter, and combine sequences of items. Sequences are never nested—for example, combining the values 1, (2, 3), and () into a single sequence results in the sequence (1, 2, 3).

3.5.1 Constructing Sequences

ExprSeq    :=    expr, (",", expr)*;
RangeExpr    :=    AdditiveExpr, ("to", AdditiveExpr)?;

3.5.2 Combining Node Sequences

UnionExpr    :=    IntersectExceptExpr, ( ("union" | "|"), IntersectExceptExpr )*;
IntersectExceptExpr    :=    InstanceofExpr, ( ("intersect" | "except"), InstanceofExpr )*;

3.6 Arithmetic Expressions

Candle provides arithmetic operators for addition, subtraction, multiplication, division, and modulus, in their usual forms.

AdditiveExpr    :=    MultiplicativeExpr, (("+" | "-"), MultiplicativeExpr)*
MultiplicativeExpr    :=    UnionExpr, (("*" | "div" | "idiv" | "mod"), UnionExpr)*;
UnaryExpr    :=    ("-" | "+")*, ValueExpr;
ValueExpr    :=    ValidateExpr | PathExpr | ExtensionExpr;

3.7 Comparison Expressions

Comparison expressions allow two values to be compared. XQuery provides three kinds of comparison expressions, called value comparisons, general comparisons, and node comparisons.
ComparisonExpr    :=    RangeExpr, ((ValueComp | GeneralComp | NodeComp), RangeExpr)?;
ValueComp    :=    "=" | "!=" | "<" | "<=" | ">" | ">="
GeneralComp    :=    "eq" | "ne" | "lt" | "le" | "gt" | "ge";
NodeComp    :=    "is" | "<<" | ">>"

The operators of ValueComp and those of GeneralComp are swapped comparing to XQuery.
[Rationale: this is because ValueComp is used more often than GeneralComp, and thus should use the syntax that is commonly used in most programming languages.]

GeneralComp is not supported in this release.

3.8 Logical Expressions

OrExpr    :=    AndExpr, ("or", AndExpr)*;
AndExpr    :=    ComparisonExpr, ("and", ComparisonExpr)*

3.9 Flow Control Expressions

FlowControlExpr := FLWORExpr | WithExpr;
FLWORExpr    :=    (((ForClause | LetClause)+, WhereClause?) | ForeachClause), OrderByClause?,
"return", expr;
ForClause    :=    "for", VarName, TypeDeclaration?, PositionalVar?, "in", expr,
(",", VarName, TypeDeclaration?, PositionalVar?, "in", expr)*;
ForeachClause    :=  "foreach", "(", expr, ")";
LetClause    :=    "let", VarName, TypeDeclaration?, "=", expr,
(",", VarName, TypeDeclaration?, "=", expr)*;
TypeDeclaration    :=    "as", SequenceType;
PositionalVar    :=    "at", VarName;
WhereClause    :=    "where", expr;
OrderByClause    :=    (("order", "by") | ("stable", "order", "by")), OrderSpecList;
OrderSpecList    :=    OrderSpec, (",", OrderSpec)*;
OrderSpec    :=    expr, OrderModifier;
OrderModifier    :=    ("asc" | "desc")?, ("empty", ("greatest" | "least"))?,
("collation", URILiteral)?;
WithExpr := "with", "(", expr, ")", "return", expr;

Candle FLWOR expressions differ from XQuery in several ways:
Some features of FLWOR expressions like position variable and collation in ordering are not supported in this release.

3.10 Ordered and Unordered Expressions

OrderedExpr    :=    "ordered", "{", Expr, "}";
UnorderedExpr    :=    "unordered", "{", Expr, "}";

This part is not supported in current release;

3.11 Conditional Expressions

IfExpr    :=    "if", "(", expr, ")", "then", expr, "else", expr;
SwitchExpr := "switch", "(", expr, ")", "case", expr, "return", expr, "default", "return", expr;

3.12 Quantified Expressions

QuantifiedExpr    :=    ("some" | "every"), VarName, TypeDeclaration?, "in", Expr, (",", VarName, TypeDeclaration?, "in", Expr)*, "satisfies", Expr;
TypeDeclaration    :=    "as", SequenceType;

This part is not supported in current release;

3.13 Expressions on SequenceTypes

In addition to their use in function parameters and results, sequence types are used in instance of, cast, castable, and treat expressions.

This part is not supported in current release;

3.14 Validate Expressions

This part is not supported in current release;

4. Statements

XQuery uses expression exclusively for its function body construction, this is not always the best. Statement syntax looks cleaner than expression syntax when the logic is complicated. Moreover, Candle also supports procedural logic, thus statement syntax is inevitable, as the sequencing of the statements clearly reflects the execution order.

Another unique and important feature of Candle is the separation of side-effects. In procedural languages, side-effects can occur almost anywhere in the code, and it is up to the programmers to discipline themselves to clearly separate code with side-effects from code without side-effects. Whereas, in functional languages, making desired changes to the data is painfully difficult. Candle solves the problem through a mechanism called separation of side-effects. It works as following:
In this way, side-effects are isolated as much as possible and desired changes can still be made in ways familiar to most programmers.

4.1 Functional Statements

The primary role of functional statements is to construct content in a structured manner. And the functional statements can be roughly grouped into 3 categories: functional flow control statements, content construction statements and function call statement.

FunctionalStatement    :=    ForStam | ForeachStam | LetStam | PutStam | WithStam |
        | IfStam | SwitchStam                  
        | ApplyStam |
ApplyToStam | EnclosedExprStam 
        | ElmtStam | AttrStam | TextStam | CommentStam
        | FuncCallStam | DynamicFuncCallStam;

4.1.1 Functional Flow Control Statements

ForStam := "for", "(", ForVarDeclare, (",", ForVarDeclare)*, ")", stam-block;
ForeachStam := "foreach", "(", expr, ")", stam-block;
LetStam    :=    "let", VarDeclare, (",", VarDeclare)*, (";" | stam-block) ;
PutStam := "put", "(", (qname, "=", expr), (",", qname, "=", expr)*, ")", stam-block;
WithStam := "with", "(", expr, ")", stam-block;
IfStam := "if", "(", expr, ")", stam-block, ("else", (IfStam | stam-block))?;
SwitchStam := "switch", "(", expr, ")", CaseStam*, DefaultStam?; 
CaseStam := "case", "(", expr, ")", stam-block;
DefaultStam := "default", stam-block;
VarDeclare := VarName, TypeDeclaration?, "=", expr;
ForVarDeclare := VarName, TypeDeclaration?, "in", expr;
stam-block := "{", block-content, "}";

Most for the statements should be self-explanatory. Their semantics are similar to the corresponding Candle expression, except that in IfStam, else branch is optional and in SwitchStam, default branch is optional.

WithStam establishes the result of expr as the context item for the following statement block. The query runtime checks that size of the evaluated result of expr is 1.  Put Statement

Put statement puts a value on the runtime stack with a Qname, which can be retrieved later by inner functions with the same Qname. If a value of the same Qname is already pushed on the stack, then the new value shadows the old one. Inner functions always see the inner-most pushed value. At the end of the evaluation of the put statement, the new value is popped out from the stack. It works like the tunneled paramter in XSLT.

4.1.2 Content Construction Statements

ApplyStam    :=    "apply", "(", ParamList?, ")", ";";
ApplyToStam    :=   "apply-to", "(", expr, (",", ParamList)?, ")", ";";
ExclosedExprStam := "{", expr, "}";
ElmtStam := "element", "(", expr, ")", stam-block;
AttrStam := "attribute", "(", expr, ")", "{", expr, "}";
TextStam := ("text", "(", expr, ")") | ("cdata", "(", expr, ")");
DataStam := "data", "(", expr, ")";
CommentStam := "comment", "(", expr, ")";

Apply statement is similar to the apply-templates element in XSLT.

Enclosed-expression statement is similar to that in XQuery.

Element statement constructs an element dynamically. The first expr should evaluates to a Qname that is then used as the name of the constructed element.

Attribute statement constructs an attribute dynamically. The first expr should evaluates to a Qname that is then used as the name of the constructed attribute. The second expr is used as the value of the attribute.

Text statement, data statement, comment statement dynamically construct the corresponding node using the value of the expr.

4.1.3 Function Call Statement

FuncCallStam := FunctionCall, ";";

Calls a statement function or named template. Expression functions cannot be called directly at statement level.

Methods cannot be called in functional statement. This is a feature of the separation-of-side-effects mechanism in Candle.

4.1.4 Dynamic Function Call Statement

DynamicFuncCallStam := "(", expr, ")", ArgumentList, ";";

The expr should evaluate to a function item. The function item is then dynamically invoked. Expression functions cannot be called directly at statement level.

Methods cannot be called in functional statement. This is a feature of the separation-of-side-effects mechanism in Candle.

4.2 Procedural Statements

Procedural statements can only occur in a method. Procedural statements can be roughly grouped into 3 categories: procedural flow-control statements, node-update statements and method-call statement.
ProceduralStatement :=  LetActionStam | PutActionStam | WithActionStam | ForActionStam
        | ForeachActionStam | IfActionStam | SwitchActionStam
        | SetStam | InsertStam | DeleteStam | MoveStam | RenameStam

        | OutputStam | SaveStam
        | MethodCallStam | DynamicMethodCallStam;

4.2.1 Procedural Flow Control Statements

LetActionStam    :=    "let", VarDeclare, (",", VarDeclare)*, (";" | action-block) ;
PutActionStam := "put", "(", (qname, "=", expr), (",", qname, "=", expr)*, ")", action-block;
WithActionStam := "with", "(", expr, ")", action-block;
ForActionStam := "for", "(", VarDeclare, (",", VarDeclare)*, ")", action-block;
ForeachActionStam := "foreach", "(", expr")", action-block;
IfActionStam := "if", "(", expr")", action-block, ("else", (IfActionStam | action-block))?;
SwitchActionStam := "switch", "(", expr, ")", CaseActionStam*, DefaultActionStam?; 
CaseActionStam := "case", "(", expr, ")", action-block;
DefaultActionStam := "default", action-block;
action-block := "{", ProceduralStatement*, "}";

Most for the statements should be self-explanatory. Their semantics are similar to the corresponding functional flow control statement, except that the statement body contains procedural statements instead of functional statements.

4.2.2 Node Update Statements

SetStam    :=    "set", Expr, "=", Expr, ";";
InsertStam := "insert", Expr, ("into" | "before" | "after"), Expr, ";";
DeleteStam := "delete", Expr, ";" ;
MoveStam := "move", Expr, ("into" | "before" | "after"), Expr, ";";
RenameStam := "rename", Expr, "as", Expr, ";";

The semantics of these statements are close to that defined in XQuery Update.

Current release does not support transaction. Each update statement takes immediate effect, in other words, it is like the auto-commit mode in SQL.

The InsertStam also stores an reference to the newly inserted node in an internal variable. The value of this internal variable can be retrieved through built-in function result().

4.2.3 Method Call Statement

MethodCallStam := MethodCall, ";";
MethodCall := qname, "(", (expr, (",", expr)*)?, ")";

Method-call statement calls a method. If the method returns a value, the value is stored in the dynamic context. The value can be retrieved by an expression through the system function result().

Functions and templates cannot be called at procedural statement level.

4.2.4 Dynamic Method Call Statement

DynamicMethodCallStam := "(", expr, ")", ArgumentList, ";";

The expr should evaluate to a method item. The method item is then dynamically invoked.

Functions and templates cannot be called at procedural statement level.

5. Routines

There are 4 types of routine in Candle: expression function, statement function, template and method:

5.1 Expression Function Declaration

ExprFunctionDecl    :=    "function", qname, "(", ParamList?, ")", ReturnType, "{", expr, "}";
ParamList    :=    Param, (",", Param)*;
Param    :=    qname, TypeDeclaration?;
TypeDeclaration    :=    "as", SequenceType;
ReturnType :=  "as", SequenceType;

5.2 Statement Function Declaration

StamFunctionDecl    :=    "function", qname, "(", ParamList?, ")", StamFuncBody;
StamFuncBody :=  stam-block;

Statement function does not have return-type clause, which differentiate it from a expression function. The return type of a statement function is always node*.

5.3 Template Declaration

TemplateDecl    :=    "template", (qname, ",")?, (MatchClause | BindMatchClause), 
        ("(", ParamList?, ")")?, ModeClause?, PriorityClause?, StamFuncBody;
ModeClause := "default" | "current" | "all" | qname;
PriorityClause := "priority", Number;
MatchClause := "<", MatchPattern, ">";
BindMatchClause := "[", MatchPattern, "]";
MatchPattern := PathPattern, ("|", PathPattern)*;
PathPattern := DescendantPathPattern | RootPathPattern | RelativePathPattern;
RootPathPattern := "/", RelativePathPattern?;
DescendantPathPattern := "//", RelativePathPattern;
RelativePathPattern := PatternStep, (("//" | "/"), PatternStep)*;
PatternStep := PatternAxis?, NodeTest, PredicateList;
PatternAxis := ("child", "::") | ("attribute", "::") | "@";

Template name is optional. Template parameter list is also optional. Template mode is optional.

The template mode, priority and match pattern are the same as that in XSLT.

5.4 Method Declaration

MethodDecl    :=    "method", Qname, "(", ParamList?, ")", ReturnType?, MethodBody;
MethodBody :=  action-block;
action-block := "{", ProceduralStatement*, "}";

5.4.1 Method Return Value

Method can have an optional return type. However, as method cannot be called at expression level, you cannot, for example, directly assign the return value of a method to a variable in the LetActionStam. Instead the return value of a method call is stored in an internal variable in the dynamic context. You can retrieve the value of this interval variable through the built-in function result().

This internal variable is thread specific. When you call another method, the previous return value is replaced with the current one. Any function call does not change the value of this internal variable.

5.5 Calling Native Routines

Candle also supports invocation of native C routines. To access such routines, you just need to declare them at the prolog level.

NativeRoutineDecl    :=    NativeExprFunctionDecl | NativeMethodDecl;
NativeExprFunctionDecl := "native", "function", Qname, "(", ParamList?, ")", ReturnType; 
NativeMethodDecl := "native", "method", Qname, "(", ParamList?, ")", ReturnType?;

To call native C void function as Candle expression function, you must specify the return type as empty. To call native C void function as Candle method, you must omit the return type.

In order for Candle to load the native module (DLL on Windows), the namespace of the native routine name must follow certain patterns:
Only a subset of Candle atomic types can be mapped into native C types directly:

Candle Type Native C Type
boolean bool
byte char
ubyte unsigned char
short short
ushort ushort
int int
uint uint
long win32: __int64
unix: long long
ulong win32: unsigned __int64
unix: unsigned long long
float float
double double
string wchar* (UTF16)

Other advanced C types, like struct, pointer, array, etc. are not supported in this release.

Candle cannot check whether a native routine has side-effect or not, thus Candle depends on your proper declaration of routine type (function or method) to work properly.

Below is an example of Candle calling win32 API functions:

<?csp1.0?>
namespace user32=candle:runtime:native:winstd:user32,
    winmm=candle:runtime:native:winstd:winmm;

native function user32:MessageBoxW(hwnd as int, message as string,
    caption as string, type as int) as int;
native function winmm:PlaySoundW(pszSound as string, hmod as int, flags as int) as boolean;

method main() {
        !! play a sound; SND_ALIAS = 0x10000 = 65536
        let ret2 = winmm:PlaySoundW("SystemStart", 0, 65536);
        !! popup the message box; MB_OK = 0x00000000L
        let ret = user32:MessageBoxW(0, "Hello world!", "From Candle Native Call", 0);
}

6. Prologs

Prologs    :=    NamespaceDecl | ModuleImport | RoutineDecl | ;

6.1 Type (Class) Declaration

TypeDecl    :=    'type', qname, ('extend', qname)?, "{"
member-attr-decl*, member-routine-decl*
"}";
member-attr-decl  :=  'attribute', qname, 'as', TypeDeclaration;
member-routine-decl :=  member-function | member-method;
member-function := ExprFunctionDecl | StamFunctionDecl;
member-method := MethodDecl;

As you can see, type in Candle is very much like the class in object-oriented programming languages. A type can extend another type and a type can have member attribute and member routines.

In current release, an user defined type is always an element or object. In future, an user defined type will also be able to extend atomic types and other node types.

Here's an example of a simple type declaration:
type Person {
   
attribute first-name as string;
    attribute last-name as string;
    function full-name() as string {
       
@first-name + " " + @last-name
    }
}

The way you construct an object of a declared type the same as any other objects. And you can use '?' to access it members. Here's an example:
function main() {
    let someone = Person { first-name = "Perter" last-name="Foo" };
    "Someone's first-name: " { someone?first-name?value }
    "Someone's last-name: " { someone?last-name?value }
    "Someone's full-name: " { someone?full-name() }
}

6.2 Grammar Declaration

Please refer to Grammar section in Candle Pattern Reference.

6.3 Schema Declaration

Please refer to Schema section in Candle Pattern Reference.

6.5 Module Import

ModuleImport    :=    "import", "at", uri;

6.6 Namespace Declaration

NamespaceDecl    :=    "namespace", (DefaultNamespaceDeclNormalNamespaceDecl), (",", (DefaultNamespaceDeclNormalNamespaceDecl))*;
DefaultNamespaceDecl :=  URILiteral;
NormalNamespaceDecl := NCName, "=", URILiteral;

6.7 Global Variable Declaration

Candle does not support global variable. You can use tunneled variable or wrap the global variable as a global function.

6.8 Routine Declaration

RoutineDecl    :=    ExprFunctionDecl | StamFunctionDecl | TemplateDecl | MethodDecl | NativeRoutineDecl;

Please refer to Section 5 for details.

Appendices

A. References

B. Candle Built-in Routines

For the details of Candle built-in routines, please refer to Candle System Routines Reference.

C. Precedence Order

The grammar in the document normatively defines built-in precedence among the operators of Candle. These operators are summarized here to make clear the order of their precedence from lowest to highest. The associativity column indicates the order in which operators of equal precedence in an expression are applied.

# Operator Associativity
1 , (comma) left-to-right
2 := (assignment) right-to-left
3 for, some, every, switch, if left-to-right
4 or left-to-right
5 and left-to-right
6 eq, ne, lt, le, gt, ge, =, !=, <, <=, >, >=, is, <<, >> left-to-right
7 to left-to-right
8 +, - left-to-right
9 *, div, idiv, mod left-to-right
10 union, | left-to-right
11 intersect, except left-to-right
12 instance of left-to-right
13 treat left-to-right
14 castable left-to-right
15 cast left-to-right
16 -(unary), +(unary) right-to-left
17 ?, *(OccurrenceIndicator), +(OccurrenceIndicator) left-to-right
18 /, // left-to-right
19 [ ] left-to-right

Note:

Parentheses can be used to override the operator precedence in the usual way.

D. Error Conditions

(To be documented.)

E. Candle Script Media Type

E.1 MIME Type for Candle Script

The MIME type to be used for Candle script should be application/x-candle at this moment. In future, we might register a formal MIME type for Candle script.

E.2 File Extensions

File extensions to be use for Candle Script should be .csp.

The appropriate Macintosh file type code is TEXT.

E.3 Recognizing Candle Script Files

A Candle Script file should start with the opening signature "<csp1.0>". Only whitespaces are allow before the opening signature. Currently the version number must be "1.0".

E.4 Charset Default Rules

Candle Script files use the Unicode character set and only UTF-8 encoding is supported.