@venn-lang/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +303 -0
- package/dist/index.d.ts +3654 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13137 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/ast/call-args.ts +15 -0
- package/src/ast/dotted-path.ts +22 -0
- package/src/ast/index.ts +7 -0
- package/src/ast/is-statement.ts +40 -0
- package/src/ast/split-call.ts +28 -0
- package/src/ast/walk.ts +6 -0
- package/src/codes/build-problem.ts +24 -0
- package/src/codes/catalog.ts +35 -0
- package/src/codes/code.types.ts +7 -0
- package/src/codes/index.ts +3 -0
- package/src/compile/compile.ts +169 -0
- package/src/compile/compile.types.ts +40 -0
- package/src/compile/index.ts +3 -0
- package/src/compile/lex-scope.ts +78 -0
- package/src/compile/nodes/binary.ts +56 -0
- package/src/compile/nodes/call.ts +50 -0
- package/src/compile/nodes/collection.ts +83 -0
- package/src/compile/nodes/const-lit.ts +30 -0
- package/src/compile/nodes/fast-binary.ts +71 -0
- package/src/compile/nodes/fn.ts +87 -0
- package/src/compile/nodes/index.ts +8 -0
- package/src/compile/nodes/literal.ts +86 -0
- package/src/compile/nodes/map-fields.ts +79 -0
- package/src/compile/nodes/member.ts +32 -0
- package/src/events/envelope.types.ts +17 -0
- package/src/events/event-data.types.ts +25 -0
- package/src/events/ids.types.ts +10 -0
- package/src/events/index.ts +5 -0
- package/src/events/run-plan.types.ts +18 -0
- package/src/events/status.types.ts +2 -0
- package/src/expand/accepted-kinds.ts +23 -0
- package/src/expand/deco/deco-decorator.ts +77 -0
- package/src/expand/deco/deco-env.ts +24 -0
- package/src/expand/deco/deco.types.ts +43 -0
- package/src/expand/deco/document-decos.ts +64 -0
- package/src/expand/deco/index.ts +7 -0
- package/src/expand/deco/read-signature.ts +57 -0
- package/src/expand/deco/run-body.ts +119 -0
- package/src/expand/decorate-callable.ts +49 -0
- package/src/expand/decorations.ts +41 -0
- package/src/expand/expand.ts +108 -0
- package/src/expand/expand.types.ts +78 -0
- package/src/expand/handles/around-verbs.ts +35 -0
- package/src/expand/handles/binding-verbs.ts +27 -0
- package/src/expand/handles/common-verbs.ts +40 -0
- package/src/expand/handles/fn-verbs.ts +58 -0
- package/src/expand/handles/handle.types.ts +33 -0
- package/src/expand/handles/index.ts +4 -0
- package/src/expand/handles/kind-of.ts +36 -0
- package/src/expand/handles/make-handle.ts +100 -0
- package/src/expand/handles/missing-verb.ts +27 -0
- package/src/expand/handles/runnable-verbs.ts +13 -0
- package/src/expand/handles/type-verbs.ts +56 -0
- package/src/expand/index.ts +40 -0
- package/src/expand/make-context.ts +69 -0
- package/src/expand/node-meta.ts +30 -0
- package/src/expand/node-span.ts +17 -0
- package/src/expand/swap-node.ts +28 -0
- package/src/expand/wrong-kind.ts +102 -0
- package/src/expr/cell.types.ts +25 -0
- package/src/expr/closure.ts +53 -0
- package/src/expr/closure.types.ts +31 -0
- package/src/expr/eval-env.types.ts +9 -0
- package/src/expr/evaluate.ts +18 -0
- package/src/expr/frame.ts +60 -0
- package/src/expr/index.ts +14 -0
- package/src/expr/invoke.ts +140 -0
- package/src/expr/member-value.ts +91 -0
- package/src/expr/methods/index.ts +65 -0
- package/src/expr/methods/list-grouping.ts +107 -0
- package/src/expr/methods/list-methods.ts +57 -0
- package/src/expr/methods/list-selection.ts +142 -0
- package/src/expr/methods/map-extras.ts +87 -0
- package/src/expr/methods/map-methods.ts +17 -0
- package/src/expr/methods/number-methods.ts +29 -0
- package/src/expr/methods/string-extras.ts +66 -0
- package/src/expr/methods/string-methods.ts +32 -0
- package/src/expr/methods/unit-methods.ts +54 -0
- package/src/expr/namespace.ts +20 -0
- package/src/expr/native.types.ts +40 -0
- package/src/expr/operators.ts +91 -0
- package/src/expr/pending.ts +47 -0
- package/src/expr/prelude.ts +75 -0
- package/src/expr/task.ts +71 -0
- package/src/format/format-text.ts +22 -0
- package/src/format/format.types.ts +18 -0
- package/src/format/from-settings.ts +40 -0
- package/src/format/index.ts +5 -0
- package/src/format/organize-header.ts +66 -0
- package/src/format/reindent.ts +35 -0
- package/src/generated/ast.ts +2383 -0
- package/src/generated/grammar.ts +5236 -0
- package/src/generated/module.ts +25 -0
- package/src/grammar/venn.langium +291 -0
- package/src/graph/graph.types.ts +20 -0
- package/src/graph/index.ts +2 -0
- package/src/graph/to-graph.ts +87 -0
- package/src/index.ts +93 -0
- package/src/interpolation/compile-template.ts +40 -0
- package/src/interpolation/index.ts +4 -0
- package/src/interpolation/interpolation.types.ts +18 -0
- package/src/interpolation/scan-interpolations.ts +47 -0
- package/src/interpolation/template.types.ts +19 -0
- package/src/lang/default-services.ts +14 -0
- package/src/lang/index.ts +3 -0
- package/src/lang/venn-lexer.ts +34 -0
- package/src/lang/venn-module.ts +51 -0
- package/src/module/index.ts +5 -0
- package/src/module/specifier.ts +21 -0
- package/src/parse/error-to-problem.ts +43 -0
- package/src/parse/index.ts +3 -0
- package/src/parse/parse-expression.ts +27 -0
- package/src/parse/parse-output.types.ts +8 -0
- package/src/parse/parse.ts +26 -0
- package/src/problem/build-diff.ts +116 -0
- package/src/problem/diff.types.ts +20 -0
- package/src/problem/format-value.ts +40 -0
- package/src/problem/index.ts +8 -0
- package/src/problem/problem-error.ts +15 -0
- package/src/problem/problem.types.ts +21 -0
- package/src/problem/related.types.ts +7 -0
- package/src/problem/severity.types.ts +2 -0
- package/src/problem/span.types.ts +8 -0
- package/src/typecheck/action-signature.ts +53 -0
- package/src/typecheck/builtin-types.ts +63 -0
- package/src/typecheck/builtins.ts +267 -0
- package/src/typecheck/catalog.types.ts +16 -0
- package/src/typecheck/check-deco.ts +174 -0
- package/src/typecheck/check-stmts.ts +151 -0
- package/src/typecheck/check-types.ts +232 -0
- package/src/typecheck/context.ts +31 -0
- package/src/typecheck/imported-types.ts +127 -0
- package/src/typecheck/index.ts +26 -0
- package/src/typecheck/infer.ts +416 -0
- package/src/typecheck/kind-types.ts +79 -0
- package/src/typecheck/member-docs.ts +211 -0
- package/src/typecheck/named-types.ts +57 -0
- package/src/typecheck/prelude-types.ts +152 -0
- package/src/typecheck/reshaped-fns.ts +58 -0
- package/src/typecheck/scheme.ts +75 -0
- package/src/typecheck/seed-params.ts +72 -0
- package/src/typecheck/seed-values.ts +64 -0
- package/src/typecheck/show.ts +64 -0
- package/src/typecheck/solidify.ts +60 -0
- package/src/typecheck/spec-to-type.ts +88 -0
- package/src/typecheck/type-env.ts +46 -0
- package/src/typecheck/type-ref.ts +62 -0
- package/src/typecheck/type.types.ts +168 -0
- package/src/typecheck/unify.ts +192 -0
- package/src/typecheck/unit-types.ts +49 -0
- package/src/units/combine.ts +97 -0
- package/src/units/index.ts +6 -0
- package/src/units/parse-instant.ts +12 -0
- package/src/units/parse-number.ts +48 -0
- package/src/units/unit-guards.ts +16 -0
- package/src/units/unit.types.ts +38 -0
- package/src/value/equals.ts +4 -0
- package/src/value/index.ts +4 -0
- package/src/value/is-numeric.ts +6 -0
- package/src/value/truthiness.ts +9 -0
- package/src/value/value.types.ts +12 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vinicius Borges
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# @venn-lang/core
|
|
2
|
+
|
|
3
|
+
> The Venn compiler: grammar, parser, type checker, expression compiler, decorator expansion, and the `Problem` model.
|
|
4
|
+
|
|
5
|
+
Everything that turns `.vn` text into something another package can run, check or draw lives here.
|
|
6
|
+
The kernel is deliberately small: it knows flows, steps, expressions, types and decorators, and it
|
|
7
|
+
knows nothing about HTTP, browsers or files. Protocols arrive as plugins built on
|
|
8
|
+
[`@venn-lang/sdk`](../sdk); the core only ever sees the tree they decorate.
|
|
9
|
+
|
|
10
|
+
`@venn-lang/core` never imports `node:*`. It is built with `platform: "neutral"` so the same bundle runs
|
|
11
|
+
in Node, in the CLI, and inside the Web Worker that hosts the language server. Its runtime
|
|
12
|
+
dependencies are Langium (parsing) and [`@venn-lang/types`](../types) (the published type vocabulary).
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { checkTypes, parse, toGraph } from "@venn-lang/core";
|
|
18
|
+
|
|
19
|
+
const uri = "file:///hello.vn";
|
|
20
|
+
const source = `flow "Hello" {
|
|
21
|
+
step "Ping" {
|
|
22
|
+
http.get "https://example.com/health"
|
|
23
|
+
expect res.status == 200
|
|
24
|
+
}
|
|
25
|
+
}`;
|
|
26
|
+
|
|
27
|
+
const { ast, problems } = parse(source, { uri });
|
|
28
|
+
const checked = checkTypes(ast, { uri });
|
|
29
|
+
|
|
30
|
+
for (const problem of [...problems, ...checked.problems]) {
|
|
31
|
+
console.log(`${problem.code} ${problem.title} (${problem.span.line}:${problem.span.column})`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const graph = toGraph(ast); // flow -> step -> action/expect, for the node editor
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`parse` is synchronous and touches no filesystem. Error recovery keeps a partial AST, so a file with
|
|
38
|
+
a syntax error still produces a tree the editor can work with.
|
|
39
|
+
|
|
40
|
+
## Module map
|
|
41
|
+
|
|
42
|
+
| Module | Responsibility |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| `grammar/` | `venn.langium`, the whole grammar of the language. The single source the parser is generated from. |
|
|
45
|
+
| `generated/` | Langium output: the AST interfaces, the `isX` type guards, the grammar object and the services module. Regenerated by `pnpm --filter @venn-lang/core langium:generate`. |
|
|
46
|
+
| `lang/` | The Langium services `parse` uses, plus `VennLexer`, which makes newlines significant between statements and suppresses them inside `( )` and `[ ]`. |
|
|
47
|
+
| `parse/` | `parse` and `parseExpression`. Turns text into a `Document` plus VN1xxx problems. |
|
|
48
|
+
| `ast/` | Small readers over the generated tree: `walkAst`, `dottedPath`, `callArgs`, `splitCall`, `isRunnable`. |
|
|
49
|
+
| `problem/` | The `Problem` shape shared by compile diagnostics and runtime failures, with `Span`, `Diff`, `Severity`, `ProblemError` and `buildDiff`. |
|
|
50
|
+
| `codes/` | `CODES`, the catalog of every VNxxxx the kernel can raise, and `buildProblem`. |
|
|
51
|
+
| `expand/` | The expansion phase. Runs every `@decorator` over the tree once, before anything else reads it. |
|
|
52
|
+
| `typecheck/` | Hindley-Milner inference with generics, the `Type` algebra, the plugin `TypeCatalog`, cross-file `importedTypes`, and the prose the editor shows on hover. |
|
|
53
|
+
| `compile/` | Compiles each `Expr` into a `Thunk`, a closure over the environment. Memoised per node, so the tree is walked once and not once per evaluation. |
|
|
54
|
+
| `expr/` | The evaluator surface: `evaluate`, closures and frames, `invoke`, `memberValue`, the built-in method tables, and the prelude values. |
|
|
55
|
+
| `value/` | What a runtime value is, and the three questions asked of one: `truthy`, `strictEquals`, `isNumeric`. |
|
|
56
|
+
| `units/` | Unit-typed values (`300ms`, `2mb`, `50%`, ISO instants) and the arithmetic that keeps units honest. |
|
|
57
|
+
| `interpolation/` | `${…}` placeholders, described once for both the evaluator and the editor. |
|
|
58
|
+
| `format/` | `formatText`, shared by `venn fmt` and the language server so both agree on the result. |
|
|
59
|
+
| `graph/` | `toGraph`: a pure AST transform into nodes and edges for the visual editor. |
|
|
60
|
+
| `events/` | The event envelope the runner emits and the UI consumes. Types only, no runtime. |
|
|
61
|
+
| `module/` | Which of the three kinds an import specifier is: relative, alias or package. |
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
### Parsing
|
|
66
|
+
|
|
67
|
+
| Export | What it gives you |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `parse(text, { uri? })` | `ParseOutput`: the `Document` AST and the VN1xxx problems. |
|
|
70
|
+
| `parseExpression(source)` | An `Expr` for a standalone expression, or `undefined` when it is not one. |
|
|
71
|
+
| `EXPRESSION_OFFSET` | How far `parseExpression` shifts CST offsets, so a caller can map back onto the `${…}` it came from. |
|
|
72
|
+
| `vennServices()` / `createVennServices()` | The Langium services, cached and fresh respectively. |
|
|
73
|
+
| `VennLexer` | The lexer that suppresses newlines inside brackets. |
|
|
74
|
+
| `VennGeneratedModule`, `VennGeneratedSharedModule`, `VennLanguageMetaData` | The generated Langium modules, for a host that builds its own services. |
|
|
75
|
+
|
|
76
|
+
Everything from `generated/ast.ts` is re-exported: `Document`, `FlowDecl`, `StepDecl`, `ActionCall`,
|
|
77
|
+
`ExpectStmt`, `FnDecl`, `DecoDecl`, `Expr` and the rest, each with its `isX` guard.
|
|
78
|
+
|
|
79
|
+
The AST readers exist because the grammar spells some things two ways:
|
|
80
|
+
|
|
81
|
+
| Export | What it answers |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `callArgs(call)` | The arguments of a call as one list, whether it was written `http.get "url"` or `conn.close()`. |
|
|
84
|
+
| `splitCall(args, takes)` | Which trailing `{ … }` is an options map and which is a real argument. |
|
|
85
|
+
| `dottedPath(expr)` | The dotted name an expression spells (`http.get`), or `undefined` when it is not a plain chain. |
|
|
86
|
+
| `isRunnable(decl)` | Whether a top-level node runs or merely defines. |
|
|
87
|
+
| `walkAst(root)` | Every descendant, depth first. |
|
|
88
|
+
|
|
89
|
+
### Problems and codes
|
|
90
|
+
|
|
91
|
+
Every failure, at compile time or at run time, is a `Problem`: a stable `code`, a `severity`, a
|
|
92
|
+
one-line `title` in the user's vocabulary, a `span`, and optional `help`, `related`, `diff`, `note`
|
|
93
|
+
and `docs`. One shape means one renderer serves the terminal, the editor and the UI.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { buildProblem, CODES, ProblemError } from "@venn-lang/core";
|
|
97
|
+
|
|
98
|
+
throw new ProblemError(
|
|
99
|
+
buildProblem({
|
|
100
|
+
spec: CODES.VN6001_ASSERTION_FAILED,
|
|
101
|
+
span: { uri, offset: 0, length: 0, line: 1, column: 1 },
|
|
102
|
+
title: "The response did not arrive before the deadline",
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| Family | Covers |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `VN1xxx` | Lexical and syntactic. |
|
|
110
|
+
| `VN2xxx` | Name resolution, imports, decorators, capability negotiation. |
|
|
111
|
+
| `VN3xxx` | Types and units. |
|
|
112
|
+
| `VN4xxx` | Concurrency and isolation. |
|
|
113
|
+
| `VN5xxx` | Lint. |
|
|
114
|
+
| `VN6xxx` | Assertions, at run time. |
|
|
115
|
+
| `VN7xxx` | Actions and protocols, at run time. |
|
|
116
|
+
| `VN8xxx` | Timeouts and resource limits. |
|
|
117
|
+
|
|
118
|
+
`CODES` holds the codes the kernel itself raises, from `VN1001_LEX` to `VN8002_LOOP_LIMIT`. Plugins
|
|
119
|
+
add their own in the same families. `buildDiff` turns two compared values into a structured `Diff`,
|
|
120
|
+
walking them field by field when they line up, so a failure names the field that moved instead of
|
|
121
|
+
printing two renderings side by side. `formatValue` renders a single value for a report.
|
|
122
|
+
|
|
123
|
+
### Type checking
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { checkTypes, showType } from "@venn-lang/core";
|
|
127
|
+
|
|
128
|
+
const { problems, types, slots } = checkTypes(ast, { uri, catalog, decos, imports });
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`checkTypes` runs Hindley-Milner inference over the whole document. Functions are generalised, so one
|
|
132
|
+
`fn id(x) => x` serves every type; `dynamic` unifies with everything and never errors, so a plugin
|
|
133
|
+
result or a parsed HTTP response places no annotation burden on the pure parts of a file. It returns
|
|
134
|
+
the problems, every expression's inferred type keyed by node (for hover), and the expressions parsed
|
|
135
|
+
out of each string literal's `${…}` slots.
|
|
136
|
+
|
|
137
|
+
`CheckTypesOptions` is how the checker learns about the world outside the file: `catalog` (what the
|
|
138
|
+
loaded plugins publish), `decos` (the `pub deco`s the imports reach) and `imports` (what each
|
|
139
|
+
imported name turned out to be).
|
|
140
|
+
|
|
141
|
+
| Export | Purpose |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| `Type`, `FnType`, `RecordType`, `UnionType`, `OpaqueType`, `LiteralType` | The type algebra. |
|
|
144
|
+
| `DYNAMIC`, `literal`, `opaque`, `union` | Constructors for the ones a caller builds by hand. |
|
|
145
|
+
| `prune` | Follow a type variable to what it has been solved to. |
|
|
146
|
+
| `showType`, `showTypes` | Render types for a hover or a diagnostic. `showTypes` names variables across a group, so two unrelated parameters are not both called `a`. |
|
|
147
|
+
| `TypeCatalog` | The two questions the core asks about plugins: `typeOf(name)` and `signatureOf(target)`. |
|
|
148
|
+
| `specToType`, `ResolveRef` | Read a published `TypeSpec` from [`@venn-lang/types`](../types) into the checker's own type. |
|
|
149
|
+
| `importedTypes`, `ImportedTypes` | The types of the names a document imports, worked out from the files it names. Cycles answer with nothing rather than looping. |
|
|
150
|
+
| `memberType`, `resolveMember` | The type of `xs.map`, `s.length`, `p.name`. |
|
|
151
|
+
| `createContext` | Fresh per-check inference state, so two checks never share variable ids. |
|
|
152
|
+
| `BUILTIN_TYPES`, `isBuiltinType` | `string`, `number`, `bool`, `duration`, `size`, `percent`, `instant` and friends, each with a line of documentation and an example. |
|
|
153
|
+
| `PRELUDE_SPECS`, `isPrelude`, `PreludeSpec`, `PreludeArg` | The prelude, described once: types for the checker, prose for the editor. |
|
|
154
|
+
| `MEMBER_DOCS`, `MemberDoc`, `memberKind` | What each built-in member does, for completion and hover. |
|
|
155
|
+
| `KIND_SPECS`, `KIND_TYPES` | What a decorator target handle offers, published as types. |
|
|
156
|
+
|
|
157
|
+
### Compiling and evaluating expressions
|
|
158
|
+
|
|
159
|
+
An expression is compiled once into a `Thunk`, a function of the environment. Everything the source
|
|
160
|
+
settles (which operator, which literal, which slot a name lives in) is decided at compile time.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import { evaluate, type EvalEnv } from "@venn-lang/core";
|
|
164
|
+
|
|
165
|
+
const env: EvalEnv = { lookup: (name) => (name === "res" ? { status: 200 } : undefined) };
|
|
166
|
+
evaluate(subject, env); // true, for `res.status == 200`
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Export | Purpose |
|
|
170
|
+
| --- | --- |
|
|
171
|
+
| `compileExpr(expr)` | The compiled `Thunk`. Memoised per node. |
|
|
172
|
+
| `closureOfDecl(decl, env)` | A top-level `fn` as a callable value bound into an environment. |
|
|
173
|
+
| `evaluate(expr, env)` | Compile if needed, then run. The seam every caller uses. |
|
|
174
|
+
| `EvalEnv` | One method, `lookup(name)`. Actions and matchers are not here: they belong to the runtime registry. |
|
|
175
|
+
| `childEnv(parent, bindings)` | A nested scope. |
|
|
176
|
+
| `Cell`, `CellEnv`, `hasCells` | Bindings addressed by cell, which is what lets a recursive `fn` capture itself. |
|
|
177
|
+
| `invoke`, `invoke1`, `callClosure`, `isCallable` | Calling a Venn callable, with fixed arities for the hot paths. |
|
|
178
|
+
| `Closure`, `isClosure`, `NativeFn`, `nativeFn`, `isNativeFn` | The two kinds of callable. |
|
|
179
|
+
| `memberValue(receiver, member)` | What `.x` means on any value: a map's own data first, then the built-in member tables. |
|
|
180
|
+
| `namespaceValue`, `isNamespaceValue` | A plugin namespace as a value, so `fmt.table(rows)` works inside any expression. |
|
|
181
|
+
| `PRELUDE_VALUES` | `range`, `str`, `typeOf`, `pretty`, `spawn`. |
|
|
182
|
+
| `display(value)`, `typeName(value)` | How `print` renders a value, and what the language calls its type. |
|
|
183
|
+
|
|
184
|
+
`Value` (from `value/`) is the shape a runtime value can take, with `truthy`, `strictEquals` and
|
|
185
|
+
`isNumeric` alongside it. There is no coercion: `"99.00"` never equals `99`.
|
|
186
|
+
|
|
187
|
+
### Decorator expansion
|
|
188
|
+
|
|
189
|
+
`expand` is the phase between parsing and everything else. It is the only place a `@name` means
|
|
190
|
+
anything. The kernel does not know what `@retry` is; it knows that a name written with an `@` is
|
|
191
|
+
looked up in a `DecoratorSource`, handed the node it sits on, and allowed to rewrite it. Decorators
|
|
192
|
+
written in TypeScript by a plugin and decorators written in Venn with `deco` go through the same
|
|
193
|
+
door.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
import { expand } from "@venn-lang/core";
|
|
197
|
+
|
|
198
|
+
const { problems } = expand({ document: ast, decorators, uri, imported });
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Applied innermost first, so a decorator that rewrites a body finds a body its own decorators have
|
|
202
|
+
already finished with. An `ExpandContext` gives a decorator the node, its evaluated `args`, the same
|
|
203
|
+
arguments as syntax in `written`, the `parent`, and four verbs: `replace`, `remove`, `meta` and
|
|
204
|
+
`reject`.
|
|
205
|
+
|
|
206
|
+
| Export | Purpose |
|
|
207
|
+
| --- | --- |
|
|
208
|
+
| `expand`, `ExpandResult`, `ExpandContext`, `DecoratorDefinition`, `DecoratorSource`, `DecoratedNode`, `NodeMeta` | The mechanism and its contracts. |
|
|
209
|
+
| `TargetKind`, `TARGET_KINDS`, `isTargetKind`, `kindOf` | The words a `deco` uses about what it decorates: `Fn`, `Flow`, `Step`, `Binding`, `Type`, `Node`. `kindOf` is the one place that vocabulary meets the compiler's `$type` names. |
|
|
210
|
+
| `makeHandle`, `handleSurface`, `TargetHandle`, `HandleSurface` | The value a `deco` body holds for its target, and what it publishes. |
|
|
211
|
+
| `readSignature`, `DecoSignature`, `SignatureResult`, `acceptedKinds`, `decoTarget` | Reading what a `deco` decorates off the type of its first parameter. |
|
|
212
|
+
| `decoDecorator`, `withDocumentDecos`, `ImportedDeco`, `DocumentDecoArgs`, `decoCannotCall`, `DecoBodyArgs` | Turning a `deco` declaration, local or imported, into a definition expansion can run. |
|
|
213
|
+
| `metaOf`, `readMeta`, `writeMeta` | Facts a decorator leaves on a node for the runtime. Non-enumerable, so they never land in a serialised AST. |
|
|
214
|
+
| `readDecorations`, `addDecoration`, `AROUND_KEYS`, `Decorations`, `decorateCallable` | Where `.wrap`, `.before` and `.after` leave their closures, and how a callable picks them up. |
|
|
215
|
+
| `swapNode`, `spanOf` | Replacing a node in its container, and locating one. |
|
|
216
|
+
| `wrongKind`, `wrongKindTitle`, `wrongTargetTitle`, `kindWords`, `nodeWord`, `everyKindWritten` | The prose behind VN2014, phrased in the author's words rather than in node type names. |
|
|
217
|
+
|
|
218
|
+
### Units
|
|
219
|
+
|
|
220
|
+
A number literal may carry a unit, and the unit survives arithmetic.
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
expect res.duration < 300ms
|
|
224
|
+
expect res.size <= 2mb
|
|
225
|
+
const rate = 99.9%
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`parseNumber` turns a NUMBER lexeme into a plain number or a `UnitValue`; `parseInstant` turns an
|
|
229
|
+
ISO-8601 lexeme into an `Instant` that keeps its source text. `combine({ op, left, right })` does the
|
|
230
|
+
arithmetic and comparison: `300ms + 1s` succeeds, `300ms + 2mb` returns the mismatch behind VN3012.
|
|
231
|
+
`isUnitValue` and `isInstant` are the guards. Canonical bases are milliseconds, bytes, a ratio from 0
|
|
232
|
+
to 1, and epoch milliseconds.
|
|
233
|
+
|
|
234
|
+
### Interpolation
|
|
235
|
+
|
|
236
|
+
`scanInterpolations(text)` locates every `${…}` precisely enough to highlight, hover and jump to.
|
|
237
|
+
`compileTemplate(text)` splits a literal once into its constant `chunks` and its `holes`, each hole
|
|
238
|
+
carrying both its source and its parsed `Expr`. There is always exactly one more chunk than holes, so
|
|
239
|
+
rejoining them cannot drop text. Both are cached by text, because a `.vn` file holds a fixed set of
|
|
240
|
+
string literals.
|
|
241
|
+
|
|
242
|
+
### Formatting
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
import { DEFAULT_FORMAT, formatOptionsFrom, formatText } from "@venn-lang/core";
|
|
246
|
+
|
|
247
|
+
formatText(source, { indentWidth: 4 });
|
|
248
|
+
formatText(source, formatOptionsFrom(manifest.format)); // the [format] table of venn.toml
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`formatText` re-indents by bracket depth and, by default, moves every `use` above every `import`. It
|
|
252
|
+
never joins or splits lines, and it is idempotent. `organizeHeader` and `reindent` are the two steps
|
|
253
|
+
on their own.
|
|
254
|
+
|
|
255
|
+
### Graph and events
|
|
256
|
+
|
|
257
|
+
`toGraph(document)` derives the node graph from the AST: a `flow` contains its steps, a step contains
|
|
258
|
+
its actions and expectations, and sequential edges run between siblings. Pure, with no runtime state.
|
|
259
|
+
|
|
260
|
+
The `events/` module is types only: `Envelope` is the single contract between runner, host and UI,
|
|
261
|
+
carrying a monotonic `seq`, a timestamp, a `RunId`, a kind and its payload. `EventKind` is derived
|
|
262
|
+
from the keys of `EventData`, so adding an event is one edit. `RunPlan` is what the UI draws in grey
|
|
263
|
+
before anything executes.
|
|
264
|
+
|
|
265
|
+
### Modules
|
|
266
|
+
|
|
267
|
+
`specifierKind(spec)` classifies an import specifier the way Node does: `./util.vn` is relative,
|
|
268
|
+
`#shared/auth.vn` is an alias resolved through `[paths]`, and a bare name is an installed package.
|
|
269
|
+
`isPackageSpecifier` is the common question asked of it.
|
|
270
|
+
|
|
271
|
+
## Grammar
|
|
272
|
+
|
|
273
|
+
The grammar lives in [`src/grammar/venn.langium`](src/grammar/venn.langium) and is the fixed part of
|
|
274
|
+
the language. It knows `flow`, `step`, `group`, `fragment`, `fn`, `deco`, `type`, `config`, `matrix`,
|
|
275
|
+
control flow, lifecycle hooks, `expect`, and one rule that absorbs every protocol present and future:
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
ActionCall:
|
|
279
|
+
target=QualifiedName (called?='(' (call=ArgList)? ')')?
|
|
280
|
+
(args+=ActionArg)* (opts=MapLit)?;
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
That is why `http.get "url" { headers }` needs no grammar change to exist. Whether a dotted target is
|
|
284
|
+
a plugin verb or a method on something in scope is decided by what the name resolves to, not by how
|
|
285
|
+
the call is written.
|
|
286
|
+
|
|
287
|
+
Statements are terminated by a newline or `;`. The lexer drops those inside `( )` and `[ ]`, so an
|
|
288
|
+
argument list or a list literal may still span lines, while blocks and maps keep their newlines.
|
|
289
|
+
|
|
290
|
+
Regenerate the parser after editing the grammar:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
pnpm --filter @venn-lang/core langium:generate
|
|
294
|
+
pnpm --filter @venn-lang/core test
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## See also
|
|
298
|
+
|
|
299
|
+
- [`@venn-lang/runtime`](../runtime) walks the checked document and executes it.
|
|
300
|
+
- [`@venn-lang/types`](../types) is the type vocabulary as plain data, shared with plugins.
|
|
301
|
+
- [`@venn-lang/lsp`](../lsp) reuses the parser, checker and formatter to serve editors.
|
|
302
|
+
- [`docs/venn-language.md`](../../docs/venn-language.md) is the language specification;
|
|
303
|
+
[`docs/type-system.md`](../../docs/type-system.md) covers the types.
|