4.1. Quick Start
This page covers the minimum needed to run a daslang program from a C++ host application. For a complete step-by-step tutorial, see tutorial_integration_cpp_hello_world.
4.1.1. Virtual machine overview
daslang uses a tree-based interpreter — the compiled program is a tree
of SimNode objects, each representing one operation (add, load, call,
etc.). Interpretation walks the tree, calling each node’s eval method.
Key properties of this design:
Statically typed, 128-bit words — every value fits in
vec4f(an SSE register), so operations are branchless type dispatches at compile time, not runtime.Zero-copy C++ interop — the in-memory representation matches C++ ABI, so calling between daslang and C++ has no marshalling overhead.
Seamless AOT — the same
SimNodetree can be walked by the interpreter or compiled ahead-of-time into C++, with identical semantics (Advanced Topics).Value types vs reference types — types that fit in 128 bits may be value types (passed in registers). Whether a type is a reference type depends on its nature (e.g. handled types are always reference types regardless of size), not purely on size.
4.1.1.1. Execution context
A Context is the runtime state for one daslang program: a call stack,
two heap allocators (string heap + heap), and a global variable segment.
One context per program — globals, functions, and type info are per-context.
Multiple contexts per thread — you can have multiple contexts in one thread, but only one executes at a time. Contexts can make direct cross-context calls within a thread via
pinvoke. Contexts are not thread-safe — do not share a context across threads.Cheap reset — both heaps use bump allocation. Resetting a stateless script is nearly free (pointer reset, no deallocation).
Garbage collection — stop-the-world, triggered manually by calling
context.collectHeap()or equivalent from the host. There is currently no automatic GC triggered by heap pressure.
4.1.2. Minimal host program
Every C++ host follows the same pattern:
#include "daScript/daScript.h"
using namespace das;
void run_script() {
TextPrinter tout; // output sink
ModuleGroup dummyLibGroup; // module group
auto fAccess = make_smart<FsFileAccess>(); // file system access
// 1. Compile the script
auto program = compileDaScript(
getDasRoot() + "/path/to/script.das",
fAccess, tout, dummyLibGroup);
if (program->failed()) {
for (auto & err : program->errors) {
tout << reportError(err.at, err.what, err.extra,
err.fixme, err.cerr);
}
return;
}
// 2. Simulate (link + initialize)
Context ctx(program->getContextStackSize());
if (!program->simulate(ctx, tout)) {
for (auto & err : program->errors) {
tout << reportError(err.at, err.what, err.extra,
err.fixme, err.cerr);
}
return;
}
// 3. Find and call a function
auto fn = ctx.findFunction("main");
if (fn) {
ctx.evalWithCatch(fn, nullptr);
if (auto ex = ctx.getException()) {
tout << "Exception: " << ex << "\n";
}
}
}
int main(int, char * []) {
NEED_ALL_DEFAULT_MODULES; // register built-in modules
Module::Initialize(); // initialize the module system
run_script();
Module::Shutdown(); // clean up
return 0;
}
The three-step flow is always the same:
Compile —
compileDaScriptparses and type-checks the.dasfile, producing aProgramPtr.Simulate —
program->simulate(ctx, tout)generates theSimNodetree and initializes globals.Evaluate —
ctx.evalWithCatch(fn, nullptr)runs a function.
4.1.3. Key types
TextPrinterOutput sink that writes to stdout. Any
TextWritersubclass works.FsFileAccessFile system access for the compiler.
setFileInfocan register virtual files for compiling from strings (tutorial_integration_cpp_dynamic_scripts).ModuleGroupGroups modules for shared compilation state. For simple hosts, an empty
dummyLibGroupsuffices.ContextRuntime state — stack, heaps, globals. Created with the stack size reported by the compiled program.
SimFunctionPointer to a compiled function. Retrieved via
ctx.findFunction("name").
4.1.4. Calling daslang functions with arguments
To pass arguments and receive return values, use das_invoke_function:
// For: def add(a, b : int) : int
auto fn = ctx.findFunction("add");
int32_t result = das_invoke_function<int32_t>::invoke(
&ctx, nullptr, fn, 10, 20);
This handles argument marshalling automatically and is the preferred approach. See tutorial_integration_cpp_calling_functions for a complete example.
4.1.5. Next steps
Bind C++ functions → tutorial_integration_cpp_binding_functions
Bind C++ types → tutorial_integration_cpp_binding_types
Create custom modules → tutorial_integration_cpp_custom_modules
Full API reference → C++ API Reference