Expressions and macros
An expression is a document. The example builds an expression program once and evaluates it with an input document. The macro example expands an expression before compilation and evaluation.
Example
Build an expression and evaluate it
expression_text holds this document:
[
"+",
"?x",
1
]
input_text holds this document:
{
"x": 41
}
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
program := stardust.build(expression) or_return
defer stardust.close(&program)
input := stardust.parse(input_text, .JSON) or_return
defer stardust.close(&input)
result := stardust.evaluate(program, input) or_return
defer stardust.close(&result)42
Reusing programs
A program keeps the expression that you built, independently of any one evaluation.
- You can evaluate one program concurrently with separate input documents.
- Keep the program until its evaluations finish.
- Then release it under the ownership rule of its operation.
Operations
| Operation | Returns | Summary |
|---|---|---|
| build | program | build(expression) borrows the expression document and returns an owned program. |
| build_macro | program | build_macro(title, authored, arguments) binds AST arguments into an unstored macro and returns an owned program. |
| expand_macro | document | expand_macro(title, authored, arguments) returns the expanded expression document without building it. |
| evaluate | document | program.evaluate(input) returns an independent owned result document. |
| close | none | Release the program handle. |
| expression | program | Build an owned program from a path or inline expression, expanding stored macros. |
build
build :: proc(
expression: Document,
explain: ^Build_Explain = nil,
allocator := context.allocator,
) -> (
Program,
Error,
)Parameters
| Parameter | Type | Ownership | Default | Meaning |
|---|---|---|---|---|
expression | Document | Borrowed for the call | Required | The native expression AST to compile. The call borrows this document. |
explain | ^Build_Explain | Caller-owned output | nil | Optional explain output. This record contains explain output for build. |
allocator | mem.Allocator | Value | context.allocator | Allocator for copied return values and diagnostics. The caller releases them with the same allocator. |
Errors
| Status | When |
|---|---|
.Compile_Failed | the expression does not compile |
.Out_Of_Memory | native memory is exhausted |
Notes
Examples
Build an expression and evaluate its input
expression_text holds this document:
[
"+",
"?x",
1
]
input_text holds this document:
{
"x": 41
}
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
program := stardust.build(expression) or_return
defer stardust.close(&program)
input := stardust.parse(input_text, .JSON) or_return
defer stardust.close(&input)
result := stardust.evaluate(program, input) or_return
defer stardust.close(&result)42
Inspect one measured cost stage
expression_text holds this document:
[
"+",
"?x",
1
]
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
explain: stardust.Build_Explain
program := stardust.build(expression, &explain) or_return
defer stardust.close(&program)
result := explain.total{
"cpu": 20,
"wall": 20,
"arena_bytes": 0
}Explain expression compilation
expression_text holds this document:
[
"+",
"?x",
1
]
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
explain: stardust.Build_Explain
program := stardust.build(expression, &explain) or_return
defer stardust.close(&program)
result := explain{
"prepare_expression": {
"cpu": 3,
"wall": 3,
"arena_bytes": 0
},
"compile": {
"cpu": 11,
"wall": 11,
"arena_bytes": 0
},
"total": {
"cpu": 18,
"wall": 18,
"arena_bytes": 0
},
"arena_capacity": 65536,
"stages_completed": 2,
"cache_hit": true
}C exports: stardust_expr_build, stardust_expr_program_error
build_macro
build_macro :: proc(
title: string,
authored, arguments: Document,
allocator := context.allocator,
) -> (
Program,
Error,
)Parameters
| Parameter | Type | Ownership | Default | Meaning |
|---|---|---|---|---|
title | string | Value | Required | The diagnostic title of this unstored macro. |
authored | Document | Borrowed for the call | Required | The native authored macro definition with its declared parameters and expression body. |
arguments | Document | Borrowed for the call | Required | Native AST arguments bound to the macro's declared parameters before expansion. |
allocator | mem.Allocator | Value | context.allocator | Allocator for copied return values and diagnostics. The caller releases them with the same allocator. |
Errors
| Status | When |
|---|---|
.Invalid_Argument | the arguments include an undeclared macro parameter |
.Invalid_Definition | the macro is invalid or expands recursively |
.Not_Found | the macro refers to an unknown macro |
.Compile_Failed | the expansion does not compile |
.Out_Of_Memory | native memory is exhausted |
Notes
Examples
Bind an unstored macro and evaluate it
macro_text holds this document:
{
"params": [
"input"
],
"expands": [
"+",
{
"insert": "input"
},
1
]
}
arguments_text holds this document:
{
"input": [
"*",
"?amount",
2
]
}
input_text holds this document:
{
"amount": 10
}
authored := stardust.parse(macro_text, .JSON) or_return
defer stardust.close(&authored)
arguments := stardust.parse(arguments_text, .JSON) or_return
defer stardust.close(&arguments)
program := stardust.build_macro("twice-plus-one", authored, arguments) or_return
defer stardust.close(&program)
input := stardust.parse(input_text, .JSON) or_return
defer stardust.close(&input)
result := stardust.evaluate(program, input) or_return
defer stardust.close(&result)21
C exports: stardust_macro_build, stardust_expr_program_error
expand_macro
expand_macro :: proc(
title: string,
authored, arguments: Document,
allocator := context.allocator,
) -> (
Document,
Error,
)Parameters
| Parameter | Type | Ownership | Default | Meaning |
|---|---|---|---|---|
title | string | Value | Required | The diagnostic title of this unstored macro. |
authored | Document | Borrowed for the call | Required | The native authored macro definition with its declared parameters and expression body. |
arguments | Document | Borrowed for the call | Required | Native AST arguments bound to the macro's declared parameters before expansion. |
allocator | mem.Allocator | Value | context.allocator | Allocator for copied return values and diagnostics. The caller releases them with the same allocator. |
Errors
| Status | When |
|---|---|
.Invalid_Argument | the arguments include an undeclared macro parameter |
.Invalid_Definition | the macro is invalid or expands recursively |
.Not_Found | the macro refers to an unknown macro |
.Out_Of_Memory | native memory is exhausted |
Notes
Examples
Expand an unstored macro as a native document
macro_text holds this document:
{
"params": [
"input"
],
"expands": [
"+",
{
"insert": "input"
},
1
]
}
arguments_text holds this document:
{
"input": [
"*",
"?amount",
2
]
}
authored := stardust.parse(macro_text, .JSON) or_return
defer stardust.close(&authored)
arguments := stardust.parse(arguments_text, .JSON) or_return
defer stardust.close(&arguments)
result := stardust.expand_macro("twice-plus-one", authored, arguments) or_return
defer stardust.close(&result)[
"+",
[
"*",
"?amount",
2
],
1
]C exports: stardust_macro_expand, stardust_document_error
evaluate
evaluate :: proc(
program: Program,
input: Document = {},
explain: ^Eval_Explain = nil,
allocator := context.allocator,
) -> (
Document,
Error,
)Parameters
| Parameter | Type | Ownership | Default | Meaning |
|---|---|---|---|---|
program | Program | Borrowed for the call | Required | The program owner for this operation. Keep it alive during the call. |
input | Document | Borrowed for the call | {} | Variables for evaluation. Absent input uses an empty object. |
explain | ^Eval_Explain | Caller-owned output | nil | Optional explain output. This record contains explain output for evaluate. |
allocator | mem.Allocator | Value | context.allocator | Allocator for copied return values and diagnostics. The caller releases them with the same allocator. |
Errors
| Status | When |
|---|---|
.Evaluation_Failed | the expression fails on the input |
.Closed | the program is closed |
.Out_Of_Memory | native memory is exhausted |
Notes
Examples
Build an expression and evaluate its input
expression_text holds this document:
[
"+",
"?x",
1
]
input_text holds this document:
{
"x": 41
}
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
program := stardust.build(expression) or_return
defer stardust.close(&program)
input := stardust.parse(input_text, .JSON) or_return
defer stardust.close(&input)
result := stardust.evaluate(program, input) or_return
defer stardust.close(&result)42
Explain expression evaluation
expression_text holds this document:
[
"+",
"?x",
1
]
input_text holds this document:
{
"x": 41
}
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
program := stardust.build(expression) or_return
defer stardust.close(&program)
input := stardust.parse(input_text, .JSON) or_return
defer stardust.close(&input)
explain: stardust.Eval_Explain
output := stardust.evaluate(program, input, &explain) or_return
defer stardust.close(&output)
result := explain{
"prepare_variables": {
"cpu": 4,
"wall": 5,
"arena_bytes": 0
},
"evaluate": {
"cpu": 47,
"wall": 47,
"arena_bytes": 0
},
"adopt_document": {
"cpu": 3,
"wall": 3,
"arena_bytes": 0
},
"total": {
"cpu": 57,
"wall": 59,
"arena_bytes": 0
},
"arena_capacity": 65536,
"document_bytes": 42,
"stages_completed": 3
}C exports: stardust_expr_evaluate, stardust_result_take_document, stardust_result_error, stardust_result_release
close
close :: proc(program: ^Program)Consumes the receiver handle.
Parameters
| Parameter | Type | Ownership | Default | Meaning |
|---|---|---|---|---|
program | ^Program | Consumed owner | Required | The program owner to release. Do not use it after this call. |
Examples
Build an expression and evaluate its input
expression_text holds this document:
[
"+",
"?x",
1
]
input_text holds this document:
{
"x": 41
}
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
program := stardust.build(expression) or_return
defer stardust.close(&program)
input := stardust.parse(input_text, .JSON) or_return
defer stardust.close(&input)
result := stardust.evaluate(program, input) or_return
defer stardust.close(&result)
stardust.close(&program)42
C exports: stardust_expr_program_release
expression
expression :: proc(
db: Database,
path: string,
explain: ^Build_Explain = nil,
allocator := context.allocator,
) -> (
Program,
Error,
)expression :: proc(
db: Database,
definition: Document,
explain: ^Build_Explain = nil,
allocator := context.allocator,
) -> (
Program,
Error,
)Parameters
| Parameter | Type | Ownership | Default | Meaning |
|---|---|---|---|---|
db | Database | Borrowed for the call | Required | The database owner for this operation. Keep it alive during the call. |
path | string | Value | Required | The stored definition path selected at run time. |
explain | ^Build_Explain | Caller-owned output | nil | Optional explain output. This record contains explain output for build. |
allocator | mem.Allocator | Value | context.allocator | Allocator for copied return values and diagnostics. The caller releases them with the same allocator. |
definition | Document | Borrowed for the call | Required | The inline native definition copied into the opened handle. |
Errors
| Status | When |
|---|---|
.Not_Found | no expression is stored at the path |
.Invalid_Definition | a macro it calls is invalid or expands recursively |
.Compile_Failed | the expanded expression does not compile |
.Closed | the database is closed |
.Out_Of_Memory | native memory is exhausted |
Notes
The program keeps the expression and macros selected at build time and survives database closure. Build again to use later definition changes.
Examples
Build an expression with the database's macros and evaluate it
expression_text holds this document:
[
"+",
"?x",
1
]
input_text holds this document:
{
"x": 41
}
expression := stardust.parse(expression_text, .JSON) or_return
defer stardust.close(&expression)
program := stardust.expression(db, expression) or_return
defer stardust.close(&program)
input := stardust.parse(input_text, .JSON) or_return
defer stardust.close(&input)
result := stardust.evaluate(program, input) or_return
defer stardust.close(&result)42
C exports: stardust_db_expression_build, stardust_expr_program_error