gaijinentertainment/dascript/daslang

Claude Code and agent skill by gaijinentertainment/dascript

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

daslang (formerly daScript) language reference - gen2 syntax, type system, memory model, generics, macros, standard library. Invoke whenever a task involves writing, reviewing, refactoring, debugging, or understanding .das files or a daslang project.

Install

npx vskill@latest install gaijinentertainment/dascript/daslang

SKILL.md

daslang

Statically typed scripting language for games and real-time applications, by Gaijin Entertainment. .das files run interpreted, AOT-compiled to C++, or LLVM-JIT-compiled; data layout mirrors C++.

gen2 is the DEFAULT parser: a .das file is gen2 (C-like, braces) unless it opts out with options gen2 = false - never infer gen1 (indentation-based) from a missing options gen2 marker. Never write gen1; by convention new files still open with options gen2. Everything below is gen2.

References

Detailed semantics live in ./references/:

  • types.md - type catalog, vector lattice, literal suffixes, enums/variants/tuples/

bitfields, fixed arrays, the two const positions, temporary (#) and distinct types

  • functions.md - parameters, named arguments, overload resolution, operator overloading,

computed properties, pipes, precedence

  • structs-and-classes.md - initialization modes, virtuals, sealed/static, runtime type checks
  • closures.md - blocks/lambdas/function pointers, capture modes, generators, iterators
  • memory.md - the const model, move/copy/clone, finalizers, inscope, delete semantics,

contexts and threading, unsafe catalog

  • generics.md - auto(TT), type contracts, typeinfo traits, static_if, pattern matching
  • macros.md - compilation pipeline, macro classes, qmacro, qmatch, annotations
  • modules-and-stdlib.md - module declarations, require, with (module ...), options,

containers, daslib catalog

  • strings.md - the string surface, byte views, the parse family, build_string,

conversions, regular expressions

  • files-and-paths.md - fio helpers, directory walking, subprocess capture, glob patterns
  • json.md - sprint_json/sscan_json, JV, JsonValue?, safe navigation
  • queries.md - comprehensions, the linq surface, what fuses into one pass
  • cli-and-config.md - argv parsing, environment twins, config knobs
  • everything.md - generated digest of every module: what it is for, every public symbol,

each with a one-line description where the source carries one; search it by symbol or intent before writing a helper, and read it whole only when auditing a file set for duplicates

Functions

das
def add(a, b : int) : int { // `a, b : int` - one type for both names
return a + b
}
def twice(a) => a + a // arrow body; untyped param makes it generic
  • Typed parameter groups separate with , or ;.
  • A parameter is const unless declared var a : int.
  • Return type follows :, inferred when omitted; a => body's expression must start on the

same line as the =>.

  • Named arguments follow positionals: foo(pos, name = value).
  • Defaults: def greet(name : string = "world").
  • Visibility is a prefix keyword - def private helper(); there is no [private] annotation.

Variables and the const model

das
let a = 13 // immutable handle: type is `int const`
var b = 13 // mutable: type is `int`
var c : float = 0.5

let x = e means x : auto const = e - const lives entirely in the type, and dereference, indexing and field access flow it onto the result, so a let handle gives const access to everything reachable through it. Never strip const with reinterpret to write: the optimizer trusts the const type and may silently delete the write.

Control flow

das
if (x > 0) {
r = 1
} elif (x < 0) {
r = -1
} else {
r = 0
}
for (i in range(10)) { ... } // 0..9
for (x in arr) { ... } // arrays, tables, iterators
while (running) { ... }
  • Conditions must be bool - no truthiness: if (ptr != null). if / for / while /

static_if all require the parentheses.

  • Postfix conditionals: return x if (cond), likewise break / continue.
  • A bare { ... } at statement level is a lexical scope, and takes { ... } finally { ... }.
  • for (k, v in keys(tab), values(tab)) iterates in parallel.

Strings

  • Strings are immutable; interpolate {expr} as in "hello, {name}" - not ${} (compiles,

prints a literal $), not %s - with format specifiers "{value:08x}", escaping literal braces "literal \{braces\}". Number to string: "{x}" or string(42).

  • length(s) / empty(s) need no require; the rest of the string API needs

require strings.

  • int("123") does NOT exist; to_int (require strings) silently returns 0 on garbage.

External input goes through try_to_int / try_to_float from require daslib/strings_convert, whose Result distinguishes invalid input from a real zero.

Pipes and block arguments

das
foo |> setXY(10, 11) // setXY(foo, 10, 11)
arr |> sort() $(a, b) => a < b // trailing block pipes as last argument
build_string() $(var writer) { // block with parameters
writer |> write("hello")
}
  • A block/lambda immediately after a call is piped as its LAST argument ("assumed pipe"); a

parameterless block needs no $: defer() { cleanup() }.

  • Arrow shorthand also spells lambdas: @(x) => x + 1 (capturing), @@(x) => x + 1

(no-capture function pointer).

  • a.foo(b) is sugar for foo(a, b) only when a is a struct/class value; primitives and

lambda-typedef values need |>.

Collections

das
var a <- [1, 2, 3] // array<int> literal (heap)
let f = fixed_array(1, 2, 3) // fixed-size int[3] (stack)
var t <- { "hp" => 100, "mp" => 50 } // table<string; int> literal
var s : table<string> // one type param = a SET
let v = t?["hp"] ?? 0 // safe lookup with default
var sq <- [for (x in range(10)); x * x] // array comprehension
var m <- { for (x in range(5)); x => x * x } // table comprehension
  • table[key] on a mutable table INSERTS a default entry when missing - read with

t?[key] ?? default, test with key_exists(t, k).

  • Never do two [] lookups on the same table in one expression - rehashing can invalidate

the first reference.

  • push copies, emplace moves (zeroes the source), push_clone deep-clones. Bulk forms

push_from / push_clone_from take a whole array at once.

Move, copy, clone

OperatorEffect
=copy - value types (int, float, bool, string, pointers, POD structs)
<-move - transfers ownership, source is zeroed
:=clone - deep copy, source unchanged
das
def make() : array<int> {
var r <- [1, 2, 3]
return <- r // moving return for non-copyable types
}

Structs are copyable only if all fields are. delete on a lambda requires unsafe - copies alias one shared capture frame.

Pointers

das
var p = new Foo(x = 1) // heap allocation, type Foo?
let x = p?.x ?? 0 // safe navigation + null coalescing
var inscope q = new Foo() // auto-deleted at scope exit
unsafe {
delete p // manual delete is unsafe
}
  • T? is a nullable pointer with TWO const positions: Foo const? = const pointee,

Foo? const = const pointer. Writing through a parameter needs both non-const: var p : Foo?.

  • addr(x) requires unsafe; safe_addr(x) yields a temporary pointer (T?#) without it.

Enums, variants, tuples, bitfields

das
enum Color {
red
green
}
let i = int(Color.red) // dot access; explicit cast to int
var t = (1, 2.0, "three")
let first = t._0 // access by index
let (x, y, z) = t // destructuring
bitfield Flags {
read
write
}
var fl : Flags = Flags.read | Flags.write
fl.write = false // single-bit assignment
if (fl.read) { ... } // single-bit test

Without the explicit : Flags, var fl = Flags.read | Flags.write infers an ANONYMOUS bitfield type and the named single-bit access (fl.read) stops compiling.

Variants (tagged unions) are declared like structs, constructed with exactly one field (Value(asInt = 42)), tested with is, read with as / ?as ... ?? default. Writing a variant field or switching the active field requires unsafe. A case declared without a type (variant Maybe { nothing; value : int }) carries no value: Maybe(nothing) constructs it, is tests it, and as, ?as and field reads do not compile on it.

Memory model

Locals and structs live on the stack; new, arrays and tables use the current context's heap. Cleanup is deterministic and explicit - delete, var inscope, or moving ownership out with <-; a plain local var arr : array<int> is NOT finalized at scope exit. Each context (thread) owns its heap and cannot retain pointers into another's - clone what crosses. delete on a container of pointers finalizes AND FREES every pointee; clear() first when the pointers are non-owning.

Error handling

  • panic("msg"), and any runtime error (a failed bounds check, an error raised by a bound C++

function), unwinds to the nearest enclosing try { } recover { }; the recover block runs and execution continues after it, in every execution tier. recover binds nothing - there is no exception value to match on; the message is this_context().last_exception (require daslib/rtti), with a trailing newline. Under the JIT the pair compiles to a builtin call, and a return inside the try block is a compile error there (the interpreter allows it). With no enclosing try the error unwinds out of the script: the daslang CLI prints it and exits nonzero, an embedding host gets it back as a context error. Never design APIs around panic-as-control-flow.

  • assert(cond, "msg") may be stripped in release; verify(cond, "msg") always runs. The

message must be a string CONSTANT - for a runtime-value diagnostic write if (!cond) panic("bad n = {n}"). An asserted expression with side effects (invoking a lambda counts) is rejected; use verify.

  • Recoverable errors are values: return bool, T?, or a variant with an error case.
  • { } finally { } is SKIPPED on panic, by design - no must-run-on-failure cleanup there.

Callable types

KindPrefixAllocationCapturesStorableCopyable
block$stacksurrounding scope by referencenono
lambda@heapexplicit modes: copy/move/clone/refyesyes - pointer copy (alias)
function@@nonenoneyesyes

@@name is a pointer to a named function.

Gotchas

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
1,157
Repository forks
121
7-day trend score
35

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/gaijinentertainment/dascript/daslang/badge)](https://verified-skill.com/skills/gaijinentertainment/dascript/daslang)

Something wrong with this skill or its page? Tell us.