ChaiScript, once parsed, is executed top to bottom in a single pass. Definitions and statements have the same precedence.
Recommendation: ChaiScript source files have a .chai extension.
Comments follow the same format as C++ comments.
/* This is a multi-line comment. */ //This is a single line comment.
If Block ::= "if" "(" condition ")" block
Else If Block ::= "else if" "(" condition ")" block
Else Block ::= "else" block
While Block ::= "while" "(" condition ")" block
This loop can be broken using the break command.
For Block ::= "for" "(" [initial] ";" stop_condition ";" loop_expression ")" block
This loop can be broken using the break command.
Try Block ::= "try" block ("catch" ["(" variable ")"] [":" guards] block)+ ["finally" block]
Function Definition ::= [annotation + CR/LF] "def" identifier "(" [arg ("," arg)*] ")" [":" guard] block
annotation: meta-annotation on function, currently used as documentation. Optional.
identifier: name of function. Required.
args: comma-delimited list of parameter names. Optional.
guards: guarding statement that act as a prerequisite for the function. Optional.
{ }: scoped block as function body. Required.
Functions return values in one of two ways:
return call, optionally passing the value to be returned.Lambda ::= "fun" "(" [variable] ("," variable)* ")" block
Creates an anonymous function (sometimes called a lambda).
In-place Vector ::= "[" [expression ("," expression)*] "]"
In-place Ranged Vector ::= "[" value ".." value "]"
Creates a vector over a range (eg. 1..10)
In-place Map ::= "[" (string ":" expression)+ "]"
You may extend C++ classes that you have previously registered with the ChaiScript engine using the method definition syntax:
Method Definition ::= class_name "::" method_name "(" [arg ("," arg)*] ")" block
Using the same method definition syntax you can create a constructor and add methods to a new type. For example:
def MyClass::MyClass() { }
This creates a constructor for the 'MyClass' type, which, if it doesn't already exist, will now be visible to your script. To instantiate a value of 'MyClass', call its constructor directly:
var myobject = MyClass()
Attribute Definition ::= "attr" class_name "::" attribute_name
In addition to extending your new type with methods, you may also add attributes.
Extended example:
attr Rectangle::height attr Rectangle::width def Rectangle::Rectangle() { this.height = 10; this.width = 20 } def Rectangle::area() { this.height * this.width } var rect = Rectangle() rect.height = 30 print(rect.area())
ChaiScript, at its core, has some very functional programming-inspired habits. Few places show this off as clearly as the prelude, itself a name taken as a nod to the popular functional language Haskell. This prelude is available to all standard ChaiScript applications, and provides a simple foundation for using numbers, strings, and ranges (the general category of containers and their iteration).
to_string(x): Converts x into a string.
eval> to_string(3).is_type("string") true
puts(x): Prints x to the terminal, without a trailing carriage return.
eval> puts("hi, "); puts("there") hi, there
print(x): Prints x to the terminal, with a trailing carriage return.
eval> print("hello") hello
find(str, substr): Finds the first instance of substr in str.
eval> find("abab", "ab") 0
rfind(str, substr): Finds the last instance of substr in str.
eval> rfind("abab", "ab") 2
find_first_of(str, list): Finds the first of characters in list in the str string.
eval> find_first_of("abab", "bec") 1
find_last_of(str, list): Finds the last of characters in list in the str string.
eval> find_last_of("abab", "bec") 3
find_first_not_of(str, list): Finds the first non-matching character to list in the str string.
eval> find_first_not_of("abcd", "fec") 0
find_last_not_of(str, list): Finds the last non-matching character to list in the str string.
eval> find_last_not_of("abcd", "fec") 3
ltrim(str): Removes whitespace from the front of the string.
eval> ltrim(" bob") bob
rtrim(str): Removes whitespace from the back of the string.
eval> rtrim("bob ") + "|" bob|
trim(str): Removes whitespace from the front and back of the string.
eval> trim(" bob ") + "|" bob|
max(a, b): Returns the maximum value of a or b.
eval> max(4, 10) 10
min(a, b): Returns the minimum value of a or b.
eval> min(4, 10) 4
even(x): Returns true if x is even, otherwise returns false.
eval> even(4) true
odd(x): Returns true if x is odd, otherwise returns false.
eval> odd(4) false
for_each(container, f): Applies the function f over each element in the container.
eval> for_each([1, 2, 3], print) 1 2 3
map(container, f): Applies f over each element in the container, joining all the results.
eval> map([1, 2, 3], odd) [true, false, true]
foldl(container, f, initial): Starts with the initial value and applies the function f to it and the first element of the container. The result is then applied to the second element, and so on until the elements are exhausted.
eval> foldl([1, 2, 3, 4], `+`, 0) 10
sum(container): Returns the sum total of the values in the container.
eval> sum([1, 2, 3, 4]) 10
product(container): Returns the product of the value in the container.
eval> product([1, 2, 3, 4]) 24
take(container, num): Takes num elements from the container, returning them.
eval> take([1, 2, 3, 4], 2) [1, 2]
take_while(container, f): Takes elements from the container that match function f, stopping at the first non-match, returning them as a new Vector.
eval> take_while([1, 2, 3], odd) [1]
drop(container, num): Drops num elements from the container, returning the remainder.
eval> drop([1, 2, 3, 4], 2) [3, 4]
drop_while(container, f): Drops elements from the container that match f, stopping at the first non-match, returning the remainder.
eval> drop_while([1, 2, 3], odd) [2, 3]
reduce(container, f): Similar to foldl, this takes the first two elements as its starting values for f. This assumes container has at least 2 elements.
eval> reduce([1, 2, 3, 4], `+`) 10
filter(container, f): Takes elements from container that match function f, return them.
eval> filter([1, 2, 3, 4], odd) [1, 3]
join(container, delim): Joins the elements of the container into a string, delimiting each with the delim string.
eval> join([1, 2, 3], "*") 1*2*3
reverse(container): Returns the contents of the container in reversed order.
eval> reverse([1, 2, 3, 4, 5, 6, 7]) [7, 6, 5, 4, 3, 2, 1]
generate_range(x, y): Generates a new Vector filled with values starting at x and ending with y.
eval> generate_range(1, 10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
concat(x, y): Returns a new Vector with x and y concatenated.
eval> concat([1, 2, 3], [4, 5, 6]) [1, 2, 3, 4, 5, 6]
collate(x, y): Returns a new Vector with x and y as its values.
eval> collate(1, 2) [1, 2]
zip_with(f, x, y): Applies f to elements of x and y, returning a new Vector with the result of each application.
eval> zip_with(`+`, [1, 2, 3], [4, 5, 6]) [5, 7, 9]
zip(x, y): Collates elements of x and y, returning a new Vector with the result.
eval> zip([1, 2, 3], [4, 5, 6]) [[1, 4], [2, 5], [3, 6]]
Statements are formed by combining one or more of the following:
ChaiScript supports both ints and doubles.
Example int:
10Example doubles:
3.14, NaN, Infinity
Example booleans:
true, false
Any variable identifier that follows the C naming convention.
Example variable:
bob
Quoted string values.
Example string:
"test me"Strings accept the following escaped sequences:
| Sequence | Description |
|---|---|
| \b | Backspace |
| \f | Form feed |
| \n | Newline |
| \r | Carriage return |
| \t | Tab |
| \' | Single quote |
| \" | Double quote |
| \\ | Single backslash |
Strings also allow in-string evaluation, which allows you to evaluate simple expressions inside of the string. For example:
var five = 5 "3 + 5 = ${3 + five}"
Single-Quoted char values.
Example char:
'b'Chars also accept the following escaped sequences:
| Sequence | Description |
|---|---|
| \b | Backspace |
| \f | Form feed |
| \n | Newline |
| \r | Carriage return |
| \t | Tab |
| \' | Single quote |
| \" | Double quote |
| \\ | Single backslash |
A special form of the operator that allows you to reference it as an identifier.
Example operator literal:
`+`Note: These may be used as first-class functions.
Example expression:
3 + 4 * 5
Mathematical expression following the order of precedence mentioned in "Operators".
Variable Declaration ::= "var" identifier
A variable name preceded by the keyword var, which declares the variable as an anonymous type. Once a variable has been given a type by assigning it to a value, the variable must maintain this type while it's in scope.
Equation ::= lvalue "=" rvalue
Takes a copy of what is on the right hand side and assigns it to the identifier named on the left hand side. For complex types this calls the "clone" method for that type.
Function Call ::= fun_name "(" [arg ("," arg)*] ")"
Calls the function pointed to by the lhs value.
Method Call ::= obj_name "." fun_name "(" [arg ("," arg)*] ")"
In ChaiScript the above notation is identical to:
fun_name "(" obj_name ("," arg)* ")"
Array Call ::= obj_name "[" key "]"
An array value lookup. In maps, 'key' is a string value, in vectors it is a numeric index.
Throw ::= "throw" "(" value ")"
The following are natively supported types in ChaiScript:
| Type | Example |
|---|---|
| int | 10 |
| double | 1.2 |
| bool | true |
| string | "hello" |
| char | 'b' |
| Vector | [1, 2] and [1..10] |
| Map | ["key":100] |
All C++ types are support (value, reference, and pointer types included). Additionally, values of boost::shared_ptr are also supported.