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:
- Expression level:
at this level, you see language constructs like literal data, markup
elements and nodes, and all kinds of expressions, from arithmetic,
logic to
path and FLWOR expressions. Expressions in Candle are always functional
and they are primarily design to construct items and sequence.
- Statement level:
at this level, you see language constructs like flow control
statements and transformation statements. There are two types of
statements: functional and procedural. Functional statements
are primarily
design to construct nodes. Procedural statements are designed to carry
out CRUD operations and other operations with side-effects.
- Routine level:
functions,
transformation templates and methods are defined at this level.
- Prolog level:
the top
level of the language consists of constructs like namespace
declaration, module import, native routine declarations,
class and schema definitions;
Here are some of the general syntax rules of Candle script:
- Names in Candle
are case-sensitive. And Candle adapts a
lower-case, dash-separated naming convention.
- The reserved
keywords in Candle are:
true
and false
,
which are used to represent boolean values;
this
and super
,
which are used in
OOP;
error
,
which is used to represent error value;
nan
and infinity
, which are use to
represent special floating point number;
- Comments in Candle script
can be expressed in two forms:
- Line comment starts with
token '
!!
'
and extends to the end
of line:
line-comment |
= |
"!!",
(char
- ("&cr;" | "&lf;"))*, (" &cr;"
| "&lf;");
|
- Block
comment starts with token '
!*
',
can span across several lines
of text, can contain nested block comment, and ends with token '*!
':
block-comment |
= |
"!*',
((char
- ("!" | "*")),
("!", char
- "*") |
("*", char
- "!") |
block-comment)*, ("!" | "*")?, "*!";
|
- Names in Candle script are
resolved based the following rules:
- Fully expanded names are
fully defined and do not require additional resolution;
- Prefixed
names are always resolved under the namespace referred to by
the prefix;
- Unprefixed names are
normally resolved under the default namespace declared at the beginning
of the script, unless stated otherwise. There are several cases where
unprefixed names are resolved under system namespace candle:core, they
are documented in details in the following sections.
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
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
3.1.5
Function Calls
ExprFunctionCall |
:= |
FunctionCall; |
Function Call |
:= |
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-node
| cdata-node
| comment-node
| data-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" | "&"))* | 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:
- Candle text node is always
quoted with double-quote characters;
- Literal value can appear
directly in element content as data node, thus text node is just a
special form of data node;
- Candle CData
node uses triple
<<<
and >>>
rather than XML syntax <![CDATA[...]]>
;
- As text nodes are quoted,
functional statements and function call can appear directly in element
content;
- Candle attribute allows
literal values to be specified without quote, and attribute can have
complex attribute content;
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-step
| forward-step ), predicate* ; |
forward-step |
:= |
( forward-axis ,
node-test)
| abbrev-forward-step ; |
reverse-step |
:= |
( reverse-axis , node-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:
- FieldPredicate: in this beta
release, it can only be used to access built-in data components of an
item. These fields include:
?context-position
as integer |
- returns the
context position of the context item as integer ; |
?context-size
as integer |
- returns the
context size as integer ; |
?local-name
as string |
- returns the
local-name of the context item as string ; |
?namespace
as uri |
- returns the
namespace URI of the context item as uri ; |
?node-name
as qname |
- returns the
qualified name of the context item as qname ; |
?element-name
as qname |
- returns the
element name of the context item as qname ; |
?kind
as qname |
- returns the kind
of the context item as qname ; |
?number
as number |
- returns the
numeric value of a numeric type ; |
?unit
as qname |
- returns the unit
of a measure as qname ; |
?list
as atomic* |
- returns a list of
atomized values of the context item; |
?string
as string |
- returns the string
value of the context item; |
?source
as string |
- returns the
serialized markup source text of the context item; |
?year,
?month, ?day,
?week-day, ?hour,
?minute, ?second, ?millisecond as integer |
- returns the
corresponding component of the datetime
type as integer ;
The range of these fields are:
- ?year: unlimited
- ?month: 1 ~ 12
- ?day: 1 ~31
- ?week-day: Sun =
0, Mon = 1, ..., Sat = 6
- ?hour: 0 ~ 23
- ?minute: 0 ~ 59
- ?second: 0 ~ 59
- ?millisecond: 0 ~
999
|
?r,
?g, ?b as integer |
- returns the r, g,
or b component of a color
as integer ; |
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:
- Candle introduces two new
expressions:
foreach
expression and with
expression;
let
expression use '=' instead of ':=';
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:
- All expressions in Candle
are pure functional;
- Statements in Candle are
separated into two categories:
functional and procedural. Functional statements can be nested inside
prodedural statements, but not vice versa;
- Routines in Candle are also
separated into two categories:
functional and procedural. Functional routines can only
contain
functional statements and expressions, and only call other functional
routines. Procedural routines can contain both categories of
statements, and call both categories of routines.
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) ; |
Put Action Stam |
:= |
"put", "(", (qname,
"=", expr), (",",
qname,
"=", expr)* , ")", action-block;
|
With Action Stam |
:= |
"with", "(",
expr ,
")",
action-block
;
|
For Action Stam |
:= |
"for",
"(", VarDeclare, (",",
VarDeclare)*, ")", action-block ; |
Foreach Action Stam |
:= |
"foreach", "(",
expr ,
")",
action-block
;
|
If Action Stam |
:= |
"if", "(",
expr ,
")",
action-block
,
("else", (IfActionStam |
action-block
))?;
|
Switch Action Stam |
:= |
"switch", "(",
expr ,
")",
Case Action Stam*,
Default Action Stam?;
|
Case Action Stam |
:= |
"case", "(", expr ,
")",
action-block
;
|
Default Action Stam |
:= |
"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:
- Expression function:
corresponds to XQuery function and can only
be called at expression level. Expression function must always specify
the return type.
- Statement function:
corresponds to XSLT function and can only be
called at statement level. Statement function does no return value,
instead it outputs content to the default output stream directly.
- Template:
corresponds to the
template defined in XSLT. Like statement function, template does not
return value, but outputs content to the default output stream.
- Method:
like the traditional
procedure routine.
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 | Bind MatchClause),
("(",
ParamList?, ")")?, ModeClause?, PriorityClause?,
StamFuncBody; |
ModeClause |
:= |
"default"
| "current" | "all" | qname; |
PriorityClause |
:= |
"priority",
Number; |
MatchClause |
:= |
"<", MatchPattern,
">"; |
BindMatch Clause |
:= |
"[", 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
| NativeMethod Decl; |
NativeExprFunctionDecl |
:= |
"native",
"function",
Qname, "(", ParamList?, ")", ReturnType; |
NativeMethod Decl |
:= |
"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:
- it must start with
candle:runtime:native
;
- if the calling convention of
the native routine is win32 standard call, then it should be followed
by
winstd
;
if the calling convention is C default cdecl
call, then it should be followd by cstd
;
- then followed by the module
name, e.g.
user32
;
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", ( DefaultNamespaceDecl
| NormalNamespaceDecl), (",", ( DefaultNamespaceDecl
| NormalNamespaceDecl ))* ; |
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.