一键导入
builtin-dsl
How to add or modify builtin functions and methods in `pkg/dang/stdlib.go`. Use when extending Dang's standard library.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
How to add or modify builtin functions and methods in `pkg/dang/stdlib.go`. Use when extending Dang's standard library.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Dang language reference for writing, editing, and reviewing `.dang` code — syntax, types/nullability, prototype objects, copy-on-write mutation, control flow, errors, GraphQL interop, stdlib, and CLI. Use when authoring or reviewing `.dang` files or Dang modules, or any time precise Dang language behavior matters.
Non-obvious invariants in Dang's compiler — multi-pass hoisting, the Fork/Clone/dynamic-scope-cell model, and `Module.Eq` subtyping. Use when editing `pkg/dang/` infer/eval/scope code, adding a new type-like declaration, or debugging mutation/scoping issues.
How to maintain editor syntax definitions for Dang. Use when adding or removing keywords, tokens, or language constructs.
How to run tests, add error tests, update golden files, and report nice errors in Dang. Use when running or writing tests.
| name | builtin-dsl |
| description | How to add or modify builtin functions and methods in `pkg/dang/stdlib.go`. Use when extending Dang's standard library. |
All builtins are defined in a single place: the registerStdlib() function in
pkg/dang/stdlib.go. The DSL handles type registration, eval-env registration,
method dispatch, and default-value application — you only edit one file.
Avoid polluting the global namespace. Methods on types compose better with autocomplete and chaining.
"hello".toUpper() not toUpper("hello")users.length not len(users)"a,b".split(",") not split("a,b", ",")Only add a global function when it doesn't naturally belong to one type
(print, assert).
Builtin("print").
Doc("prints a value to stdout").
Example(`print("hello, world")`).
Params("value", TypeVar('a')).
Returns(TypeVar('n')).
Impl(func(ctx context.Context, args Args) (Value, error) {
val, _ := args.Get("value")
writer := ioctx.StdoutFromContext(ctx)
fmt.Fprintln(writer, val.String())
return NullValue{}, nil
})
Method(StringType, "toUpper").
Doc("converts a string to uppercase").
Example(`"hello".toUpper`).
Returns(NonNull(StringType)).
Impl(func(ctx context.Context, self Value, args Args) (Value, error) {
str := self.(StringValue).Val
return ToValue(strings.ToUpper(str))
})
Receiver types currently available: StringType, IntType, BooleanType.
Custom scalar receivers dispatch generically: Select.Eval has a
ScalarValue case that resolves builtin methods via
GetMethodKey(v.ScalarType, name) and then the type's Dang-defined methods,
so registering Method(SomeScalarType, ...) on a ScalarValue-backed scalar
needs no new dispatch code.
Before writing a builtin in Go, consider whether it belongs in the
Dang-source prelude (pkg/dang/prelude/*.dang): stdlib expressible in
the core language (string/list manipulation, string-refinement scalars with
methods and a new() hook) lives there — Path is the model. Prelude
members document themselves with a prose docstring plus an @example
directive whose argument is a ```dang fenced template holding a
runnable snippet (enforced + evaluated by TestPreludeExamples), and the
docs reference renders them via the same card machinery. Go builtins remain
for anything needing Go (I/O, regexp engine, crypto/random).
Every builtin must declare .Example(...): a tiny, self-contained snippet of
Dang that evaluates to something illustrative. The stdlib reference renders it
as a pre-seeded, runnable REPL, and two tests enforce it
(pkg/dang/stdlib_examples_test.go): one fails if any builtin lacks an example,
the other parses + type-checks + evaluates every example so it can't drift from
the implementation. Keep examples runnable in the core language only (no GraphQL
imports), and write them as a reader would call the builtin — e.g.
`"a,b,c".split(",")`, `[1, 2, 3].map { x => x * 2 }`,
`Random.int(1, 7)`. A regex example needs a Go double-quoted string since
Dang regex literals use backticks: Example("\"abc123\".containsMatch(`\\d+`)").
Include the default value after the type in Params():
Params(
"separator", NonNull(StringType),
"limit", IntType, IntValue{Val: 0}, // optional, default 0
)
TypeVar(rune) — type variable, e.g. TypeVar('a')NonNull(t) — non-null wrapperListOf(t) — list typeargs.Get(name) (Value, bool), args.GetString, args.GetInt, args.GetBool,
args.GetList, args.Require (panics if missing).
ToValue — the single source of truth for Go→DangUse ToValue(any) (Value, error) to convert Go values. It's shared between
stdlib.go, eval.go (GraphQL result conversion), and ast_expressions.go
(GraphQL field values). If you need a new Go→Dang conversion, extend
ToValue rather than open-coding it.
Supported: nil, any Value, string, all int kinds (float truncates),
bool, []string, []int, []bool, []any (element type inferred).
pkg/dang/stdlib.go inside registerStdlib().go test ./tests/ -run "TestDang/TestLanguage/your_test" -v.