UNPKG

6.02 kBPlain TextView Raw
1import type { CompileTimeComponent } from '../../index.js';
2import type { Nullable } from '../core.js';
3import type { CompileTimeConstants } from '../program.js';
4import type { HandleResult, NamedBlocks } from '../template.js';
5import type { VmMachineOp as MachineOp, VmOp as Op } from '../vm-opcodes.js';
6import type { SingleBuilderOperand } from './operands.js';
7import type * as WireFormat from './wire-format/api.js';
8
9// These values are used in the same space as standard opcodes, so we need to
10// start them at a higher value to prevent collisions
11export type HighLevelLabel = 1000;
12export type HighLevelStartLabels = 1001;
13export type HighLevelStopLabels = 1002;
14export type HighLevelStart = HighLevelLabel;
15export type HighLevelEnd = HighLevelStopLabels;
16
17export type HighLevelBuilderOpcode = HighLevelLabel | HighLevelStartLabels | HighLevelStopLabels;
18
19export type HighLevelResolveModifier = 1003;
20export type HighLevelResolveComponent = 1004;
21export type HighLevelResolveHelper = 1005;
22export type HighLevelResolveComponentOrHelper = 1007;
23export type HighLevelResolveOptionalComponentOrHelper = 1008;
24export type HighLevelResolveLocal = 1010;
25export type HighLevelResolveTemplateLocal = 1011;
26export type HighLevelResolveStart = HighLevelResolveModifier;
27export type HighLevelRevolveEnd = HighLevelResolveTemplateLocal;
28
29export type HighLevelResolutionOpcode =
30 | HighLevelResolveModifier
31 | HighLevelResolveComponent
32 | HighLevelResolveHelper
33 | HighLevelResolveComponentOrHelper
34 | HighLevelResolveOptionalComponentOrHelper
35 | HighLevelResolveLocal
36 | HighLevelResolveTemplateLocal;
37
38export interface SimpleArgsOptions {
39 positional: Nullable<WireFormat.Core.Params>;
40 named: Nullable<WireFormat.Core.Hash>;
41 atNames: boolean;
42}
43
44export interface ArgsOptions extends SimpleArgsOptions {
45 named: WireFormat.Core.Hash;
46 blocks: NamedBlocks;
47}
48
49export type StartLabelsOp = [op: HighLevelStartLabels];
50
51export type StopLabelsOp = [op: HighLevelStopLabels];
52
53export type LabelOp = [op: HighLevelLabel, op1: string];
54
55export type HighLevelBuilderOp = StartLabelsOp | StopLabelsOp | LabelOp;
56
57export type ResolveModifierOp = [
58 op: HighLevelResolveModifier,
59 op1: WireFormat.Expressions.Expression,
60 op2: (handle: number) => void,
61];
62
63export type ResolveComponentOp = [
64 op: HighLevelResolveComponent,
65 op1: WireFormat.Expressions.Expression,
66 op2: (component: CompileTimeComponent) => void,
67];
68
69export type ResolveComponentOrHelperOp = [
70 op: HighLevelResolveComponentOrHelper,
71 op1: WireFormat.Expressions.Expression,
72 op2: {
73 ifComponent: (component: CompileTimeComponent) => void;
74 ifHelper: (handle: number) => void;
75 },
76];
77
78export type ResolveHelperOp = [
79 op: HighLevelResolveHelper,
80 op1: WireFormat.Expressions.Expression,
81 op2: (handle: number) => void,
82];
83
84export type ResolveOptionalComponentOrHelperOp = [
85 op: HighLevelResolveOptionalComponentOrHelper,
86 op1: WireFormat.Expressions.Expression,
87 op2: {
88 ifComponent: (component: CompileTimeComponent) => void;
89 ifHelper: (handle: number) => void;
90 ifValue: (handle: number) => void;
91 },
92];
93
94export type ResolveTemplateLocalOp = [
95 op: HighLevelResolveTemplateLocal,
96 op1: number,
97 op2: (handle: number) => void,
98];
99
100export type ResolveLocalOp = [
101 op: HighLevelResolveLocal,
102 op1: number,
103 op2: (name: string, moduleName: string) => void,
104];
105
106export type HighLevelResolutionOp =
107 | ResolveModifierOp
108 | ResolveComponentOp
109 | ResolveComponentOrHelperOp
110 | ResolveHelperOp
111 | ResolveOptionalComponentOrHelperOp
112 | ResolveTemplateLocalOp
113 | ResolveLocalOp;
114
115export type HighLevelOp = HighLevelBuilderOp | HighLevelResolutionOp;
116
117export type BuilderOpcode = Op | MachineOp;
118
119export type BuilderOp = [
120 op: BuilderOpcode,
121 op1?: SingleBuilderOperand,
122 op1?: SingleBuilderOperand,
123 op1?: SingleBuilderOperand,
124];
125
126export interface EncoderError {
127 problem: string;
128 span: {
129 start: number;
130 end: number;
131 };
132}
133
134/**
135 * The Encoder receives a stream of opcodes from the syntax compiler and turns
136 * them into a binary program.
137 */
138export interface Encoder {
139 /**
140 * Finalize the current compilation unit, add a `(Return)`, and push the opcodes from
141 * the buffer into the program. At this point, some of the opcodes might still be
142 * placeholders, such as in the case of recursively compiled templates.
143 *
144 * @param compiler
145 * @param size
146 */
147 commit(size: number): HandleResult;
148
149 /**
150 * Push a syscall into the program with up to three optional
151 * operands.
152 *
153 * @param opcode
154 * @param args up to three operands, formatted as
155 * { type: "type", value: value }
156 */
157 push(
158 constants: CompileTimeConstants,
159 opcode: BuilderOpcode,
160 ...args: SingleBuilderOperand[]
161 ): void;
162
163 /**
164 * Start a new labels block. A labels block is a scope for labels that
165 * can be referred to before they are declared. For example, when compiling
166 * an `if`, the `JumpUnless` opcode occurs before the target label. To
167 * accommodate this use-case ergonomically, the `Encoder` allows a syntax
168 * to create a labels block and then refer to labels that have not yet
169 * been declared. Once the block is complete, a second pass replaces the
170 * label names with offsets.
171 *
172 * The pattern is:
173 *
174 * ```ts
175 * encoder.reserve(Op.JumpUnless);
176 * encoder.target(encoder.pos, 'ELSE');
177 * ```
178 *
179 * The `reserve` method creates a placeholder opcode with space for a target
180 * in the future, and the `target` method registers the blank operand position
181 * to be replaced with an offset to `ELSE`, once it's known.
182 */
183 startLabels(): void;
184
185 /**
186 * Finish the current labels block and replace label names with offsets,
187 * now that all of the offsets are known.
188 */
189 stopLabels(): void;
190
191 /**
192 * Mark the current position with a label name. This label name
193 * can be used by any other opcode in this label block.
194 * @param name
195 * @param index
196 */
197 label(name: string): void;
198
199 error(error: EncoderError): void;
200}