UNPKG

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