openpinescript 0.0.0-stage → 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.
Files changed (103) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +346 -2
  3. package/dist/cli.mjs +108686 -0
  4. package/dist/index.cjs +108670 -0
  5. package/dist/index.mjs +108624 -0
  6. package/dist/types/index.d.ts +31 -0
  7. package/dist/types/parser/v1/generated/PineV1Lexer.d.ts +66 -0
  8. package/dist/types/parser/v1/generated/PineV1Parser.d.ts +555 -0
  9. package/dist/types/parser/v1/generated/PineV1ParserVisitor.d.ts +318 -0
  10. package/dist/types/parser/v1/index.d.ts +39 -0
  11. package/dist/types/parser/v2/generated/PineV2Lexer.d.ts +67 -0
  12. package/dist/types/parser/v2/generated/PineV2Parser.d.ts +568 -0
  13. package/dist/types/parser/v2/generated/PineV2ParserVisitor.d.ts +325 -0
  14. package/dist/types/parser/v2/index.d.ts +2 -0
  15. package/dist/types/parser/v3/generated/PineV3Lexer.d.ts +67 -0
  16. package/dist/types/parser/v3/generated/PineV3Parser.d.ts +568 -0
  17. package/dist/types/parser/v3/generated/PineV3ParserVisitor.d.ts +325 -0
  18. package/dist/types/parser/v3/index.d.ts +2 -0
  19. package/dist/types/parser/v4/generated/PineV4Lexer.d.ts +86 -0
  20. package/dist/types/parser/v4/generated/PineV4Parser.d.ts +673 -0
  21. package/dist/types/parser/v4/generated/PineV4ParserVisitor.d.ts +367 -0
  22. package/dist/types/parser/v4/index.d.ts +2 -0
  23. package/dist/types/parser/v5/generated/PineV5Lexer.d.ts +95 -0
  24. package/dist/types/parser/v5/generated/PineV5Parser.d.ts +964 -0
  25. package/dist/types/parser/v5/generated/PineV5ParserVisitor.d.ts +521 -0
  26. package/dist/types/parser/v5/index.d.ts +2 -0
  27. package/dist/types/parser/v6/generated/PineV6Lexer.d.ts +98 -0
  28. package/dist/types/parser/v6/generated/PineV6Parser.d.ts +984 -0
  29. package/dist/types/parser/v6/generated/PineV6ParserVisitor.d.ts +528 -0
  30. package/dist/types/parser/v6/index.d.ts +2 -0
  31. package/dist/types/runtime/v1/Series.d.ts +61 -0
  32. package/dist/types/runtime/v1/broker/Broker.d.ts +325 -0
  33. package/dist/types/runtime/v1/broker/index.d.ts +158 -0
  34. package/dist/types/runtime/v1/broker/val.d.ts +28 -0
  35. package/dist/types/runtime/v1/constDefault.d.ts +11 -0
  36. package/dist/types/runtime/v1/context.d.ts +1705 -0
  37. package/dist/types/runtime/v1/footprint.d.ts +32 -0
  38. package/dist/types/runtime/v1/index.d.ts +7 -0
  39. package/dist/types/runtime/v1/language-spec.d.ts +12 -0
  40. package/dist/types/runtime/v1/openTrades.d.ts +12 -0
  41. package/dist/types/runtime/v1/palette.d.ts +18 -0
  42. package/dist/types/runtime/v1/session.d.ts +482 -0
  43. package/dist/types/runtime/v1/sessions.d.ts +31 -0
  44. package/dist/types/runtime/v1/stateClone.d.ts +19 -0
  45. package/dist/types/runtime/v1/stdlib/alerts.d.ts +31 -0
  46. package/dist/types/runtime/v1/stdlib/arrays.d.ts +133 -0
  47. package/dist/types/runtime/v1/stdlib/barmerge.d.ts +27 -0
  48. package/dist/types/runtime/v1/stdlib/barstate.d.ts +79 -0
  49. package/dist/types/runtime/v1/stdlib/cast.d.ts +81 -0
  50. package/dist/types/runtime/v1/stdlib/chart.d.ts +283 -0
  51. package/dist/types/runtime/v1/stdlib/color.d.ts +51 -0
  52. package/dist/types/runtime/v1/stdlib/core.d.ts +162 -0
  53. package/dist/types/runtime/v1/stdlib/dataset.d.ts +36 -0
  54. package/dist/types/runtime/v1/stdlib/display.d.ts +50 -0
  55. package/dist/types/runtime/v1/stdlib/drawings.d.ts +407 -0
  56. package/dist/types/runtime/v1/stdlib/errors.d.ts +21 -0
  57. package/dist/types/runtime/v1/stdlib/font.d.ts +20 -0
  58. package/dist/types/runtime/v1/stdlib/footprint.d.ts +76 -0
  59. package/dist/types/runtime/v1/stdlib/format.d.ts +57 -0
  60. package/dist/types/runtime/v1/stdlib/index.d.ts +71 -0
  61. package/dist/types/runtime/v1/stdlib/input.d.ts +14 -0
  62. package/dist/types/runtime/v1/stdlib/inputs.d.ts +60 -0
  63. package/dist/types/runtime/v1/stdlib/late_members.d.ts +97 -0
  64. package/dist/types/runtime/v1/stdlib/logging.d.ts +31 -0
  65. package/dist/types/runtime/v1/stdlib/maps.d.ts +55 -0
  66. package/dist/types/runtime/v1/stdlib/math.d.ts +71 -0
  67. package/dist/types/runtime/v1/stdlib/matrix.d.ts +201 -0
  68. package/dist/types/runtime/v1/stdlib/metadata.d.ts +14 -0
  69. package/dist/types/runtime/v1/stdlib/mtf.d.ts +15 -0
  70. package/dist/types/runtime/v1/stdlib/renames.d.ts +117 -0
  71. package/dist/types/runtime/v1/stdlib/renames5.d.ts +113 -0
  72. package/dist/types/runtime/v1/stdlib/renames6.d.ts +81 -0
  73. package/dist/types/runtime/v1/stdlib/request.d.ts +207 -0
  74. package/dist/types/runtime/v1/stdlib/scale.d.ts +19 -0
  75. package/dist/types/runtime/v1/stdlib/session.d.ts +113 -0
  76. package/dist/types/runtime/v1/stdlib/sort_field.d.ts +12 -0
  77. package/dist/types/runtime/v1/stdlib/sources.d.ts +24 -0
  78. package/dist/types/runtime/v1/stdlib/str.d.ts +117 -0
  79. package/dist/types/runtime/v1/stdlib/strategy.d.ts +314 -0
  80. package/dist/types/runtime/v1/stdlib/syminfo.d.ts +209 -0
  81. package/dist/types/runtime/v1/stdlib/ta.d.ts +409 -0
  82. package/dist/types/runtime/v1/stdlib/time.d.ts +158 -0
  83. package/dist/types/runtime/v1/stdlib/trades.d.ts +108 -0
  84. package/dist/types/runtime/v1/stdlib/ui.d.ts +196 -0
  85. package/dist/types/runtime/v1/stdlib/v6_members.d.ts +68 -0
  86. package/dist/types/runtime/v1/timeframes.d.ts +139 -0
  87. package/dist/types/runtime/v1/zones.d.ts +30 -0
  88. package/dist/types/transpiler/common/index.d.ts +51 -0
  89. package/dist/types/transpiler/common/libraries.d.ts +29 -0
  90. package/dist/types/transpiler/common/parseErrors.d.ts +38 -0
  91. package/dist/types/transpiler/common/passes/ScopeAnalysis.d.ts +158 -0
  92. package/dist/types/transpiler/common/passes/TypeRules.d.ts +26 -0
  93. package/dist/types/transpiler/common/profiles/index.d.ts +96 -0
  94. package/dist/types/transpiler/common/version.d.ts +40 -0
  95. package/dist/types/transpiler/v1/ToJsVisitor.d.ts +720 -0
  96. package/dist/types/transpiler/v2/ToJsVisitor.d.ts +72 -0
  97. package/dist/types/transpiler/v3/ToJsVisitor.d.ts +87 -0
  98. package/dist/types/transpiler/v4/ToJsVisitor.d.ts +263 -0
  99. package/dist/types/transpiler/v5/ToJsVisitor.d.ts +1101 -0
  100. package/dist/types/transpiler/v6/ToJsVisitor.d.ts +237 -0
  101. package/dist/types/transpiler/v6/rules.d.ts +94 -0
  102. package/dist/types/utils/v2/common.d.ts +4 -0
  103. package/package.json +92 -4
@@ -0,0 +1,1101 @@
1
+ /**
2
+ * Pine Script v5 → JavaScript emitter.
3
+ *
4
+ * v5 inherits every guard v3 added and every declaration form v4 added. The
5
+ * migration guide relaxes none of them, so nothing here undoes anything.
6
+ *
7
+ * What v5 adds falls into four groups:
8
+ *
9
+ * NAMES (runtime/v1/stdlib/renames5.ts + the V5_VIEW registry)
10
+ * The §4a namespace migration — `sma` → `ta.sma`, `abs` → `math.abs`,
11
+ * `security` → `request.security`, `tostring` → `str.tostring` — plus the
12
+ * §4b renames that keep their namespace (`study` → `indicator`) and the §4c
13
+ * removals (`iff`, `offset`, `transp=`). Those are lookups and rejections,
14
+ * driven from a data table, not emit rules.
15
+ *
16
+ * SYNTAX (this file)
17
+ * `while`, `switch`, and `for … in`. None is a v4 construct — an early
18
+ * draft of the delta spec said otherwise about the first two and was wrong
19
+ * — so v4 emits nothing for them and v5 emits all three here.
20
+ *
21
+ * RESERVED WORDS (this file)
22
+ * Twelve of the thirteen words v5 will not let a script NAME anything (the
23
+ * thirteenth, `in`, is a lexer keyword — see RESERVED below). Enforced on the
24
+ * identifier rather than in the lexer, because `text` is simultaneously a
25
+ * live namespace (`text.align_left`) and a forbidden variable name — a
26
+ * distinction a token cannot draw.
27
+ *
28
+ * KEYWORD ARGUMENTS (this file)
29
+ * §4b renamed parameters without renaming their functions:
30
+ * `study(resolution=)` became `indicator(timeframe=)`, `strategy.entry(long=)`
31
+ * became `direction=`. Where the RUNTIME still spells one the old way — it is
32
+ * one implementation across versions — the emitter translates. Where it has
33
+ * taken the new name (`strategy.entry`'s `direction`), there is nothing to
34
+ * translate, and v1–v4's `long=` is mapped the other way, in the runtime
35
+ * (`V4_RENAMED_PARAMS`). tests/v5/transpiler/keyword_aliases.test.ts fails
36
+ * if an alias targets a name the runtime does not have.
37
+ *
38
+ * ── What is NOT implemented at v5 ───────────────────────────────────────────
39
+ *
40
+ * User-defined types (`type`), methods (`method`), and libraries
41
+ * (`import`/`export`). Each needs a type system this engine does not have:
42
+ * `p.x` is currently always a namespace member, and telling it apart from a
43
+ * field access requires knowing that `p` came from `Point.new()`.
44
+ *
45
+ * `type` is absent from the GRAMMAR, so a script using it fails with "parsing
46
+ * failed" — the same verdict v1 gives `:=` and v4 gives `while`. The other three
47
+ * DO parse, because the inherited grammar can read what follows the keyword on
48
+ * its own, so they are rejected by NAME instead — see UNSUPPORTED below. Either
49
+ * way the script is refused rather than compiled into something it does not say.
50
+ */
51
+ import type { PineVersion } from "../common/version.js";
52
+ import { V4ToJsVisitor } from "../v4/ToJsVisitor.js";
53
+ import type { StdlibEntry } from "../../runtime/v1/stdlib/metadata.js";
54
+ import type { ParseTree } from "antlr4ng";
55
+ import { parse as parseV5 } from "../../parser/v5/index.js";
56
+ import { While_exprContext, For_in_exprContext, Call_suffixContext, Switch_exprContext, Switch_caseContext, Fun_callContext, Var_defsContext, Var_assignContext, IdContext, StmtContext, Type_def_stmtContext, Enum_def_stmtContext, Method_def_stmtContext, Export_stmtContext, Import_stmtContext, Fun_headContext, Pine_scriptContext, Fun_def_singlelineContext, Fun_def_multilineContext } from "../../parser/v5/generated/PineV5Parser.js";
57
+ /** One declaration of an overloaded function name. */
58
+ /**
59
+ * A type as overloads compare it: no whitespace, and no library alias on any
60
+ * part — `lib.Point` and `Point`, `array<lib.Point>` and `array<Point>`, are
61
+ * the same type to a library's own declarations.
62
+ */
63
+ export declare function normaliseType(t: string): string;
64
+ /**
65
+ * `float` or `int` for an arithmetic expression whose type its text settles:
66
+ * a price series or a decimal literal makes it float, as does `/`; integer
67
+ * literals alone keep it int. Anything with a call or another name is
68
+ * unknown — a runtime value cannot tell `22.0` from `22`, so the guess has to
69
+ * be made here or not at all.
70
+ */
71
+ export declare function numericTypeOf(text: string): "int" | "float" | null;
72
+ interface FnOverload {
73
+ /** Fewest arguments a call may pass — parameters without a default. */
74
+ min: number;
75
+ /** Most — every parameter. */
76
+ max: number;
77
+ /** Each parameter's DECLARED type, or null where none is written. */
78
+ types: Array<string | null>;
79
+ }
80
+ /** Anything carrying a source position (see the v1 base for why it is structural). */
81
+ interface SourceLocated {
82
+ start?: {
83
+ line: number;
84
+ column: number;
85
+ } | null;
86
+ }
87
+ /** Construction options — how a v5 script reaches code outside itself. */
88
+ export interface V5Options {
89
+ /**
90
+ * Library sources, keyed by the path an `import` names
91
+ * (`"someuser/somelib/1"`). Supplied by the host; see the field of the same
92
+ * name on the visitor for why they cannot be fetched.
93
+ */
94
+ readonly libraries?: Readonly<Record<string, string>>;
95
+ /**
96
+ * Apply the checks TradingView's chart editor makes and its compile endpoint
97
+ * does not (an indicator with no output, `request.*()` in a conditional at
98
+ * v5, `color.new()` with no transparency, a colour for `input.string`).
99
+ * Off for bare transpiles, so fixtures need not be complete scripts.
100
+ */
101
+ readonly editorRules?: boolean;
102
+ /** Disambiguates emitted source locations. Set when compiling a library. */
103
+ readonly locationTag?: string;
104
+ /** Disambiguates the names a script DECLARES. Set when compiling a library. */
105
+ readonly nameScope?: string;
106
+ /** The library paths being compiled above this one, outermost first. Set when compiling a library. */
107
+ readonly libraryChain?: readonly string[];
108
+ }
109
+ /** One field of a user-defined type. */
110
+ interface TypeField {
111
+ readonly name: string;
112
+ /** Its `= …` initialiser, or null — an undeclared default is `na`. */
113
+ readonly defaultExpr: any | null;
114
+ }
115
+ /** One member of an `enum` declaration. */
116
+ interface EnumField {
117
+ readonly name: string;
118
+ /**
119
+ * Its `= "title"` expression, or null.
120
+ *
121
+ * "If the programmer does not specify a field's title, its title is the
122
+ * 'string' representation of its name."
123
+ */
124
+ readonly titleExpr: any | null;
125
+ }
126
+ /**
127
+ * Keyword arguments v5 renamed, per CALLEE.
128
+ *
129
+ * §4b renamed these parameters without renaming their functions. The runtime
130
+ * still spells most of them the v1–v4 way — it is one implementation across versions,
131
+ * and `Context.call` matches a keyword argument by looking its written name up
132
+ * in the registry entry's parameter list — so an unmatched key is DROPPED
133
+ * SILENTLY. A v5 script writing `indicator(timeframe="D")` would therefore have
134
+ * had its timeframe ignored and fallen back to the chart's.
135
+ *
136
+ * Scoped per callee rather than applied globally because the new names are
137
+ * ordinary words: `source` is a parameter of half the `input.*` family, and
138
+ * rewriting it everywhere would corrupt those calls to fix `nz`.
139
+ */
140
+ export declare const KEYWORD_ALIASES: Readonly<Record<string, Readonly<Record<string, string>>>>;
141
+ export declare class V5ToJsVisitor extends V4ToJsVisitor {
142
+ protected readonly version: PineVersion;
143
+ /**
144
+ * v5's view of the stdlib: v4's, minus the spellings v5 renamed away, plus
145
+ * the namespaces it introduced and the aliases it created.
146
+ *
147
+ * Subtracting matters as much as adding — leaving `sma` in beside `ta.sma`
148
+ * would accept both dialects, and a script written half in each compiles here
149
+ * and fails on TradingView.
150
+ */
151
+ protected get registry(): Record<string, StdlibEntry>;
152
+ /**
153
+ * The callee whose arguments are currently being emitted, innermost last.
154
+ *
155
+ * `visitKw_arg` needs to know which function a keyword belongs to before it
156
+ * can decide whether to translate its name, and the grammar gives it no way
157
+ * up to the call. A stack rather than a single field because arguments nest:
158
+ * `strategy.entry("L", direction=strategy.long, qty=nz(q, replacement=1))`.
159
+ */
160
+ private calleeStack;
161
+ /** Declared type name → its fields, in declaration order. */
162
+ protected userTypes: Map<string, TypeField[]>;
163
+ /**
164
+ * `enum Name` declarations, name → its fields in declaration order.
165
+ *
166
+ * Collected in the same pre-pass as `userTypes`, and for the same reason: a
167
+ * member may be READ above the line that declares its enum, inside any
168
+ * function body, and a single-pass emitter cannot know that yet.
169
+ */
170
+ protected userEnums: Map<string, EnumField[]>;
171
+ /**
172
+ * Names declared with `method`.
173
+ *
174
+ * Kept apart from `userFunctions` — which already contains them, since a
175
+ * method's body IS a function definition — because only a method may be
176
+ * called as `receiver.name(…)`. A plain function of the same name may not,
177
+ * and answering that question wrongly turns a typo into a silent field read.
178
+ */
179
+ protected userMethods: Set<string>;
180
+ /**
181
+ * method name → the receiver type of each declaration of it, in file order.
182
+ *
183
+ * A single entry is the ordinary case and changes nothing. Two or more is an
184
+ * OVERLOAD SET: "User-defined methods can override and overload existing
185
+ * built-in and user-defined methods with the same identifier ... The
186
+ * underlying type of each variable determines which overload of `getType()`
187
+ * the compiler will use."
188
+ */
189
+ protected methodOverloads: Map<string, string[]>;
190
+ /**
191
+ * method name → every declaration's receiver AND full signature, in file
192
+ * order. A receiver may carry several: "User-defined methods can override and
193
+ * overload existing built-in and user-defined methods", told apart the way
194
+ * any overload is — by required-parameter count, then by type.
195
+ */
196
+ protected methodSignatures: Map<string, Array<{
197
+ receiver: string;
198
+ sig: FnOverload;
199
+ }>>;
200
+ /** type name → field name → the field's declared type, where one is written. */
201
+ protected userFieldTypes: Map<string, Map<string, string>>;
202
+ /**
203
+ * Declared types of the names in scope while a function or method body is
204
+ * emitted, innermost last: its parameters, then its typed or constructed
205
+ * locals. Script-scope names come from `scopes.staticTypes`.
206
+ */
207
+ protected localTypes: Array<Map<string, string | null>>;
208
+ /** `import … as alias` → the library path it names. */
209
+ protected importAliases: Map<string, string>;
210
+ /** Library path → the names that library exports. */
211
+ protected libraryExports: Map<string, Set<string>>;
212
+ /**
213
+ * `<path>::<TypeName>` → that type's field names, in declaration order.
214
+ *
215
+ * Needed because `ml.Pair.new(1, 2)` has to map POSITIONAL arguments onto
216
+ * fields, and the field order lives in the library rather than here.
217
+ */
218
+ protected libraryTypeFields: Map<string, string[]>;
219
+ /**
220
+ * An imported library's exported METHOD name → the alias that owns it.
221
+ *
222
+ * Importing a library brings its methods into scope on values of its types,
223
+ * so `pair.total()` has to resolve even though `total` is declared in another
224
+ * file. Without this the call fell through to `Context.builtinMethod`, which
225
+ * correctly reported that a plain object has no built-in methods — a true
226
+ * statement about the wrong question.
227
+ */
228
+ protected libraryMethods: Map<string, string>;
229
+ /**
230
+ * Sources for `import`, keyed by the path a script writes.
231
+ *
232
+ * A library lives on TradingView, and this engine cannot fetch one — so the
233
+ * host supplies them, the same way it supplies higher-timeframe candles for
234
+ * `security()`. An import with no source is REFUSED rather than stubbed:
235
+ * a library that silently resolves to nothing produces a script full of `na`
236
+ * that still runs.
237
+ */
238
+ protected readonly libraries: Readonly<Record<string, string>>;
239
+ /**
240
+ * Appended to every source location this visitor emits.
241
+ *
242
+ * Empty for a script, `@<alias>` for a library compiled into one. Call ids
243
+ * key per-call-site state — `ta.sma@L12:C4` is what keeps two `ta.sma` calls
244
+ * from sharing one rolling window — and a library's line 12 has nothing to do
245
+ * with the importing script's. Without the tag they collide silently, and two
246
+ * unrelated indicators quietly share a buffer.
247
+ */
248
+ protected readonly locationTag: string;
249
+ /**
250
+ * Inserted into every name this script DECLARES. Empty for a script,
251
+ * `$lib$<alias>$` for a library compiled into one.
252
+ *
253
+ * ── Why the IIFE is not enough ────────────────────────────────────────────
254
+ *
255
+ * A library's body is wrapped in an immediately-invoked function, so its
256
+ * `let opsv2_len` is lexically its own. That is only half the isolation: a
257
+ * variable is also a SERIES, registered in `ctx.vars` under its emitted name,
258
+ * and `ctx.new_var` looks that registry up BY NAME. Two scripts each
259
+ * declaring `len` therefore shared one series — the second write overwrote
260
+ * the first, and the library's functions, closing over their own `let`, read
261
+ * the importing script's value.
262
+ *
263
+ * It was worth 220 instead of 26 in the first library this engine ran, and
264
+ * nothing about the emitted JavaScript looked wrong.
265
+ *
266
+ * Built-ins are NOT scoped: `close` must stay `opsv2_close`, which is what
267
+ * the sandbox binds. Only names the script itself binds are rewritten, so the
268
+ * declaration and every read of it move together.
269
+ */
270
+ protected readonly nameScope: string;
271
+ /** The libraries being compiled above this visitor, so an import back into one is named as a cycle. */
272
+ protected readonly libraryChain: readonly string[];
273
+ constructor(options?: V5Options);
274
+ /**
275
+ * The emitted name of an identifier — scoped when this script declares it.
276
+ *
277
+ * The single place that decision is made, so the JS binding, the series
278
+ * registry key and every read of it can never disagree.
279
+ */
280
+ protected localName(text: string): string;
281
+ protected funcName(pineName: string): string;
282
+ protected getLocId(ctx: SourceLocated): string;
283
+ /** Names this script marks `export`. Non-empty only in a library. */
284
+ protected exportedNames: Set<string>;
285
+ /** Does this script declare itself a library? Set at the entry point. */
286
+ protected get declaresLibrary(): boolean;
287
+ /** Is this visitor compiling a library INTO another script? */
288
+ protected get isImportedLibrary(): boolean;
289
+ /**
290
+ * Types and methods are collected BEFORE anything is emitted.
291
+ *
292
+ * Both are whole-script facts a single pass cannot have: `p.x` has to know
293
+ * that `p` might be an object, and `r.area()` has to know that `area` is a
294
+ * method, and either can appear above its declaration inside a function body
295
+ * (which runs at call time, so it is not a forward reference).
296
+ *
297
+ * The same reasoning, and the same shape, as `collectFunctionNames` in the v1
298
+ * base.
299
+ */
300
+ visitPine_script(ctx: Pine_scriptContext): string;
301
+ /**
302
+ * v5 `request.*()` is static unless the declaration says
303
+ * `dynamic_requests = true`. (v6 has its own, explicit-opt-out rule.)
304
+ */
305
+ private editorRules;
306
+ private v5StaticRequests;
307
+ /**
308
+ * Whole-script rules TradingView's chart editor applies (its compile
309
+ * endpoint does not): an `indicator()` must display something.
310
+ */
311
+ protected enforceEditorRules(root: any): void;
312
+ /** An `indicator()` must display something (log.* counts: a log-only script loads). */
313
+ protected enforceIndicatorOutput(root: any): void;
314
+ /** Call-site rules the chart editor applies at v5 and v6 alike. */
315
+ protected enforceEditorCallRules(name: string, ctx: any): void;
316
+ /** Walks the whole tree for `type` and `method` declarations. */
317
+ protected collectDeclarations(root: any): void;
318
+ /** A type declaration's fields, in declaration order. */
319
+ protected fieldsOf(ctx: Type_def_stmtContext): TypeField[];
320
+ /**
321
+ * Is `root` a variable or parameter bound in a scope that contains this
322
+ * call? A local or parameter counts inside its own span; a script-scope
323
+ * binding (recorded with a null span) counts everywhere, which is safe
324
+ * because the caller asks only for a name the namespace does not define,
325
+ * and the namespace path would fail on it anyway. A namespace is never
326
+ * shadowed by a name this script does not actually declare.
327
+ */
328
+ protected shadowsNamespace(root: string, ctx: any): boolean;
329
+ /** Is `name` something this script binds — and therefore a possible receiver? */
330
+ protected isReceiverName(name: string): boolean;
331
+ /**
332
+ * Rejects a v1–v4 spelling with the name — or the construct — that replaced it.
333
+ *
334
+ * Hooked on identifiers and calls rather than driven off the registry,
335
+ * because a missing registry entry is not by itself an error: `visitId` emits
336
+ * any identifier it does not recognise, since most identifiers are the
337
+ * script's own variables. So `sma` at v5 would just emit `opsv2_sma` and read
338
+ * as `undefined` — an indicator that is silently `na` on a chart that still
339
+ * draws.
340
+ */
341
+ protected enforceRenamedInV5(name: string, ctx: SourceLocated): void;
342
+ /** Rejects a declaration or reference that names one of v5's reserved words. */
343
+ protected enforceNotReserved(name: string, ctx: SourceLocated): void;
344
+ /**
345
+ * Rejects a v5 feature this engine does not implement, by name.
346
+ *
347
+ * Reported as "not implemented" rather than as a Pine error, because it is
348
+ * not one: TradingView accepts all four. Saying so is the difference between
349
+ * an author knowing to rewrite the script and an author hunting for a typo.
350
+ * The message reaches the script's author, so it names no repository path;
351
+ * the known gaps are in docs/common/VERSIONS.md §7.
352
+ */
353
+ protected enforceSupported(name: string, ctx: SourceLocated): void;
354
+ visitId(ctx: IdContext): string;
355
+ /**
356
+ * `p.x`, `p.inner.x` → nested `ctx.field` reads, or null if `text` is not a
357
+ * field access at all.
358
+ *
359
+ * A namespace ALWAYS wins. `strategy.long` stays a namespace member even in a
360
+ * script that happens to bind a variable called `strategy`, because Pine
361
+ * would reject that script and reading it the other way would silently give
362
+ * `na` instead.
363
+ */
364
+ protected emitFieldChain(text: string): string | null;
365
+ /**
366
+ * `p.x := expr` — a field WRITE, and `p.x += expr` with it.
367
+ *
368
+ * Not routed through the inherited `visitVar_assign`: that emits
369
+ * `<name> = ctx.new_var(…)`, and the name it would build here is a
370
+ * `ctx.field(…)` read, which is not assignable. The declared-before-assigned
371
+ * guard is skipped too, deliberately — a field is not a script-scope
372
+ * variable, and `p.x` is declared by `type Point`, not by an `=` statement.
373
+ */
374
+ visitVar_assign(ctx: Var_assignContext): string;
375
+ /**
376
+ * The tuple form, `[a, b, c] = ta.bb(...)`.
377
+ *
378
+ * Overridden only to get the diagnostic right. The inherited implementation
379
+ * finds the callee and — when the name is absent from this version's registry
380
+ * but present in the runtime union — reports "added in a later version",
381
+ * which is exactly backwards for `[a, b, c] = bb(close, 20, 2)` at v5.
382
+ */
383
+ visitVar_defs(ctx: Var_defsContext): string;
384
+ /** The name of the first function CALL in a subtree, if there is one. */
385
+ private firstCallee;
386
+ /**
387
+ * v5 renames `study()` to `indicator()`, keeps `strategy()`, and adds
388
+ * `library()` — a script that declares functions for others to import and
389
+ * plots nothing itself.
390
+ */
391
+ protected detectDirective(node: ParseTree): 'indicator' | 'strategy' | 'library' | undefined;
392
+ /**
393
+ * An `indicator()` script is in indicator mode, so `strategy.*` is fatal —
394
+ * the same rule the base applies to `study()`, under v5's spelling of it.
395
+ *
396
+ * A LIBRARY is not refused. The manual's Libraries page restricts what an
397
+ * exported function may use (no non-const globals, no `input.*()`) and says
398
+ * nothing against `strategy.*`, and published libraries call it —
399
+ * `strategy.position_size`, `strategy.closedtrades`, `strategy.entry` — to
400
+ * be imported by strategies, whose broker they then read.
401
+ */
402
+ protected enforceStrategyContext(name: string, ctx: SourceLocated): void;
403
+ /**
404
+ * A call to a function's own NAME is recursion only when it can reach this
405
+ * definition. The manual forbids recursion ("cannot contain calls to
406
+ * themselves within their bodies") but allows overloads, and an overload
407
+ * calling its sibling is the documented way to share code:
408
+ *
409
+ * export getHexString(series float r, series float g, series float b, series float t = 0.0) => …
410
+ * export getHexString(series color source) =>
411
+ * getHexString(color.r(source), color.g(source), color.b(source), color.t(source))
412
+ *
413
+ * So a call counts only when its argument count fits this definition and no
414
+ * sibling overload's — `f(int x) => f(x)` beside `f(float x, int y)` still
415
+ * calls itself, and would overflow the stack. Siblings of the same arity are
416
+ * told apart by type, which is not known here, so they are let through. A
417
+ * method `alert(string message, string key)` that calls the built-in
418
+ * `alert(message)` does not call itself either.
419
+ */
420
+ protected enforceNoRecursion(name: string, body: ParseTree, ctx: SourceLocated): void;
421
+ visitFun_call(ctx: Fun_callContext): string;
422
+ /** The call itself, before any `.method()` chained onto its result. */
423
+ protected emitBaseCall(ctx: Fun_callContext): string;
424
+ /**
425
+ * The LAST link of a chain is what a destructuring unpacks.
426
+ *
427
+ * [sampleMean, highBand, lowBand] =
428
+ * sourceArray.maintainQueue(sourceInput, newSample).calcBB(multiplier, newSample)
429
+ *
430
+ * `maintainQueue` returns the array; `calcBB` returns "a tuple containing the
431
+ * basis, upper band, and lower band respectively". The base reads the call's
432
+ * own `id`, which here is the receiver plus the FIRST method — so the arity
433
+ * check asked `maintainQueue` and was told, correctly, that it returns no
434
+ * tuple.
435
+ *
436
+ * A trailing FIELD suffix is not a callee, so it is skipped: `f().x` unpacks
437
+ * nothing, and naming `x` would produce a message about a function that does
438
+ * not exist.
439
+ */
440
+ /**
441
+ * v5 widens where a `[a, b] = …` may take its values from:
442
+ *
443
+ * - an `if` or `switch` whose branches end in tuples (manual: "If the
444
+ * final statement is a conditional structure … the function returns that
445
+ * structure's result", and the same holds for a declaration);
446
+ * - a METHOD call — `[lv, t] = this.eventHorizon(close)` — and a library
447
+ * function, whose definitions this script cannot see;
448
+ * - a function ending in a call or a `switch`, whose width is not written;
449
+ * - `ta.vwap(source, anchor, stdev_mult)`, which "will calculate the
450
+ * standard deviation bands … and return a [vwap, upper_band,
451
+ * lower_band] tuple".
452
+ *
453
+ * It still refuses what it can prove wrong: a built-in that returns one
454
+ * value, a width that disagrees with the definition's, and a function every
455
+ * one of whose exits is plainly a single value.
456
+ */
457
+ protected checkTupleSource(ctx: any, ids: string[]): void;
458
+ /**
459
+ * v5's declaration rule reads the initialiser the way the language does:
460
+ *
461
+ * - `x = arr.last().x` and `float y = verts.get(i).y` read a FIELD called
462
+ * `x`/`y` off a value. A field after a dot is not the variable.
463
+ * - `result = if cond` + a branch that declares its own `result` reads
464
+ * that branch's local, not the one being declared.
465
+ */
466
+ protected enforceNoSelfReference(name: string, value: ParseTree, ctx: SourceLocated): void;
467
+ /** Is `root` a namespace, user type, enum or library alias — a qualifier, not a variable? */
468
+ protected isQualifierRoot(root: string): boolean;
469
+ /**
470
+ * `(expr).field` and `(expr).method()` — see `atom` in PineV5Parser.g4.
471
+ * The receiver is a value, so it folds through the same `emitChainedMethod`
472
+ * a call's result does.
473
+ */
474
+ visitAtom(ctx: any): string;
475
+ /** The first call in an expression, the way the base check finds it. */
476
+ private firstCallOf;
477
+ protected destructuringCallee(call: Fun_callContext): string;
478
+ /**
479
+ * `a.f().g()` — the chained method calls hanging off a call's result.
480
+ *
481
+ * Folded here rather than inside each emit path, because every one of them
482
+ * returns a VALUE and the chain applies to the value, whatever produced it:
483
+ * a built-in call, a method call, a UDT constructor, a library function.
484
+ *
485
+ * The receiver of a chained call is an expression, so it cannot go through
486
+ * `emitMethodCall`, which resolves a receiver NAME to a local. Dispatch is
487
+ * otherwise identical, and `Context.builtinMethod` was already receiving a
488
+ * value rather than a name.
489
+ */
490
+ protected emitCallChain(base: string, ctx: Fun_callContext): string;
491
+ /** One `.method(args)` — or `.field` — applied to an already-emitted receiver. */
492
+ protected emitChainedMethod(receiver: string, ctx: Call_suffixContext, receiverType?: string | null): string;
493
+ /** A chained call to a user method, `overload` or the plain name. */
494
+ private emitUserChainedCall;
495
+ /**
496
+ * A dotted callee whose root is NOT a built-in namespace.
497
+ *
498
+ * Three things can be, and they are checked in this order:
499
+ *
500
+ * Point.new(…) a user type's constructor
501
+ * lib.f(…) a function from an imported library
502
+ * p.area(…) a method call, on a user type or on a built-in collection
503
+ *
504
+ * Returns null when none applies, so the caller falls through to the ordinary
505
+ * namespace path. A real namespace always wins — see `emitFieldChain`.
506
+ */
507
+ protected emitDottedCall(name: string, ctx: Fun_callContext): string | null;
508
+ /**
509
+ * `label.all.size()` — a method called on a namespace member's VALUE.
510
+ *
511
+ * `id` is greedy, so the whole of `label.all.size` arrives as one dotted
512
+ * name and the ordinary namespace path asks the registry for a function of
513
+ * that name. There is none: `label.all` is an ARRAY, and `size` is a method
514
+ * on it.
515
+ *
516
+ * So the longest registry-known PREFIX is taken as the receiver and whatever
517
+ * follows is applied to it — the same split `emitChainedMethod` performs on a
518
+ * dotted call suffix, arrived at from the other side. Returns null when no
519
+ * prefix resolves, which leaves the existing "has no member" diagnostic to
520
+ * report the name the script actually wrote.
521
+ */
522
+ protected emitNamespaceValueMethod(name: string, ctx: Fun_callContext): string | null;
523
+ /** `label.all` → `opsv2_label.opsv2_all`, the way visitId prefixes a dotted read. */
524
+ protected namespacedName(dotted: string): string;
525
+ /** `Point.new(…)` and `Point.copy(p)` — the two calls a TYPE answers. */
526
+ protected emitTypeCall(typeName: string, member: string, ctx: Fun_callContext): string | null;
527
+ /**
528
+ * Maps a `Type.new(…)` argument list onto field names.
529
+ *
530
+ * Positional arguments take fields in declaration order; keyword arguments
531
+ * name them. Both are checked, because neither mistake is visible at run
532
+ * time: an unknown field name would just add a property nothing reads, and a
533
+ * ninth positional argument to an eight-field type would be dropped.
534
+ */
535
+ protected constructorFields(typeName: string, fields: readonly string[], ctx: Fun_callContext): Map<string, string>;
536
+ /**
537
+ * `receiver.name(args)`.
538
+ *
539
+ * A USER method becomes `name(receiver, args)`, which is what it already is —
540
+ * see `visitMethod_def_stmt`. Anything else is a BUILT-IN method, and which
541
+ * namespace owns it depends on what the receiver turns out to be at run time,
542
+ * so that dispatch is deferred to `Context.builtinMethod`.
543
+ *
544
+ * `.copy()` is intercepted first because three different namespaces spell it
545
+ * — `array.copy`, `matrix.copy`, and a UDT's shallow copy — and only the
546
+ * value knows which it is.
547
+ */
548
+ protected emitMethodCall(receiver: string, method: string, ctx: Fun_callContext): string;
549
+ /**
550
+ * `<value>.method(args)` where the receiver is an already-emitted VALUE of a
551
+ * known type — an enum member — rather than a name.
552
+ */
553
+ protected emitValueMethodCall(receiver: string, receiverType: string, method: string, ctx: Fun_callContext): string;
554
+ /** Runs `emit` with `name` on the callee stack, so visitKw_arg can see it. */
555
+ private withCallee;
556
+ /**
557
+ * Function OVERLOADING — several definitions of one name.
558
+ *
559
+ * SOURCING. From the v5 release notes:
560
+ *
561
+ * // Two parameters
562
+ * mult(x1, x2) => x1 * x2
563
+ * // Three parameters
564
+ * mult(x1, x2, x3) => x1 * x2 * x3
565
+ * plot(mult(7, 4))
566
+ * plot(mult(7, 4, 2))
567
+ *
568
+ * and, for the harder case, "When overloads have the same number of
569
+ * parameters, all parameters in each overload must be explicitly typified,
570
+ * and their type combinations must be unique".
571
+ *
572
+ * ── What it was doing instead ───────────────────────────────────────────────
573
+ *
574
+ * Both definitions were emitted as `function opsv2_$fn_mult(…)`, so the second
575
+ * simply replaced the first in JavaScript. `mult(7, 4)` then called the
576
+ * three-parameter body with one argument missing and plotted `na` on every
577
+ * bar — no error anywhere, because a redeclared function is legal JavaScript.
578
+ */
579
+ protected functionOverloads: Map<string, FnOverload[]>;
580
+ /** The arity range and declared parameter types of one definition. */
581
+ protected overloadOf(inner: Fun_def_singlelineContext | Fun_def_multilineContext): FnOverload;
582
+ /**
583
+ * The suffix that separates one overload's emitted name from its siblings.
584
+ *
585
+ * Arity alone where the arities differ, and the declared types as well where
586
+ * they do not — which the manual requires to be unique, so the pair always
587
+ * is. A name with a single definition gets no suffix at all, so nothing about
588
+ * an ordinary script's output changes.
589
+ */
590
+ protected overloadSuffix(o: FnOverload): string;
591
+ /** The definition currently being emitted, when its name is overloaded. */
592
+ private emittingOverload;
593
+ /** The function or method whose body is being emitted, overloaded or not. */
594
+ private enclosingDefinition;
595
+ private withOverload;
596
+ visitFun_def_singleline(ctx: Fun_def_singlelineContext): string;
597
+ visitFun_def_multiline(ctx: Fun_def_multilineContext): string;
598
+ /**
599
+ * The STATIC type of a call argument, as far as it can be known here.
600
+ *
601
+ * Literals carry their own type, and a variable carries whatever type its
602
+ * declaration wrote down. Anything else is null — unknown — and an overload
603
+ * set that cannot be resolved from what is known says so rather than picking
604
+ * one, because picking wrong calls a body written for another type and
605
+ * returns a plausible wrong number.
606
+ */
607
+ protected argumentType(expr: ParseTree | null): string | null;
608
+ /** Does an argument of type `arg` fit a parameter declared `param`? */
609
+ private fits;
610
+ /**
611
+ * An enum member may not stand in for a member of a DIFFERENT enum.
612
+ *
613
+ * SOURCING. From the manual's Enums page: "Scripts cannot compare members of
614
+ * different enums or use such members in expressions requiring a specific
615
+ * enum type, EVEN IF THE FIELDS HAVE IDENTICAL NAMES AND TITLES." A parameter
616
+ * declared `OscType selection` is such an expression.
617
+ *
618
+ * TradingView's own `v5-language-enums-05` is written to show the refusal —
619
+ * it declares `OscType` and `OscType2` with identical fields, passes an
620
+ * `OscType2` where an `OscType` belongs, and comments the plot "Raises a
621
+ * compilation error because only members of `OscType` are allowed." This
622
+ * engine compiled it and plotted `na` on every bar instead, which is the
623
+ * worse of the two answers: the script looks like it ran.
624
+ *
625
+ * ⚠ The COMPARISON half of that sentence — `OscType.rsi == OscType2.rsi` —
626
+ * is not refused here. It is the same rule and needs the same type
627
+ * information on both operands of a binary expression; no corpus script
628
+ * witnesses it, so it is left as a stated gap rather than a guess. The
629
+ * runtime keeps the two members distinct regardless, which
630
+ * tests/v5/transpiler/enums.test.ts asserts.
631
+ */
632
+ private checkEnumArguments;
633
+ protected callFunctionName(pineName: string, ctx: Fun_callContext): string;
634
+ /**
635
+ * v5 keeps the mutable-argument restriction for ONE member of the family.
636
+ *
637
+ * SOURCING. The manual's Other timeframes and data page states it only of
638
+ * `request.security_lower_tf`: its `expression` parameter "accepts most of the
639
+ * same arguments discussed in that section, excluding direct references to
640
+ * collections and mutable variables declared in the script's main scope". It
641
+ * is said of that function as a DIFFERENCE from `request.security()`, which
642
+ * the same page restricts only INSIDE A LOOP — "all parameters defining parts
643
+ * of the requested context can accept arguments that depend on variables from
644
+ * the loop's header or mutable variables that change within the loop's local
645
+ * scope. However, a request.*() call's evaluated expression cannot depend on
646
+ * the values of those variables."
647
+ *
648
+ * TradingView's own `v5-writing-limitations-10` settles it. That script passes
649
+ * the global `var x = 0`, mutated by 300 `if` blocks, straight into
650
+ * `request.security()`, and its comment names the only error as "compilation
651
+ * error since the scope count is now 602". The blanket v3 guard rejected it
652
+ * one rule too early, for a reason v5 does not have.
653
+ *
654
+ * v3 and v4 are untouched: nothing in either archive lifts the rule there.
655
+ */
656
+ protected securityRestrictsMutableArgs(ctx: Fun_callContext): boolean;
657
+ /**
658
+ * `strategy.long` / `strategy.short` passed as `when` is rejected. They are
659
+ * direction constants, not conditions: v4 let the mistake through, where
660
+ * `strategy.entry("L", strategy.long, when = strategy.long)` read as true.
661
+ * Migration guide to v5 (https://www.tradingview.com/pine-script-docs/migration-guides/to-pine-version-5/):
662
+ * "strategy.long" cannot be passed to `when`; use `direction`.
663
+ */
664
+ protected enforceWhenIsBool(name: string, ctx: Fun_callContext): void;
665
+ /**
666
+ * `strategy.exit()` with no exit condition is rejected (§4d).
667
+ *
668
+ * Positional form is admitted from the fifth argument on: the parameter order
669
+ * is `(id, from_entry, qty, qty_percent, profit, …)`, so a fifth positional
670
+ * argument IS `profit`. Checking the count rather than the names is the only
671
+ * option there — a positional argument carries no name to check.
672
+ */
673
+ protected enforceExitCondition(ctx: Fun_callContext): void;
674
+ /**
675
+ * The collection constructors that take a TYPE ARGUMENT.
676
+ *
677
+ * `array.new<float>(0)` is v5's spelling of `array.new_float(0)`, and this
678
+ * engine implements the per-type constructors — so the type argument is not
679
+ * decoration here, it selects the function. `matrix.new<float>` and
680
+ * `map.new<string, int>` have one implementation each, so their type
681
+ * arguments are parsed and discarded.
682
+ *
683
+ * Returns null when this call is not a typed constructor, so the caller can
684
+ * fall through to the ordinary path.
685
+ */
686
+ protected emitTypedConstructor(name: string, ctx: Fun_callContext): string | null;
687
+ /** Emits `ctx.call("name@L:C", ctx.builtin("name"), …args)` for a built-in. */
688
+ private emitCall;
689
+ /**
690
+ * The RUNTIME's name for a keyword the script spelled the v5 way, or null.
691
+ *
692
+ * Consulted from `visitId` rather than from `visitKw_arg`, which is where it
693
+ * started. `emitSecurity` builds its keyword object itself — it has to, so it
694
+ * can defer the `expression` argument as a thunk — and reads each key by
695
+ * visiting the id directly, so a translation living in `visitKw_arg` was
696
+ * bypassed for exactly the call that needs it most:
697
+ * `request.security(…, timeframe="D")` silently fell back to the chart's
698
+ * timeframe. `visitId` is the one point both paths go through.
699
+ */
700
+ protected keywordAliasFor(written: string): string | undefined;
701
+ /** v5's `stmt` gained four alternatives; the base knows two. */
702
+ visitStmt(ctx: StmtContext): string;
703
+ /**
704
+ * `type Name` + fields → a FACTORY FUNCTION.
705
+ *
706
+ * type Point
707
+ * float x
708
+ * float y = 0.0
709
+ *
710
+ * becomes
711
+ *
712
+ * function opsv2_$type_Point(_a) {
713
+ * const _o = { __type: "Point" };
714
+ * _o.x = ctx.fieldValue(_a.x !== undefined ? _a.x : (NaN));
715
+ * _o.y = ctx.fieldValue(_a.y !== undefined ? _a.y : (0.0));
716
+ * return _o;
717
+ * }
718
+ *
719
+ * A function DECLARATION rather than an object template, for two reasons.
720
+ * Declarations hoist, so a type may be used above the line that declares it
721
+ * inside any function body. And a default has to be RE-EVALUATED per
722
+ * instance: `type Bag\n array<float> xs = array.new<float>(0)` must give
723
+ * every Bag its own array, and a shared template would give them all one.
724
+ *
725
+ * Fields are stored UNPREFIXED. They live inside an object of their own, so
726
+ * there is nothing in the sandbox for them to collide with, and `p.x` reads
727
+ * better in a debugger than `p.opsv2_x`.
728
+ */
729
+ visitType_def_stmt(ctx: Type_def_stmtContext): string;
730
+ /**
731
+ * `enum Name` + fields → one frozen object of MEMBER objects.
732
+ *
733
+ * enum OscType
734
+ * rsi = "Relative Strength Index"
735
+ * mfi = "Money Flow Index"
736
+ *
737
+ * becomes
738
+ *
739
+ * const opsv2_$enum_OscType = ctx.declareEnum("OscType", {
740
+ * "rsi": "Relative Strength Index", "mfi": "Money Flow Index",
741
+ * });
742
+ *
743
+ * whose members are the STRINGS `"OscType.rsi"` and `"OscType.mfi"`. See
744
+ * `Context.declareEnum` for why a member is a string rather than an object —
745
+ * in one line, because `x == OscType.rsi` compares a Series to the member,
746
+ * and JavaScript compares two objects by reference while it coerces an object
747
+ * against a primitive.
748
+ *
749
+ * The enum NAME is part of every member, which keeps the rule the manual
750
+ * states: "Scripts cannot compare members of different enums ... even if the
751
+ * fields have identical names and titles."
752
+ *
753
+ * ── The title default ──────────────────────────────────────────────────
754
+ *
755
+ * "If the programmer does not specify a field's title, its title is the
756
+ * 'string' representation of its name."
757
+ */
758
+ visitEnum_def_stmt(ctx: Enum_def_stmtContext): string;
759
+ /** An enum declaration's fields, in declaration order. */
760
+ protected enumFieldsOf(ctx: Enum_def_stmtContext): EnumField[];
761
+ /** The emitted name of an enum's member table. */
762
+ protected enumFactory(enumName: string): string;
763
+ /** The emitted name of a type's factory. */
764
+ protected typeFactory(typeName: string): string;
765
+ /**
766
+ * `method name(Receiver self, …) => …`.
767
+ *
768
+ * Emitted as an ordinary function, because that is what it is: Pine's
769
+ * `r.area()` and `area(r)` are the same call, and the receiver is simply the
770
+ * first argument. Only the CALL SITES differ, and `visitFun_call` handles
771
+ * those.
772
+ *
773
+ * ── The one limitation ────────────────────────────────────────────────────
774
+ *
775
+ * Pine dispatches on the receiver's declared type, so two methods may share a
776
+ * name if their receivers differ. This engine dispatches on the NAME alone,
777
+ * because it does not track types — so a second method of the same name would
778
+ * emit a second JavaScript function of the same name and silently win. It is
779
+ * rejected instead.
780
+ */
781
+ visitMethod_def_stmt(ctx: Method_def_stmtContext): string;
782
+ /**
783
+ * A method's receiver type — the declared type of its FIRST parameter.
784
+ *
785
+ * "Since user-defined methods require explicit type specification for their
786
+ * first parameter (the receiver object)", this is always written down, and
787
+ * it is the whole basis of overload resolution. A parameter with no declared
788
+ * type is recorded as `?`, which no overload set can be resolved against and
789
+ * which reads correctly in the diagnostic.
790
+ */
791
+ protected receiverTypeOf(inner: Fun_def_singlelineContext | Fun_def_multilineContext): string;
792
+ /**
793
+ * The JavaScript name for one method.
794
+ *
795
+ * Unqualified while the name has a single declaration, so nothing about a
796
+ * script without overloads changes; qualified by receiver type as soon as it
797
+ * has more than one, because two JavaScript functions of the same name are
798
+ * one function and the second silently wins.
799
+ */
800
+ protected methodFunctionName(name: string, receiver: string | null, sig?: FnOverload | null): string;
801
+ /** The signature of the method definition currently being emitted. */
802
+ protected emittingMethodSig: FnOverload | null;
803
+ /** The receiver type of the method definition currently being emitted. */
804
+ protected emittingMethodFor: string | null;
805
+ /**
806
+ * A method's definition takes the qualified name; every other definition
807
+ * keeps its own. Only `visitMethod_def_stmt` sets `emittingMethodFor`, and a
808
+ * definition cannot nest inside another, so the flag cannot leak.
809
+ */
810
+ protected definitionFunctionName(pineName: string): string;
811
+ private withMethodReceiver;
812
+ /**
813
+ * Which overload of `name` a receiver spelled `expression` resolves to.
814
+ *
815
+ * Returns null when `name` is not overloaded — the caller then takes its
816
+ * ordinary path. Throws when it IS overloaded and the receiver's type cannot
817
+ * be proved, because guessing would dispatch to a body written for another
818
+ * type and return a plausible wrong answer.
819
+ */
820
+ protected resolveOverload(name: string, receiverType: string | null, ctx: SourceLocated, argCount?: number | null): string | null;
821
+ /**
822
+ * The declared type of `name` where the code being emitted sits: a
823
+ * parameter or typed local of the enclosing function, else a script-scope
824
+ * declaration.
825
+ */
826
+ protected typeOfName(name: string): string | null;
827
+ /** Script-scope types settled by an initialiser, beyond the scope pass's. */
828
+ protected scriptTypes: Map<string, string>;
829
+ /** The type of `receiver.field1.field2…`, following declared field types. */
830
+ protected typeOfPath(receiver: string, fields: readonly string[]): string | null;
831
+ /**
832
+ * A type stated by a local's initialiser: `P.new(…)`, `lib.P.new(…)`,
833
+ * `array.new<T>(…)` and its `map`/`matrix` siblings, `xs.copy()`. Anything
834
+ * else is unknown rather than guessed.
835
+ */
836
+ protected typeOfInitialiser(expr: ParseTree | null): string | null;
837
+ /**
838
+ * After the last declaration of an overloaded name, a function under the
839
+ * PLAIN name that picks the overload at run time — by argument count, then
840
+ * by the arguments' own types (Context.pickOverload).
841
+ *
842
+ * Calls the emitter can resolve go straight to their overload and never
843
+ * reach it. It serves the rest: a receiver whose type is not written down
844
+ * where it is used, and a library's export, which is published under the
845
+ * plain name and so was "not defined" whenever the name was overloaded.
846
+ */
847
+ protected emitOverloadDispatcher(name: string): string;
848
+ /** How many declarations of each overloaded name have been emitted so far. */
849
+ private emittedOverloads;
850
+ /**
851
+ * Every declaration of `name`, functions and methods together: they share
852
+ * one JavaScript name, so they are one overload set. A library declaring
853
+ * `export dot(Vec2 a, Vec2 b, …)` and `export method dot(float[] a, …)`
854
+ * emitted both as the same function, and the second replaced the first.
855
+ */
856
+ protected overloadTotal(name: string): number;
857
+ /** How many arguments a call passes, positional and keyword. */
858
+ protected argumentCount(args: any | null): number;
859
+ /**
860
+ * A local's declared type — `Point p = …`, or one its initialiser states —
861
+ * recorded for the method calls later in the same function body.
862
+ */
863
+ visitVar_def(ctx: any): string;
864
+ /**
865
+ * TradingView does not evaluate a plain local whose value nothing reads, so
866
+ * an out-of-bounds `array.get` in one raises no error (probes: pe6 in
867
+ * conformance/common/tradingview-findings.md, v6-dead-local; the same read
868
+ * used errors: pe6b, v6-dead-local-used). Only what the probes showed is
869
+ * skipped: a non-`var` local inside a block, never named elsewhere in that
870
+ * block (a loop body re-runs, so earlier statements count), whose value is
871
+ * not the block's result and whose initialiser is built from nothing but
872
+ * reads and `array.get` / `.get`. Anything else is evaluated as before.
873
+ */
874
+ protected isDeadLocal(ctx: any): boolean;
875
+ /** Is `name` (or a field path rooted at it) written anywhere under `node`, bar `skip`? */
876
+ protected mentionsName(node: any, name: string, skip: any): boolean;
877
+ /**
878
+ * Is the value of this statement thrown away? A block's last statement is its
879
+ * value, so it is only discarded when the construct holding the block is
880
+ * itself a statement whose own value is discarded. Unknown shapes say no.
881
+ */
882
+ protected valueDiscarded(content: any): boolean;
883
+ /** Reads, operators and `array.get` / `.get` only: nothing that can have an effect. */
884
+ protected isPureRead(node: any): boolean;
885
+ /** The dispatcher, when `name`'s last declaration has just been emitted. */
886
+ protected afterDefinition(name: string): string;
887
+ /** `name/receiverType` for every method ALREADY EMITTED — the duplicate check above. */
888
+ private definedMethods;
889
+ /**
890
+ * `export` in front of a function, method or type.
891
+ *
892
+ * The declaration is emitted unchanged; the keyword only records that the
893
+ * name is part of a library's public surface. Outside a library it is an
894
+ * error, which is TradingView's rule and is worth enforcing: `export` in an
895
+ * indicator is a script that thinks it is something it is not.
896
+ */
897
+ visitExport_stmt(ctx: Export_stmtContext): string;
898
+ /** The name a `fun_def_stmt` binds, whichever of its two forms it takes. */
899
+ protected definitionName(def: any): string;
900
+ /**
901
+ * `f(float x, int n = 2)` — v5 parameters carry a type and may carry a
902
+ * default.
903
+ *
904
+ * The TYPE is parsed and discarded: this engine evaluates everything as a
905
+ * series, so an annotation cannot change a result, and rejecting a script for
906
+ * carrying one would be worse than ignoring it. The DEFAULT is not — it maps
907
+ * straight onto a JavaScript default parameter, which has the semantics Pine
908
+ * describes (evaluated per call, only when the argument is absent).
909
+ */
910
+ /** v5 parameters are a rule of their own, and may carry a default. */
911
+ protected paramNames(ctx: Fun_headContext): string[];
912
+ visitFun_head(ctx: Fun_headContext): string;
913
+ /**
914
+ * `import user/library/version as alias`.
915
+ *
916
+ * The library is compiled INLINE, into an immediately-invoked function whose
917
+ * result is the namespace object the alias refers to:
918
+ *
919
+ * const opsv2_$lib$mylib = (() => {
920
+ * function opsv2_$fn_f(opsv2_x) { … }
921
+ * return { "f": opsv2_$fn_f };
922
+ * })();
923
+ *
924
+ * ── Why inline, and why an IIFE ───────────────────────────────────────────
925
+ *
926
+ * Inline, because there is nowhere else to put it: the emitted script is one
927
+ * JavaScript function body that the runtime re-invokes per bar, and a library
928
+ * has to be inside that scope to reach `ctx`.
929
+ *
930
+ * An IIFE, because a library has its own script scope. Two scripts that both
931
+ * declare `len = 14` at top level are not sharing a variable, and emitted
932
+ * flat they would be — `let opsv2_len` twice in one scope is a redeclaration
933
+ * error, and with `var` it is worse: it silently works and they overwrite
934
+ * each other.
935
+ *
936
+ * The library's body therefore re-runs per bar exactly as the importing
937
+ * script's does, which is what Pine specifies: a library's top-level code is
938
+ * script-scope code.
939
+ */
940
+ visitImport_stmt(ctx: Import_stmtContext): string;
941
+ /**
942
+ * `alias.EnumName` → its field names, for every enum an import exports.
943
+ *
944
+ * Keyed by the ALIAS rather than the path, because that is what a read
945
+ * spells: two aliases of one library are two namespaces to the script.
946
+ */
947
+ protected libraryEnums: Map<string, string[]>;
948
+ /** The emitted name of an imported library's namespace object. */
949
+ protected libraryNamespace(alias: string): string;
950
+ /**
951
+ * Parses a library's source, and says which version it was parsed as.
952
+ *
953
+ * A seam rather than an inline `parseV5`: a v6 script can import a library
954
+ * written in either version, and each must be read by its OWN grammar — a v5
955
+ * library binding a variable called `once` is legal and must stay so. v5
956
+ * itself only ever had v5 libraries, so this reads everything as v5, exactly
957
+ * as before.
958
+ */
959
+ protected parseLibrary(source: string): {
960
+ parsed: ReturnType<typeof parseV5>;
961
+ version: PineVersion;
962
+ };
963
+ /** The visitor a library parsed as `version` is compiled with. See parseLibrary. */
964
+ protected createLibraryVisitor(_version: PineVersion, options: V5Options): V5ToJsVisitor;
965
+ /**
966
+ * The JavaScript an exported name is reached by, on the library's own
967
+ * visitor — a type's factory, an enum's, or a function. A seam because v6
968
+ * adds a fourth kind of export, the constant.
969
+ */
970
+ protected exportedMemberJs(name: string, types: ReadonlyMap<string, unknown>, enums: ReadonlyMap<string, unknown>): string;
971
+ /**
972
+ * Compiles a library's source with a visitor of its own.
973
+ *
974
+ * A fresh visitor, not this one: a library has its own types, its own
975
+ * methods, its own scope analysis and its own set of exported names, and
976
+ * threading two scripts' worth of that through one instance is how a library
977
+ * would end up able to see the importing script's declarations.
978
+ *
979
+ * Nested imports are allowed — the child gets the same library table. An
980
+ * import back into a library already being compiled (itself, or a cycle
981
+ * through others) is refused by `libraryChain`, and the depth is bounded so a
982
+ * long chain of distinct libraries cannot exhaust the stack either.
983
+ */
984
+ protected compileLibrary(path: string, alias: string, source: string, ctx: SourceLocated): {
985
+ js: string;
986
+ exports: Set<string>;
987
+ types: Map<string, string[]>;
988
+ methods: Set<string>;
989
+ members: string[];
990
+ enums: Map<string, string[]>;
991
+ };
992
+ /**
993
+ * `alias.f(args)` — a call into an imported library.
994
+ *
995
+ * Only EXPORTED names resolve. A library's private helpers are inside the
996
+ * IIFE and unreachable from here, so an unexported name would emit a property
997
+ * read that is `undefined` at run time; naming it at compile time is the
998
+ * whole point of the export list.
999
+ */
1000
+ protected emitLibraryCall(alias: string, path: string, member: string, ctx: Fun_callContext): string;
1001
+ /** `alias.Type.new(…)` and `alias.Type.copy(obj)` — a library's type. */
1002
+ protected emitLibraryTypeCall(alias: string, path: string, typeName: string, member: string, ctx: Fun_callContext): string;
1003
+ /**
1004
+ * v5's `global_stmt_content` / `local_stmt_content` gained `while_expr`, and
1005
+ * the global one gained `switch_expr` directly rather than through the
1006
+ * `arith_expr` wrapper. The statement dispatcher has to route both;
1007
+ * everything else falls through to the inherited implementation.
1008
+ */
1009
+ protected visitContent(ctx: any): string;
1010
+ /** `arith_expr` gained `switch_expr` and `for_in_expr`; the base knows three. */
1011
+ visitArith_expr(ctx: any): string;
1012
+ /**
1013
+ * `for item in xs` and `for [index, item] in xs`.
1014
+ *
1015
+ * Emitted as a real JavaScript `for … of` over `Context.forIn`, for the same
1016
+ * reason `while` is emitted as a real `while`: `break` and `continue` cannot
1017
+ * cross a function boundary, and Pine allows both here.
1018
+ *
1019
+ * The whole thing still sits inside an IIFE, because — unlike `while` — a
1020
+ * `for … in` is an EXPRESSION. The manual's syntax block opens with
1021
+ * `[variables = | :=]`, and its body ends with a `return_expression`, so the
1022
+ * loop has a value: the last one its body produced. `captureLoopResult`
1023
+ * rewrites the block's trailing `return` into an assignment to `_res`, which
1024
+ * is exactly what `visitFor_expr` does for the numeric form — the two loops
1025
+ * differ in how they step, not in what they evaluate to.
1026
+ *
1027
+ * ── Why the pair comes from the runtime rather than the emitter ───────────
1028
+ *
1029
+ * `item` means something different per collection — an element of an array, a
1030
+ * ROW of a matrix, the VALUE half of a map entry — and the emitter cannot
1031
+ * know which it has: `xs` is an expression, and this engine does not track
1032
+ * element types. `Context.forIn` decides at runtime, where the value is,
1033
+ * and hands back a uniform `[key, value]`. It also owns the two size rules,
1034
+ * which differ between maps and the rest.
1035
+ */
1036
+ visitFor_in_expr(ctx: For_in_exprContext): string;
1037
+ /**
1038
+ * `while cond` + block. A STATEMENT: it evaluates to nothing.
1039
+ *
1040
+ * Emitted as a real JavaScript `while` rather than an IIFE, so `break` and
1041
+ * `continue` inside it are legal — the same reason `visitIf_expr` drops the
1042
+ * IIFE for a statement-`if` inside a loop. `loopDepth` is raised for exactly
1043
+ * that: it is what makes a nested statement-`if` emit as a plain `if`.
1044
+ *
1045
+ * The trailing return that a block normally ends with is SUPPRESSED, because
1046
+ * there is no function boundary here to contain it — a `return` would leave
1047
+ * the enclosing user function, or be a syntax error at script scope.
1048
+ */
1049
+ visitWhile_expr(ctx: While_exprContext): string;
1050
+ /**
1051
+ * `switch` — an EXPRESSION, in both of its forms.
1052
+ *
1053
+ * switch expr each label is compared to `expr`
1054
+ * 1 => "one"
1055
+ * => "other" a label-less arm is the default
1056
+ *
1057
+ * switch each label is a condition in its own right
1058
+ * x > 5 => "big"
1059
+ *
1060
+ * Emitted as an IIFE, because the arms have to be able to evaluate to
1061
+ * something and a `return` needs a function to belong to. The subject is
1062
+ * bound to a temporary first so it is evaluated ONCE — Pine evaluates it once,
1063
+ * and re-evaluating a `ta.*` call per arm would advance its history several
1064
+ * times a bar and quietly desynchronise it.
1065
+ */
1066
+ /**
1067
+ * The loop depth at each enclosing `switch`. A `switch` is emitted as an
1068
+ * arrow function, so a `break` in one of its arms that belongs to a loop
1069
+ * OUTSIDE it cannot be a JavaScript `break`: Pine allows
1070
+ *
1071
+ * for i = 0 to n
1072
+ * switch kind
1073
+ * 1 =>
1074
+ * if found
1075
+ * break
1076
+ *
1077
+ * and the emitted `break` was an "Illegal break statement". It is thrown as
1078
+ * a loop signal instead, which that loop's body catches (captureLoopResult).
1079
+ */
1080
+ protected switchLoopFloors: number[];
1081
+ visitLoop_break(ctx: any): string;
1082
+ visitLoop_continue(ctx: any): string;
1083
+ visitSwitch_expr(ctx: Switch_exprContext): string;
1084
+ /**
1085
+ * What a switch evaluates to when no arm matches. `na` at v5; a seam for the
1086
+ * same reason as `ifFallthrough` in the v1 base.
1087
+ */
1088
+ protected switchFallthrough(_ctx: Switch_exprContext): string;
1089
+ /**
1090
+ * One arm's body, as a JavaScript block that RETURNS the arm's value.
1091
+ *
1092
+ * An indented block already ends in a `return` — that is what
1093
+ * `visitLocal_stmts_list` does with a block's last statement. A single-line
1094
+ * body does not, and cannot simply be wrapped in one either: `1 => x = 2`
1095
+ * emits a declaration, and `return let x = …` is a syntax error. A trailing
1096
+ * binding evaluates to the bound name, which is the same rule a function body
1097
+ * follows — so this is exactly `singleLineBody`.
1098
+ */
1099
+ protected caseBody(arm: Switch_caseContext): string;
1100
+ }
1101
+ export {};