@smoothbricks/lmao-ttsc 0.0.0-bootstrap.0 → 0.1.6

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.
@@ -0,0 +1,453 @@
1
+ // taginline.go — spec 01o §4 tag-chain inlining (smoo/lmao!n/transformer-tag-chain-inline)
2
+ //
3
+ // Checker-backed tag-chain inliner: rewrites statement-level
4
+ // `ctx.tag.a(x).b(y).with({...})` chains into a Block of direct columnar
5
+ // buffer writes (null-bitmap |= 1, values[0] = v), with enum indices folded
6
+ // to constants for literal arguments and switch-IIFEs for dynamic ones.
7
+ //
8
+ // Conservative by construction — the chain is transformed ONLY when the tsgo
9
+ // Checker proves the receiver of `.tag` is a TagWriter/GeneratedTagWriter;
10
+ // anything unprovable is left untouched (the runtime fluent path is always
11
+ // correct, just slower). Column names are the library-local (unprefixed)
12
+ // names per spec 01e — remapping is cold-path-only via RemappedBufferView.
13
+ //
14
+ // Output-shape parity with the TS inliner is the invariant (spec 01o: "the
15
+ // running invariant is the transformed output the tests assert"): all plain
16
+ // tag calls emit first in execution order, then .with() calls unrolled, each
17
+ // via the same boolean/enum/direct write shapes.
18
+ package main
19
+
20
+ import (
21
+ "sort"
22
+ "strings"
23
+
24
+ shimast "github.com/microsoft/typescript-go/shim/ast"
25
+ shimchecker "github.com/microsoft/typescript-go/shim/checker"
26
+ )
27
+
28
+ var tagWriterTypeNames = []string{"TagWriter", "GeneratedTagWriter"}
29
+
30
+ type schemaFieldKind int
31
+
32
+ const (
33
+ fieldDirect schemaFieldKind = iota // category/text/number: direct value write
34
+ fieldBool
35
+ fieldEnum
36
+ )
37
+
38
+ type schemaField struct {
39
+ kind schemaFieldKind
40
+ enumValues []string // sorted, for fieldEnum
41
+ eager bool
42
+ }
43
+
44
+ type tagWrite struct {
45
+ field string
46
+ arg *shimast.Node
47
+ }
48
+
49
+ // --- chain detection ---------------------------------------------------------
50
+
51
+ // findTagChain walks receiver-wards from the outermost call. Returns the ctx
52
+ // expression and the writes in execution order (plain tag calls first, then
53
+ // unrolled with() properties — matching the TS inliner), or ok=false.
54
+ func (t *fileTransformer) findTagChain(call *shimast.CallExpression) (ctxExpr *shimast.Node, writes []tagWrite, schema map[string]schemaField, ok bool) {
55
+ if t.checker == nil {
56
+ return nil, nil, nil, false
57
+ }
58
+ var tagCalls []tagWrite
59
+ var withProps [][]tagWrite
60
+ current := call
61
+ for {
62
+ expr := current.Expression
63
+ if expr.Kind != shimast.KindPropertyAccessExpression {
64
+ return nil, nil, nil, false
65
+ }
66
+ pa := expr.AsPropertyAccessExpression()
67
+ name := shimast.NodeText(pa.Name())
68
+
69
+ if name == "with" {
70
+ if len(current.Arguments.Nodes) != 1 || current.Arguments.Nodes[0].Kind != shimast.KindObjectLiteralExpression {
71
+ return nil, nil, nil, false // non-literal with(): can't unroll
72
+ }
73
+ var props []tagWrite
74
+ for _, prop := range current.Arguments.Nodes[0].AsObjectLiteralExpression().Properties.Nodes {
75
+ if prop.Kind != shimast.KindPropertyAssignment {
76
+ continue // spreads/shorthand/computed: skip (TS parity)
77
+ }
78
+ p := prop.AsPropertyAssignment()
79
+ nameNode := p.Name()
80
+ if nameNode.Kind != shimast.KindIdentifier && nameNode.Kind != shimast.KindStringLiteral {
81
+ continue
82
+ }
83
+ props = append(props, tagWrite{field: shimast.NodeText(nameNode), arg: p.Initializer})
84
+ }
85
+ withProps = append([][]tagWrite{props}, withProps...)
86
+ } else {
87
+ if len(current.Arguments.Nodes) != 1 {
88
+ return nil, nil, nil, false
89
+ }
90
+ tagCalls = append([]tagWrite{{field: name, arg: current.Arguments.Nodes[0]}}, tagCalls...)
91
+ }
92
+
93
+ next := pa.Expression
94
+ if next.Kind == shimast.KindCallExpression {
95
+ current = next.AsCallExpression()
96
+ continue
97
+ }
98
+ // Chain root: must be `<ctx>.tag` and the Checker must prove TagWriter.
99
+ if next.Kind != shimast.KindPropertyAccessExpression {
100
+ return nil, nil, nil, false
101
+ }
102
+ rootPA := next.AsPropertyAccessExpression()
103
+ if shimast.NodeText(rootPA.Name()) != "tag" {
104
+ return nil, nil, nil, false
105
+ }
106
+ tagType := t.checker.GetTypeAtLocation(next)
107
+ if tagType == nil || !isTagWriterType(t.checker, tagType) {
108
+ return nil, nil, nil, false
109
+ }
110
+ schema = extractSchema(t.checker, tagType)
111
+ writes = tagCalls
112
+ for _, props := range withProps {
113
+ writes = append(writes, props...)
114
+ }
115
+ if len(writes) == 0 {
116
+ return nil, nil, nil, false
117
+ }
118
+ return rootPA.Expression, writes, schema, true
119
+ }
120
+ }
121
+
122
+ func isTagWriterType(chk *shimchecker.Checker, t *shimchecker.Type) bool {
123
+ name := chk.TypeToString(t)
124
+ for _, w := range tagWriterTypeNames {
125
+ if name == w || strings.HasPrefix(name, w+"<") {
126
+ return true
127
+ }
128
+ }
129
+ if sym := shimchecker.Type_getTypeNameSymbol(t); sym != nil {
130
+ for _, w := range tagWriterTypeNames {
131
+ if sym.Name == w {
132
+ return true
133
+ }
134
+ }
135
+ }
136
+ return false
137
+ }
138
+
139
+ // extractSchema mirrors extractSchemaFromTagType: per property, the first
140
+ // call-signature parameter's type decides the field kind; `_eager: true` on
141
+ // the property type marks eager columns.
142
+ func extractSchema(chk *shimchecker.Checker, tagType *shimchecker.Type) map[string]schemaField {
143
+ schema := map[string]schemaField{}
144
+ for _, sym := range shimchecker.Checker_getPropertiesOfType(chk, tagType) {
145
+ name := sym.Name
146
+ if name == "with" || strings.HasPrefix(name, "_") {
147
+ continue
148
+ }
149
+ propType := shimchecker.Checker_getTypeOfSymbol(chk, sym)
150
+ sigs := shimchecker.Checker_getSignaturesOfType(chk, propType, shimchecker.SignatureKindCall)
151
+ if len(sigs) == 0 {
152
+ continue
153
+ }
154
+ params := shimchecker.Signature_parameters(sigs[0])
155
+ if len(params) == 0 {
156
+ continue
157
+ }
158
+ paramType := shimchecker.Checker_getTypeOfSymbol(chk, params[0])
159
+ eager := false
160
+ if et := shimchecker.Checker_getTypeOfPropertyOfType(chk, propType, "_eager"); et != nil {
161
+ eager = chk.TypeToString(et) == "true"
162
+ }
163
+
164
+ if paramType.IsUnion() {
165
+ var values []string
166
+ allLiterals := true
167
+ for _, member := range paramType.Types() {
168
+ if member.IsStringLiteral() {
169
+ if v, isStr := member.AsLiteralType().Value().(string); isStr {
170
+ values = append(values, v)
171
+ continue
172
+ }
173
+ }
174
+ allLiterals = false
175
+ break
176
+ }
177
+ if allLiterals && len(values) > 0 {
178
+ sort.Strings(values) // sorted-order indexing matches runtime dictionaries
179
+ schema[name] = schemaField{kind: fieldEnum, enumValues: values, eager: eager}
180
+ continue
181
+ }
182
+ }
183
+ switch chk.TypeToString(paramType) {
184
+ case "string":
185
+ schema[name] = schemaField{kind: fieldDirect, eager: eager}
186
+ case "number":
187
+ schema[name] = schemaField{kind: fieldDirect, eager: eager}
188
+ case "boolean":
189
+ schema[name] = schemaField{kind: fieldBool, eager: eager}
190
+ }
191
+ }
192
+ return schema
193
+ }
194
+
195
+ // --- code generation ----------------------------------------------------------
196
+
197
+ func isCompileTimeLiteral(n *shimast.Node) bool {
198
+ switch n.Kind {
199
+ case shimast.KindStringLiteral, shimast.KindNumericLiteral, shimast.KindTrueKeyword, shimast.KindFalseKeyword:
200
+ return true
201
+ }
202
+ return false
203
+ }
204
+
205
+ type inlineEmitter struct {
206
+ bufferExpr *shimast.Node // ctx._buffer
207
+ varCounter int
208
+ stmts []*shimast.Node
209
+ }
210
+
211
+ func (e *inlineEmitter) freshVar() *shimast.Node {
212
+ name := "$$v" + itoa(e.varCounter)
213
+ e.varCounter++
214
+ return ident(name)
215
+ }
216
+
217
+ func itoa(n int) string {
218
+ if n == 0 {
219
+ return "0"
220
+ }
221
+ var b [8]byte
222
+ i := len(b)
223
+ for n > 0 {
224
+ i--
225
+ b[i] = byte('0' + n%10)
226
+ n /= 10
227
+ }
228
+ return string(b[i:])
229
+ }
230
+
231
+ // columnAccess builds `<buffer>.<field>_<suffix>[0]`.
232
+ func (e *inlineEmitter) columnAccess(field, suffix string) *shimast.Node {
233
+ return factory.NewElementAccessExpression(
234
+ propAccess(e.bufferExpr, field+"_"+suffix), nil, num(0), shimast.NodeFlagsNone)
235
+ }
236
+
237
+ func binaryStmt(left *shimast.Node, op shimast.Kind, right *shimast.Node) *shimast.Node {
238
+ return factory.NewExpressionStatement(
239
+ factory.NewBinaryExpression(nil, left, nil, factory.NewToken(op), right))
240
+ }
241
+
242
+ func (e *inlineEmitter) emitNullsSet(field string) {
243
+ e.stmts = append(e.stmts, binaryStmt(e.columnAccess(field, "nulls"), shimast.KindBarEqualsToken, num(1)))
244
+ }
245
+
246
+ func (e *inlineEmitter) emitField(w tagWrite, schema map[string]schemaField) {
247
+ info, known := schema[w.field]
248
+ literal := isCompileTimeLiteral(w.arg)
249
+ if known && info.kind == fieldBool {
250
+ e.emitBool(w, info.eager, literal)
251
+ return
252
+ }
253
+ if known && info.kind == fieldEnum {
254
+ e.emitEnum(w, info, literal)
255
+ return
256
+ }
257
+ eager := known && info.eager
258
+ e.emitDirect(w, eager, literal)
259
+ }
260
+
261
+ func (e *inlineEmitter) emitBool(w tagWrite, eager, literal bool) {
262
+ values := func() *shimast.Node { return e.columnAccess(w.field, "values") }
263
+ setTrue := func() *shimast.Node { return binaryStmt(values(), shimast.KindBarEqualsToken, num(1)) }
264
+ setFalse := func() *shimast.Node {
265
+ return binaryStmt(values(), shimast.KindAmpersandEqualsToken,
266
+ factory.NewPrefixUnaryExpression(shimast.KindTildeToken, num(1)))
267
+ }
268
+ if literal {
269
+ if !eager {
270
+ e.emitNullsSet(w.field)
271
+ }
272
+ if w.arg.Kind == shimast.KindTrueKeyword {
273
+ e.stmts = append(e.stmts, setTrue())
274
+ } else {
275
+ e.stmts = append(e.stmts, setFalse())
276
+ }
277
+ return
278
+ }
279
+ v := e.freshVar()
280
+ e.stmts = append(e.stmts, constDecl(v, w.arg))
281
+ var ifBody []*shimast.Node
282
+ if !eager {
283
+ ifBody = append(ifBody, binaryStmt(e.columnAccess(w.field, "nulls"), shimast.KindBarEqualsToken, num(1)))
284
+ }
285
+ ifBody = append(ifBody, factory.NewIfStatement(ident(identText(v)),
286
+ factory.NewBlock(factory.NewNodeList([]*shimast.Node{setTrue()}), false),
287
+ factory.NewBlock(factory.NewNodeList([]*shimast.Node{setFalse()}), false)))
288
+ e.stmts = append(e.stmts, notNullGuard(v, ifBody))
289
+ }
290
+
291
+ func (e *inlineEmitter) emitEnum(w tagWrite, info schemaField, literal bool) {
292
+ if !info.eager {
293
+ e.emitNullsSet(w.field)
294
+ }
295
+ if literal && w.arg.Kind == shimast.KindStringLiteral {
296
+ idx := 0
297
+ for i, v := range info.enumValues {
298
+ if v == shimast.NodeText(w.arg) {
299
+ idx = i
300
+ break
301
+ }
302
+ }
303
+ e.stmts = append(e.stmts, binaryStmt(e.columnAccess(w.field, "values"), shimast.KindEqualsToken, num(idx)))
304
+ return
305
+ }
306
+ e.stmts = append(e.stmts, binaryStmt(e.columnAccess(w.field, "values"), shimast.KindEqualsToken,
307
+ enumSwitchIIFE(w.arg, info.enumValues)))
308
+ }
309
+
310
+ func (e *inlineEmitter) emitDirect(w tagWrite, eager, literal bool) {
311
+ if literal {
312
+ if !eager {
313
+ e.emitNullsSet(w.field)
314
+ }
315
+ e.stmts = append(e.stmts, binaryStmt(e.columnAccess(w.field, "values"), shimast.KindEqualsToken, w.arg))
316
+ return
317
+ }
318
+ v := e.freshVar()
319
+ e.stmts = append(e.stmts, constDecl(v, w.arg))
320
+ var ifBody []*shimast.Node
321
+ if !eager {
322
+ ifBody = append(ifBody, binaryStmt(e.columnAccess(w.field, "nulls"), shimast.KindBarEqualsToken, num(1)))
323
+ }
324
+ ifBody = append(ifBody, binaryStmt(e.columnAccess(w.field, "values"), shimast.KindEqualsToken, ident(identText(v))))
325
+ e.stmts = append(e.stmts, notNullGuard(v, ifBody))
326
+ }
327
+
328
+ func identText(n *shimast.Node) string { return shimast.NodeText(n) }
329
+
330
+ func constDecl(name *shimast.Node, init *shimast.Node) *shimast.Node {
331
+ decl := factory.NewVariableDeclaration(name, nil, nil, init)
332
+ return factory.NewVariableStatement(nil,
333
+ factory.NewVariableDeclarationList(factory.NewNodeList([]*shimast.Node{decl}), shimast.NodeFlagsConst))
334
+ }
335
+
336
+ // notNullGuard builds `if (<v> != null) { <body> }`.
337
+ func notNullGuard(v *shimast.Node, body []*shimast.Node) *shimast.Node {
338
+ cond := factory.NewBinaryExpression(nil, ident(identText(v)), nil,
339
+ factory.NewToken(shimast.KindExclamationEqualsToken),
340
+ factory.NewKeywordExpression(shimast.KindNullKeyword))
341
+ return factory.NewIfStatement(cond, factory.NewBlock(factory.NewNodeList(body), true), nil)
342
+ }
343
+
344
+ // enumSwitchIIFE builds `(($$v) => { switch ($$v) { case 'A': return 0; ... default: return 0; } })(arg)`.
345
+ func enumSwitchIIFE(arg *shimast.Node, values []string) *shimast.Node {
346
+ param := ident("$$v")
347
+ var clauses []*shimast.Node
348
+ for i, v := range values {
349
+ clauses = append(clauses, factory.NewCaseOrDefaultClause(shimast.KindCaseClause, str(v),
350
+ factory.NewNodeList([]*shimast.Node{factory.NewReturnStatement(num(i))})))
351
+ }
352
+ clauses = append(clauses, factory.NewCaseOrDefaultClause(shimast.KindDefaultClause, nil,
353
+ factory.NewNodeList([]*shimast.Node{factory.NewReturnStatement(num(0))})))
354
+ sw := factory.NewSwitchStatement(ident("$$v"), factory.NewCaseBlock(factory.NewNodeList(clauses)))
355
+ arrow := factory.NewArrowFunction(nil, nil,
356
+ factory.NewNodeList([]*shimast.Node{factory.NewParameterDeclaration(nil, nil, param, nil, nil, nil)}),
357
+ nil, nil, factory.NewToken(shimast.KindEqualsGreaterThanToken),
358
+ factory.NewBlock(factory.NewNodeList([]*shimast.Node{sw}), true))
359
+ return factory.NewCallExpression(factory.NewParenthesizedExpression(arrow), nil, nil,
360
+ factory.NewNodeList([]*shimast.Node{arg}), shimast.NodeFlagsNone)
361
+ }
362
+
363
+ // --- two-phase statement-level entry ----------------------------------------------
364
+ //
365
+ // Phase A resolves chains with the Checker over the untouched tree; phase B
366
+ // splices synthesized blocks. Splitting matters: lazy type checking triggered
367
+ // by a phase-A query re-walks whole containing declarations, and would panic
368
+ // on any already-spliced synthesized node (pos -1 source reads).
369
+
370
+ type tagInline struct {
371
+ list *shimast.NodeList
372
+ index int
373
+ ctxExpr *shimast.Node
374
+ writes []tagWrite
375
+ schema map[string]schemaField
376
+ }
377
+
378
+ // collectTagInlines finds every provable tag-chain and log-chain
379
+ // ExpressionStatement. Checker queries happen here and only here; the tree
380
+ // is not modified.
381
+ func (t *fileTransformer) collectTagInlines(root *shimast.Node) ([]tagInline, []logInline, []resultInline) {
382
+ var found []tagInline
383
+ var foundLogs []logInline
384
+ var foundResults []resultInline
385
+ var visit func(node *shimast.Node)
386
+ scanList := func(list *shimast.NodeList) {
387
+ if list == nil {
388
+ return
389
+ }
390
+ for i, stmt := range list.Nodes {
391
+ var inner *shimast.Node
392
+ isReturn := false
393
+ switch stmt.Kind {
394
+ case shimast.KindExpressionStatement:
395
+ inner = stmt.AsExpressionStatement().Expression
396
+ case shimast.KindReturnStatement:
397
+ inner = stmt.AsReturnStatement().Expression
398
+ isReturn = true
399
+ default:
400
+ continue
401
+ }
402
+ if inner == nil || inner.Kind != shimast.KindCallExpression {
403
+ continue
404
+ }
405
+ call := inner.AsCallExpression()
406
+ if !isReturn {
407
+ if ctxExpr, writes, schema, ok := t.findTagChain(call); ok {
408
+ t.processed[call] = true
409
+ found = append(found, tagInline{list: list, index: i, ctxExpr: ctxExpr, writes: writes, schema: schema})
410
+ continue
411
+ }
412
+ if in, ok := t.findLogInline(call); ok {
413
+ t.processed[call] = true
414
+ in.list, in.index = list, i
415
+ foundLogs = append(foundLogs, *in)
416
+ continue
417
+ }
418
+ }
419
+ if in, ok := t.findResultInline(call); ok {
420
+ t.processed[call] = true
421
+ in.list, in.index, in.isReturn = list, i, isReturn
422
+ foundResults = append(foundResults, *in)
423
+ }
424
+ }
425
+ }
426
+ visit = func(node *shimast.Node) {
427
+ if node == nil {
428
+ return
429
+ }
430
+ if node.Kind == shimast.KindSourceFile {
431
+ scanList(node.AsSourceFile().Statements)
432
+ } else if node.CanHaveStatements() {
433
+ scanList(node.StatementList())
434
+ }
435
+ node.ForEachChild(func(child *shimast.Node) bool {
436
+ visit(child)
437
+ return false
438
+ })
439
+ }
440
+ visit(root)
441
+ return found, foundLogs, foundResults
442
+ }
443
+
444
+ // applyTagInlines splices the replacement blocks (phase B — no checker use).
445
+ func (t *fileTransformer) applyTagInlines(inlines []tagInline) {
446
+ for _, in := range inlines {
447
+ e := &inlineEmitter{bufferExpr: propAccess(in.ctxExpr, "_buffer")}
448
+ for _, w := range in.writes {
449
+ e.emitField(w, in.schema)
450
+ }
451
+ in.list.Nodes[in.index] = factory.NewBlock(factory.NewNodeList(e.stmts), true)
452
+ }
453
+ }