@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.
- package/dist/bun-register.d.ts +2 -0
- package/dist/bun-register.d.ts.map +1 -0
- package/dist/bun-register.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/package.json +113 -4
- package/plugin/go.mod +9 -0
- package/plugin/loginline.go +296 -0
- package/plugin/main.go +572 -0
- package/plugin/main_test.go +43 -0
- package/plugin/optimization.go +462 -0
- package/plugin/resultinline.go +211 -0
- package/plugin/taginline.go +453 -0
- package/plugin/template_test.go +264 -0
- package/plugin.cjs +19 -0
- package/plugin.d.cts +5 -0
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bun-register.d.ts","sourceRoot":"","sources":["../src/bun-register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, register } from '@ttsc/unplugin/bun-register';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TtscUnpluginOptions } from '@ttsc/unplugin';
|
|
2
|
+
import type { BunLikePlugin } from '@ttsc/unplugin/bun';
|
|
3
|
+
export declare function createBunTtscPlugin(options?: TtscUnpluginOptions): BunLikePlugin;
|
|
4
|
+
export default createBunTtscPlugin;
|
|
5
|
+
export type { BunLikeBuild, BunLoader } from '@ttsc/unplugin/bun';
|
|
6
|
+
export type { BunLikePlugin, TtscUnpluginOptions };
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKxD,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAahF;eAEc,mBAAmB;AAClC,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as bunAdapterModule from '@ttsc/unplugin/bun';
|
|
2
|
+
const bunAdapter = bunAdapterModule.default;
|
|
3
|
+
export function createBunTtscPlugin(options) {
|
|
4
|
+
if (typeof bunAdapter === 'function') {
|
|
5
|
+
return bunAdapter(options);
|
|
6
|
+
}
|
|
7
|
+
if (typeof bunAdapter === 'object' &&
|
|
8
|
+
bunAdapter !== null &&
|
|
9
|
+
'default' in bunAdapter &&
|
|
10
|
+
typeof bunAdapter.default === 'function') {
|
|
11
|
+
return bunAdapter.default(options);
|
|
12
|
+
}
|
|
13
|
+
throw new TypeError('@ttsc/unplugin/bun did not export a Bun adapter factory');
|
|
14
|
+
}
|
|
15
|
+
export default createBunTtscPlugin;
|
package/package.json
CHANGED
|
@@ -1,14 +1,123 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smoothbricks/lmao-ttsc",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": [
|
|
6
|
+
"./dist/bun-register.js"
|
|
7
|
+
],
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
"./package.json": "./package.json",
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./bun": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./bun-register": {
|
|
21
|
+
"types": "./dist/bun-register.d.ts",
|
|
22
|
+
"import": "./dist/bun-register.js"
|
|
23
|
+
},
|
|
24
|
+
"./ttsc-plugin": {
|
|
25
|
+
"types": "./plugin.d.cts",
|
|
26
|
+
"require": "./plugin.cjs",
|
|
27
|
+
"default": "./plugin.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"ttsc": {
|
|
31
|
+
"plugin": {
|
|
32
|
+
"transform": "@smoothbricks/lmao-ttsc/ttsc-plugin"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"plugin.cjs",
|
|
38
|
+
"plugin.d.cts",
|
|
39
|
+
"plugin",
|
|
40
|
+
"!**/*.tsbuildinfo"
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@ttsc/unplugin": "0.18.4",
|
|
44
|
+
"ttsc": "^0.18.4",
|
|
45
|
+
"typescript": "^7.0.2"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@smoothbricks/lmao": "0.2.1",
|
|
49
|
+
"@smoothbricks/validation": "0.1.2"
|
|
50
|
+
},
|
|
51
|
+
"nx": {
|
|
52
|
+
"sourceRoot": "packages/lmao-ttsc/src",
|
|
53
|
+
"projectType": "library",
|
|
54
|
+
"targets": {
|
|
55
|
+
"lint": {
|
|
56
|
+
"dependsOn": [
|
|
57
|
+
"go-vet",
|
|
58
|
+
"tsc-js",
|
|
59
|
+
"typecheck",
|
|
60
|
+
"typecheck-tests"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"go-vet": {
|
|
64
|
+
"executor": "@smoothbricks/nx-plugin:bounded-exec",
|
|
65
|
+
"cache": true,
|
|
66
|
+
"inputs": [
|
|
67
|
+
"{projectRoot}/plugin/**/*.go",
|
|
68
|
+
"{projectRoot}/plugin/go.mod",
|
|
69
|
+
"{projectRoot}/scripts/gen-go-work.mjs"
|
|
70
|
+
],
|
|
71
|
+
"options": {
|
|
72
|
+
"command": "bun ../scripts/gen-go-work.mjs && go vet ./...",
|
|
73
|
+
"cwd": "{projectRoot}/plugin",
|
|
74
|
+
"timeoutMs": 600000,
|
|
75
|
+
"killAfterMs": 1e4
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"go-test": {
|
|
79
|
+
"executor": "@smoothbricks/nx-plugin:bounded-exec",
|
|
80
|
+
"cache": true,
|
|
81
|
+
"inputs": [
|
|
82
|
+
"{projectRoot}/plugin/**/*.go",
|
|
83
|
+
"{projectRoot}/plugin/go.mod",
|
|
84
|
+
"{projectRoot}/scripts/gen-go-work.mjs"
|
|
85
|
+
],
|
|
86
|
+
"options": {
|
|
87
|
+
"command": "bun ../scripts/gen-go-work.mjs && go test ./...",
|
|
88
|
+
"cwd": "{projectRoot}/plugin",
|
|
89
|
+
"timeoutMs": 600000,
|
|
90
|
+
"killAfterMs": 1e4
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"test": {
|
|
94
|
+
"executor": "@smoothbricks/nx-plugin:bounded-exec",
|
|
95
|
+
"dependsOn": [
|
|
96
|
+
"go-test"
|
|
97
|
+
],
|
|
98
|
+
"options": {
|
|
99
|
+
"command": "bun test --timeout=30000 --parallel=3",
|
|
100
|
+
"cwd": "{projectRoot}",
|
|
101
|
+
"timeoutMs": 120000,
|
|
102
|
+
"killAfterMs": 1e4
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"tags": [
|
|
107
|
+
"npm:public"
|
|
108
|
+
],
|
|
109
|
+
"name": "lmao-ttsc"
|
|
110
|
+
},
|
|
5
111
|
"license": "MIT",
|
|
112
|
+
"publishConfig": {
|
|
113
|
+
"access": "public"
|
|
114
|
+
},
|
|
6
115
|
"repository": {
|
|
7
116
|
"type": "git",
|
|
8
117
|
"url": "git+https://github.com/smoothbricks/codebase.git",
|
|
9
118
|
"directory": "packages/lmao-ttsc"
|
|
10
119
|
},
|
|
11
|
-
"
|
|
12
|
-
"
|
|
120
|
+
"scripts": {
|
|
121
|
+
"test": "nx run lmao-ttsc:test --outputStyle=stream"
|
|
13
122
|
}
|
|
14
123
|
}
|
package/plugin/go.mod
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// loginline.go — partial inlining of statement-level log chains.
|
|
2
|
+
//
|
|
3
|
+
// The SpanBuffer design makes this a PARTIAL inline by construction: row
|
|
4
|
+
// allocation stays runtime (`logger._checkOverflow()` +
|
|
5
|
+
// `buffer._traceRoot.writeLogEntry(buffer, ENTRY_TYPE)` — overflow chaining,
|
|
6
|
+
// capacity tuning, and timestamps live there), while every fluent dispatch
|
|
7
|
+
// after it becomes a direct write at the returned row index through the
|
|
8
|
+
// buffer's STABLE column getters (lazy getters allocate on first access, so
|
|
9
|
+
// the transformer needs no eager/lazy knowledge).
|
|
10
|
+
//
|
|
11
|
+
// ctx.log.info('msg').userId('u1');
|
|
12
|
+
//
|
|
13
|
+
// becomes
|
|
14
|
+
//
|
|
15
|
+
// {
|
|
16
|
+
// const $$l = ctx.log;
|
|
17
|
+
// $$l._checkOverflow();
|
|
18
|
+
// const $$b = $$l._buffer;
|
|
19
|
+
// const $$i = $$b._traceRoot.writeLogEntry($$b, 8);
|
|
20
|
+
// $$l._writeIndex = $$i;
|
|
21
|
+
// if ($$b.message_values) { $$b.message_values[$$i] = 'msg';
|
|
22
|
+
// if ($$b.message_nulls) $$b.message_nulls[$$i >>> 3] |= 1 << ($$i & 7); }
|
|
23
|
+
// $$b.constructor.stats.totalWrites++;
|
|
24
|
+
// if ($$b.line_values) { $$b.line_values[$$i] = 3; ... }
|
|
25
|
+
// if ($$b.userId_values) { $$b.userId_values[$$i] = 'u1'; ... }
|
|
26
|
+
// }
|
|
27
|
+
//
|
|
28
|
+
// Parity contract is the GENERATED SpanLogger source
|
|
29
|
+
// (packages/lmao/src/lib/codegen/spanLoggerGenerator.ts): raw getter writes
|
|
30
|
+
// with the same if-guards for message/line/category/text/number fields;
|
|
31
|
+
// enum and boolean fields go through the buffer's positional method
|
|
32
|
+
// (`$$b.field($$i, v)`) exactly like the generated setters, with the
|
|
33
|
+
// string→index switch constant-folded for literal enum values.
|
|
34
|
+
//
|
|
35
|
+
// Conservative bails (chain left untouched, runtime path is always correct):
|
|
36
|
+
// receiver not Checker-proved SpanLogger/GeneratedSpanLogger, a second
|
|
37
|
+
// log-level call in the same chain, a chained method that is neither a
|
|
38
|
+
// schema field nor line/with, non-single-arg links, non-object-literal
|
|
39
|
+
// with(), or non-statement context.
|
|
40
|
+
package main
|
|
41
|
+
|
|
42
|
+
import (
|
|
43
|
+
"strings"
|
|
44
|
+
|
|
45
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
46
|
+
shimchecker "github.com/microsoft/typescript-go/shim/checker"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
var spanLoggerTypeNames = []string{"SpanLogger", "GeneratedSpanLogger", "FluentLogEntry"}
|
|
50
|
+
|
|
51
|
+
// Entry-type dictionary values, pinned to
|
|
52
|
+
// packages/lmao/src/lib/schema/systemSchema.ts (ENTRY_TYPE_*). The fixture
|
|
53
|
+
// parity test exercises these; a runtime renumbering fails it.
|
|
54
|
+
var logEntryTypes = map[string]int{
|
|
55
|
+
"trace": 6,
|
|
56
|
+
"debug": 7,
|
|
57
|
+
"info": 8,
|
|
58
|
+
"warn": 9,
|
|
59
|
+
"error": 10,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type logInline struct {
|
|
63
|
+
list *shimast.NodeList
|
|
64
|
+
index int
|
|
65
|
+
logExpr *shimast.Node // the `ctx.log` expression
|
|
66
|
+
level string // info/debug/...
|
|
67
|
+
message *shimast.Node
|
|
68
|
+
templateID uint16 // nonzero only for checker-proved Op-local literals
|
|
69
|
+
line int // source line of the log call (spec 01o §6, folded in)
|
|
70
|
+
lineArg *shimast.Node // explicit .line(N) argument if present in source
|
|
71
|
+
writes []tagWrite // chained attribute writes in execution order
|
|
72
|
+
schema map[string]schemaField
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
func isSpanLoggerType(chk *shimchecker.Checker, t *shimchecker.Type) bool {
|
|
76
|
+
name := chk.TypeToString(t)
|
|
77
|
+
for _, w := range spanLoggerTypeNames {
|
|
78
|
+
if name == w || strings.HasPrefix(name, w+"<") {
|
|
79
|
+
return true
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if sym := shimchecker.Type_getTypeNameSymbol(t); sym != nil {
|
|
83
|
+
for _, w := range spanLoggerTypeNames {
|
|
84
|
+
if sym.Name == w {
|
|
85
|
+
return true
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// findLogInline analyzes a statement-level call chain. Checker queries only;
|
|
93
|
+
// no mutation (must run in the collect phase).
|
|
94
|
+
func (t *fileTransformer) findLogInline(call *shimast.CallExpression) (*logInline, bool) {
|
|
95
|
+
if t.checker == nil {
|
|
96
|
+
return nil, false
|
|
97
|
+
}
|
|
98
|
+
type link struct {
|
|
99
|
+
name string
|
|
100
|
+
args []*shimast.Node
|
|
101
|
+
node *shimast.CallExpression
|
|
102
|
+
}
|
|
103
|
+
var links []link
|
|
104
|
+
current := call
|
|
105
|
+
for {
|
|
106
|
+
expr := current.Expression
|
|
107
|
+
if expr.Kind != shimast.KindPropertyAccessExpression {
|
|
108
|
+
return nil, false
|
|
109
|
+
}
|
|
110
|
+
pa := expr.AsPropertyAccessExpression()
|
|
111
|
+
links = append([]link{{name: shimast.NodeText(pa.Name()), args: current.Arguments.Nodes, node: current}}, links...)
|
|
112
|
+
next := pa.Expression
|
|
113
|
+
if next.Kind == shimast.KindCallExpression {
|
|
114
|
+
current = next.AsCallExpression()
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
// Chain root: the receiver of the FIRST link. It must be the log
|
|
118
|
+
// object, Checker-proved.
|
|
119
|
+
if len(links) == 0 || !logMethods[links[0].name] {
|
|
120
|
+
return nil, false
|
|
121
|
+
}
|
|
122
|
+
recvType := t.checker.GetTypeAtLocation(next)
|
|
123
|
+
if recvType == nil || !isSpanLoggerType(t.checker, recvType) {
|
|
124
|
+
return nil, false
|
|
125
|
+
}
|
|
126
|
+
if len(links[0].args) != 1 {
|
|
127
|
+
return nil, false
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
in := &logInline{
|
|
131
|
+
logExpr: next,
|
|
132
|
+
level: links[0].name,
|
|
133
|
+
message: links[0].args[0],
|
|
134
|
+
templateID: t.logTemplateIDs[links[0].node],
|
|
135
|
+
line: t.lineOf(links[0].node.AsNode()),
|
|
136
|
+
schema: extractLogSchema(t.checker, recvType),
|
|
137
|
+
}
|
|
138
|
+
for _, l := range links[1:] {
|
|
139
|
+
switch {
|
|
140
|
+
case logMethods[l.name]:
|
|
141
|
+
return nil, false // second log entry in one chain: bail
|
|
142
|
+
case l.name == "line":
|
|
143
|
+
if len(l.args) != 1 {
|
|
144
|
+
return nil, false
|
|
145
|
+
}
|
|
146
|
+
in.lineArg = l.args[0]
|
|
147
|
+
case l.name == "with":
|
|
148
|
+
if len(l.args) != 1 || l.args[0].Kind != shimast.KindObjectLiteralExpression {
|
|
149
|
+
return nil, false
|
|
150
|
+
}
|
|
151
|
+
for _, prop := range l.args[0].AsObjectLiteralExpression().Properties.Nodes {
|
|
152
|
+
if prop.Kind != shimast.KindPropertyAssignment {
|
|
153
|
+
return nil, false
|
|
154
|
+
}
|
|
155
|
+
p := prop.AsPropertyAssignment()
|
|
156
|
+
nameNode := p.Name()
|
|
157
|
+
if nameNode.Kind != shimast.KindIdentifier && nameNode.Kind != shimast.KindStringLiteral {
|
|
158
|
+
return nil, false
|
|
159
|
+
}
|
|
160
|
+
field := shimast.NodeText(nameNode)
|
|
161
|
+
if _, known := in.schema[field]; !known {
|
|
162
|
+
return nil, false
|
|
163
|
+
}
|
|
164
|
+
in.writes = append(in.writes, tagWrite{field: field, arg: p.Initializer})
|
|
165
|
+
}
|
|
166
|
+
default:
|
|
167
|
+
if len(l.args) != 1 {
|
|
168
|
+
return nil, false
|
|
169
|
+
}
|
|
170
|
+
if _, known := in.schema[l.name]; !known {
|
|
171
|
+
return nil, false // not a schema field setter: bail, never miscompile
|
|
172
|
+
}
|
|
173
|
+
in.writes = append(in.writes, tagWrite{field: l.name, arg: l.args[0]})
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return in, true
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// extractLogSchema reuses the tag schema extraction but excludes the log/system
|
|
181
|
+
// methods that would otherwise classify as string fields.
|
|
182
|
+
func extractLogSchema(chk *shimchecker.Checker, logType *shimchecker.Type) map[string]schemaField {
|
|
183
|
+
schema := extractSchema(chk, logType)
|
|
184
|
+
for name := range logMethods {
|
|
185
|
+
delete(schema, name)
|
|
186
|
+
}
|
|
187
|
+
delete(schema, "line")
|
|
188
|
+
return schema
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// --- emission -------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
// guardedRawWrite emits the generated-setter shape:
|
|
194
|
+
//
|
|
195
|
+
// if (b.f_values) { b.f_values[i] = v; if (b.f_nulls) b.f_nulls[i>>>3] |= 1 << (i&7); }
|
|
196
|
+
func guardedRawWrite(buf, idx *shimast.Node, field string, value *shimast.Node) *shimast.Node {
|
|
197
|
+
values := func() *shimast.Node { return propAccess(buf, field+"_values") }
|
|
198
|
+
nulls := func() *shimast.Node { return propAccess(buf, field+"_nulls") }
|
|
199
|
+
at := func(arr *shimast.Node) *shimast.Node {
|
|
200
|
+
return factory.NewElementAccessExpression(arr, nil, idx, shimast.NodeFlagsNone)
|
|
201
|
+
}
|
|
202
|
+
// b.f_nulls[i >>> 3] |= 1 << (i & 7)
|
|
203
|
+
nullSlot := factory.NewElementAccessExpression(nulls(), nil,
|
|
204
|
+
factory.NewBinaryExpression(nil, idx, nil, factory.NewToken(shimast.KindGreaterThanGreaterThanGreaterThanToken), num(3)),
|
|
205
|
+
shimast.NodeFlagsNone)
|
|
206
|
+
nullBit := factory.NewBinaryExpression(nil, num(1), nil, factory.NewToken(shimast.KindLessThanLessThanToken),
|
|
207
|
+
factory.NewParenthesizedExpression(
|
|
208
|
+
factory.NewBinaryExpression(nil, idx, nil, factory.NewToken(shimast.KindAmpersandToken), num(7))))
|
|
209
|
+
setNull := factory.NewIfStatement(nulls(),
|
|
210
|
+
factory.NewBlock(factory.NewNodeList([]*shimast.Node{
|
|
211
|
+
binaryStmt(nullSlot, shimast.KindBarEqualsToken, nullBit),
|
|
212
|
+
}), false), nil)
|
|
213
|
+
body := []*shimast.Node{
|
|
214
|
+
binaryStmt(at(values()), shimast.KindEqualsToken, value),
|
|
215
|
+
setNull,
|
|
216
|
+
}
|
|
217
|
+
return factory.NewIfStatement(values(), factory.NewBlock(factory.NewNodeList(body), true), nil)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// applyLogInlines splices replacement blocks (phase B — no checker use).
|
|
221
|
+
func (t *fileTransformer) applyLogInlines(inlines []logInline) {
|
|
222
|
+
for _, in := range inlines {
|
|
223
|
+
logger := ident("$$l")
|
|
224
|
+
buf := ident("$$b")
|
|
225
|
+
idx := ident("$$i")
|
|
226
|
+
// Overflow happy-path inline: one compare instead of a method call;
|
|
227
|
+
// the (rare) overflow path still runs the runtime's _checkOverflow,
|
|
228
|
+
// which owns buffer switching, capacity tuning, and scope prefill.
|
|
229
|
+
overflowCheck := factory.NewIfStatement(
|
|
230
|
+
factory.NewBinaryExpression(nil,
|
|
231
|
+
propAccess(propAccess(ident("$$l"), "_buffer"), "_writeIndex"), nil,
|
|
232
|
+
factory.NewToken(shimast.KindGreaterThanEqualsToken),
|
|
233
|
+
propAccess(propAccess(ident("$$l"), "_buffer"), "_capacity")),
|
|
234
|
+
factory.NewBlock(factory.NewNodeList([]*shimast.Node{
|
|
235
|
+
factory.NewExpressionStatement(callExpr(propAccess(ident("$$l"), "_checkOverflow"), nil)),
|
|
236
|
+
}), false), nil)
|
|
237
|
+
stmts := []*shimast.Node{
|
|
238
|
+
constDecl(logger, in.logExpr),
|
|
239
|
+
overflowCheck,
|
|
240
|
+
constDecl(buf, propAccess(logger, "_buffer")),
|
|
241
|
+
constDecl(idx, callExpr(propAccess(propAccess(buf, "_traceRoot"), "writeLogEntry"),
|
|
242
|
+
[]*shimast.Node{buf, num(logEntryTypes[in.level])})),
|
|
243
|
+
binaryStmt(propAccess(logger, "_writeIndex"), shimast.KindEqualsToken, idx),
|
|
244
|
+
}
|
|
245
|
+
if in.templateID != 0 {
|
|
246
|
+
stmts = append(stmts, binaryStmt(
|
|
247
|
+
factory.NewElementAccessExpression(propAccess(buf, "_messageTemplateIds"), nil, idx, shimast.NodeFlagsNone),
|
|
248
|
+
shimast.KindEqualsToken,
|
|
249
|
+
num(int(in.templateID)),
|
|
250
|
+
))
|
|
251
|
+
} else {
|
|
252
|
+
stmts = append(stmts, guardedRawWrite(buf, idx, "message", in.message))
|
|
253
|
+
}
|
|
254
|
+
stmts = append(stmts, factory.NewExpressionStatement(factory.NewPostfixUnaryExpression(
|
|
255
|
+
propAccess(propAccess(propAccess(buf, "constructor"), "stats"), "totalWrites"),
|
|
256
|
+
shimast.KindPlusPlusToken)))
|
|
257
|
+
|
|
258
|
+
lineValue := in.lineArg
|
|
259
|
+
if lineValue == nil {
|
|
260
|
+
lineValue = num(in.line) // §6 semantics folded into the inline
|
|
261
|
+
}
|
|
262
|
+
stmts = append(stmts, guardedRawWrite(buf, idx, "line", lineValue))
|
|
263
|
+
|
|
264
|
+
for _, w := range in.writes {
|
|
265
|
+
info := in.schema[w.field]
|
|
266
|
+
switch info.kind {
|
|
267
|
+
case fieldEnum:
|
|
268
|
+
// Positional buffer method, string→index folded when literal
|
|
269
|
+
// (mirrors the generated enum override setter).
|
|
270
|
+
var enumIdx *shimast.Node
|
|
271
|
+
if isCompileTimeLiteral(w.arg) && w.arg.Kind == shimast.KindStringLiteral {
|
|
272
|
+
v := 0
|
|
273
|
+
for i, ev := range info.enumValues {
|
|
274
|
+
if ev == shimast.NodeText(w.arg) {
|
|
275
|
+
v = i
|
|
276
|
+
break
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
enumIdx = num(v)
|
|
280
|
+
} else {
|
|
281
|
+
enumIdx = enumSwitchIIFE(w.arg, info.enumValues)
|
|
282
|
+
}
|
|
283
|
+
stmts = append(stmts, factory.NewExpressionStatement(
|
|
284
|
+
callExpr(propAccess(buf, w.field), []*shimast.Node{idx, enumIdx})))
|
|
285
|
+
case fieldBool:
|
|
286
|
+
// Bit-packed at row granularity — go through the buffer's
|
|
287
|
+
// positional method like the generated setter does.
|
|
288
|
+
stmts = append(stmts, factory.NewExpressionStatement(
|
|
289
|
+
callExpr(propAccess(buf, w.field), []*shimast.Node{idx, w.arg})))
|
|
290
|
+
default:
|
|
291
|
+
stmts = append(stmts, guardedRawWrite(buf, idx, w.field, w.arg))
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
in.list.Nodes[in.index] = factory.NewBlock(factory.NewNodeList(stmts), true)
|
|
295
|
+
}
|
|
296
|
+
}
|