diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f2ce251d..d8339b9c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -152,12 +152,15 @@ jobs: # A prerelease is a GitHub prerelease and never "Latest". channel=() if [ "$PRERELEASE" = true ]; then channel=(--prerelease --latest=false); fi + # The diagnostics catalog (docs/PUBLIC_CONTRACT.md, "Diagnostic codes"). + catalog="diagnostics_catalog-${GIT_TAG}.json" + cp pineforge_codegen/diagnostics_catalog.json "${catalog}" gh release create "${GIT_TAG}" \ --title "${GIT_TAG}" \ --generate-notes \ --notes "Install: \`pip install pineforge-codegen==${PYPI_VERSION}\`" \ ${channel[@]+"${channel[@]}"} \ - dist/* + dist/* "${catalog}" # Notify the pineforge-release hub: it bumps its CODEGEN_VERSION pin, # rebuilds the combined image, and fans out to the MCPs. FAIL LOUD (no diff --git a/AGENTS.md b/AGENTS.md index ce3975a1..626d5930 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -171,6 +171,13 @@ pineforge_codegen/ ├── tv_input_choices.py input.string options metadata ├── errors.py CompileError + SourceLocation + │ Diagnostic + Level / Phase +├── diagnostic_codes.py Stable diagnostic codes: a Diagnostic's +│ code/args are read off its text by the +│ ICU templates of diagnostics_catalog.json +│ (scripts/gen_diagnostics_catalog.py adds a +│ code per new template; the pin in +│ tests/fixtures/diagnostic_codes_pin.json +│ never changes a code's meaning). ├── pine_spelling.py String-literal-safe helpers for the Pine │ spellings of TA ctor args (inline │ input calls kept whole; see quirk 10) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3559b8a2..14197629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,26 @@ supported as exact pairs; on the 0.x line they are independent. See the without the extension warn and run, including their requests, without proving eligibility. Default batch computation is unchanged. +### Diagnostic codes + +An additive change to the public API; it leaves the emitted C++ unchanged. + +- **Diagnostic codes.** Every transpile diagnostic carries a stable `code` + (`PF-E1203` / `PF-W0412`) and named, raw `args`, in + `transpile_full(...)["diagnostics"]`, in `CompileError.diagnostics` and in + the `transpile_json` envelopes. `diagnostics_catalog()` and + `pineforge_codegen/diagnostics_catalog.json` (attached to each GitHub + release) give each code its severity, English ICU MessageFormat templates, + argument kinds and a one-line explanation; the templates render the + `message` and `hint` byte for byte, which keep their text. Codes are never + reused (`tests/fixtures/diagnostic_codes_pin.json`). See + [Diagnostic codes](docs/PUBLIC_CONTRACT.md#diagnostic-codes). +- **First error in source order.** Since 1.1.0 the settings metadata visited + every input's `defval`, `options`, `minval`, `maxval` and `step` ahead of + the script body, so an error there (an unknown name in `minval`) was raised + before an error on an earlier line. The script's first error in source + order is raised again; no emitted C++ changes. + ## Release note policy - Keep a section for each released version, including prereleases. Use the exact diff --git a/CLAUDE.md b/CLAUDE.md index 87c2cf0a..82f483fc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -171,6 +171,13 @@ pineforge_codegen/ ├── tv_input_choices.py input.string options metadata ├── errors.py CompileError + SourceLocation + │ Diagnostic + Level / Phase +├── diagnostic_codes.py Stable diagnostic codes: a Diagnostic's +│ code/args are read off its text by the +│ ICU templates of diagnostics_catalog.json +│ (scripts/gen_diagnostics_catalog.py adds a +│ code per new template; the pin in +│ tests/fixtures/diagnostic_codes_pin.json +│ never changes a code's meaning). ├── pine_spelling.py String-literal-safe helpers for the Pine │ spellings of TA ctor args (inline │ input calls kept whole; see quirk 10) diff --git a/README.md b/README.md index 508f4df4..253ecdd5 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,33 @@ warnings; since 1.1.0 the success envelope also carries `requests`. See the for the exact fields, severity values, and input key rules. There is no installed CLI or exit-code contract. +### Diagnostic codes + +Every diagnostic carries a stable `code` and named `args` (since 1.2.0): +`PF-E1203` for an error, `PF-W0412` for a warning, and the data its English +`message` and `hint` were built from — identifiers, types, keywords and +numbers, raw. + +```python +from pineforge_codegen import diagnostics_catalog, transpile_full + +for d in transpile_full(source)["diagnostics"]: + print(d.code, d.args, d.message) +# PF-W1067 {'name': 'bar_index'} bar_index diverges from TradingView semantics in PineForge. + +entry = diagnostics_catalog()["codes"]["PF-W1067"] +# {'severity': 'warning', 'area': 'support', +# 'message': '{name} diverges from TradingView semantics in PineForge.', +# 'hint': '...', 'explanation': '...', 'args': {'name': {'kind': 'identifier'}}} +``` + +The catalog (`pineforge_codegen/diagnostics_catalog.json`, also attached to +each GitHub release) gives each code its severity, English ICU MessageFormat +templates and a one-line explanation; rendering the templates with `args` +gives the `message` and `hint` byte for byte, so an application can translate +a diagnostic by its code. Codes are never reused. See +[Diagnostic codes](docs/PUBLIC_CONTRACT.md#diagnostic-codes). + ### List the other symbols a script requests A run reads another symbol's bars only from the feed it is given for that diff --git a/docs/PUBLIC_CONTRACT.md b/docs/PUBLIC_CONTRACT.md index a7bb77f4..d54b2027 100644 --- a/docs/PUBLIC_CONTRACT.md +++ b/docs/PUBLIC_CONTRACT.md @@ -239,9 +239,50 @@ and `diagnostics` contains the error's diagnostics; `cpp`, `inputs`, integer `line` and `col`, a `message` string, and `severity` equal to `"warning"` or `"error"`. `endCol` is included when the source location provides it. A diagnostic hint, when present, is appended to -`message` after ` — `. The glue catches `CompileError`; an unexpected Python -exception may propagate instead of producing an envelope. The JSON entry -point does not accept a `filename` argument. +`message` after ` — `. Since 1.2.0 every JSON diagnostic also has `code` and +`args` ([Diagnostic codes](#diagnostic-codes)). The glue catches +`CompileError`; an unexpected Python exception may propagate instead of +producing an envelope. The JSON entry point does not accept a `filename` +argument. + +## Diagnostic codes + +Since 1.2.0 every `Diagnostic` (in `transpile_full(...)["diagnostics"]`, in a +`CompileError`'s `diagnostics`, and in the glue envelopes) carries: + +- `code`: a stable string `PF-`, `S` being `E` for an error and `W` + for a warning. Its first digit is the area that spells the text: `0` + source (lexer, parser, limits), `1` support checker and requests, `2` + analysis, `3` `request.security`, `4` libraries and imports, `5` code + generation, `6` array and matrix history, `7` `ta.*`. The support checker + reports what it refuses inside a `switch` arm as a warning: `PF-W1nnn` with + `nnn` below 500 is `PF-E1nnn` there. +- `args`: an object of named values, raw: identifiers, types, keywords and + Pine spellings as strings, counts as JSON numbers; never quoting, backticks + or a formatted number. + +`diagnostics_catalog()` returns the catalog, which ships as +`pineforge_codegen/diagnostics_catalog.json` (schema +`pineforge-diagnostics-catalog/v1`) and is attached to each GitHub release. +Per code it gives `severity`, `area`, the English ICU MessageFormat `message` +template, the `hint` template or `null`, a one-line `explanation`, and `args`: +per argument its `kind` — `identifier`, `type`, `keyword`, `number`, `vocab` +(an English word or phrase the transpiler picks from the closed set listed in +`values`, which an application may translate) or `text` (open English text the +transpiler builds, such as a nested reason; shown as is). The templates use +simple `{name}` arguments and ICU apostrophe quoting (`''` is one apostrophe, +`'{'` a literal brace); a string argument renders as is and a number in plain +decimal digits. `render_diagnostic(code, args)` returns the English +`(message, hint)`, which equal the diagnostic's `message` and `hint` byte for +byte; in the glue envelope `message` is the message, plus ` — ` and the hint +when there is one. + +A code is never removed or reused, and a changed meaning gets a new code +(`tests/fixtures/diagnostic_codes_pin.json` pins each code's templates). A +text no template renders carries `PF-E0000` / `PF-W0000` with the text in +`args.message` (and `args.hint`); the test suite refuses it. The `message` +text itself is unchanged and stays the English rendering; `runtime.error` +text a strategy authors is not a transpile diagnostic. ## Compatibility boundary diff --git a/gate/glue.py b/gate/glue.py index 7ddb8d71..9e364682 100644 --- a/gate/glue.py +++ b/gate/glue.py @@ -23,6 +23,10 @@ def _diagnostic_entries(diagnostics) -> list: "col": loc.col if loc else 1, "message": message, "severity": getattr(d.level, "value", "error"), + # The stable code and named arguments of the catalog templates the + # message (and the hint after " — ") render from. + "code": d.code, + "args": d.args, } end_col = getattr(loc, "end_col", None) if loc else None if end_col is not None: diff --git a/npm/package.json b/npm/package.json index b5405ba0..257f7071 100644 --- a/npm/package.json +++ b/npm/package.json @@ -7,7 +7,8 @@ "exports": { ".": "./index.mjs", "./tables.json": "./tables.json", - "./release.json": "./release.json" + "./release.json": "./release.json", + "./diagnostics_catalog.json": "./pineforge_codegen/diagnostics_catalog.json" }, "files": [ "index.mjs", diff --git a/pineforge_codegen/__init__.py b/pineforge_codegen/__init__.py index b9d5a7eb..34a7dac2 100644 --- a/pineforge_codegen/__init__.py +++ b/pineforge_codegen/__init__.py @@ -6,6 +6,7 @@ from .parser import Parser from .analyzer import Analyzer from .codegen import CodeGen +from .diagnostic_codes import diagnostics_catalog, render_diagnostic from .errors import CompileError, Level, Phase from .external_requests import lower_no_data_requests from .builtin_keywords import bind_builtin_keywords diff --git a/pineforge_codegen/codegen/base.py b/pineforge_codegen/codegen/base.py index 095379f2..98c7d2f7 100644 --- a/pineforge_codegen/codegen/base.py +++ b/pineforge_codegen/codegen/base.py @@ -4414,7 +4414,44 @@ def _declared_cpp_type(self, decl: VarDecl) -> str | None: return None def generate(self) -> str: - """Generate C++ source from the AnalyzerContext.""" + """Generate C++ source from the AnalyzerContext. + + An error the settings metadata finds in an input's arguments (emitted + in the constructor, ahead of the body: ``checked_settings``) is held + until the rest is generated; the error raised is the first in source + order, as before that metadata visited the arguments.""" + self._deferred_settings_errors: list[CompileError] | None = [] + try: + try: + cpp = self._generate_cpp() + except CompileError as error: + first = self._first_settings_error_before(error) + if first is None: + raise + raise first from None + if self._deferred_settings_errors: + raise self._deferred_settings_errors[0] + return cpp + finally: + self._deferred_settings_errors = None + + def _defer_settings_error(self, error: CompileError) -> None: + held = getattr(self, "_deferred_settings_errors", None) + if held is None: # outside generate(): nothing holds it + raise error + held.append(error) + + def _first_settings_error_before(self, error: CompileError) -> CompileError | None: + """A held settings error located before ``error``, else None.""" + def where(err: CompileError): + loc = err.diagnostics[0].location if err.diagnostics else None + return (loc.line, loc.col) if loc is not None else (float("inf"), 0) + held = sorted(self._deferred_settings_errors, key=where) + if held and where(held[0]) < where(error): + return held[0] + return None + + def _generate_cpp(self) -> str: # Every input is keyed by its title: refuse a non-constant one first, # then flag inputs one override key would reach together. self._check_input_titles() diff --git a/pineforge_codegen/codegen/checked_settings.py b/pineforge_codegen/codegen/checked_settings.py index 58d80a37..87976a6e 100644 --- a/pineforge_codegen/codegen/checked_settings.py +++ b/pineforge_codegen/codegen/checked_settings.py @@ -1,6 +1,19 @@ """Opt-in settings metadata, validation and exception-contained C exports.""" from ..ast_nodes import Identifier, MemberAccess +from ..errors import CompileError + + +def _visit_setting_arg(emitter, expr) -> str: + """An input argument's C++ for the settings metadata. The metadata is + emitted in the constructor, ahead of the script body: an error here is + held until the body is generated (``CodeGen.generate``), so the script's + first error in source order is the one raised.""" + try: + return emitter._visit_expr(expr) + except CompileError as error: + emitter._defer_settings_error(error) + return "0" def emit_settings_members(emitter, lines: list[str], constructor: list[str]) -> None: @@ -38,7 +51,7 @@ def emit_settings_members(emitter, lines: list[str], constructor: list[str]) -> key = emitter._input_key_literal(name) default = emitter._get_input_default(node) getter = emitter._input_getter_for_call(node, func_name, namespace) - default_cpp = emitter._visit_expr(default) if default is not None else "0" + default_cpp = _visit_setting_arg(emitter, default) if default is not None else "0" default_cpp = emitter._coerce_string_input_default(getter, default_cpp) value_type = { "get_input_int": "int", "get_input_int64": "int", @@ -89,7 +102,7 @@ def emit_settings_members(emitter, lines: list[str], constructor: list[str]) -> declared = getattr(arguments.get("options"), "elements", None) if declared: for option in declared: - option_cpp = emitter._visit_expr(option) + option_cpp = _visit_setting_arg(emitter, option) options.append(option_cpp if getter == "get_input_string" else f'::pineforge::checked_settings::number({option_cpp})') expression = f'{getter}({key}, {default_cpp})' @@ -98,7 +111,7 @@ def emit_settings_members(emitter, lines: list[str], constructor: list[str]) -> if default_serialized is None: default_serialized = (default_cpp if value_type in ("string", "source") else f'::pineforge::checked_settings::number({default_cpp})') - constraints = [emitter._visit_expr(arguments[name]) if arguments.get(name) is not None + constraints = [_visit_setting_arg(emitter, arguments[name]) if arguments.get(name) is not None else "std::numeric_limits::quiet_NaN()" for name in ("minval", "maxval", "step")] metadata = (f'{{{key}, "{value_type}", {default_serialized}, ' diff --git a/pineforge_codegen/diagnostic_codes.py b/pineforge_codegen/diagnostic_codes.py new file mode 100644 index 00000000..b476a45c --- /dev/null +++ b/pineforge_codegen/diagnostic_codes.py @@ -0,0 +1,246 @@ +"""Stable codes and named arguments for every transpile diagnostic. + +Every :class:`~pineforge_codegen.errors.Diagnostic` carries a ``code`` +(``PF-E1203`` for an error, ``PF-W0412`` for a warning) and ``args``, the +named data its English ``message`` and ``hint`` were built from. The codes, +their severities, English ICU MessageFormat templates and one-line +explanations live in ``diagnostics_catalog.json`` beside this module, which +ships with the package and is returned by :func:`diagnostics_catalog`. + +The emitters keep spelling their English text as they always have, so the +``message`` stays byte for byte what it was; a diagnostic is coded by the +catalog template its text renders from (:func:`classify`). The template's +literal text must equal the message's around its arguments, so a code is +never guessed: a text no template renders gets the uncatalogued code of its +severity (``PF-E0000`` / ``PF-W0000``), which the test suite refuses. + +Rendering (:func:`render`) is the ICU MessageFormat subset the catalog uses: +literal text with ICU apostrophe quoting (``''`` is one apostrophe, ``'{'`` +a literal brace) and simple ``{name}`` arguments, a string argument +inserted as is and a number in plain decimal digits. +""" + +from __future__ import annotations + +import json +import re +from functools import lru_cache +from pathlib import Path +from typing import Any + +CATALOG_PATH = Path(__file__).with_name("diagnostics_catalog.json") +CATALOG_SCHEMA = "pineforge-diagnostics-catalog/v1" +UNCATALOGUED = {"error": "PF-E0000", "warning": "PF-W0000"} + + +@lru_cache(maxsize=1) +def _load() -> dict: + with CATALOG_PATH.open(encoding="utf-8") as handle: + return json.load(handle) + + +def diagnostics_catalog() -> dict: + """The diagnostics catalog: ``{"schema", "codes": {code: entry}}``. + + Each entry gives ``severity`` (``error`` / ``warning``), ``area``, the + English ICU MessageFormat ``message`` template, the ``hint`` template or + ``None``, a one-line ``explanation`` and ``args``: per argument name its + ``kind`` (``identifier``, ``type``, ``keyword``, ``number``, ``vocab`` or + ``text``) and, for ``vocab``, its closed set of ``values``. A fresh copy + is returned on every call. + """ + return json.loads(json.dumps(_load())) + + +# --------------------------------------------------------------------------- +# ICU MessageFormat subset +# --------------------------------------------------------------------------- + +_SPECIAL = "{}" + + +def parse_template(template: str) -> list: + """Split a catalog template into literal strings and ``(name,)`` argument + tuples, applying ICU's apostrophe rules (``ApostropheMode.DOUBLE_OPTIONAL``, + the ICU and FormatJS default).""" + parts: list = [] + text: list[str] = [] + i, n = 0, len(template) + while i < n: + ch = template[i] + if ch == "'": + if i + 1 < n and template[i + 1] == "'": + text.append("'") + i += 2 + continue + if i + 1 < n and template[i + 1] in _SPECIAL: + # A quoted literal runs to the next lone apostrophe. + i += 1 + while i < n: + if template[i] == "'": + if i + 1 < n and template[i + 1] == "'": + text.append("'") + i += 2 + continue + i += 1 + break + text.append(template[i]) + i += 1 + continue + text.append("'") + i += 1 + continue + if ch == "{": + end = template.find("}", i) + if end < 0: + raise ValueError(f"unclosed argument in template: {template!r}") + name = template[i + 1:end].strip() + if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", name): + raise ValueError(f"unsupported argument {name!r} in template: {template!r}") + if text: + parts.append("".join(text)) + text = [] + parts.append((name,)) + i = end + 1 + continue + if ch == "}": + raise ValueError(f"unbalanced '}}' in template: {template!r}") + text.append(ch) + i += 1 + if text: + parts.append("".join(text)) + return parts + + +def escape_literal(text: str) -> str: + """ICU-escape literal text: every apostrophe doubled, every brace quoted.""" + out: list[str] = [] + for ch in text: + if ch == "'": + out.append("''") + elif ch in _SPECIAL: + out.append("'" + ch + "'") + else: + out.append(ch) + return "".join(out) + + +def format_arg(value: Any) -> str: + """An argument's text: a string as is, a number in plain decimal digits.""" + if isinstance(value, bool): + raise TypeError("diagnostic arguments are strings or numbers") + if isinstance(value, int): + return str(value) + if isinstance(value, float): + return repr(value) + if isinstance(value, str): + return value + raise TypeError(f"diagnostic argument of type {type(value).__name__}") + + +def render(template: str | None, args: dict) -> str | None: + """Render a catalog template with a diagnostic's ``args``.""" + if template is None: + return None + return "".join( + part if isinstance(part, str) else format_arg(args[part[0]]) + for part in parse_template(template) + ) + + +def render_diagnostic(code: str, args: dict) -> tuple[str, str | None]: + """The English ``(message, hint)`` a code renders with ``args``.""" + entry = _load()["codes"][code] + return render(entry["message"], args), render(entry.get("hint"), args) + + +# --------------------------------------------------------------------------- +# Classification +# --------------------------------------------------------------------------- + +# Joins a message and its hint into one subject, so an argument both name is +# one value (a backreference). No template spells it. +_JOIN = "\x00" +_CANONICAL_INT = re.compile(r"-?(?:0|[1-9][0-9]*)") +_CANONICAL_FLOAT = re.compile(r"-?(?:0|[1-9][0-9]*)\.[0-9]+") + + +class _Matcher: + __slots__ = ("code", "has_hint", "prefix", "suffix", "specificity", + "_parts", "_regex", "_kinds") + + def __init__(self, code: str, entry: dict): + self.code = code + message = parse_template(entry["message"]) + hint = entry.get("hint") + self.has_hint = hint is not None + self._parts = message + ([_JOIN] + parse_template(hint) if hint is not None else []) + self.prefix = message[0] if message and isinstance(message[0], str) else "" + self.suffix = message[-1] if message and isinstance(message[-1], str) else "" + self.specificity = sum(len(p) for p in self._parts if isinstance(p, str)) + self._regex = None + self._kinds = {name: spec.get("kind") for name, spec in entry.get("args", {}).items()} + + def match(self, subject: str) -> dict | None: + if self._regex is None: + pieces: list[str] = [] + seen: set[str] = set() + for part in self._parts: + if isinstance(part, str): + pieces.append(re.escape(part)) + elif part[0] in seen: + pieces.append(f"(?P={part[0]})") + else: + seen.add(part[0]) + pieces.append(f"(?P<{part[0]}>.*?)") + self._regex = re.compile("".join(pieces), re.DOTALL) + found = self._regex.fullmatch(subject) + if found is None: + return None + args: dict[str, Any] = {} + for name, value in found.groupdict().items(): + if self._kinds.get(name) == "number": + if _CANONICAL_INT.fullmatch(value): + args[name] = int(value) + continue + if _CANONICAL_FLOAT.fullmatch(value) and repr(float(value)) == value: + args[name] = float(value) + continue + args[name] = value + return args + + +@lru_cache(maxsize=1) +def _matchers() -> dict[str, list[_Matcher]]: + by_severity: dict[str, list[_Matcher]] = {"error": [], "warning": []} + for code, entry in _load()["codes"].items(): + if code in UNCATALOGUED.values(): + continue + by_severity[entry["severity"]].append(_Matcher(code, entry)) + for matchers in by_severity.values(): + # The template with the most literal text wins: a message two templates + # render reads as the more specific one (both render it byte for byte). + matchers.sort(key=lambda m: (-m.specificity, m.code)) + return by_severity + + +def classify(severity: str, message: str, hint: str | None = None) -> tuple[str, dict]: + """The ``(code, args)`` of a diagnostic's English text. + + ``severity`` is ``"error"`` or ``"warning"``. A text no catalog template + renders gets ``PF-E0000`` / ``PF-W0000`` with its text as ``args``. + """ + subject = message if hint is None else message + _JOIN + hint + for matcher in _matchers().get(severity, ()): + if matcher.has_hint != (hint is not None): + continue + if not message.startswith(matcher.prefix) or not message.endswith(matcher.suffix): + continue + args = matcher.match(subject) + if args is not None: + return matcher.code, args + args = {"message": message} + if hint is not None: + args["hint"] = hint + code = UNCATALOGUED.get(severity, UNCATALOGUED["error"]) + return code, args diff --git a/pineforge_codegen/diagnostics_catalog.json b/pineforge_codegen/diagnostics_catalog.json new file mode 100644 index 00000000..e214060e --- /dev/null +++ b/pineforge_codegen/diagnostics_catalog.json @@ -0,0 +1,631 @@ +{"schema": "pineforge-diagnostics-catalog/v1", + "codes": { + "PF-E0000": {"severity": "error", "area": "uncatalogued", "message": "{message}", "hint": "{hint}", "explanation": "A diagnostic whose text no catalog template renders; the test suite refuses it, so a release never emits it.", "args": {"message": {"kind": "text"}, "hint": {"kind": "text"}}}, + "PF-E0001": {"severity": "error", "area": "source", "message": "Block nesting depth exceeds {max_nesting_depth} levels.", "hint": null, "explanation": "Indented blocks (if, for, while, functions) are nested deeper than PineForge allows; flatten the structure.", "args": {"max_nesting_depth": {"kind": "number"}}}, + "PF-E0002": {"severity": "error", "area": "source", "message": "Invalid color literal: expected hex digits after ''#''", "hint": "Color literals must be #RRGGBB or #RRGGBBAA", "explanation": "A '#' starts a color literal but no hex digits follow it; write the color as #RRGGBB or #RRGGBBAA.", "args": {}}, + "PF-E0003": {"severity": "error", "area": "source", "message": "Delimiter nesting depth exceeds {max_nesting_depth} levels.", "hint": null, "explanation": "Parentheses or square brackets are nested deeper than PineForge allows; split the expression into simpler steps.", "args": {"max_nesting_depth": {"kind": "number"}}}, + "PF-E0004": {"severity": "error", "area": "source", "message": "Unexpected character: ''{ch}''", "hint": null, "explanation": "The script contains a character that is not valid Pine syntax outside a string; remove or replace it.", "args": {"ch": {"kind": "identifier"}}}, + "PF-E0005": {"severity": "error", "area": "source", "message": "Malformed scientific notation: expected digits after exponent", "hint": "Example: 1.5e-3 or 2E10", "explanation": "A number in scientific notation has an exponent marker (e or E) with no digits after it; add the exponent digits or drop the marker.", "args": {}}, + "PF-E0006": {"severity": "error", "area": "source", "message": "Unterminated string literal: the line ends before its closing quote and the next line is not indented as a wrapped line.", "hint": "Close the string on its line, indent the line it wraps onto, or use a multiline string (\"\"\"...\"\"\").", "explanation": "A string is not closed on its line and the next line is not an indented continuation; close the quote or use a triple-quoted string.", "args": {}}, + "PF-E0007": {"severity": "error", "area": "source", "message": "Unterminated multiline string literal: no closing {delimiter} before the end of the script.", "hint": "A multiline string ends at the next \"\"\" (or '''''' for one opened with ''''''); escape a quote that would end it early.", "explanation": "A triple-quoted string never reaches its closing delimiter before the script ends; add the closing triple quote or escape an early quote.", "args": {"delimiter": {"kind": "identifier"}}}, + "PF-E0008": {"severity": "error", "area": "source", "message": "Source size exceeds {max_source_chars} characters.", "hint": null, "explanation": "The script is larger than the maximum source size PineForge accepts; shorten it.", "args": {"max_source_chars": {"kind": "number"}}}, + "PF-E0009": {"severity": "error", "area": "source", "message": "AST nesting depth exceeds {max_nesting_depth} nodes.", "hint": null, "explanation": "An expression or operator chain is so long that its syntax tree is deeper than PineForge allows; break it into several statements.", "args": {"max_nesting_depth": {"kind": "number"}}}, + "PF-E0010": {"severity": "error", "area": "source", "message": "Transpilation time exceeds {max_transpile_seconds} seconds.", "hint": null, "explanation": "Transpiling the script ran past the time limit; simplify it, for example by reducing very large or deeply nested code.", "args": {"max_transpile_seconds": {"kind": "number"}}}, + "PF-E0011": {"severity": "error", "area": "source", "message": "Expected {expected_token}, got {token_type}(''{token}''). {msg}", "hint": null, "explanation": "The parser required one specific token here and found another; fix the syntax at the reported position.", "args": {"expected_token": {"kind": "keyword"}, "token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}, "msg": {"kind": "text"}}}, + "PF-E0012": {"severity": "error", "area": "source", "message": "Nesting depth exceeds {max_nesting_depth} levels.", "hint": null, "explanation": "Blocks, else-if chains, prefix operators or nested expressions go deeper than PineForge's nesting limit; flatten the code.", "args": {"max_nesting_depth": {"kind": "number"}}}, + "PF-E0013": {"severity": "error", "area": "source", "message": "Unexpected token {token_type}(''{token}'') after statement; expected a line break or comma", "hint": null, "explanation": "Two expressions sit on one line with nothing between them; separate statements with a line break or a comma.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0014": {"severity": "error", "area": "source", "message": "''export'' declarations belong to Pine libraries; PineForge transpiles strategies only", "hint": null, "explanation": "export marks a Pine library declaration, but PineForge transpiles strategies only; remove export or write a strategy.", "args": {}}, + "PF-E0015": {"severity": "error", "area": "source", "message": "Expected LPAREN, got {token_type}(''{token}'').", "hint": null, "explanation": "A '(' is missing where a call, a declaration's argument list or a function definition requires one.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0016": {"severity": "error", "area": "source", "message": "Expected RPAREN, got {token_type}(''{token}'').", "hint": null, "explanation": "A ')' is missing or misplaced: a call, parameter list or parenthesized expression is not closed properly.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0017": {"severity": "error", "area": "source", "message": "''export'' must precede a function, method, type, enum or const declaration", "hint": null, "explanation": "In a library, export must be followed by a function, method, type, enum or const declaration; nothing else can be exported.", "args": {}}, + "PF-E0018": {"severity": "error", "area": "source", "message": "Expected IMPORT, got {token_type}(''{token}'').", "hint": null, "explanation": "The parser expected the import keyword to start an import statement but found another token; check the line's spelling.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0019": {"severity": "error", "area": "source", "message": "Expected IDENT, got {token_type}(''{token}'').", "hint": null, "explanation": "A name was expected here (a variable, function, parameter, field, type or loop variable) but another token was found.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0020": {"severity": "error", "area": "source", "message": "Expected EQUALS, got {token_type}(''{token}'').", "hint": null, "explanation": "An '=' was expected after the declared name (variable, tuple or for-loop start); add it or fix the declaration.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0021": {"severity": "error", "area": "source", "message": "Expected LBRACKET, got {token_type}(''{token}'').", "hint": null, "explanation": "A tuple declaration must start with '[' as in [a, b] = f(); the opening bracket is missing or misplaced.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0022": {"severity": "error", "area": "source", "message": "Expected RBRACKET, got {token_type}(''{token}'').", "hint": null, "explanation": "A ']' is missing: a tuple declaration, for-in destructuring, array literal or index expression is not closed.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0023": {"severity": "error", "area": "source", "message": "Expected FAT_ARROW, got {token_type}(''{token}'').", "hint": null, "explanation": "A function or method definition, or a switch case, needs '=>' here; it is missing or misplaced.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0024": {"severity": "error", "area": "source", "message": "Expected IF, got {token_type}(''{token}'').", "hint": null, "explanation": "The parser expected the if keyword at the start of an if statement but found another token.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0025": {"severity": "error", "area": "source", "message": "Expected NEWLINE, got {token_type}(''{token}'').", "hint": null, "explanation": "An if, else, for, while or switch header must end its line before its indented body; other tokens follow it on the same line.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0026": {"severity": "error", "area": "source", "message": "Expected INDENT, got {token_type}(''{token}'').", "hint": null, "explanation": "An indented block was expected after the header or definition, but the next line is not indented further; indent the block's statements.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0027": {"severity": "error", "area": "source", "message": "Expected DEDENT, got {token_type}(''{token}'').", "hint": null, "explanation": "The parser expected an indented block to end but found other tokens; check the indentation of the block's lines.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0028": {"severity": "error", "area": "source", "message": "Expected FOR, got {token_type}(''{token}'').", "hint": null, "explanation": "The parser expected the for keyword at the start of a for loop but found another token.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0029": {"severity": "error", "area": "source", "message": "Expected IN, got {token_type}(''{token}'').", "hint": null, "explanation": "A for-in loop with destructured variables is missing the in keyword after them.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0030": {"severity": "error", "area": "source", "message": "Expected TO, got {token_type}(''{token}'').", "hint": null, "explanation": "A counted for loop is missing the to keyword between its start and end values, as in for i = 0 to n.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0031": {"severity": "error", "area": "source", "message": "Expected WHILE, got {token_type}(''{token}'').", "hint": null, "explanation": "The parser expected the while keyword at the start of a while loop but found another token.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0032": {"severity": "error", "area": "source", "message": "Expected SWITCH, got {token_type}(''{token}'').", "hint": null, "explanation": "The parser expected the switch keyword at the start of a switch but found another token.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0033": {"severity": "error", "area": "source", "message": "Expected COLON, got {token_type}(''{token}''). Expected '':'' in ternary", "hint": null, "explanation": "A ternary condition ? value must be followed by ':' and an else value; add the colon or complete the expression.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0034": {"severity": "error", "area": "source", "message": "Expected IDENT, got {token_type}(''{token}''). Expected member name", "hint": null, "explanation": "A '.' must be followed by a member name (a field or method); the token after the dot is not a name.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E0035": {"severity": "error", "area": "source", "message": "duplicate keyword argument ''{key_tok}''", "hint": "Remove one ''{key_tok}='' binding; a keyword argument may be specified only once.", "explanation": "A call binds the same keyword argument twice; keep only one binding.", "args": {"key_tok": {"kind": "identifier"}}}, + "PF-E0036": {"severity": "error", "area": "source", "message": "Numeric literal exceeds the generated C++ range.", "hint": null, "explanation": "A numeric literal is too large to be written in the generated C++ code; use a smaller number.", "args": {}}, + "PF-E0037": {"severity": "error", "area": "source", "message": "Unexpected token {token_type}(''{token}'')", "hint": null, "explanation": "The parser found a token that cannot start or continue an expression here; look for a stray or misplaced token.", "args": {"token_type": {"kind": "keyword"}, "token": {"kind": "identifier"}}}, + "PF-E1001": {"severity": "error", "area": "support", "message": "{context}: map keys must be string in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge supports maps with string keys only; declare the map's key type as string.", "args": {"context": {"kind": "text"}}}, + "PF-E1002": {"severity": "error", "area": "support", "message": "{context}: map values must be primitive in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge supports maps whose values are float, int, bool or string only; use one of those as the value type.", "args": {"context": {"kind": "text"}}}, + "PF-E1003": {"severity": "error", "area": "support", "message": "matrix<{element_type}> is not supported when the UDT contains a map field; rollback would retain live map aliases.", "hint": "Use array for recursively checkpointed state.", "explanation": "A matrix of a user-defined type with a map field is refused because rollback would keep live map references; use an array of that type instead.", "args": {"element_type": {"kind": "type"}}}, + "PF-E1004": {"severity": "error", "area": "support", "message": "matrix<{element_type}>: nested collection element types not supported in v1.", "hint": null, "explanation": "A matrix cannot hold another collection as its element type in PineForge; use float, int, bool, string, color or a user-defined type.", "args": {"element_type": {"kind": "type"}}}, + "PF-E1005": {"severity": "error", "area": "support", "message": "input.color(...) requires a color defval (e.g. color.red or color.new(color.red, 50)).", "hint": null, "explanation": "input.color needs a color as its default value, for example color.red or color.new(color.red, 50).", "args": {}}, + "PF-E1006": {"severity": "error", "area": "support", "message": "input.color(...) defval must be a color constant (color.red, ...), a color literal (#rrggbb), or a color.new(...) / color.rgb(...) builder. Arbitrary expressions are not supported: the engine has no color helper, so codegen routes input.color through the int getter — any non-color defval would silently store a numeric value with no color encoding.", "hint": "Replace the defval with color. or color.new(...).", "explanation": "The default of input.color must be a color constant, a #rrggbb literal or a color.new or color.rgb call; other expressions are refused.", "args": {}}, + "PF-E1007": {"severity": "error", "area": "support", "message": "input.source(...) requires a native series defval (close, open, high, low, hl2, hlc3, ohlc4, ...).", "hint": null, "explanation": "input.source needs a default chart series such as close as its first argument or defval.", "args": {}}, + "PF-E1008": {"severity": "error", "area": "support", "message": "input.source(...) defval must be a native chart series (open, high, low, close, volume, hl2, hlc3, ohlc4, hlcc4). User series, computed expressions, and indicator outputs are not supported: input.source is restricted to native OHLCV series.", "hint": "Use one of: close, open, high, low, hl2, hlc3, ohlc4.", "explanation": "The default of input.source must be a native chart series (open, high, low, close, volume, hl2, hlc3, ohlc4, hlcc4); computed series are refused.", "args": {}}, + "PF-E1009": {"severity": "error", "area": "support", "message": "{kind}() declarations are not supported; PineForge runs strategies only.", "hint": "Replace the declaration with strategy(...) and add explicit entry/exit calls.", "explanation": "PineForge runs strategies only, so a script declared with indicator() or library() is refused; declare it with strategy() and add orders.", "args": {"kind": {"kind": "identifier"}}}, + "PF-E1010": {"severity": "error", "area": "support", "message": "Tuple reassignment [..] {op} is not Pine syntax: TradingView declares a tuple with ''='' and has no tuple reassignment.", "hint": "Declare new names with [a, b] = f(), then reassign each variable on its own line.", "explanation": "Pine has no tuple reassignment: declare a tuple once with '=' and reassign each variable on its own line.", "args": {"op": {"kind": "keyword"}}}, + "PF-E1011": {"severity": "error", "area": "support", "message": "A tuple literal [..] cannot be a variable''s value: TradingView rejects it here (Syntax error at input ''['', CE10156). A tuple is only a function''s or an if/switch arm''s value or a request.security expression.", "hint": "Declare each variable on its own line (a = x, b = y), or return the tuple from a function: f() => [x, y], then [a, b] = f().", "explanation": "A tuple literal such as [a, b] cannot be assigned to a variable; return it from a function or if/switch arm and destructure the result.", "args": {}}, + "PF-E1012": {"severity": "error", "area": "support", "message": "A ternary cannot return a tuple: TradingView rejects [a, b] = c ? [..] : [..] (\"Ternary operations cannot return tuples\").", "hint": "Select the tuple with an if or switch: [a, b] = if c, each arm ending in its tuple.", "explanation": "A ternary cannot produce a tuple (TradingView rejects it too); choose between tuples with an if or switch instead.", "args": {}}, + "PF-E1013": {"severity": "error", "area": "support", "message": "ta.stoch(...) returns a single series in PineForge; tuple destructuring is not supported.", "hint": "Use k = ta.stoch(...) and compute smoothing separately if needed.", "explanation": "ta.stoch returns one series in PineForge, so destructuring it into a tuple is refused; assign it to a single variable.", "args": {}}, + "PF-E1014": {"severity": "error", "area": "support", "message": "History references on UDT drawing fields are not supported in PineForge.", "hint": "{var_name}.{object_member}[...] would be read as the current-bar field, not prior-bar history. Copy the field to a bare drawing variable first, or remove the history reference.", "explanation": "A history index on a drawing field of a user-defined type would silently read the current field, so it is refused; copy the field to a variable first.", "args": {"var_name": {"kind": "identifier"}, "object_member": {"kind": "identifier"}}}, + "PF-E1015": {"severity": "error", "area": "support", "message": "History references on tuple-destructured drawing handles are not supported in PineForge.", "hint": "{object_name}[...] is a drawing handle from tuple destructuring; PineForge cannot historize that tuple element safely.", "explanation": "A drawing handle bound by tuple destructuring cannot be read through a history index; remove the history reference.", "args": {"object_name": {"kind": "identifier"}}}, + "PF-E1016": {"severity": "error", "area": "support", "message": "x[k].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: (x[k]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses.", "args": {"member": {"kind": "identifier"}}}, + "PF-E1017": {"severity": "error", "area": "support", "message": "x[k].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: ({object_name}[{index}]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses.", "args": {"member": {"kind": "identifier"}, "object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}}}, + "PF-E1018": {"severity": "error", "area": "support", "message": "{object_name}[{index}].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: (x[k]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1019": {"severity": "error", "area": "support", "message": "{object_name}[{index}].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: ({object_name}[{index}]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1020": {"severity": "error", "area": "support", "message": "x[k].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: (x[k]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses.", "args": {"member": {"kind": "identifier"}}}, + "PF-E1021": {"severity": "error", "area": "support", "message": "x[k].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: ({object_name}[{index}]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses.", "args": {"member": {"kind": "identifier"}, "object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}}}, + "PF-E1022": {"severity": "error", "area": "support", "message": "{object_name}[{index}].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: (x[k]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1023": {"severity": "error", "area": "support", "message": "{object_name}[{index}].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: ({object_name}[{index}]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1024": {"severity": "error", "area": "support", "message": "footprint.{footprint}(...) is not supported.", "hint": "PineForge reads a footprint''s delta() only: the fp_delta__ column of the feed a requests manifest pins for the symbol requested.", "explanation": "PineForge reads only the delta of a footprint value; every other footprint member is refused.", "args": {"footprint": {"kind": "identifier"}}}, + "PF-E1025": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "Currency conversion data not available in PineForge.", "explanation": "PineForge has no currency-conversion data, so request.currency_rate is refused; supply the rate yourself, for example as an input.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1026": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "External Quandl data not available in PineForge.", "explanation": "PineForge cannot load external Quandl data, so request.quandl is refused; remove it.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1027": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "External seed data feeds not available in PineForge.", "explanation": "PineForge cannot load external seed data feeds, so request.seed is refused; remove it.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1028": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.kagi() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.kagi builds a Kagi symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1029": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.linebreak() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.linebreak builds a Line Break symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1030": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.modify() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.modify builds a modified symbol identifier, which PineForge cannot request; PineForge supports multi-timeframe requests on the chart's own symbol only.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1031": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.new() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.new builds another symbol identifier, which PineForge cannot request; PineForge supports multi-timeframe requests on the chart's own symbol only.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1032": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.pointfigure() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.pointfigure builds a Point and Figure symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1033": {"severity": "error", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.renko() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.renko builds a Renko symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1034": {"severity": "error", "area": "support", "message": "ticker.heikinashi(...) is supported only for the chart''s own symbol.", "hint": "Pass syminfo.tickerid: PineForge applies the Heikin-Ashi candle transform to the chart symbol inside request.security, but cannot load an alternate symbol''s HA candles.", "explanation": "ticker.heikinashi is accepted only for the chart's own symbol (syminfo.tickerid); another symbol's Heikin-Ashi candles cannot be loaded.", "args": {}}, + "PF-E1035": {"severity": "error", "area": "support", "message": "{full}(...) is not implemented yet.", "hint": "timeframe.from_seconds is not yet implemented; codegen would emit ''false'' and silently produce wrong TF strings.", "explanation": "This call names a function on PineForge's not-yet-implemented list, so it is refused rather than compiled into something that silently misbehaves.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1036": {"severity": "error", "area": "support", "message": "{name}(...) is not implemented yet.", "hint": "timeframe.from_seconds is not yet implemented; codegen would emit ''false'' and silently produce wrong TF strings.", "explanation": "This call names a function on PineForge's not-yet-implemented list, so it is refused rather than compiled into something that silently misbehaves.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1037": {"severity": "error", "area": "support", "message": "{full}: footprint.* (bid/ask volume rows) is not supported in PineForge batch backtests; it requires tick-level data the engine does not consume.", "hint": "Remove the call or replace it with native OHLCV-based logic.", "explanation": "footprint.* calls need tick-level bid/ask volume rows, which a PineForge batch backtest does not load.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1038": {"severity": "error", "area": "support", "message": "{full}: volume_row.* is not supported in PineForge batch backtests; same reason as footprint.*.", "hint": "Remove the call or replace it with native OHLCV-based logic.", "explanation": "volume_row.* calls need tick-level volume rows, which a PineForge batch backtest does not load.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1039": {"severity": "error", "area": "support", "message": "library() declarations are not supported; PineForge runs strategies only.", "hint": "Use strategy(...) and inline or pre-expand library code before uploading.", "explanation": "PineForge runs strategies only, so a library() declaration is refused; use strategy() and paste any library code into the script.", "args": {}}, + "PF-E1040": {"severity": "error", "area": "support", "message": "Bare barssince(...) is broken in PineForge codegen.", "hint": "Use ta.barssince(...) instead.", "explanation": "The bare barssince(...) form does not work in PineForge; call ta.barssince(...) instead.", "args": {}}, + "PF-E1041": {"severity": "error", "area": "support", "message": "ta.sum is not a PineScript v6 function.", "hint": "Use math.sum(...) instead.", "explanation": "ta.sum does not exist in Pine v6; use math.sum(source, length) for a rolling sum.", "args": {}}, + "PF-E1042": {"severity": "error", "area": "support", "message": "ta.{name} is a PineScript v6 variable, not a function.", "hint": "Use ta.{name} without parentheses.", "explanation": "This ta.* name is a built-in variable, not a function, so write it without parentheses.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1043": {"severity": "error", "area": "support", "message": "{full}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "This strategy.closedtrades or strategy.opentrades accessor is not available in PineForge; use one of the supported trade accessors.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1044": {"severity": "error", "area": "support", "message": "{full}(...) is not implemented in PineForge runtime.", "hint": "{hint}", "explanation": "Open trades have no exit data in Pine v6: this accessor exists only on strategy.closedtrades, so it cannot be read from strategy.opentrades.", "args": {"full": {"kind": "identifier"}, "hint": {"kind": "text"}}}, + "PF-E1045": {"severity": "error", "area": "support", "message": "strategy.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "This strategy.* function is not implemented in PineForge; check the spelling or use a supported strategy function.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1046": {"severity": "error", "area": "support", "message": "strategy.exit(...) requires at least one price or trailing parameter in PineForge.", "hint": "Use strategy.close(...) for market exits.", "explanation": "strategy.exit needs a price or trailing parameter (profit, loss, limit, stop or a trail setting); use strategy.close for a plain market exit.", "args": {}}, + "PF-E1047": {"severity": "error", "area": "support", "message": "{full}(...) is not supported. Only request.security(...) and request.security_lower_tf(...) are available in PineForge.", "hint": "External request feeds and other request.* variants are intentionally unavailable.", "explanation": "Only request.security and request.security_lower_tf are supported; other request.* calls need data feeds PineForge does not provide.", "args": {"full": {"kind": "identifier"}}}, + "PF-E1048": {"severity": "error", "area": "support", "message": "ta.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this ta.* function, so the call is refused instead of compiling to a silent stub.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1049": {"severity": "error", "area": "support", "message": "math.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this math.* function, so the call is refused instead of compiling to a silent stub.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1050": {"severity": "error", "area": "support", "message": "str.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this str.* function, so the call is refused instead of compiling to a silent stub.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1051": {"severity": "error", "area": "support", "message": "input.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this input.* function, so the call is refused; use one of the supported input functions.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1052": {"severity": "error", "area": "support", "message": "timeframe.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only timeframe.change and timeframe.in_seconds; any other timeframe.* function is refused.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1053": {"severity": "error", "area": "support", "message": "color.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only color.new, color.rgb and color.r/g/b/t; any other color.* function is refused.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1054": {"severity": "error", "area": "support", "message": "runtime.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only runtime.error; any other runtime.* function is refused.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1055": {"severity": "error", "area": "support", "message": "log.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only log.info, log.warning and log.error; any other log.* function is refused.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1056": {"severity": "error", "area": "support", "message": "array.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this array.* function, so the call is refused instead of compiling to a silent stub.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1057": {"severity": "error", "area": "support", "message": "map.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this map.* function, so the call is refused instead of compiling to a silent stub.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1058": {"severity": "error", "area": "support", "message": "map keys must be string in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge maps support only string keys; declare the map with string as its key type.", "args": {}}, + "PF-E1059": {"severity": "error", "area": "support", "message": "map values must be primitive in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge maps can hold only float, int, bool or string values; other value types such as collections or objects are refused.", "args": {}}, + "PF-E1060": {"severity": "error", "area": "support", "message": "matrix<{t}>: nested collection element types not supported in v1.", "hint": null, "explanation": "A matrix cannot hold another collection as its element type in PineForge; use float, int, bool, string, color or a user-defined type.", "args": {"t": {"kind": "type"}}}, + "PF-E1061": {"severity": "error", "area": "support", "message": "matrix<{t}> is not supported when the UDT contains a map field; rollback would retain live map aliases.", "hint": "Use array for recursively checkpointed state.", "explanation": "A matrix of a user-defined type with a map field is refused because rollback would keep live map references; use an array of that type instead.", "args": {"t": {"kind": "type"}}}, + "PF-E1062": {"severity": "error", "area": "support", "message": "matrix<{t}> element type not supported. Allowed: float, int, bool, string, color, or a declared UDT.", "hint": null, "explanation": "A matrix element must be float, int, bool, string, color or a declared user-defined type; any other element type is refused.", "args": {"t": {"kind": "type"}}}, + "PF-E1063": {"severity": "error", "area": "support", "message": "matrix.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this matrix.* function, so the call is refused instead of compiling to a silent stub.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1064": {"severity": "error", "area": "support", "message": "{ns}.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only part of the line, box, label and linefill functions; this one is not implemented, so the call is refused.", "args": {"ns": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E1065": {"severity": "error", "area": "support", "message": "chart.point.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only chart.point.new, now, from_index, from_time and copy; any other chart.point.* function is refused.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1066": {"severity": "error", "area": "support", "message": "''export'' is a Pine library keyword; PineForge runs strategies only and does not support exported functions/types.", "hint": "Remove the ''export'' keyword (and inline any library code into the strategy script).", "explanation": "'export' marks library code; PineForge runs strategies only, so remove the keyword and inline any library code into the strategy.", "args": {}}, + "PF-E1067": {"severity": "error", "area": "support", "message": "{name} diverges from TradingView semantics in PineForge.", "hint": "bar_index depends on the data window; PineForge and TradingView produce different values for the same script.", "explanation": "bar_index counts bars of the data window PineForge is fed, so its value can differ from TradingView's for the same script.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1068": {"severity": "error", "area": "support", "message": "{name} diverges from TradingView semantics in PineForge.", "hint": "last_bar_index is the final index of PineForge''s fed data window; it can diverge from TradingView when the window does not cover the same chart history.", "explanation": "last_bar_index is the last index of the data window PineForge is fed, so it can differ from TradingView's when the history windows differ.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1069": {"severity": "error", "area": "support", "message": "{name} diverges from TradingView semantics in PineForge.", "hint": "timenow is aliased to the current bar timestamp in PineForge; it is not real wall-clock time.", "explanation": "timenow is aliased to the current bar's time in PineForge, not real wall-clock time, so logic relying on the real time will differ.", "args": {"name": {"kind": "identifier"}}}, + "PF-E1070": {"severity": "error", "area": "support", "message": "{chain} diverges from TradingView semantics in PineForge.", "hint": "bar_index depends on the data window; PineForge and TradingView produce different values for the same script.", "explanation": "bar_index counts bars of the data window PineForge is fed, so its value can differ from TradingView's for the same script.", "args": {"chain": {"kind": "identifier"}}}, + "PF-E1071": {"severity": "error", "area": "support", "message": "{chain} diverges from TradingView semantics in PineForge.", "hint": "last_bar_index is the final index of PineForge''s fed data window; it can diverge from TradingView when the window does not cover the same chart history.", "explanation": "last_bar_index is the last index of the data window PineForge is fed, so it can differ from TradingView's when the history windows differ.", "args": {"chain": {"kind": "identifier"}}}, + "PF-E1072": {"severity": "error", "area": "support", "message": "{chain} diverges from TradingView semantics in PineForge.", "hint": "timenow is aliased to the current bar timestamp in PineForge; it is not real wall-clock time.", "explanation": "timenow is aliased to the current bar's time in PineForge, not real wall-clock time, so logic relying on the real time will differ.", "args": {"chain": {"kind": "identifier"}}}, + "PF-E1073": {"severity": "error", "area": "support", "message": "{object_name}.{member}: footprint.* (bid/ask volume rows) is not supported in PineForge batch backtests; it requires tick-level data the engine does not consume.", "hint": null, "explanation": "Members of the footprint.* namespace need tick-level bid/ask volume rows, which a PineForge batch backtest does not load.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1074": {"severity": "error", "area": "support", "message": "{object_name}.{member}: volume_row.* is not supported in PineForge batch backtests; same reason as footprint.*.", "hint": null, "explanation": "Members of the volume_row.* namespace need tick-level volume rows, which a PineForge batch backtest does not load.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1075": {"severity": "error", "area": "support", "message": "{object_name}.{member}: dividends.* is not available in PineForge — fundamental dividend data is not loaded.", "hint": null, "explanation": "dividends.* fields read fundamental dividend data, which PineForge does not load outside a recorded request.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1076": {"severity": "error", "area": "support", "message": "{object_name}.{member}: earnings.* is not available in PineForge — fundamental earnings data is not loaded.", "hint": null, "explanation": "earnings.* fields read fundamental earnings data, which PineForge does not load outside a recorded request.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1077": {"severity": "error", "area": "support", "message": "{object_name}.{member}: splits.* is not available in PineForge — corporate-action split data is not loaded.", "hint": null, "explanation": "splits.* fields read corporate-action split data, which PineForge does not load outside a recorded request.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1078": {"severity": "error", "area": "support", "message": "{object_name}.{member} is a visual/style constant with no runtime value in PineForge backtests; it is only accepted as an argument to visual calls (plot, plotshape, hline, label.new, table.cell, ...), which PineForge parses and skips.", "hint": "Constant-namespace members cannot flow into strategy logic; codegen would emit a string literal while the analyzer types the read as int.", "explanation": "A visual or style constant has no value in a backtest; it may only be passed to plotting and drawing calls, which PineForge skips.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1079": {"severity": "error", "area": "support", "message": "{object_name}.{member} is not a Pine alert constant; only alert.freq_all, alert.freq_once_per_bar and alert.freq_once_per_bar_close exist.", "hint": "Constant-namespace members cannot flow into strategy logic; codegen would emit a string literal while the analyzer types the read as int.", "explanation": "The alert.* member is not one of Pine's alert frequency constants.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1080": {"severity": "error", "area": "support", "message": "{object_name}.{member} is not a barmerge constant; only barmerge.gaps_on, barmerge.gaps_off, barmerge.lookahead_on and barmerge.lookahead_off exist.", "hint": "Constant-namespace members cannot flow into strategy logic; codegen would emit a string literal while the analyzer types the read as int.", "explanation": "The barmerge.* member is not one of Pine's gaps or lookahead constants.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E1081": {"severity": "error", "area": "support", "message": "syminfo.{member} is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge does not implement this syminfo.* member, so reading it is refused.", "args": {"member": {"kind": "identifier"}}}, + "PF-E1082": {"severity": "error", "area": "support", "message": "request.security parameter ''{kw_name}'' is not allowed in PineForge.", "hint": "Only symbol, timeframe, expression, gaps, and lookahead are accepted.", "explanation": "request.security accepts only a few named parameters in PineForge; this one is refused instead of being silently ignored, so remove it.", "args": {"kw_name": {"kind": "identifier"}}}, + "PF-E1083": {"severity": "error", "area": "support", "message": "Extra positional arguments to request.security are not allowed in PineForge.", "hint": "Only symbol, timeframe, expression, gaps, and lookahead are accepted.", "explanation": "request.security accepts at most five positional arguments (symbol, timeframe, expression, gaps, lookahead); remove the extra ones.", "args": {}}, + "PF-E1084": {"severity": "error", "area": "support", "message": "request.security gaps must be barmerge.gaps_on or barmerge.gaps_off.", "hint": "Codegen only recognizes the barmerge.gaps_* literal; other values are silently treated as gaps_off.", "explanation": "The gaps argument of request.security must be written literally as barmerge.gaps_on or barmerge.gaps_off, the only forms PineForge reads.", "args": {}}, + "PF-E1085": {"severity": "error", "area": "support", "message": "request.security lookahead must be barmerge.lookahead_on or barmerge.lookahead_off.", "hint": "Codegen only recognizes the barmerge.lookahead_* literal; other values are silently treated as lookahead_off.", "explanation": "The lookahead argument of request.security must be written literally as barmerge.lookahead_on or barmerge.lookahead_off, the only forms PineForge reads.", "args": {}}, + "PF-E1086": {"severity": "error", "area": "support", "message": "request.security: {kw_name}={object_name}.{val_member} is not supported. The engine ignores this kwarg, which would silently produce different prices from TradingView.", "hint": "Allowed values: {allowed}.", "explanation": "PineForge ignores request.security's price-adjustment settings, so only no-op values are accepted; others would silently give prices unlike TradingView's.", "args": {"kw_name": {"kind": "identifier"}, "object_name": {"kind": "identifier"}, "val_member": {"kind": "identifier"}, "allowed": {"kind": "identifier"}}}, + "PF-E1087": {"severity": "error", "area": "support", "message": "request.security: {kw_name}=... must be a constant member access of the form {kw_name}. (got a non-constant expression).", "hint": "Allowed values: {allowed}.", "explanation": "A request.security price-adjustment setting must be a plain constant of the form name.value (like adjustment.none), not a computed expression.", "args": {"kw_name": {"kind": "identifier"}, "allowed": {"kind": "identifier"}}}, + "PF-E1088": {"severity": "error", "area": "support", "message": "{name} {message} (TradingView: {spelled}).", "hint": "Use the parameters of TradingView''s signature.", "explanation": "A nz or fixnan call whose arguments match none of TradingView's signatures (unknown name, too many or missing arguments) is refused, as TradingView refuses it.", "args": {"name": {"kind": "identifier"}, "message": {"kind": "text"}, "spelled": {"kind": "identifier"}}}, + "PF-E1089": {"severity": "error", "area": "support", "message": "ta.{name} {message} (TradingView: {signature}).", "hint": "Use the parameters of TradingView''s signature.", "explanation": "A ta.* call whose arguments match none of TradingView's signatures (unknown or repeated parameter, too many or missing arguments) is refused.", "args": {"name": {"kind": "identifier"}, "message": {"kind": "text"}, "signature": {"kind": "identifier"}}}, + "PF-E1090": {"severity": "error", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "empty timeframe literal", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-E1091": {"severity": "error", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "non-integer timeframe magnitude ''{digits}''", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}, "digits": {"kind": "identifier"}}}, + "PF-E1092": {"severity": "error", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "timeframe magnitude must be positive", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-E1093": {"severity": "error", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "unknown timeframe suffix ''{suffix}''", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}, "suffix": {"kind": "identifier"}}}, + "PF-E1094": {"severity": "error", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "empty timeframe literal", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-E1095": {"severity": "error", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "non-integer timeframe magnitude ''{digits}''", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}, "digits": {"kind": "identifier"}}}, + "PF-E1096": {"severity": "error", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "timeframe magnitude must be positive", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-E1097": {"severity": "error", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "unknown timeframe suffix ''{suffix}''", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused.", "args": {"timeframe": {"kind": "identifier"}, "suffix": {"kind": "identifier"}}}, + "PF-E2001": {"severity": "error", "area": "analysis", "message": "Missing PineScript version directive. PineForge supports PineScript v6 only.", "hint": "Add //@version=6 as the first line of your script.", "explanation": "PineForge accepts only Pine v6 scripts; add //@version=6 as the first line.", "args": {}}, + "PF-E2002": {"severity": "error", "area": "analysis", "message": "PineForge supports PineScript v6 only (found //@version={version}).", "hint": "Migrate the script to //@version=6 using TradingView''s editor.", "explanation": "The script declares a Pine version other than 6, which PineForge does not support; migrate it to v6 using TradingView's editor.", "args": {"version": {"kind": "number"}}}, + "PF-E2003": {"severity": "error", "area": "analysis", "message": "Direct temporary-array element call ''{callee_name}()'' resolves to a local or parameter, not a user-defined function.", "hint": null, "explanation": "A function ends by reading a temporary array built from a call such as f(), but f is a local or parameter there, not a user-defined function; rename it.", "args": {"callee_name": {"kind": "identifier"}}}, + "PF-E2004": {"severity": "error", "area": "analysis", "message": "Tuple-return helper wrapper ''{wrapper_name}'' calls later-defined helper ''{callee_name}''; forward tuple-wrapper calls are not supported yet. Move ''{callee_name}'' above ''{wrapper_name}'' before passing the wrapper to request.security().", "hint": null, "explanation": "A function that returns another function's tuple must come after it; define the called helper above the wrapper before passing the wrapper to request.security.", "args": {"wrapper_name": {"kind": "identifier"}, "callee_name": {"kind": "identifier"}}}, + "PF-E2005": {"severity": "error", "area": "analysis", "message": "Recursive direct temporary-array reader cycle is not supported: {cycle}.", "hint": null, "explanation": "Functions that read an element of a temporary array call each other in a cycle; Pine forbids recursion and PineForge cannot emit it.", "args": {"cycle": {"kind": "identifier"}}}, + "PF-E2006": {"severity": "error", "area": "analysis", "message": "Persistent bindings named ''{raw_name}'' still share generated storage across distinct lexical declarations; this declaration shape is not supported yet.", "hint": null, "explanation": "A var declaration reuses a name that another declaration in a different scope also uses, and PineForge would give them one shared storage slot; rename one.", "args": {"raw_name": {"kind": "identifier"}}}, + "PF-E2007": {"severity": "error", "area": "analysis", "message": "A top-level block history binding named ''{name}'' shares raw generated Series state with another lexical declaration; declaration-exact block storage is not supported yet.", "hint": null, "explanation": "A top-level block variable whose history is read shares its name with another declaration, so PineForge cannot keep their histories apart; rename one.", "args": {"name": {"kind": "identifier"}}}, + "PF-E2008": {"severity": "error", "area": "analysis", "message": "A callable history local named ''{name}'' shares raw generated Series state with another lexical declaration; declaration-exact callable storage is not supported yet.", "hint": null, "explanation": "A function-local variable has its history read and shares its name with another declaration, so PineForge cannot keep separate history; rename one.", "args": {"name": {"kind": "identifier"}}}, + "PF-E2009": {"severity": "error", "area": "analysis", "message": "History references on a scalar callable local named ''{raw_name}'' conflict with a persistent map local of the same name in another callable; scoped Series member storage is not implemented yet.", "hint": null, "explanation": "A function-local scalar read with history shares its name with a persistent map variable in another function, which PineForge cannot yet separate; rename one.", "args": {"raw_name": {"kind": "identifier"}}}, + "PF-E2010": {"severity": "error", "area": "analysis", "message": "A top-level block binding named ''{name}'' shadows a direct script binding with history, aggregate, or incompatible typed state; declaration-exact block storage is not supported yet.", "hint": null, "explanation": "A variable declared inside a top-level block reuses the name of a script-level variable with history, a collection or a different type; rename one.", "args": {"name": {"kind": "identifier"}}}, + "PF-E2011": {"severity": "error", "area": "analysis", "message": "Persistent drawing bindings named ''{name}'' in distinct lexical owners would share one generated state member; rename one binding until callable-owned persistent storage is owner-qualified.", "hint": null, "explanation": "Two var-declared drawing objects (line, box, label or linefill) in different scopes share one name and would share one state member; rename one.", "args": {"name": {"kind": "identifier"}}}, + "PF-E2012": {"severity": "error", "area": "analysis", "message": "Persistent drawing state named ''{name}'' collides with a top-level class-member binding; rename one binding until persistent storage is owner-qualified.", "hint": null, "explanation": "A var-declared drawing object shares its name with a top-level script variable, so PineForge would give them one state member; rename one.", "args": {"name": {"kind": "identifier"}}}, + "PF-E2013": {"severity": "error", "area": "analysis", "message": "Persistent drawing binding ''{name}'' shadows an ancestor callable parameter or local; rename one binding until callable-owned persistent storage has lexical owner qualification.", "hint": null, "explanation": "A var-declared drawing object inside a function reuses the name of an enclosing parameter or local; rename one.", "args": {"name": {"kind": "identifier"}}}, + "PF-E2014": {"severity": "error", "area": "analysis", "message": "Callable TA ownership propagation did not converge; recursive stateful call paths are unsupported.", "hint": null, "explanation": "PineForge could not work out which functions own the ta.* state because stateful functions call each other recursively; remove the recursion.", "args": {}}, + "PF-E2015": {"severity": "error", "area": "analysis", "message": "Cannot safely specialize untyped parameter ''{param}'' of callable ''{callee}'': distinct primitive types collapse onto the same written-call variant cs{cs_idx}. Inline the calls or declare an explicit parameter type.", "hint": null, "explanation": "An untyped parameter receives different primitive types (such as int and float) from calls PineForge cannot tell apart; declare its type or inline the calls.", "args": {"param": {"kind": "identifier"}, "callee": {"kind": "identifier"}, "cs_idx": {"kind": "number"}}}, + "PF-E2016": {"severity": "error", "area": "analysis", "message": "Cannot infer the per-callsite primitive type of history parameter ''{param}'' in callable ''{name}'' variant cs{cs_idx}; declare its type explicitly.", "hint": null, "explanation": "A function reads history of a parameter whose type PineForge cannot infer at this call; declare the parameter type explicitly.", "args": {"param": {"kind": "identifier"}, "name": {"kind": "identifier"}, "cs_idx": {"kind": "number"}}}, + "PF-E2017": {"severity": "error", "area": "analysis", "message": "request.security timeframe parameter ''{tf_param}'' of function ''{containing}'' is passed a timeframe that reads the chart bar (''{series}''): PineForge registers each call site''s timeframe before the first bar.", "hint": null, "explanation": "A timeframe passed to a helper's request.security reads chart-bar data, but PineForge fixes it before the first bar; pass a constant or input timeframe instead.", "args": {"tf_param": {"kind": "identifier"}, "containing": {"kind": "identifier"}, "series": {"kind": "identifier"}}}, + "PF-E2018": {"severity": "error", "area": "analysis", "message": "Import is not supported: ''{import_path}''", "hint": null, "explanation": "The script imports a library PineForge cannot inline, usually because its source was not supplied or pinned, or it is not open source.", "args": {"import_path": {"kind": "identifier"}}}, + "PF-E2019": {"severity": "error", "area": "analysis", "message": "Import is not supported: ''{import_path}'': {reason}", "hint": null, "explanation": "The script imports a library PineForge cannot inline, usually because its source was not supplied or pinned, or it is not open source.", "args": {"import_path": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-E2020": {"severity": "error", "area": "analysis", "message": "Undefined variable: ''{name}''", "hint": null, "explanation": "The script assigns a new value (:=) to a name that was never declared; declare the variable first.", "args": {"name": {"kind": "identifier"}}}, + "PF-E2021": {"severity": "error", "area": "analysis", "message": "PineScript has no ta.sum; use math.sum(source, length) for rolling sum", "hint": null, "explanation": "ta.sum does not exist in Pine v6; use math.sum(source, length) for a rolling sum.", "args": {}}, + "PF-E2022": {"severity": "error", "area": "analysis", "message": "{name}.copy(...) expects exactly one object argument", "hint": null, "explanation": "The functional copy form Type.copy(obj) needs exactly one object argument and no named arguments.", "args": {"name": {"kind": "type"}}}, + "PF-E2023": {"severity": "error", "area": "analysis", "message": "{receiver_spec_name}.copy() expects no arguments", "hint": null, "explanation": "obj.copy() on a user-defined type takes no arguments; call it with empty parentheses.", "args": {"receiver_spec_name": {"kind": "type"}}}, + "PF-E2024": {"severity": "error", "area": "analysis", "message": "{key}: argument ''{name}'' passed both positionally and by keyword", "hint": null, "explanation": "A call to a typed method gives the same parameter both by position and by keyword; pass it only once.", "args": {"key": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E2025": {"severity": "error", "area": "analysis", "message": "{key}: missing required argument ''{name}''", "hint": null, "explanation": "A call to a typed method omits a parameter that has no default value; pass an argument for it.", "args": {"key": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E2026": {"severity": "error", "area": "analysis", "message": "{key}: too many positional arguments (expected {names_count}, got {args_count})", "hint": null, "explanation": "A call to a typed method passes more positional arguments than the method declares; remove the extra arguments.", "args": {"key": {"kind": "identifier"}, "names_count": {"kind": "number"}, "args_count": {"kind": "number"}}}, + "PF-E2027": {"severity": "error", "area": "analysis", "message": "{key}: unknown keyword argument ''{name}''", "hint": null, "explanation": "A call to a typed method uses a keyword argument name that the method does not declare; check the parameter spelling.", "args": {"key": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E2028": {"severity": "error", "area": "analysis", "message": "History references on map IDs are not supported in PineForge; map rollback uses identity snapshots rather than Series.", "hint": null, "explanation": "PineForge cannot read earlier-bar history of a map with the [] operator; read the map directly or keep earlier values in other variables.", "args": {}}, + "PF-E2029": {"severity": "error", "area": "analysis", "message": "History references on map-bearing UDTs or collections are not supported in PineForge; their Series value copy would retain live map aliases.", "hint": null, "explanation": "PineForge cannot read earlier-bar history of a user-defined type or collection that contains a map, because the copy would keep live map references.", "args": {}}, + "PF-E2030": {"severity": "error", "area": "analysis", "message": "User function ''{owner}'' is called with incompatible map parameter types; PineForge cannot emit multiple map specializations for one untyped function.", "hint": null, "explanation": "A function with untyped parameters is called with different map types, and PineForge can generate only one map specialization per function; declare the type.", "args": {"owner": {"kind": "identifier"}}}, + "PF-E2031": {"severity": "error", "area": "analysis", "message": "History references on scalar local or loop bindings that shadow a map ID are not supported until PineForge can allocate a lexically scoped Series buffer for that binding.", "hint": null, "explanation": "A local or loop variable that reuses a map's name is read with history ([n]), which PineForge cannot buffer yet; rename the variable.", "args": {}}, + "PF-E2032": {"severity": "error", "area": "analysis", "message": "{receiver}.{member}[...]: TradingView refuses the history-referencing operator on fields of user-defined types (CE10290).", "hint": "Read the field of the object''s history: ({receiver}[1]).{member}.", "explanation": "TradingView refuses the [] history operator on a field of a user-defined type; read the field of the object's history instead, as (obj[1]).field.", "args": {"receiver": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E2033": {"severity": "error", "area": "analysis", "message": "request.security tuple-return helpers support two or more int, float, bool or string elements; inferred {tuple_size} element(s) [{inferred_types}]", "hint": null, "explanation": "A tuple-returning helper called inside request.security must yield two or more int, float, bool or string elements; its inferred shape did not qualify.", "args": {"tuple_size": {"kind": "number"}, "inferred_types": {"kind": "type"}}}, + "PF-E2034": {"severity": "error", "area": "analysis", "message": "request.security_lower_tf has unknown parameter(s): {unknown}. Supported parameters: {param_names}", "hint": null, "explanation": "request.security_lower_tf was called with keyword arguments it does not accept; use only the supported parameters listed.", "args": {"unknown": {"kind": "identifier"}, "param_names": {"kind": "identifier"}}}, + "PF-E2035": {"severity": "error", "area": "analysis", "message": "request.security_lower_tf requires an expression argument", "hint": null, "explanation": "request.security_lower_tf was called without its expression argument, so there is nothing to evaluate on the lower timeframe.", "args": {}}, + "PF-E2036": {"severity": "error", "area": "analysis", "message": "request.security_lower_tf does not support tuple expressions yet. Issue separate request.security_lower_tf calls for each series.", "hint": null, "explanation": "request.security_lower_tf cannot return a tuple; issue one request.security_lower_tf call for each series you need.", "args": {}}, + "PF-E2037": {"severity": "error", "area": "analysis", "message": "request.security_lower_tf element type ''{element_label}'' is not yet supported. Supported element types: float, int, bool. UDT / color / string element types are out of scope.", "hint": null, "explanation": "request.security_lower_tf can only collect float, int or bool values per intrabar; string, color and object expressions are not supported.", "args": {"element_label": {"kind": "type"}}}, + "PF-E2038": {"severity": "error", "area": "analysis", "message": "Enum ''{ename}'' must be declared above this input.enum() call (or the name is misspelled).", "hint": null, "explanation": "input.enum() names an enum that is not declared above the call (or is misspelled); declare the enum first or fix the name.", "args": {"ename": {"kind": "identifier"}}}, + "PF-E2039": {"severity": "error", "area": "analysis", "message": "Cannot materialize callable state for unknown function ''{func_name}''.", "hint": null, "explanation": "Internal error: PineForge could not find a user function or method whose indicator state it needed to copy; this is a transpiler bug to report.", "args": {"func_name": {"kind": "identifier"}}}, + "PF-E3001": {"severity": "error", "area": "request-security", "message": "request.security timeframe ''{name}'' cannot be resolved before the first bar: PineForge registers every requested timeframe before the script runs.", "hint": "Pass a literal, an input or a global to the helper that holds request.security.", "explanation": "The timeframe given to request.security is a name whose value PineForge cannot compute before the first bar; use a literal, an input or a global.", "args": {"name": {"kind": "identifier"}}}, + "PF-E3002": {"severity": "error", "area": "request-security", "message": "request.security timeframe expression cannot be resolved before the first bar: PineForge registers every requested timeframe before the script runs.", "hint": "Pass a literal, an input or a global to the helper that holds request.security.", "explanation": "The timeframe expression given to request.security cannot be computed before the first bar; use a literal, an input or a global.", "args": {}}, + "PF-E3003": {"severity": "error", "area": "request-security", "message": "request.security timeframe switch arms must contain one expression", "hint": "Compute multi-statement timeframe logic before the request.security call or rewrite it as pure switch arms.", "explanation": "A switch that picks a request.security timeframe must have exactly one expression in each arm; compute multi-statement logic beforehand.", "args": {}}, + "PF-E3004": {"severity": "error", "area": "request-security", "message": "request.security_lower_tf timeframe switch arm is na", "hint": "TradingView reads an na timeframe as the chart''s, which the engine''s lower-timeframe request rejects: spell a strictly finer timeframe.", "explanation": "A switch arm in a request.security_lower_tf timeframe is na, which a lower-timeframe request rejects; spell a strictly finer timeframe.", "args": {}}, + "PF-E3005": {"severity": "error", "area": "request-security", "message": "request.security timeframe switch arm is na", "hint": "TradingView reads an na timeframe as the chart''s: spell the arm timeframe.period.", "explanation": "A switch arm in a request.security timeframe is na, which TradingView reads as the chart's timeframe; write timeframe.period instead.", "args": {}}, + "PF-E3006": {"severity": "error", "area": "request-security", "message": "request.security timeframe switch arm could not be resolved at setup", "hint": null, "explanation": "A switch arm used as a request.security timeframe could not be evaluated, because PineForge registers every request before the first bar.", "args": {}}, + "PF-E3007": {"severity": "error", "area": "request-security", "message": "request.security_lower_tf timeframe switch requires a default arm", "hint": "When no arm matches, TradingView reads the chart''s timeframe (one intrabar per chart bar); the engine''s lower-timeframe request needs a strictly finer timeframe.", "explanation": "A switch picking a request.security_lower_tf timeframe needs a default arm; without one TradingView uses the chart's timeframe, which is rejected.", "args": {}}, + "PF-E3008": {"severity": "error", "area": "request-security", "message": "request.security timeframe switch selector could not be resolved at setup", "hint": null, "explanation": "The selector of a switch that picks a request.security timeframe could not be evaluated before the first bar; use literals, inputs or timeframe values.", "args": {}}, + "PF-E3009": {"severity": "error", "area": "request-security", "message": "request.security timeframe switch case could not be resolved at setup", "hint": null, "explanation": "A case value in a switch that picks a request.security timeframe could not be evaluated before the first bar; use literals, inputs or timeframe values.", "args": {}}, + "PF-E3010": {"severity": "error", "area": "request-security", "message": "request.security timeframe parameter ''{param_name}'' of ''{func_name}'' has no single timeframe across its call sites", "hint": "Pass the timeframe as a positional literal, input or global.", "explanation": "A helper's timeframe parameter used by request.security receives different timeframes at its call sites; pass one literal, input or global.", "args": {"param_name": {"kind": "identifier"}, "func_name": {"kind": "identifier"}}}, + "PF-E3011": {"severity": "error", "area": "request-security", "message": "request.security helper-parameter history currently requires a direct OHLC/time bar-series binding", "hint": null, "explanation": "History of a helper parameter inside request.security is only supported when the argument is a plain bar series such as close or time.", "args": {}}, + "PF-E3012": {"severity": "error", "area": "request-security", "message": "request.security payload reads ''{name}'' with history and outside the helper block its call is lowered in: its state would advance twice a bar", "hint": "Read ''{name}'' once at the helper''s top level and use that local in the block.", "explanation": "A global holding a stateful call is read with history both inside and outside the helper block that lowers it, so its state would advance twice per bar.", "args": {"name": {"kind": "identifier"}}}, + "PF-E3013": {"severity": "error", "area": "request-security", "message": "Internal: request.security string helper state without its declared series map", "hint": null, "explanation": "Internal error: string state in a request.security helper was used before its series storage was declared; this is a transpiler bug to report.", "args": {}}, + "PF-E3014": {"severity": "error", "area": "request-security", "message": "Internal security helper emission requested for a non-linear helper plan", "hint": null, "explanation": "Internal error: PineForge tried to emit a request.security helper as straight-line code although its shape is not; this is a transpiler bug to report.", "args": {}}, + "PF-E3015": {"severity": "error", "area": "request-security", "message": "request.security helper-local var state currently supports only int, float, bool and string values", "hint": "Hoist collection, UDT, or drawing state outside request.security().", "explanation": "A var inside a request.security helper can only hold int, float, bool or string values; move collection, object or drawing state outside the request.", "args": {}}, + "PF-E3016": {"severity": "error", "area": "request-security", "message": "request.security multi-statement helpers may only assign to local identifier temporaries", "hint": null, "explanation": "A multi-statement request.security helper can only assign to plain local variables, not to fields, array elements or other targets.", "args": {}}, + "PF-E3017": {"severity": "error", "area": "request-security", "message": "request.security multi-statement helper assignment target must be declared before use", "hint": null, "explanation": "A multi-statement request.security helper assigns to a variable it never declared; declare the local before assigning to it.", "args": {}}, + "PF-E3018": {"severity": "error", "area": "request-security", "message": "request.security helper tuple declaration: a string element read with history is not supported", "hint": "Declare the element with its own string variable.", "explanation": "A string element of a tuple declared in a request.security helper is read with history, which is unsupported; declare it as its own string variable.", "args": {}}, + "PF-E3019": {"severity": "error", "area": "request-security", "message": "request.security multi-statement helpers may only use local declarations, assignments, and if-branches before the final expression", "hint": null, "explanation": "A multi-statement request.security helper may contain only local declarations, assignments, if-branches and loops before its final expression.", "args": {}}, + "PF-E3020": {"severity": "error", "area": "request-security", "message": "request.security helper while-loop conditions must be plain expressions of the helper''s values", "hint": null, "explanation": "A while-loop condition in a request.security helper must be a plain expression of the helper's own values.", "args": {}}, + "PF-E3021": {"severity": "error", "area": "request-security", "message": "request.security helper calls must target named user-defined functions", "hint": null, "explanation": "request.security can only inline calls to named user-defined functions or typed methods, not other call forms.", "args": {}}, + "PF-E3022": {"severity": "error", "area": "request-security", "message": "request.security helper function ''{func_name}'' is not defined", "hint": null, "explanation": "A function called while inlining a request.security helper is not a user-defined function PineForge knows, so it cannot be inlined.", "args": {"func_name": {"kind": "identifier"}}}, + "PF-E3023": {"severity": "error", "area": "request-security", "message": "request.security helper call has unknown parameter(s): {unknown_list}", "hint": null, "explanation": "A helper called inside request.security is given keyword arguments that are not among the function's parameters.", "args": {"unknown_list": {"kind": "identifier"}}}, + "PF-E3024": {"severity": "error", "area": "request-security", "message": "request.security helper calls must bind every parameter explicitly", "hint": null, "explanation": "A helper called inside request.security must be given an argument for every parameter; omitted defaults are not filled in there.", "args": {}}, + "PF-E3025": {"severity": "error", "area": "request-security", "message": "request.security multi-statement helpers must end with a final expression result", "hint": null, "explanation": "A multi-statement request.security helper must end with an expression, declaration or assignment that gives its result.", "args": {}}, + "PF-E3026": {"severity": "error", "area": "request-security", "message": "request.security does not support multi-statement helpers with control flow", "hint": "Inline a straight-line helper body or hoist the control-flow helper outside request.security().", "explanation": "request.security cannot inline a multi-statement helper that contains for-in, switch, break or continue; inline a straight-line body or move it out.", "args": {}}, + "PF-E3027": {"severity": "error", "area": "request-security", "message": "request.security does not support helper-local varip state", "hint": "Use var for requested-context bar state; varip tick state is unavailable in batch backtests.", "explanation": "varip state is not available in a request.security helper; use var instead, since tick-level varip state does not exist in batch backtests.", "args": {}}, + "PF-E3028": {"severity": "error", "area": "request-security", "message": "request.security helper-local var declarations inside conditional control flow are not supported", "hint": "Declare persistent requested-context state at the helper''s top level.", "explanation": "A var declared inside an if or other conditional block of a request.security helper is not supported; declare it at the helper's top level.", "args": {}}, + "PF-E3029": {"severity": "error", "area": "request-security", "message": "request.security method TA constructor argument ''{cpp}'' is not a stable per-run scalar", "hint": null, "explanation": "A typed method called inside request.security builds a TA indicator whose argument is not fixed for the whole run; use a constant or input value.", "args": {"cpp": {"kind": "identifier"}}}, + "PF-E3030": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a TA call", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A for or while loop in a request.security helper cannot contain a ta.* call; compute it before the loop, on the requested bar.", "args": {}}, + "PF-E3031": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a TA call (through {via})", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A loop in a request.security helper reaches a ta.* call through a parameter or global it reads; compute that value before the loop.", "args": {"via": {"kind": "text"}}}, + "PF-E3032": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a user function call", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A for or while loop in a request.security helper cannot call a user-defined function; compute the value before the loop.", "args": {}}, + "PF-E3033": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a user function call (through {via})", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A loop in a request.security helper reaches a user function call through a parameter or global it reads; compute that value before the loop.", "args": {"via": {"kind": "text"}}}, + "PF-E3034": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a var declaration", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A for or while loop in a request.security helper cannot declare a var; compute the value before the loop.", "args": {}}, + "PF-E3035": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a var declaration (through {via})", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A loop in a request.security helper reaches a var declaration through a parameter or global it reads; compute that value before the loop.", "args": {"via": {"kind": "text"}}}, + "PF-E3036": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a {namespace}.* call", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A for or while loop in a request.security helper cannot call request.* or strategy.* functions; compute the value before the loop.", "args": {"namespace": {"kind": "identifier"}}}, + "PF-E3037": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold a {namespace}.* call (through {via})", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A loop in a request.security helper reaches a request.* or strategy.* call through a parameter or global it reads; compute it before the loop.", "args": {"namespace": {"kind": "identifier"}, "via": {"kind": "text"}}}, + "PF-E3038": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold the local ''{name}'', which is read with history", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A loop in a request.security helper cannot read a local that is also read with history; compute that local before the loop.", "args": {"name": {"kind": "identifier"}}}, + "PF-E3039": {"severity": "error", "area": "request-security", "message": "request.security helper loops cannot hold the local ''{name}'', which is read with history (through {via})", "hint": "Compute it before the loop, on the requested bar.", "explanation": "A loop in a request.security helper reaches a local read with history through a parameter or global; compute that local before the loop.", "args": {"name": {"kind": "identifier"}, "via": {"kind": "text"}}}, + "PF-E3040": {"severity": "error", "area": "request-security", "message": "request.security mutable global rebinding does not support top-level switch", "hint": "Rewrite the switch as if/else assignments before passing the value to request.security().", "explanation": "A global read by the request.security expression is rebound inside a top-level switch, which PineForge cannot replay; rewrite it as if/else assignments.", "args": {}}, + "PF-E3041": {"severity": "error", "area": "request-security", "message": "request.security mutable global rebinding does not support top-level loops", "hint": "Move loop-driven mutable state out of request.security() expressions or rewrite it as direct assignments.", "explanation": "A global read by the request.security expression is rebound inside a top-level loop, which PineForge cannot replay; use direct assignments or move it out.", "args": {}}, + "PF-E3042": {"severity": "error", "area": "request-security", "message": "request.security does not support TA constructor args that depend on rebound mutable globals", "hint": "Keep TA constructor arguments immutable/simple inside request.security(), or hoist the TA call outside the security expression.", "explanation": "A TA length or other indicator argument inside request.security depends on a global the script reassigns; keep it constant or compute the TA outside.", "args": {}}, + "PF-E3043": {"severity": "error", "area": "request-security", "message": "History of a {kind} reference inside a request.security expression is not supported in PineForge: TradingView reads the references the variable held on the requested timeframe''s bars, which PineForge does not keep.", "hint": "Request the field values the expression needs (request.security(..., obj.field)) and read their history on the chart.", "explanation": "request.security cannot read the history of a user-defined type or drawing reference, because PineForge keeps no references from the requested bars.", "args": {"kind": {"kind": "type"}}}, + "PF-E3044": {"severity": "error", "area": "request-security", "message": "request.security payload reads ''{name}'', an element of a tuple declaration it cannot re-evaluate", "hint": null, "explanation": "The request.security expression reads a name bound by a tuple declaration that PineForge cannot re-evaluate on the requested bar.", "args": {"name": {"kind": "identifier"}}}, + "PF-E3045": {"severity": "error", "area": "request-security", "message": "request.security payload reads ''{name}'', an element of a TA tuple it does not compute once per requested bar", "hint": null, "explanation": "The request.security expression reads an element of a TA tuple that PineForge does not compute once per requested bar.", "args": {"name": {"kind": "identifier"}}}, + "PF-E3046": {"severity": "error", "area": "request-security", "message": "request.security() bar-field history index must be non-negative", "hint": null, "explanation": "A negative history offset on a bar series such as close[-1] is not allowed inside request.security.", "args": {}}, + "PF-E3047": {"severity": "error", "area": "request-security", "message": "request.security payload reads the history of ''{object_name}'', an element of a tuple declaration", "hint": null, "explanation": "The request.security expression reads the history of a name bound by a tuple declaration, which PineForge cannot do on the requested bars.", "args": {"object_name": {"kind": "identifier"}}}, + "PF-E3048": {"severity": "error", "area": "request-security", "message": "request.security payload reads the string global ''{object_name}'' with history, which the requested clock does not keep", "hint": null, "explanation": "A string global read with history inside request.security is not supported, because the requested clock keeps no string history.", "args": {"object_name": {"kind": "identifier"}}}, + "PF-E3049": {"severity": "error", "area": "request-security", "message": "request.security() TA history index must be a literal integer (e.g. ta.ema(close, 55)[1])", "hint": "An int computed from inputs and literals is admitted; a series index is not.", "explanation": "A history offset on a TA call inside request.security must be an integer literal or a number computed from inputs and literals, not a series.", "args": {}}, + "PF-E3050": {"severity": "error", "area": "request-security", "message": "request.security() TA history index must be non-negative", "hint": null, "explanation": "A negative history offset on a TA call inside request.security is not allowed.", "args": {}}, + "PF-E3051": {"severity": "error", "area": "request-security", "message": "request.security multi-statement helper TA history is not supported", "hint": "Use a single-expression helper for TA history offsets.", "explanation": "A TA history offset inside a multi-statement request.security helper is not supported; use a single-expression helper.", "args": {}}, + "PF-E3052": {"severity": "error", "area": "request-security", "message": "request.security helper functions must not recurse while building a security context", "hint": null, "explanation": "A request.security helper calls itself, directly or through other helpers, which PineForge cannot inline; remove the recursion.", "args": {}}, + "PF-E3053": {"severity": "error", "area": "request-security", "message": "request.security multi-statement helpers require statement-capable security evaluation context", "hint": null, "explanation": "A multi-statement helper is used inside a request.security expression at a spot where PineForge cannot emit statements, so it cannot be inlined there.", "args": {}}, + "PF-E3054": {"severity": "error", "area": "request-security", "message": "the payload reads ''{func_name}'' on the chart''s bar", "hint": null, "explanation": "The request.security expression mixes a value evaluated on the requested bar with one PineForge can only read on the chart's bar.", "args": {"func_name": {"kind": "identifier"}}}, + "PF-E3055": {"severity": "error", "area": "request-security", "message": "the payload reads ''{namespace}.{func_name}'' on the chart''s bar", "hint": null, "explanation": "The request.security expression mixes a value evaluated on the requested bar with one PineForge can only read on the chart's bar.", "args": {"namespace": {"kind": "identifier"}, "func_name": {"kind": "identifier"}}}, + "PF-E3056": {"severity": "error", "area": "request-security", "message": "the payload reads ''{name}'' on the chart''s bar", "hint": null, "explanation": "The request.security expression mixes a value evaluated on the requested bar with one PineForge can only read on the chart's bar.", "args": {"name": {"kind": "identifier"}}}, + "PF-E3057": {"severity": "error", "area": "request-security", "message": "the payload reads a user call it cannot inline on the chart''s bar", "hint": null, "explanation": "A request.security payload reads something PineForge would evaluate on the chart's bar, where TradingView evaluates it on the requested bar, so it is refused.", "args": {}}, + "PF-E3058": {"severity": "error", "area": "request-security", "message": "the payload reads a {node_type} on the chart''s bar", "hint": null, "explanation": "The request.security expression mixes a value evaluated on the requested bar with one PineForge can only read on the chart's bar.", "args": {"node_type": {"kind": "identifier"}}}, + "PF-E3059": {"severity": "error", "area": "request-security", "message": "the payload reads history it does not keep on the requested clock on the chart''s bar", "hint": null, "explanation": "A request.security payload reads something PineForge would evaluate on the chart's bar, where TradingView evaluates it on the requested bar, so it is refused.", "args": {}}, + "PF-E3060": {"severity": "error", "area": "request-security", "message": "request.security payload reads the history of ''{name}'', an element of a tuple declaration", "hint": null, "explanation": "The request.security expression reads the history of a name bound by a tuple declaration, which PineForge cannot do on the requested bars.", "args": {"name": {"kind": "identifier"}}}, + "PF-E3061": {"severity": "error", "area": "request-security", "message": "request.security helper switch arms must each be one expression", "hint": "Compute a multi-statement arm in its own helper, or on the chart.", "explanation": "A switch used as a request.security helper's value must have a single expression in each arm; move multi-statement arms into their own helper.", "args": {}}, + "PF-E3062": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: helper ''{func}'' {problem}", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A helper holding a request.security cannot have its symbol and timeframe resolved per call path, because it is overloaded or called from a method.", "args": {"request_name": {"kind": "identifier"}, "func": {"kind": "identifier"}, "problem": {"kind": "text"}}}, + "PF-E3063": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: ''{expr_name}'' is not a value fixed before the first bar", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "expr_name": {"kind": "identifier"}}}, + "PF-E3064": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: ''{expr}'' is not a value fixed before the first bar", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "expr": {"kind": "identifier"}}}, + "PF-E3065": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: ''{func}'' declares ''{names}''", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "func": {"kind": "identifier"}, "names": {"kind": "identifier"}}}, + "PF-E3066": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: ''{name}'' is not a value the requested bars recompute", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol or timeframe reached through helper parameters cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E3067": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: ''{name}'' is reassigned or declared var", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E3068": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: a {node_type} is not a value fixed before the first bar", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "node_type": {"kind": "identifier"}}}, + "PF-E3069": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: it holds a request.{request_name2} call", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "request_name2": {"kind": "identifier"}}}, + "PF-E3070": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: it reads ''{expr_name}'', a series", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "expr_name": {"kind": "identifier"}}}, + "PF-E3071": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: its value is too large", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}}}, + "PF-E3072": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: parameter ''{binding}'' has no argument", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "binding": {"kind": "identifier"}}}, + "PF-E3073": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: parameter ''{param}'' has no argument", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "param": {"kind": "identifier"}}}, + "PF-E3074": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: the helpers reach it through too many call paths", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol or timeframe reached through helper parameters cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}}}, + "PF-E3075": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: the method call {expr}", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "expr": {"kind": "identifier"}}}, + "PF-E3076": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: the user function call {callee_name}(...)", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The symbol or timeframe of a request inside a helper cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "callee_name": {"kind": "identifier"}}}, + "PF-E3077": {"severity": "error", "area": "request-security", "message": "request.{request_name} {what} cannot be resolved before the first bar on the call path {chain}: the value of ''{param}'' is not lowered on the requested bars", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol or timeframe reached through helper parameters cannot be computed before the first bar on this call path; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "what": {"kind": "text"}, "chain": {"kind": "identifier"}, "param": {"kind": "identifier"}}}, + "PF-E3078": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: ''{expr_name}'' is not a value fixed before the first bar", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "expr_name": {"kind": "identifier"}}}, + "PF-E3079": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: ''{expr}'' is not a value fixed before the first bar", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "expr": {"kind": "identifier"}}}, + "PF-E3080": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: ''{func}'' declares ''{names}''", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "func": {"kind": "identifier"}, "names": {"kind": "identifier"}}}, + "PF-E3081": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: ''{name}'' is not a value the requested bars recompute", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E3082": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: ''{name}'' is reassigned or declared var", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E3083": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: a {node_type} is not a value fixed before the first bar", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "node_type": {"kind": "identifier"}}}, + "PF-E3084": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: it holds a request.{request_name2} call", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol or timeframe holds another request, which PineForge cannot compute before the first bar.", "args": {"request_name": {"kind": "identifier"}, "request_name2": {"kind": "identifier"}}}, + "PF-E3085": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: it reads ''{expr_name}'', a series", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "expr_name": {"kind": "identifier"}}}, + "PF-E3086": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: its value is too large", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The value a request's context reads is too large for PineForge to resolve before the first bar.", "args": {"request_name": {"kind": "identifier"}}}, + "PF-E3087": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: parameter ''{binding}'' has no argument", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A helper call leaves out the parameter the request's symbol or timeframe reads, so PineForge cannot resolve the request's context.", "args": {"request_name": {"kind": "identifier"}, "binding": {"kind": "identifier"}}}, + "PF-E3088": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: parameter ''{param}'' has no argument", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A helper call leaves out the parameter the request's symbol or timeframe reads, so PineForge cannot resolve the request's context.", "args": {"request_name": {"kind": "identifier"}, "param": {"kind": "identifier"}}}, + "PF-E3089": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: the helpers reach it through too many call paths", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "The helpers holding this request are reached through too many call paths for PineForge to resolve each one's symbol and timeframe.", "args": {"request_name": {"kind": "identifier"}}}, + "PF-E3090": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: the method call {expr}", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "expr": {"kind": "identifier"}}}, + "PF-E3091": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: the user function call {callee_name}(...)", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "callee_name": {"kind": "identifier"}}}, + "PF-E3092": {"severity": "error", "area": "request-security", "message": "request.{request_name} context: the value of ''{param}'' is not lowered on the requested bars", "hint": "Pass the symbol and timeframe as literals, inputs or globals at the helper''s call sites.", "explanation": "A request's symbol, timeframe or payload parameter reads a value PineForge cannot compute before the first bar or recompute on the requested bars; pass literals, inputs or globals.", "args": {"request_name": {"kind": "identifier"}, "param": {"kind": "identifier"}}}, + "PF-E4001": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' has no valid sha256 in {where}", "hint": null, "explanation": "The imported library cannot be inlined: its pinned source is missing, unreadable or not configured for this script.", "args": {"path": {"kind": "identifier"}, "where": {"kind": "text"}}}, + "PF-E4002": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' is not among the libraries passed to transpile()", "hint": null, "explanation": "The imported library was not among the library sources supplied to the transpiler, so it cannot be inlined; supply its source text.", "args": {"path": {"kind": "identifier"}}}, + "PF-E4003": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' is not open-source (access ''{access}''); PineForge inlines open libraries only", "hint": null, "explanation": "The library's manifest entry says it is not open-source, and PineForge inlines open libraries only.", "args": {"path": {"kind": "identifier"}, "access": {"kind": "identifier"}}}, + "PF-E4004": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' is not open-source (access ''{indexed_access}'' in libraries.json); PineForge inlines open libraries only", "hint": null, "explanation": "The library index marks this library as not open-source, and PineForge inlines open libraries only.", "args": {"path": {"kind": "identifier"}, "indexed_access": {"kind": "identifier"}}}, + "PF-E4005": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' is not pinned by this script''s requests manifest ({where})", "hint": null, "explanation": "The script's requests manifest does not pin this imported library, so PineForge will not use any other source for it; add the library to the manifest.", "args": {"path": {"kind": "identifier"}, "where": {"kind": "identifier"}}}, + "PF-E4006": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' source does not match its pinned sha256 {sha}... (found {found_sha}...)", "hint": null, "explanation": "The library source that was found does not match the SHA-256 hash pinned in the manifest, so PineForge refuses to use it.", "args": {"path": {"kind": "identifier"}, "sha": {"kind": "identifier"}, "found_sha": {"kind": "identifier"}}}, + "PF-E4007": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' source is missing (sha256 {sha}... under ${requests_env}/{slug_dir_name}/files and ${libraries_env})", "hint": null, "explanation": "No file matching the library's pinned SHA-256 hash was found in the configured directories, so its source is missing.", "args": {"path": {"kind": "identifier"}, "sha": {"kind": "identifier"}, "requests_env": {"kind": "identifier"}, "slug_dir_name": {"kind": "identifier"}, "libraries_env": {"kind": "identifier"}}}, + "PF-E4008": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': library ''{path}'' source is not UTF-8 text", "hint": null, "explanation": "The imported library cannot be inlined: its pinned source is missing, unreadable or not configured for this script.", "args": {"path": {"kind": "identifier"}}}, + "PF-E4009": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{path}'': no library sources are configured", "hint": null, "explanation": "The imported library cannot be inlined: its pinned source is missing, unreadable or not configured for this script.", "args": {"path": {"kind": "identifier"}}}, + "PF-E4010": {"severity": "error", "area": "libraries", "message": "library ''{path}'' spells ''{clash}'', a name PineForge gave to an inlined definition", "hint": null, "explanation": "An imported library uses a name PineForge generates for its own inlined definitions, so the library cannot be inlined without a name clash.", "args": {"path": {"kind": "identifier"}, "clash": {"kind": "identifier"}}}, + "PF-E4011": {"severity": "error", "area": "libraries", "message": "library ''{path}'' defines ''{name}'' {defs_count} times (overloads); PineForge does not inline an overloaded library function", "hint": null, "explanation": "The library defines this function several times (overloads) in a way PineForge cannot resolve, so it will not inline it; call a non-overloaded function.", "args": {"path": {"kind": "identifier"}, "name": {"kind": "identifier"}, "defs_count": {"kind": "number"}}}, + "PF-E4012": {"severity": "error", "area": "libraries", "message": "no overload of ''{name}'' of library ''{path}'' takes the arguments of this call", "hint": null, "explanation": "None of the library function's overloads accepts the arguments in this call; check the number of arguments and any keyword names.", "args": {"name": {"kind": "identifier"}, "path": {"kind": "identifier"}}}, + "PF-E4013": {"severity": "error", "area": "libraries", "message": "library ''{path}'' does not export ''{member}''", "hint": null, "explanation": "The name exists in the imported library but is not exported, so the script cannot use it through the import; use an exported name.", "args": {"path": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E4014": {"severity": "error", "area": "libraries", "message": "library ''{path}'' does not export ''{member}'': it has no ''{member}''", "hint": null, "explanation": "The imported library has no such name at all; check the spelling of the member you access through the import alias.", "args": {"path": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E4015": {"severity": "error", "area": "libraries", "message": "''{token}'' is not a type of library ''{targets}''", "hint": null, "explanation": "A type written as alias.Type is not an exported type or enum of that library; check the type's name and that the library exports it.", "args": {"token": {"kind": "identifier"}, "targets": {"kind": "identifier"}}}, + "PF-E4016": {"severity": "error", "area": "libraries", "message": "library ''{path}'': a {statement} inside a function is not supported", "hint": null, "explanation": "A function in an imported library contains a nested declaration (function, method, type, enum, import or script declaration), which PineForge cannot inline.", "args": {"path": {"kind": "identifier"}, "statement": {"kind": "vocab", "values": ["EnumDecl", "FuncDef", "ImportStmt", "MethodDef", "StrategyDecl", "TypeDecl"]}}}, + "PF-E4017": {"severity": "error", "area": "libraries", "message": "''{alias}.{member}'' of library ''{targets}'' is a {kind}, not a value", "hint": null, "explanation": "The script reads a library function or method as a plain value; only exported constants, types and enums can be read that way, so call it instead.", "args": {"alias": {"kind": "identifier"}, "member": {"kind": "identifier"}, "targets": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["function", "method"]}}}, + "PF-E4018": {"severity": "error", "area": "libraries", "message": "library method ''{member}'' called without its receiver as the first positional argument", "hint": null, "explanation": "A library method was called through its import alias without the receiver as the first argument; pass the receiver first or call it as receiver.method().", "args": {"member": {"kind": "identifier"}}}, + "PF-E4019": {"severity": "error", "area": "libraries", "message": "''{alias}.{member}'' of library ''{targets}'' is a {kind}, not a function", "hint": null, "explanation": "The script calls an exported library type or constant like a function; only exported functions and methods can be called, so use it as a type or value.", "args": {"alias": {"kind": "identifier"}, "member": {"kind": "identifier"}, "targets": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["const", "type"]}}}, + "PF-E4020": {"severity": "error", "area": "libraries", "message": "method ''{member}'' is exported by {exporters_count} imported libraries; a keyword argument cannot be bound to one", "hint": null, "explanation": "Several imported libraries export a method with this name, so a call that uses keyword arguments is ambiguous; pass the arguments by position.", "args": {"member": {"kind": "identifier"}, "exporters_count": {"kind": "number"}}}, + "PF-E4021": {"severity": "error", "area": "libraries", "message": "''{alias}.{member}'' of library ''{main_targets}'' is a {kind}, not a value", "hint": null, "explanation": "The script reads a library function or method as a plain value; only exported constants, types and enums can be read that way, so call it instead.", "args": {"alias": {"kind": "identifier"}, "member": {"kind": "identifier"}, "main_targets": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["function", "method"]}}}, + "PF-E4022": {"severity": "error", "area": "libraries", "message": "''{alias}.{member}'' of library ''{main_targets}'' is a {kind}, not a function", "hint": null, "explanation": "The script calls an exported library type or constant like a function; only exported functions and methods can be called, so use it as a type or value.", "args": {"alias": {"kind": "identifier"}, "member": {"kind": "identifier"}, "main_targets": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["const", "type"]}}}, + "PF-E4023": {"severity": "error", "area": "libraries", "message": "import alias ''{alias}'' is used by two imports", "hint": null, "explanation": "Two imports use the same alias, so names like alias.member would be ambiguous; give each import its own alias.", "args": {"alias": {"kind": "identifier"}}}, + "PF-E4024": {"severity": "error", "area": "libraries", "message": "Import is not supported: ''{import_path}'': its alias ''{alias}'' is a built-in namespace other than ta, math or str", "hint": null, "explanation": "The import's alias is a built-in namespace other than ta, math or str, which PineForge does not allow; choose a different alias.", "args": {"import_path": {"kind": "identifier"}, "alias": {"kind": "identifier"}}}, + "PF-E4025": {"severity": "error", "area": "libraries", "message": "import alias ''{alias}'' is also declared as a variable, parameter or function", "hint": null, "explanation": "The import alias is also the name of a variable, parameter or function in the script, which would make the alias ambiguous; rename one of them.", "args": {"alias": {"kind": "identifier"}}}, + "PF-E4026": {"severity": "error", "area": "libraries", "message": "method ''{name}'' of library ''{path}'' has the same receiver type as a method of {other}", "hint": null, "explanation": "Two methods share a name and receiver type, one in this library and one in the script or another library, so one would be unreachable.", "args": {"name": {"kind": "identifier"}, "path": {"kind": "identifier"}, "other": {"kind": "text"}}}, + "PF-E4027": {"severity": "error", "area": "libraries", "message": "library ''{path}'' is //@version=5: its function reached from a request.{callee_member}() payload would run outside v5''s rules there", "hint": null, "explanation": "A function from a Pine v5 library is reached from a request.*() expression, where PineForge cannot apply v5 rules, so it is refused.", "args": {"path": {"kind": "identifier"}, "callee_member": {"kind": "identifier"}}}, + "PF-E4028": {"severity": "error", "area": "libraries", "message": "library ''{path}'' has {found}; PineForge inlines v5 and v6 libraries only", "hint": null, "explanation": "The imported library has no //@version line or a version other than 5 or 6; PineForge inlines only version 5 and 6 libraries.", "args": {"path": {"kind": "identifier"}, "found": {"kind": "text"}}}, + "PF-E4029": {"severity": "error", "area": "libraries", "message": "''{path}'' is not a library: it has {found}, not one library() declaration", "hint": null, "explanation": "The imported source is not a library: it must hold exactly one library() declaration, but it has none or a different kind of declaration.", "args": {"path": {"kind": "identifier"}, "found": {"kind": "text"}}}, + "PF-E4030": {"severity": "error", "area": "libraries", "message": "library ''{path}'' has a malformed import: ''{path2}''", "hint": null, "explanation": "An import inside the library is malformed (it lacks a version or an alias), so PineForge cannot follow it.", "args": {"path": {"kind": "identifier"}, "path2": {"kind": "identifier"}}}, + "PF-E4031": {"severity": "error", "area": "libraries", "message": "library ''{path}'' is //@version=5: {exc}", "hint": null, "explanation": "A Pine v5 library uses a v5 behaviour that PineForge does not implement, so the library is refused; the reason names the construct.", "args": {"path": {"kind": "identifier"}, "exc": {"kind": "text"}}}, + "PF-E4032": {"severity": "error", "area": "libraries", "message": "no library sources are configured", "hint": null, "explanation": "No library sources were given to the transpiler and none are configured in the environment, so imports cannot be resolved.", "args": {}}, + "PF-E4033": {"severity": "error", "area": "libraries", "message": "library ''{path}'' is not among the libraries passed to transpile()", "hint": null, "explanation": "The imported library was not among the library sources supplied to the transpiler, so it cannot be inlined; supply its source text.", "args": {"path": {"kind": "identifier"}}}, + "PF-E4034": {"severity": "error", "area": "libraries", "message": "library ''{path}'' is not pinned by this script''s requests manifest ({where})", "hint": null, "explanation": "The script's requests manifest does not pin this imported library, so PineForge will not use any other source for it; add the library to the manifest.", "args": {"path": {"kind": "identifier"}, "where": {"kind": "identifier"}}}, + "PF-E4035": {"severity": "error", "area": "libraries", "message": "library ''{path}'' is not open-source (access ''{access}''); PineForge inlines open libraries only", "hint": null, "explanation": "The library's manifest entry says it is not open-source, and PineForge inlines open libraries only.", "args": {"path": {"kind": "identifier"}, "access": {"kind": "identifier"}}}, + "PF-E4036": {"severity": "error", "area": "libraries", "message": "library ''{path}'' has no valid sha256 in {where}", "hint": null, "explanation": "The library's entry in the requests manifest has no valid SHA-256 hash, so its source cannot be verified; fix the entry.", "args": {"path": {"kind": "identifier"}, "where": {"kind": "identifier"}}}, + "PF-E4037": {"severity": "error", "area": "libraries", "message": "library ''{path}'' is not open-source (access ''{indexed_access}'' in libraries.json); PineForge inlines open libraries only", "hint": null, "explanation": "The library index marks this library as not open-source, and PineForge inlines open libraries only.", "args": {"path": {"kind": "identifier"}, "indexed_access": {"kind": "identifier"}}}, + "PF-E4038": {"severity": "error", "area": "libraries", "message": "library ''{path}'' source is not UTF-8 text", "hint": null, "explanation": "The library's source is not valid UTF-8 text, so it cannot be read or inlined.", "args": {"path": {"kind": "identifier"}}}, + "PF-E4039": {"severity": "error", "area": "libraries", "message": "library ''{path}'' source does not match its pinned sha256 {sha}... (found {found_sha}...)", "hint": null, "explanation": "The library source that was found does not match the SHA-256 hash pinned in the manifest, so PineForge refuses to use it.", "args": {"path": {"kind": "identifier"}, "sha": {"kind": "identifier"}, "found_sha": {"kind": "identifier"}}}, + "PF-E4040": {"severity": "error", "area": "libraries", "message": "library ''{path}'' source is missing (sha256 {sha}... under ${requests_env}/{slug_dir_name}/files and ${libraries_env})", "hint": null, "explanation": "No file matching the library's pinned SHA-256 hash was found in the configured directories, so its source is missing.", "args": {"path": {"kind": "identifier"}, "sha": {"kind": "identifier"}, "requests_env": {"kind": "identifier"}, "slug_dir_name": {"kind": "identifier"}, "libraries_env": {"kind": "identifier"}}}, + "PF-E5001": {"severity": "error", "area": "codegen", "message": "Recursive stateful callable cycle is not supported: {cycle}.", "hint": "Remove the recursive call; Pine user-defined functions cannot execute recursively.", "explanation": "Stateful functions (with TA calls, var variables or history reads) call each other in a cycle; Pine forbids recursion, so remove the recursive call.", "args": {"cycle": {"kind": "identifier"}}}, + "PF-E5002": {"severity": "error", "area": "codegen", "message": "matrix.{meth_name} requires matrix; got matrix<{elem_str}>", "hint": "Numeric-only methods are not available for matrix, matrix, matrix, or matrix.", "explanation": "This matrix method works only on matrix; it cannot be used on a matrix of int, bool, string or objects.", "args": {"meth_name": {"kind": "identifier"}, "elem_str": {"kind": "type"}}}, + "PF-E5003": {"severity": "error", "area": "codegen", "message": "matrix.sort requires int, bool, string, or float element type; got {elem_name}", "hint": null, "explanation": "matrix.sort can sort only int, bool, string or float matrices, and this matrix has a different element type.", "args": {"elem_name": {"kind": "type"}}}, + "PF-E5004": {"severity": "error", "area": "codegen", "message": "matrix.sort requires int, bool, string, or float element type; UDT matrices cannot be sorted", "hint": null, "explanation": "matrix.sort cannot sort a matrix of user-defined objects; only int, bool, string and float matrices can be sorted.", "args": {}}, + "PF-E5005": {"severity": "error", "area": "codegen", "message": "request.security helper call history is only supported in the payload itself", "hint": null, "explanation": "Reading the history ([k]) of a call inside a function used by request.security is not supported; do it in the expression passed to request.security itself.", "args": {}}, + "PF-E5006": {"severity": "error", "area": "codegen", "message": "Unsupported TA constructor flag ''{a}'' for {class_name}: it is neither a compile-time constant nor derived from an input, so PineForge cannot initialize the indicator with a stable per-run value.", "hint": "Use a literal, an input.*() value, or arithmetic over those for TA constructor arguments.", "explanation": "A TA indicator's boolean argument is neither a literal nor derived from an input, so PineForge cannot fix it once per run; use a literal or an input.", "args": {"a": {"kind": "identifier"}, "class_name": {"kind": "type"}}}, + "PF-E5007": {"severity": "error", "area": "codegen", "message": "Unsupported TA constructor flag ''{a}'' for {class_name}: it is neither a compile-time constant nor derived from an input, so PineForge cannot initialize the indicator with a stable per-run value.", "hint": "Use a literal, an input.*() value, or arithmetic over those for TA lengths.", "explanation": "A TA indicator's flag argument is neither a constant nor input-derived, so PineForge cannot set it once per run; use a literal or an input-based value.", "args": {"a": {"kind": "identifier"}, "class_name": {"kind": "type"}}}, + "PF-E5008": {"severity": "error", "area": "codegen", "message": "Unsupported TA constructor length ''{a}'' for {class_name}: it is neither a compile-time constant nor derived from an input, so PineForge cannot size the indicator buffer.", "hint": "Use a literal, an input.*() value, or arithmetic over those for TA constructor arguments.", "explanation": "A TA indicator's length is neither a constant nor derived from an input, so PineForge cannot size its buffer; use a literal, an input or arithmetic on those.", "args": {"a": {"kind": "identifier"}, "class_name": {"kind": "type"}}}, + "PF-E5009": {"severity": "error", "area": "codegen", "message": "Unsupported TA constructor length ''{a}'' for {class_name}: it is neither a compile-time constant nor derived from an input, so PineForge cannot size the indicator buffer.", "hint": "Use a literal, an input.*() value, or arithmetic over those for TA lengths.", "explanation": "A TA indicator's length is not a literal and not derived from an input, so PineForge cannot size its buffer; use a literal, an input or arithmetic on those.", "args": {"a": {"kind": "identifier"}, "class_name": {"kind": "type"}}}, + "PF-E5010": {"severity": "error", "area": "codegen", "message": "request.security timeframe was not resolved for registration", "hint": null, "explanation": "PineForge could not work out this request.security timeframe before the run starts, so it cannot register the request; use a constant, input or syminfo value.", "args": {}}, + "PF-E5011": {"severity": "error", "area": "codegen", "message": "input title {spelled}is not a constant string: TradingView declares title (const string), and PineForge keys an input override by its title.", "hint": "Use a string literal, or a name bound once at global scope to one (T = \"Length\").", "explanation": "An input's title must be a constant string (a literal or a name bound once to one), because PineForge keys each input override by its title.", "args": {"spelled": {"kind": "text"}}}, + "PF-E5012": {"severity": "error", "area": "codegen", "message": "{type_name}.copy() is unsupported because direct array field(s) {rendered} still use value storage", "hint": "Move the array outside the UDT and store a supported shared-ID map/matrix or nested UDT handle until array fields gain handle identity.", "explanation": "Copying an object whose type has array fields is unsupported, since PineForge would copy the arrays by value; keep the arrays outside the type.", "args": {"type_name": {"kind": "type"}, "rendered": {"kind": "identifier"}}}, + "PF-E5013": {"severity": "error", "area": "codegen", "message": "array.{method} requires a numeric array", "hint": "Use numeric arrays for aggregate/statistical array functions.", "explanation": "This array function (sum, avg, stdev and similar) needs an array of numbers, and the array has another element type.", "args": {"method": {"kind": "identifier"}}}, + "PF-E5014": {"severity": "error", "area": "codegen", "message": "{func_name}() with bars_back / timeframe_bars_back inside request.security is not supported", "hint": "Read {func_name}() with its offset outside request.security().", "explanation": "time() or time_close() with a bars-back offset is not supported inside request.security; read the offset time outside the request.", "args": {"func_name": {"kind": "identifier"}}}, + "PF-E5015": {"severity": "error", "area": "codegen", "message": "array.copy: expected exactly one receiver ''id''", "hint": "Use array.copy(source) or array.copy(id=source).", "explanation": "array.copy takes exactly one array, either positionally or as id=; this call does not match that.", "args": {}}, + "PF-E5016": {"severity": "error", "area": "codegen", "message": "map.{method}: unknown keyword argument ''{name}''", "hint": "Expected map.{method}({param_names}).", "explanation": "A map function was called with a keyword argument it does not have; use the parameter names it expects.", "args": {"method": {"kind": "identifier"}, "name": {"kind": "identifier"}, "param_names": {"kind": "identifier"}}}, + "PF-E5017": {"severity": "error", "area": "codegen", "message": "map.{method}: unknown keyword argument ''{name}''", "hint": "Use ''id2='' for the source map. Expected map.{method}({param_names}).", "explanation": "map.put_all was called with from=; its source map parameter is named id2, so use id2= or pass the map by position.", "args": {"method": {"kind": "identifier"}, "name": {"kind": "identifier"}, "param_names": {"kind": "identifier"}}}, + "PF-E5018": {"severity": "error", "area": "codegen", "message": "map.{method}: too many positional arguments (expected {param_names_count}, got {args_count})", "hint": "Expected map.{method}({param_names}).", "explanation": "A map function got more positional arguments than it accepts; remove the extra ones.", "args": {"method": {"kind": "identifier"}, "param_names_count": {"kind": "number"}, "args_count": {"kind": "number"}, "param_names": {"kind": "identifier"}}}, + "PF-E5019": {"severity": "error", "area": "codegen", "message": "map.{method}: argument ''{name}'' passed both positionally and by keyword", "hint": "Expected map.{method}({param_names}); bind each argument once.", "explanation": "A map function argument is given both by position and by keyword; pass each argument only once.", "args": {"method": {"kind": "identifier"}, "name": {"kind": "identifier"}, "param_names": {"kind": "identifier"}}}, + "PF-E5020": {"severity": "error", "area": "codegen", "message": "map.{method}: missing required argument ''{missing}''", "hint": "Expected map.{method}({param_names}).", "explanation": "A required argument of a map function is missing from the call; pass it by position or by keyword.", "args": {"method": {"kind": "identifier"}, "missing": {"kind": "identifier"}, "param_names": {"kind": "identifier"}}}, + "PF-E5021": {"severity": "error", "area": "codegen", "message": "map.{method}: keyword arguments are not supported for this functional call form", "hint": "Use the established positional form: map.{method}({param_names}).", "explanation": "Keyword arguments are not supported in this function-style map call; pass the arguments by position.", "args": {"method": {"kind": "identifier"}, "param_names": {"kind": "identifier"}}}, + "PF-E5022": {"severity": "error", "area": "codegen", "message": "map.{method}: keyword arguments are not supported for this receiver-method call form", "hint": "Use the established positional form: map.{method}({param_names}).", "explanation": "Keyword arguments are not supported in this method-style map call; pass the arguments by position.", "args": {"method": {"kind": "identifier"}, "param_names": {"kind": "identifier"}}}, + "PF-E5023": {"severity": "error", "area": "codegen", "message": "an array a call returns is passed to parameter ''{param}'' of ''{func_info_name}'', which takes the array itself: PineForge would pass a copy of it", "hint": "TradingView passes the array a function returns as itself, so the callee''s changes to it reach every variable holding it; pass a variable holding the array instead.", "explanation": "An array returned by a function call is passed to a parameter that can change it in place; PineForge would pass a copy, so store it in a variable first.", "args": {"param": {"kind": "identifier"}, "func_info_name": {"kind": "identifier"}}}, + "PF-E5024": {"severity": "error", "area": "codegen", "message": "{recv_spec_name}.copy() expects no arguments", "hint": "Call copy() on the UDT object without arguments.", "explanation": "copy() on an object takes no arguments; call it as object.copy().", "args": {"recv_spec_name": {"kind": "type"}}}, + "PF-E5025": {"severity": "error", "area": "codegen", "message": "matrix.{meth_raw}: wrong number of arguments", "hint": "Check Pine v6 matrix method signature (positional vs keyword).", "explanation": "A matrix method call has the wrong number of arguments; check the Pine v6 matrix method signature and whether arguments are positional or keyword.", "args": {"meth_raw": {"kind": "identifier"}}}, + "PF-E5026": {"severity": "error", "area": "codegen", "message": "matrix.{func_name}: wrong number of arguments", "hint": "Check Pine v6 matrix method signature (positional vs keyword).", "explanation": "A matrix method call has the wrong number of arguments; check the Pine v6 matrix method signature and whether arguments are positional or keyword.", "args": {"func_name": {"kind": "identifier"}}}, + "PF-E5027": {"severity": "error", "area": "codegen", "message": "timestamp(dateString): could not parse ''{args}''.", "hint": "Supported forms: ISO-8601 (\"2025-01-01[THH:MM:SS][±HH:MM]\") and \"DD MMM YYYY [hh:mm[:ss]] [±HHMM]\" / \"MMM DD YYYY ...\"; no time zone = GMT+0.", "explanation": "timestamp() got a date string PineForge cannot parse; use an ISO-8601 or 'DD MMM YYYY' form, or pass year, month and day numbers.", "args": {"args": {"kind": "identifier"}}}, + "PF-E5028": {"severity": "error", "area": "codegen", "message": "timestamp(dateString) requires a literal string in PineForge (Pine v6 dateString is a const string).", "hint": "Use a string literal, or timestamp(year, month, day[, hour, minute, second]).", "explanation": "timestamp(dateString) needs a string literal, because PineForge parses the date at transpile time; use a literal or numeric arguments.", "args": {}}, + "PF-E5029": {"severity": "error", "area": "codegen", "message": "timestamp(timezone, ...) requires year, month, and day arguments.", "hint": "Pine v6 signature: timestamp(timezone, year, month, day[, hour, minute, second]).", "explanation": "timestamp() with a timezone first needs year, month and day after it; add the missing arguments.", "args": {}}, + "PF-E5030": {"severity": "error", "area": "codegen", "message": "timestamp(...) with {merged_count} argument(s) is not supported — year, month, and day are required.", "hint": "Pine v6 signature: timestamp(year, month, day[, hour, minute, second]); the dateString overload is not supported in PineForge.", "explanation": "timestamp() with numeric arguments needs at least year, month and day; add the missing ones.", "args": {"merged_count": {"kind": "number"}}}, + "PF-E5031": {"severity": "error", "area": "codegen", "message": "matrix.{func_name} receiver must be a variable reference", "hint": null, "explanation": "This numeric-only matrix function needs its matrix as a plain variable so PineForge can check the element type; assign the matrix to a variable first.", "args": {"func_name": {"kind": "identifier"}}}, + "PF-E5032": {"severity": "error", "area": "codegen", "message": "matrix.{func_name}: receiver ''{recv_name}'' is not a known matrix variable", "hint": null, "explanation": "The matrix function's first argument is a variable PineForge does not know as a matrix, so it cannot check its element type.", "args": {"func_name": {"kind": "identifier"}, "recv_name": {"kind": "identifier"}}}, + "PF-E5033": {"severity": "error", "area": "codegen", "message": "{namespace}.copy(...) expects exactly one object argument", "hint": "Prefer the canonical object.copy() form.", "explanation": "Type.copy(...) takes exactly one object of that type; pass one object, or write object.copy().", "args": {"namespace": {"kind": "type"}}}, + "PF-E5034": {"severity": "error", "area": "codegen", "message": "Unknown function ''{func_name}(...)'' — not a PineForge builtin or a user-defined function.", "hint": "Check the spelling; the function may not be supported by PineForge, or needs its namespace (e.g. math./str.).", "explanation": "The called function is neither a PineForge built-in nor defined in the script; check the spelling or add its namespace, such as math. or str.", "args": {"func_name": {"kind": "identifier"}}}, + "PF-E5035": {"severity": "error", "area": "codegen", "message": "Unknown call ''{namespace}.{func_name}(...)'' — ''{namespace}'' is not a PineForge-supported namespace or a user-defined type.", "hint": "Check the spelling; this namespace may not be supported by PineForge.", "explanation": "The call's namespace is neither a supported PineForge namespace nor a user-defined type; check the spelling.", "args": {"namespace": {"kind": "identifier"}, "func_name": {"kind": "identifier"}}}, + "PF-E5036": {"severity": "error", "area": "codegen", "message": "Unknown variable ''{name}'' — not a PineForge builtin or a declared variable.", "hint": null, "explanation": "The script reads a name that is neither a PineForge built-in nor a declared variable; check the spelling or declare it first.", "args": {"name": {"kind": "identifier"}}}, + "PF-E5037": {"severity": "error", "area": "codegen", "message": "Unknown variable ''{name}'' — not a PineForge builtin or a declared variable.", "hint": "{hint}", "explanation": "The script reads a realtime-only built-in variable, which has no value in a batch backtest; remove it or compute the value another way.", "args": {"name": {"kind": "identifier"}, "hint": {"kind": "text"}}}, + "PF-E5038": {"severity": "error", "area": "codegen", "message": "ta.{member} property read could not be bound to a TA call site.", "hint": "Use the function form ta.{member}(...) instead of the bare property read.", "explanation": "A bare ta. read could not be tied to a calculation; call the function form ta.name(...) instead.", "args": {"member": {"kind": "identifier"}}}, + "PF-E5039": {"severity": "error", "area": "codegen", "message": "ta.{member} is not readable as a bare property in PineForge.", "hint": "Call the function form ta.{member}(...) with its arguments instead.", "explanation": "That ta member is not a variable in PineForge, so it cannot be read without parentheses; call it as a function with its arguments.", "args": {"member": {"kind": "identifier"}}}, + "PF-E5040": {"severity": "error", "area": "codegen", "message": "{op} na on a {kind} reference: TradingView refuses a comparison with na (CE10187: \"Cannot compare a value to \\\"na\\\" directly\").", "hint": "Test the reference with na(...).", "explanation": "Comparing an object or drawing reference with na using == or != is rejected, as in TradingView; test it with na(...) instead.", "args": {"op": {"kind": "keyword"}, "kind": {"kind": "type"}}}, + "PF-E5041": {"severity": "error", "area": "codegen", "message": "{op} on a {kind} reference: TradingView compares only line and label references (CE10123: \"Cannot call ''operator {op}''\" with an argument of the {kind} type).", "hint": "Compare the fields or getter values the objects hold, or test na(...).", "explanation": "PineForge refuses == and != on object or drawing references other than line or label of the same kind, as TradingView does; compare fields or test na().", "args": {"op": {"kind": "keyword"}, "kind": {"kind": "type"}}}, + "PF-E5042": {"severity": "error", "area": "codegen", "message": "library ''{library}'' is //@version=5: ''{op}'' of a bool reads v5''s third bool state (na), which PineForge''s two-state bool does not keep", "hint": null, "explanation": "A //@version=5 library compares a bool with == or !=, but v5 bools can be na and PineForge's two-state bool cannot, so it refuses the library.", "args": {"library": {"kind": "identifier"}, "op": {"kind": "keyword"}}}, + "PF-E5043": {"severity": "error", "area": "codegen", "message": "library ''{library}'' is //@version=5: str.format() of a bool reads v5''s third bool state (na), which PineForge''s two-state bool does not keep", "hint": null, "explanation": "A //@version=5 library passes a bool to str.format(), but v5 bools can be na and PineForge's two-state bool cannot, so it refuses the call.", "args": {"library": {"kind": "identifier"}}}, + "PF-E5044": {"severity": "error", "area": "codegen", "message": "library ''{library}'' is //@version=5: str.tostring() of a bool reads v5''s third bool state (na), which PineForge''s two-state bool does not keep", "hint": null, "explanation": "A //@version=5 library passes a bool to str.tostring(), but v5 bools can be na and PineForge's two-state bool cannot, so it refuses the call.", "args": {"library": {"kind": "identifier"}}}, + "PF-E5045": {"severity": "error", "area": "codegen", "message": "library ''{library}'' is //@version=5: string() of a bool reads v5''s third bool state (na), which PineForge''s two-state bool does not keep", "hint": null, "explanation": "A //@version=5 library passes a bool to string(), but v5 bools can be na and PineForge's two-state bool cannot, so it refuses the call.", "args": {"library": {"kind": "identifier"}}}, + "PF-E5046": {"severity": "error", "area": "codegen", "message": "library ''{library}'' is //@version=5: {func_name}() of a bool reads v5''s third bool state (na), which PineForge''s two-state bool does not keep", "hint": null, "explanation": "A //@version=5 library tests a bool with na(), nz() or fixnan(), but v5 bools can be na and PineForge's two-state bool cannot, so it refuses the call.", "args": {"library": {"kind": "identifier"}, "func_name": {"kind": "identifier"}}}, + "PF-E5047": {"severity": "error", "area": "codegen", "message": "session.{flag}[...] cannot be read here: PineForge keeps a session flag''s history on the requested clock only for a read the request.security expression reaches through its own operators, not through a call''s argument, a function or a variable.", "hint": null, "explanation": "A session flag history read inside request.security works only when the expression's own operators reach it, not via a call argument, function or variable.", "args": {"flag": {"kind": "identifier"}}}, + "PF-E5048": {"severity": "error", "area": "codegen", "message": "session.{flag}[...] cannot be read in {owner}(), {why}: PineForge keeps a session flag''s history in a function by each of its call sites, and cannot tell this one apart.", "hint": null, "explanation": "A session flag history read is in a function PineForge cannot split per call site: a method, or one a method, request.security or UDT field default calls.", "args": {"flag": {"kind": "identifier"}, "owner": {"kind": "identifier"}, "why": {"kind": "vocab", "values": ["a method, whose calls PineForge cannot always tell apart", "which a UDT field default calls once for every new()", "which a method calls", "which a request.security expression evaluates on the requested clock"]}}}, + "PF-E5049": {"severity": "error", "area": "codegen", "message": "session.{flag}[...] is not supported here: PineForge keeps a session flag''s history for the script''s top level, a function body and a request.security expression that reads it.", "hint": null, "explanation": "A session flag history read is supported only at the top level, in a function body or in a request.security expression, and this read is none of those.", "args": {"flag": {"kind": "identifier"}}}, + "PF-E5050": {"severity": "error", "area": "codegen", "message": "History of the chart.point {object_name} is not supported in PineForge when the script changes its fields: PineForge holds a chart.point as a value, where TradingView''s history reads the point object as it is now.", "hint": "Keep the field in a variable of its own and read that variable''s history, or build a new point instead of changing a field.", "explanation": "History of a chart.point variable whose fields the script changes is refused because PineForge holds points as values; use a separate variable or build a new point.", "args": {"object_name": {"kind": "identifier"}}}, + "PF-E5051": {"severity": "error", "area": "codegen", "message": "matrix ''{target_label}'' element type mismatch on reassignment: expected {target_type}, got {rhs_type}", "hint": null, "explanation": "A matrix variable is reassigned a matrix with a different element type, which Pine forbids; make the new matrix's element type match the variable's.", "args": {"target_label": {"kind": "identifier"}, "target_type": {"kind": "type"}, "rhs_type": {"kind": "type"}}}, + "PF-E6001": {"severity": "error", "area": "collection-history", "message": "matrix.{method}: wrong number of arguments", "hint": "Check Pine v6 matrix method signature (positional vs keyword).", "explanation": "A matrix method call has the wrong number of arguments; check the Pine v6 matrix method signature and whether arguments are positional or keyword.", "args": {"method": {"kind": "identifier"}}}, + "PF-E6002": {"severity": "error", "area": "collection-history", "message": "{label} := ...: an assignment to the history-referencing operator is not supported in PineForge.", "hint": null, "explanation": "TradingView refuses an assignment to a history reference; assign the variable itself.", "args": {"label": {"kind": "text"}}}, + "PF-E6003": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses for operator {op} (CE10123).", "hint": null, "explanation": "An array or matrix history read such as a[1] is an operand of an operator, which TradingView refuses; read an element or the size and use that instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "op": {"kind": "keyword"}}}, + "PF-E6004": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses for operator {op} (CE10123).", "hint": null, "explanation": "An array or matrix history read such as a[1] is an operand of an operator, which TradingView refuses; read an element or the size and use that instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "op": {"kind": "keyword"}}}, + "PF-E6005": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as the condition of ?: (CE10123).", "hint": null, "explanation": "An array or matrix history read is the condition of a ?: expression, which TradingView refuses; test an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6006": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as the condition of ?: (CE10123).", "hint": null, "explanation": "An array or matrix history read is the condition of a ?: expression, which TradingView refuses; test an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6007": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as the condition of an if statement (CE10101).", "hint": null, "explanation": "An array or matrix history read is the condition of an if statement, which TradingView refuses; test an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6008": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as the condition of an while statement (CE10101).", "hint": null, "explanation": "An array or matrix history read is the condition of a while loop, which TradingView refuses; test an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6009": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as the condition of an if statement (CE10101).", "hint": null, "explanation": "An array or matrix history read is the condition of an if statement, which TradingView refuses; test an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6010": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as the condition of an while statement (CE10101).", "hint": null, "explanation": "An array or matrix history read is the condition of a while loop, which TradingView refuses; test an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6011": {"severity": "error", "area": "collection-history", "message": "({label})[...]: the history of a {kind}''s history is not supported in PineForge.", "hint": null, "explanation": "The history of a collection's history is not kept by PineForge.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6012": {"severity": "error", "area": "collection-history", "message": "({label})[...]: the history of an {kind}''s history is not supported in PineForge.", "hint": null, "explanation": "The history of a collection's history is not kept by PineForge.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6013": {"severity": "error", "area": "collection-history", "message": "{label} is not supported in PineForge here.", "hint": null, "explanation": "A history read bound to a variable or passed to a function is used there in a way PineForge cannot lower; use it only with built-in array or matrix functions.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6014": {"severity": "error", "area": "collection-history", "message": "{label}.{method}: a {kind} has no fields.", "hint": null, "explanation": "An array or a matrix has no fields; a field read after its history reference is refused.", "args": {"label": {"kind": "text"}, "method": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6015": {"severity": "error", "area": "collection-history", "message": "{label}.{method}: an {kind} has no fields.", "hint": null, "explanation": "An array or a matrix has no fields; a field read after its history reference is refused.", "args": {"label": {"kind": "text"}, "method": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6016": {"severity": "error", "area": "collection-history", "message": "{label}.{method}(): no array or matrix method of that name.", "hint": null, "explanation": "No array or matrix method has this name, so the call on the collection's history is refused.", "args": {"label": {"kind": "text"}, "method": {"kind": "identifier"}}}, + "PF-E6017": {"severity": "error", "area": "collection-history", "message": "matrix.sum of {label} is not supported in PineForge: the matrix it returns does not compile.", "hint": null, "explanation": "matrix.sum of a matrix's history returns a matrix that never compiled in PineForge, so it is refused.", "args": {"label": {"kind": "text"}}}, + "PF-E6018": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as an argument of {name} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed to a built-in function that takes only plain numbers, strings or conditions, which TradingView refuses; pass an element.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "name": {"kind": "identifier"}}}, + "PF-E6019": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as an argument of {name} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed to a built-in function that takes only plain numbers, strings or conditions, which TradingView refuses; pass an element.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "name": {"kind": "identifier"}}}, + "PF-E6020": {"severity": "error", "area": "collection-history", "message": "{label} as an argument of {name} is not supported in PineForge.", "hint": null, "explanation": "PineForge would hand over a changeable copy of the collection's history here, where TradingView passes the read-only history, so the use is refused.", "args": {"label": {"kind": "text"}, "name": {"kind": "identifier"}}}, + "PF-E6021": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as an element of array.from (CE10122).", "hint": null, "explanation": "An array or matrix history read is used as an element of array.from(), which TradingView refuses; pass its elements instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6022": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as an element of array.from (CE10122).", "hint": null, "explanation": "An array or matrix history read is used as an element of array.from(), which TradingView refuses; pass its elements instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6023": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as an argument of {namespace}.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed to a built-in namespace function that takes plain values, which TradingView refuses; pass an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "namespace": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6024": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as an argument of {namespace}.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed to a built-in namespace function that takes plain values, which TradingView refuses; pass an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "namespace": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6025": {"severity": "error", "area": "collection-history", "message": "{label} as a field of a new {namespace} is not supported in PineForge: the field would hold a changeable copy, where TradingView''s holds the read-only history.", "hint": null, "explanation": "PineForge would hand over a changeable copy of the collection's history here, where TradingView passes the read-only history, so the use is refused.", "args": {"label": {"kind": "text"}, "namespace": {"kind": "identifier"}}}, + "PF-E6026": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as an argument of str.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed to a str function that takes a plain value, which TradingView refuses; pass an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "member": {"kind": "identifier"}}}, + "PF-E6027": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as an argument of str.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed to a str function that takes a plain value, which TradingView refuses; pass an element or the size instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "member": {"kind": "identifier"}}}, + "PF-E6028": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as the message of log.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is used as the message of a log call, which TradingView refuses; log an element or a string built from it instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "member": {"kind": "identifier"}}}, + "PF-E6029": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as the message of log.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is used as the message of a log call, which TradingView refuses; log an element or a string built from it instead.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "member": {"kind": "identifier"}}}, + "PF-E6030": {"severity": "error", "area": "collection-history", "message": "{label} as an argument of the overloaded method {member} is not supported in PineForge.", "hint": null, "explanation": "PineForge would hand over a changeable copy of the collection's history here, where TradingView passes the read-only history, so the use is refused.", "args": {"label": {"kind": "text"}, "member": {"kind": "identifier"}}}, + "PF-E6031": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as a value of {member}() (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed as a plain value, not as the collection, to an array or matrix method, which TradingView refuses.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "member": {"kind": "identifier"}}}, + "PF-E6032": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as a value of {member}() (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed as a plain value, not as the collection, to an array or matrix method, which TradingView refuses.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "member": {"kind": "identifier"}}}, + "PF-E6033": {"severity": "error", "area": "collection-history", "message": "{label} as an argument of {function}.{member} is not supported in PineForge.", "hint": null, "explanation": "PineForge would hand over a changeable copy of the collection's history here, where TradingView passes the read-only history, so the use is refused.", "args": {"label": {"kind": "text"}, "function": {"kind": "text"}, "member": {"kind": "identifier"}}}, + "PF-E6034": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses as a value of {namespace}.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed as a plain value, not as the collection, to an array or matrix function, which TradingView refuses.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "namespace": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6035": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses as a value of {namespace}.{member} (CE10123).", "hint": null, "explanation": "An array or matrix history read is passed as a plain value, not as the collection, to an array or matrix function, which TradingView refuses.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "namespace": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6036": {"severity": "error", "area": "collection-history", "message": "{label} is an array of colors, which TradingView refuses for log.{member} (CE10122).", "hint": null, "explanation": "A history read of an array of colors is a format argument of a log call, which TradingView refuses; log its elements instead.", "args": {"label": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6037": {"severity": "error", "area": "collection-history", "message": "{label} is an array of colors, which TradingView refuses for log.{member} (CE10123).", "hint": null, "explanation": "A history read of an array of colors is passed to a log call, which TradingView refuses; log its elements instead.", "args": {"label": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6038": {"severity": "error", "area": "collection-history", "message": "{label} is an array of colors, which TradingView refuses for str.format (CE10122).", "hint": null, "explanation": "A history read of an array of colors is a format argument of str.format, which TradingView refuses; format its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6039": {"severity": "error", "area": "collection-history", "message": "{label} is an array of colors, which TradingView refuses for str.format (CE10123).", "hint": null, "explanation": "A history read of an array of colors is passed to str.format, which TradingView refuses; format its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6040": {"severity": "error", "area": "collection-history", "message": "{label} is an array of colors, which TradingView refuses for str.tostring (CE10122).", "hint": null, "explanation": "A history read of an array of colors is passed to str.tostring, which TradingView refuses; convert its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6041": {"severity": "error", "area": "collection-history", "message": "{label} is an array of colors, which TradingView refuses for str.tostring (CE10123).", "hint": null, "explanation": "A history read of an array of colors is passed to str.tostring, which TradingView refuses; convert its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6042": {"severity": "error", "area": "collection-history", "message": "{label} is an array of objects, which TradingView refuses for log.{member} (CE10122).", "hint": null, "explanation": "A history read of an array of objects is a format argument of a log call, which TradingView refuses; log fields of its elements instead.", "args": {"label": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6043": {"severity": "error", "area": "collection-history", "message": "{label} is an array of objects, which TradingView refuses for log.{member} (CE10123).", "hint": null, "explanation": "A history read of an array of objects is passed to a log call, which TradingView refuses; log fields of its elements instead.", "args": {"label": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-E6044": {"severity": "error", "area": "collection-history", "message": "{label} is an array of objects, which TradingView refuses for str.format (CE10122).", "hint": null, "explanation": "A history read of an array of objects is a format argument of str.format, which TradingView refuses; format fields of its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6045": {"severity": "error", "area": "collection-history", "message": "{label} is an array of objects, which TradingView refuses for str.format (CE10123).", "hint": null, "explanation": "A history read of an array of objects is passed to str.format, which TradingView refuses; format fields of its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6046": {"severity": "error", "area": "collection-history", "message": "{label} is an array of objects, which TradingView refuses for str.tostring (CE10122).", "hint": null, "explanation": "A history read of an array of objects is passed to str.tostring, which TradingView refuses; convert fields of its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6047": {"severity": "error", "area": "collection-history", "message": "{label} is an array of objects, which TradingView refuses for str.tostring (CE10123).", "hint": null, "explanation": "A history read of an array of objects is passed to str.tostring, which TradingView refuses; convert fields of its elements instead.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6048": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses for the {type_hint} variable {name} (CE10173).", "hint": null, "explanation": "An array or matrix history read is assigned to a variable declared with a scalar type, which TradingView refuses; assign an element or declare a collection type.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "type_hint": {"kind": "type"}, "name": {"kind": "identifier"}}}, + "PF-E6049": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses for the {type_hint} variable {name} (CE10173).", "hint": null, "explanation": "An array or matrix history read is assigned to a variable declared with a scalar type, which TradingView refuses; assign an element or declare a collection type.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "type_hint": {"kind": "type"}, "name": {"kind": "identifier"}}}, + "PF-E6050": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses for the {field_type} field {member} (CE10173).", "hint": null, "explanation": "An array or matrix history read is assigned to an object field of a scalar type, which TradingView refuses; assign an element or change the field's type.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "field_type": {"kind": "type"}, "member": {"kind": "identifier"}}}, + "PF-E6051": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses for the {field_type} field {member} (CE10173).", "hint": null, "explanation": "An array or matrix history read is assigned to an object field of a scalar type, which TradingView refuses; assign an element or change the field's type.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "field_type": {"kind": "type"}, "member": {"kind": "identifier"}}}, + "PF-E6052": {"severity": "error", "area": "collection-history", "message": "{label} assigned to a field is not supported in PineForge: the field would hold a changeable copy, where TradingView''s holds the read-only history.", "hint": null, "explanation": "PineForge would hand over a changeable copy of the collection's history here, where TradingView passes the read-only history, so the use is refused.", "args": {"label": {"kind": "text"}}}, + "PF-E6053": {"severity": "error", "area": "collection-history", "message": "{label} is a {kind}, which TradingView refuses for the variable {name} of another type (CE10173).", "hint": null, "explanation": "An array or matrix history read is assigned to an existing variable of another type, which TradingView refuses; use a variable of the matching collection type.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "name": {"kind": "identifier"}}}, + "PF-E6054": {"severity": "error", "area": "collection-history", "message": "{label} is an {kind}, which TradingView refuses for the variable {name} of another type (CE10173).", "hint": null, "explanation": "An array or matrix history read is assigned to an existing variable of another type, which TradingView refuses; use a variable of the matching collection type.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}, "name": {"kind": "identifier"}}}, + "PF-E6055": {"severity": "error", "area": "collection-history", "message": "{label} assigned to {name} is not supported in PineForge here.", "hint": null, "explanation": "A history read bound to a variable or passed to a function is used there in a way PineForge cannot lower; use it only with built-in array or matrix functions.", "args": {"label": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-E6056": {"severity": "error", "area": "collection-history", "message": "{label} as a statement: TradingView reads it as a declaration and refuses it (CE10009, \"Extraneous input\").", "hint": null, "explanation": "An array or matrix history read written alone as a top-level statement is refused because TradingView reads it as a declaration; remove it or bind it to a variable.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6057": {"severity": "error", "area": "collection-history", "message": "{label} in a tuple is not supported in PineForge.", "hint": null, "explanation": "A history read bound to a variable or passed to a function is used there in a way PineForge cannot lower; use it only with built-in array or matrix functions.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6058": {"severity": "error", "area": "collection-history", "message": "{label}.slice() is not supported in PineForge here.", "hint": null, "explanation": "A slice of an array's history is used in a way PineForge cannot lower; simplify the expression or copy the array first.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6059": {"severity": "error", "area": "collection-history", "message": "{label} is bound where the script reads it both as a {kind} and through na() or str.tostring(): that is not supported in PineForge, which holds no na {kind} and does not render one.", "hint": null, "explanation": "A variable bound to an array or matrix history is read both as a collection and through na() or str.tostring(); PineForge has no na collection, so it refuses this.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6060": {"severity": "error", "area": "collection-history", "message": "{label} is bound where the script reads it both as an {kind} and through na() or str.tostring(): that is not supported in PineForge, which holds no na {kind} and does not render one.", "hint": null, "explanation": "A variable bound to an array or matrix history is read both as a collection and through na() or str.tostring(); PineForge has no na collection, so it refuses this.", "args": {"label": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6061": {"severity": "error", "area": "collection-history", "message": "{label} is not supported in PineForge here: the history of a matrix is supported as the receiver or an argument of a matrix function, na(), and the value of a variable or a function''s argument that reads it.", "hint": null, "explanation": "A matrix history is supported only as a matrix function's receiver or argument, in na(), or via a variable or function argument that reads it; this use is not.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6062": {"severity": "error", "area": "collection-history", "message": "{label} inside a request.security expression is not supported in PineForge: TradingView reads the copies the requested timeframe''s bars left, which PineForge does not keep.", "hint": null, "explanation": "request.security cannot read the history of a user-defined type or drawing reference, because PineForge keeps no references from the requested bars.", "args": {"label": {"kind": "text"}}}, + "PF-E6063": {"severity": "error", "area": "collection-history", "message": "{label} is not supported in PineForge here: the history of an array is supported as the receiver or an argument of an array function, a for...in iterable, na(), and the value of a variable or a function''s argument that reads it.", "hint": null, "explanation": "An array history is supported only as an array function's receiver or argument, a for...in iterable, in na(), or via a variable or function argument that reads it.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6064": {"severity": "error", "area": "collection-history", "message": "{label}: the history of a block''s var {read_kind} is not supported in PineForge.", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "read_kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6065": {"severity": "error", "area": "collection-history", "message": "{label}: the history of a {kind} declared in a block that redeclares a script variable is not supported in PineForge (such a block''s declarations are C++ locals).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6066": {"severity": "error", "area": "collection-history", "message": "{label}: the history of a {kind} declared in a loop is not supported in PineForge.", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6067": {"severity": "error", "area": "collection-history", "message": "{label}: the history of a {kind} function''s local is not supported in PineForge (TradingView reads one copy per call: fixtures/array_history_tv ahist_fn).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6068": {"severity": "error", "area": "collection-history", "message": "{label}: the history of a {kind} parameter is not supported in PineForge (TradingView reads one copy per call: fixtures/array_history_tv ahist_fn).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6069": {"severity": "error", "area": "collection-history", "message": "{label}: the history of a {kind} script variable read in a function is not supported in PineForge (TradingView reads one copy per call: fixtures/array_history_tv ahist_fn).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6070": {"severity": "error", "area": "collection-history", "message": "{label}: the history of an {kind} declared in a block that redeclares a script variable is not supported in PineForge (such a block''s declarations are C++ locals).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6071": {"severity": "error", "area": "collection-history", "message": "{label}: the history of an {kind} declared in a loop is not supported in PineForge.", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6072": {"severity": "error", "area": "collection-history", "message": "{label}: the history of an {kind} function''s local is not supported in PineForge (TradingView reads one copy per call: fixtures/array_history_tv ahist_fn).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6073": {"severity": "error", "area": "collection-history", "message": "{label}: the history of an {kind} parameter is not supported in PineForge (TradingView reads one copy per call: fixtures/array_history_tv ahist_fn).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6074": {"severity": "error", "area": "collection-history", "message": "{label}: the history of an {kind} script variable read in a function is not supported in PineForge (TradingView reads one copy per call: fixtures/array_history_tv ahist_fn).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for the script's top level and its blocks, not for this kind of declaration.", "args": {"label": {"kind": "text"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6075": {"severity": "error", "area": "collection-history", "message": "{label}: the history of this {read_kind} is not supported in PineForge (only a variable the script''s top level or one of its blocks declares keeps one).", "hint": null, "explanation": "PineForge keeps the history of an array or matrix only for a variable the script's top level or one of its blocks declares.", "args": {"label": {"kind": "text"}, "read_kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6076": {"severity": "error", "area": "collection-history", "message": "The history of a call''s {kind} is not supported in PineForge here: TradingView reads the copy that expression produced that many bars back, which PineForge does not keep.", "hint": "Bind the expression to a variable and read the variable''s history.", "explanation": "The history of a function call's array or matrix result is refused as PineForge keeps no per-bar copy of it; bind the call to a variable and read its history.", "args": {"kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6077": {"severity": "error", "area": "collection-history", "message": "The history of a selection''s {kind} is not supported in PineForge here: TradingView reads the copy that expression produced that many bars back, which PineForge does not keep.", "hint": "Bind the expression to a variable and read the variable''s history.", "explanation": "The history of a ?: selection's array or matrix is refused as PineForge keeps no per-bar copy of it; bind the selection to a variable and read its history.", "args": {"kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6078": {"severity": "error", "area": "collection-history", "message": "The history of an expression''s {kind} is not supported in PineForge here: TradingView reads the copy that expression produced that many bars back, which PineForge does not keep.", "hint": "Bind the expression to a variable and read the variable''s history.", "explanation": "The history of an expression's array or matrix is refused as PineForge keeps no per-bar copy of it; bind the expression to a variable and read its history.", "args": {"kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-E6079": {"severity": "error", "area": "collection-history", "message": "{label} reaches a change through a name bound to it (line ?): TradingView stops the run there (RE10051: \"Cannot modify the elements of a historical array\"); PineForge, which holds a copy, does not.", "hint": "Copy it first (array.copy({label}) or matrix.copy()) to change it.", "explanation": "A name bound to an array or matrix history is changed, which stops the run on TradingView; PineForge would change a copy silently, so copy the history first.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6080": {"severity": "error", "area": "collection-history", "message": "{label} reaches a change through a name bound to it (line {line}): TradingView stops the run there (RE10051: \"Cannot modify the elements of a historical array\"); PineForge, which holds a copy, does not.", "hint": "Copy it first (array.copy({label}) or matrix.copy()) to change it.", "explanation": "A name bound to an array or matrix history is changed on the given line, which stops the run on TradingView; PineForge would change a copy, so copy it first.", "args": {"label": {"kind": "identifier"}, "line": {"kind": "number"}}}, + "PF-E6081": {"severity": "error", "area": "collection-history", "message": "{label} reaches a change through a slice of it (line ?): TradingView stops the run there (RE10051: \"Cannot modify the elements of a historical array\"); PineForge, which holds a copy, does not.", "hint": "Copy it first (array.copy({label}) or matrix.copy()) to change it.", "explanation": "A slice of an array or matrix history is changed, which stops the run on TradingView; PineForge would silently change a copy, so copy the history first.", "args": {"label": {"kind": "identifier"}}}, + "PF-E6082": {"severity": "error", "area": "collection-history", "message": "{label} reaches a change through a slice of it (line {line}): TradingView stops the run there (RE10051: \"Cannot modify the elements of a historical array\"); PineForge, which holds a copy, does not.", "hint": "Copy it first (array.copy({label}) or matrix.copy()) to change it.", "explanation": "A slice of an array or matrix history is changed on the given line, which stops the run on TradingView; PineForge would change a copy, so copy it first.", "args": {"label": {"kind": "identifier"}, "line": {"kind": "number"}}}, + "PF-E7001": {"severity": "error", "area": "ta", "message": "Unsupported requested-context TA constructor for {class_name}: PineForge cannot bind the helper call''s arguments to its constructor arguments.", "hint": "Call the ta.* function directly inside request.security().", "explanation": "A TA function called through a helper inside request.security cannot have the helper's arguments bound to its constructor; call the ta.* function directly.", "args": {"class_name": {"kind": "identifier"}}}, + "PF-E7002": {"severity": "error", "area": "ta", "message": "Unsupported requested-context TA constructor flag ''{shown}'' for {class_name}: the helper-bound expression is not a stable per-run scalar{reason}.", "hint": "Use a literal, an input.*() value, timeframe.* metadata, or arithmetic over those for TA lengths.", "explanation": "A boolean option of a TA call inside request.security comes from a helper-bound value that is not fixed for the run; use a literal, an input or timeframe metadata.", "args": {"shown": {"kind": "identifier"}, "class_name": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-E7003": {"severity": "error", "area": "ta", "message": "Unsupported requested-context TA constructor length ''{shown}'' for {class_name}: the helper-bound expression is not a stable per-run scalar{reason}.", "hint": "Use a literal, an input.*() value, timeframe.* metadata, or arithmetic over those for TA lengths.", "explanation": "A TA length inside request.security comes from a helper-bound value not fixed for the run; use a literal, an input, timeframe metadata or arithmetic on them.", "args": {"shown": {"kind": "identifier"}, "class_name": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-E7004": {"severity": "error", "area": "ta", "message": "Unsupported TA constructor length for {class_name} inside request.security in ''{containing}'': its call sites pass different lengths ({spellings}), and one requested-context evaluator serves them all.", "hint": "Call request.security() at each call site, or pass the same length from every call.", "explanation": "A function with a request.security TA call is called with different lengths, but one evaluator serves all calls; use one length or call request.security per site.", "args": {"class_name": {"kind": "identifier"}, "containing": {"kind": "identifier"}, "spellings": {"kind": "identifier"}}}, + "PF-W0000": {"severity": "warning", "area": "uncatalogued", "message": "{message}", "hint": "{hint}", "explanation": "A diagnostic whose text no catalog template renders; the test suite refuses it, so a release never emits it.", "args": {"message": {"kind": "text"}, "hint": {"kind": "text"}}}, + "PF-W1001": {"severity": "warning", "area": "support", "message": "{context}: map keys must be string in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge supports maps with string keys only; declare the map's key type as string; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"context": {"kind": "text"}}}, + "PF-W1002": {"severity": "warning", "area": "support", "message": "{context}: map values must be primitive in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge supports maps whose values are float, int, bool or string only; use one of those as the value type; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"context": {"kind": "text"}}}, + "PF-W1003": {"severity": "warning", "area": "support", "message": "matrix<{element_type}> is not supported when the UDT contains a map field; rollback would retain live map aliases.", "hint": "Use array for recursively checkpointed state.", "explanation": "A matrix of a user-defined type with a map field is refused because rollback would keep live map references; use an array of that type instead; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"element_type": {"kind": "type"}}}, + "PF-W1004": {"severity": "warning", "area": "support", "message": "matrix<{element_type}>: nested collection element types not supported in v1.", "hint": null, "explanation": "A matrix cannot hold another collection as its element type in PineForge; use float, int, bool, string, color or a user-defined type; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"element_type": {"kind": "type"}}}, + "PF-W1005": {"severity": "warning", "area": "support", "message": "input.color(...) requires a color defval (e.g. color.red or color.new(color.red, 50)).", "hint": null, "explanation": "input.color needs a color as its default value, for example color.red or color.new(color.red, 50); inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1006": {"severity": "warning", "area": "support", "message": "input.color(...) defval must be a color constant (color.red, ...), a color literal (#rrggbb), or a color.new(...) / color.rgb(...) builder. Arbitrary expressions are not supported: the engine has no color helper, so codegen routes input.color through the int getter — any non-color defval would silently store a numeric value with no color encoding.", "hint": "Replace the defval with color. or color.new(...).", "explanation": "The default of input.color must be a color constant, a #rrggbb literal or a color.new or color.rgb call; other expressions are refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1007": {"severity": "warning", "area": "support", "message": "input.source(...) requires a native series defval (close, open, high, low, hl2, hlc3, ohlc4, ...).", "hint": null, "explanation": "input.source needs a default chart series such as close as its first argument or defval; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1008": {"severity": "warning", "area": "support", "message": "input.source(...) defval must be a native chart series (open, high, low, close, volume, hl2, hlc3, ohlc4, hlcc4). User series, computed expressions, and indicator outputs are not supported: input.source is restricted to native OHLCV series.", "hint": "Use one of: close, open, high, low, hl2, hlc3, ohlc4.", "explanation": "The default of input.source must be a native chart series (open, high, low, close, volume, hl2, hlc3, ohlc4, hlcc4); computed series are refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1009": {"severity": "warning", "area": "support", "message": "{kind}() declarations are not supported; PineForge runs strategies only.", "hint": "Replace the declaration with strategy(...) and add explicit entry/exit calls.", "explanation": "PineForge runs strategies only, so a script declared with indicator() or library() is refused; declare it with strategy() and add orders; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"kind": {"kind": "identifier"}}}, + "PF-W1010": {"severity": "warning", "area": "support", "message": "Tuple reassignment [..] {op} is not Pine syntax: TradingView declares a tuple with ''='' and has no tuple reassignment.", "hint": "Declare new names with [a, b] = f(), then reassign each variable on its own line.", "explanation": "Pine has no tuple reassignment: declare a tuple once with '=' and reassign each variable on its own line; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"op": {"kind": "keyword"}}}, + "PF-W1011": {"severity": "warning", "area": "support", "message": "A tuple literal [..] cannot be a variable''s value: TradingView rejects it here (Syntax error at input ''['', CE10156). A tuple is only a function''s or an if/switch arm''s value or a request.security expression.", "hint": "Declare each variable on its own line (a = x, b = y), or return the tuple from a function: f() => [x, y], then [a, b] = f().", "explanation": "A tuple literal such as [a, b] cannot be assigned to a variable; return it from a function or if/switch arm and destructure the result; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1012": {"severity": "warning", "area": "support", "message": "A ternary cannot return a tuple: TradingView rejects [a, b] = c ? [..] : [..] (\"Ternary operations cannot return tuples\").", "hint": "Select the tuple with an if or switch: [a, b] = if c, each arm ending in its tuple.", "explanation": "A ternary cannot produce a tuple (TradingView rejects it too); choose between tuples with an if or switch instead; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1013": {"severity": "warning", "area": "support", "message": "ta.stoch(...) returns a single series in PineForge; tuple destructuring is not supported.", "hint": "Use k = ta.stoch(...) and compute smoothing separately if needed.", "explanation": "ta.stoch returns one series in PineForge, so destructuring it into a tuple is refused; assign it to a single variable; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1014": {"severity": "warning", "area": "support", "message": "History references on UDT drawing fields are not supported in PineForge.", "hint": "{var_name}.{object_member}[...] would be read as the current-bar field, not prior-bar history. Copy the field to a bare drawing variable first, or remove the history reference.", "explanation": "A history index on a drawing field of a user-defined type would silently read the current field, so it is refused; copy the field to a variable first; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"var_name": {"kind": "identifier"}, "object_member": {"kind": "identifier"}}}, + "PF-W1015": {"severity": "warning", "area": "support", "message": "History references on tuple-destructured drawing handles are not supported in PineForge.", "hint": "{object_name}[...] is a drawing handle from tuple destructuring; PineForge cannot historize that tuple element safely.", "explanation": "A drawing handle bound by tuple destructuring cannot be read through a history index; remove the history reference; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}}}, + "PF-W1016": {"severity": "warning", "area": "support", "message": "x[k].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: (x[k]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"member": {"kind": "identifier"}}}, + "PF-W1017": {"severity": "warning", "area": "support", "message": "x[k].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: ({object_name}[{index}]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"member": {"kind": "identifier"}, "object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}}}, + "PF-W1018": {"severity": "warning", "area": "support", "message": "{object_name}[{index}].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: (x[k]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1019": {"severity": "warning", "area": "support", "message": "{object_name}[{index}].{member}(): TradingView refuses a method call straight after the history-referencing operator (CE10010; CE10011 after an array''s or a matrix''s history).", "hint": "Call the method on the history reference in parentheses: ({object_name}[{index}]).{member}().", "explanation": "TradingView rejects a method call written straight after a history index, x[k].method(); put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1020": {"severity": "warning", "area": "support", "message": "x[k].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: (x[k]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"member": {"kind": "identifier"}}}, + "PF-W1021": {"severity": "warning", "area": "support", "message": "x[k].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: ({object_name}[{index}]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"member": {"kind": "identifier"}, "object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}}}, + "PF-W1022": {"severity": "warning", "area": "support", "message": "{object_name}[{index}].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: (x[k]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1023": {"severity": "warning", "area": "support", "message": "{object_name}[{index}].{member}: TradingView refuses a field read straight after the history-referencing operator (CE10011: \"User variable identifiers should not contain ''.''\").", "hint": "Read the field of the history reference in parentheses: ({object_name}[{index}]).{member}.", "explanation": "TradingView rejects a field read written straight after a history index, x[k].field; put the history reference in parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "index": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1024": {"severity": "warning", "area": "support", "message": "footprint.{footprint}(...) is not supported.", "hint": "PineForge reads a footprint''s delta() only: the fp_delta__ column of the feed a requests manifest pins for the symbol requested.", "explanation": "PineForge reads only the delta of a footprint value; every other footprint member is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"footprint": {"kind": "identifier"}}}, + "PF-W1025": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "Currency conversion data not available in PineForge.", "explanation": "PineForge has no currency-conversion data, so request.currency_rate is refused; supply the rate yourself, for example as an input; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1026": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "External Quandl data not available in PineForge.", "explanation": "PineForge cannot load external Quandl data, so request.quandl is refused; remove it; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1027": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "External seed data feeds not available in PineForge.", "explanation": "PineForge cannot load external seed data feeds, so request.seed is refused; remove it; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1028": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.kagi() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.kagi builds a Kagi symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1029": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.linebreak() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.linebreak builds a Line Break symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1030": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.modify() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.modify builds a modified symbol identifier, which PineForge cannot request; PineForge supports multi-timeframe requests on the chart's own symbol only; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1031": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.new() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.new builds another symbol identifier, which PineForge cannot request; PineForge supports multi-timeframe requests on the chart's own symbol only; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1032": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.pointfigure() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.pointfigure builds a Point and Figure symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1033": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported.", "hint": "ticker.renko() chart-type modifier / cross-symbol construction not supported — PineForge runs same-symbol MTF only via request.security with the chart''s own tickerid.", "explanation": "ticker.renko builds a Renko symbol, which PineForge cannot run; PineForge supports multi-timeframe requests on the chart's own symbol only; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1034": {"severity": "warning", "area": "support", "message": "ticker.heikinashi(...) is supported only for the chart''s own symbol.", "hint": "Pass syminfo.tickerid: PineForge applies the Heikin-Ashi candle transform to the chart symbol inside request.security, but cannot load an alternate symbol''s HA candles.", "explanation": "ticker.heikinashi is accepted only for the chart's own symbol (syminfo.tickerid); another symbol's Heikin-Ashi candles cannot be loaded; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1035": {"severity": "warning", "area": "support", "message": "{full}(...) is not implemented yet.", "hint": "timeframe.from_seconds is not yet implemented; codegen would emit ''false'' and silently produce wrong TF strings.", "explanation": "This call names a function on PineForge's not-yet-implemented list, so it is refused rather than compiled into something that silently misbehaves; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1036": {"severity": "warning", "area": "support", "message": "{name}(...) is not implemented yet.", "hint": "timeframe.from_seconds is not yet implemented; codegen would emit ''false'' and silently produce wrong TF strings.", "explanation": "This call names a function on PineForge's not-yet-implemented list, so it is refused rather than compiled into something that silently misbehaves; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1037": {"severity": "warning", "area": "support", "message": "{full}: footprint.* (bid/ask volume rows) is not supported in PineForge batch backtests; it requires tick-level data the engine does not consume.", "hint": "Remove the call or replace it with native OHLCV-based logic.", "explanation": "footprint.* calls need tick-level bid/ask volume rows, which a PineForge batch backtest does not load; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1038": {"severity": "warning", "area": "support", "message": "{full}: volume_row.* is not supported in PineForge batch backtests; same reason as footprint.*.", "hint": "Remove the call or replace it with native OHLCV-based logic.", "explanation": "volume_row.* calls need tick-level volume rows, which a PineForge batch backtest does not load; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1039": {"severity": "warning", "area": "support", "message": "library() declarations are not supported; PineForge runs strategies only.", "hint": "Use strategy(...) and inline or pre-expand library code before uploading.", "explanation": "PineForge runs strategies only, so a library() declaration is refused; use strategy() and paste any library code into the script; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1040": {"severity": "warning", "area": "support", "message": "Bare barssince(...) is broken in PineForge codegen.", "hint": "Use ta.barssince(...) instead.", "explanation": "The bare barssince(...) form does not work in PineForge; call ta.barssince(...) instead; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1041": {"severity": "warning", "area": "support", "message": "ta.sum is not a PineScript v6 function.", "hint": "Use math.sum(...) instead.", "explanation": "ta.sum does not exist in Pine v6; use math.sum(source, length) for a rolling sum; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1042": {"severity": "warning", "area": "support", "message": "ta.{name} is a PineScript v6 variable, not a function.", "hint": "Use ta.{name} without parentheses.", "explanation": "This ta.* name is a built-in variable, not a function, so write it without parentheses; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1043": {"severity": "warning", "area": "support", "message": "{full}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "This strategy.closedtrades or strategy.opentrades accessor is not available in PineForge; use one of the supported trade accessors; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1044": {"severity": "warning", "area": "support", "message": "{full}(...) is not implemented in PineForge runtime.", "hint": "{hint}", "explanation": "Open trades have no exit data in Pine v6: this accessor exists only on strategy.closedtrades, so it cannot be read from strategy.opentrades; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}, "hint": {"kind": "text"}}}, + "PF-W1045": {"severity": "warning", "area": "support", "message": "strategy.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "This strategy.* function is not implemented in PineForge; check the spelling or use a supported strategy function; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1046": {"severity": "warning", "area": "support", "message": "strategy.exit(...) requires at least one price or trailing parameter in PineForge.", "hint": "Use strategy.close(...) for market exits.", "explanation": "strategy.exit needs a price or trailing parameter (profit, loss, limit, stop or a trail setting); use strategy.close for a plain market exit; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1047": {"severity": "warning", "area": "support", "message": "{full}(...) is not supported. Only request.security(...) and request.security_lower_tf(...) are available in PineForge.", "hint": "External request feeds and other request.* variants are intentionally unavailable.", "explanation": "Only request.security and request.security_lower_tf are supported; other request.* calls need data feeds PineForge does not provide; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1048": {"severity": "warning", "area": "support", "message": "ta.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this ta.* function, so the call is refused instead of compiling to a silent stub; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1049": {"severity": "warning", "area": "support", "message": "math.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this math.* function, so the call is refused instead of compiling to a silent stub; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1050": {"severity": "warning", "area": "support", "message": "str.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this str.* function, so the call is refused instead of compiling to a silent stub; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1051": {"severity": "warning", "area": "support", "message": "input.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this input.* function, so the call is refused; use one of the supported input functions; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1052": {"severity": "warning", "area": "support", "message": "timeframe.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only timeframe.change and timeframe.in_seconds; any other timeframe.* function is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1053": {"severity": "warning", "area": "support", "message": "color.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only color.new, color.rgb and color.r/g/b/t; any other color.* function is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1054": {"severity": "warning", "area": "support", "message": "runtime.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only runtime.error; any other runtime.* function is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1055": {"severity": "warning", "area": "support", "message": "log.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only log.info, log.warning and log.error; any other log.* function is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1056": {"severity": "warning", "area": "support", "message": "array.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this array.* function, so the call is refused instead of compiling to a silent stub; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1057": {"severity": "warning", "area": "support", "message": "map.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this map.* function, so the call is refused instead of compiling to a silent stub; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1058": {"severity": "warning", "area": "support", "message": "map keys must be string in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge maps support only string keys; declare the map with string as its key type; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1059": {"severity": "warning", "area": "support", "message": "map values must be primitive in PineForge''s supported map subset.", "hint": null, "explanation": "PineForge maps can hold only float, int, bool or string values; other value types such as collections or objects are refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1060": {"severity": "warning", "area": "support", "message": "matrix<{t}>: nested collection element types not supported in v1.", "hint": null, "explanation": "A matrix cannot hold another collection as its element type in PineForge; use float, int, bool, string, color or a user-defined type; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"t": {"kind": "type"}}}, + "PF-W1061": {"severity": "warning", "area": "support", "message": "matrix<{t}> is not supported when the UDT contains a map field; rollback would retain live map aliases.", "hint": "Use array for recursively checkpointed state.", "explanation": "A matrix of a user-defined type with a map field is refused because rollback would keep live map references; use an array of that type instead; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"t": {"kind": "type"}}}, + "PF-W1062": {"severity": "warning", "area": "support", "message": "matrix<{t}> element type not supported. Allowed: float, int, bool, string, color, or a declared UDT.", "hint": null, "explanation": "A matrix element must be float, int, bool, string, color or a declared user-defined type; any other element type is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"t": {"kind": "type"}}}, + "PF-W1063": {"severity": "warning", "area": "support", "message": "matrix.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge has no implementation of this matrix.* function, so the call is refused instead of compiling to a silent stub; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1064": {"severity": "warning", "area": "support", "message": "{ns}.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only part of the line, box, label and linefill functions; this one is not implemented, so the call is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"ns": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-W1065": {"severity": "warning", "area": "support", "message": "chart.point.{name}(...) is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge implements only chart.point.new, now, from_index, from_time and copy; any other chart.point.* function is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1066": {"severity": "warning", "area": "support", "message": "''export'' is a Pine library keyword; PineForge runs strategies only and does not support exported functions/types.", "hint": "Remove the ''export'' keyword (and inline any library code into the strategy script).", "explanation": "'export' marks library code; PineForge runs strategies only, so remove the keyword and inline any library code into the strategy; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1067": {"severity": "warning", "area": "support", "message": "{name} diverges from TradingView semantics in PineForge.", "hint": "bar_index depends on the data window; PineForge and TradingView produce different values for the same script.", "explanation": "bar_index counts bars of the data window PineForge is fed, so its value can differ from TradingView's for the same script.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1068": {"severity": "warning", "area": "support", "message": "{name} diverges from TradingView semantics in PineForge.", "hint": "last_bar_index is the final index of PineForge''s fed data window; it can diverge from TradingView when the window does not cover the same chart history.", "explanation": "last_bar_index is the last index of the data window PineForge is fed, so it can differ from TradingView's when the history windows differ.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1069": {"severity": "warning", "area": "support", "message": "{name} diverges from TradingView semantics in PineForge.", "hint": "timenow is aliased to the current bar timestamp in PineForge; it is not real wall-clock time.", "explanation": "timenow is aliased to the current bar's time in PineForge, not real wall-clock time, so logic relying on the real time will differ.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1070": {"severity": "warning", "area": "support", "message": "{chain} diverges from TradingView semantics in PineForge.", "hint": "bar_index depends on the data window; PineForge and TradingView produce different values for the same script.", "explanation": "bar_index counts bars of the data window PineForge is fed, so its value can differ from TradingView's for the same script.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1071": {"severity": "warning", "area": "support", "message": "{chain} diverges from TradingView semantics in PineForge.", "hint": "last_bar_index is the final index of PineForge''s fed data window; it can diverge from TradingView when the window does not cover the same chart history.", "explanation": "last_bar_index is the last index of the data window PineForge is fed, so it can differ from TradingView's when the history windows differ.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1072": {"severity": "warning", "area": "support", "message": "{chain} diverges from TradingView semantics in PineForge.", "hint": "timenow is aliased to the current bar timestamp in PineForge; it is not real wall-clock time.", "explanation": "timenow is aliased to the current bar's time in PineForge, not real wall-clock time, so logic relying on the real time will differ.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1073": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: footprint.* (bid/ask volume rows) is not supported in PineForge batch backtests; it requires tick-level data the engine does not consume.", "hint": null, "explanation": "Members of the footprint.* namespace need tick-level bid/ask volume rows, which a PineForge batch backtest does not load; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1074": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: volume_row.* is not supported in PineForge batch backtests; same reason as footprint.*.", "hint": null, "explanation": "Members of the volume_row.* namespace need tick-level volume rows, which a PineForge batch backtest does not load; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1075": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: dividends.* is not available in PineForge — fundamental dividend data is not loaded.", "hint": null, "explanation": "dividends.* fields read fundamental dividend data, which PineForge does not load outside a recorded request; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1076": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: earnings.* is not available in PineForge — fundamental earnings data is not loaded.", "hint": null, "explanation": "earnings.* fields read fundamental earnings data, which PineForge does not load outside a recorded request; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1077": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: splits.* is not available in PineForge — corporate-action split data is not loaded.", "hint": null, "explanation": "splits.* fields read corporate-action split data, which PineForge does not load outside a recorded request; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1078": {"severity": "warning", "area": "support", "message": "{object_name}.{member} is a visual/style constant with no runtime value in PineForge backtests; it is only accepted as an argument to visual calls (plot, plotshape, hline, label.new, table.cell, ...), which PineForge parses and skips.", "hint": "Constant-namespace members cannot flow into strategy logic; codegen would emit a string literal while the analyzer types the read as int.", "explanation": "A visual or style constant has no value in a backtest; it may only be passed to plotting and drawing calls, which PineForge skips; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1079": {"severity": "warning", "area": "support", "message": "{object_name}.{member} is not a Pine alert constant; only alert.freq_all, alert.freq_once_per_bar and alert.freq_once_per_bar_close exist.", "hint": "Constant-namespace members cannot flow into strategy logic; codegen would emit a string literal while the analyzer types the read as int.", "explanation": "The alert.* member is not one of Pine's alert frequency constants; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1080": {"severity": "warning", "area": "support", "message": "{object_name}.{member} is not a barmerge constant; only barmerge.gaps_on, barmerge.gaps_off, barmerge.lookahead_on and barmerge.lookahead_off exist.", "hint": "Constant-namespace members cannot flow into strategy logic; codegen would emit a string literal while the analyzer types the read as int.", "explanation": "The barmerge.* member is not one of Pine's gaps or lookahead constants; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1081": {"severity": "warning", "area": "support", "message": "syminfo.{member} is not implemented in PineForge runtime.", "hint": null, "explanation": "PineForge does not implement this syminfo.* member, so reading it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"member": {"kind": "identifier"}}}, + "PF-W1082": {"severity": "warning", "area": "support", "message": "request.security parameter ''{kw_name}'' is not allowed in PineForge.", "hint": "Only symbol, timeframe, expression, gaps, and lookahead are accepted.", "explanation": "request.security accepts only a few named parameters in PineForge; this one is refused instead of being silently ignored, so remove it; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"kw_name": {"kind": "identifier"}}}, + "PF-W1083": {"severity": "warning", "area": "support", "message": "Extra positional arguments to request.security are not allowed in PineForge.", "hint": "Only symbol, timeframe, expression, gaps, and lookahead are accepted.", "explanation": "request.security accepts at most five positional arguments (symbol, timeframe, expression, gaps, lookahead); remove the extra ones; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1084": {"severity": "warning", "area": "support", "message": "request.security gaps must be barmerge.gaps_on or barmerge.gaps_off.", "hint": "Codegen only recognizes the barmerge.gaps_* literal; other values are silently treated as gaps_off.", "explanation": "The gaps argument of request.security must be written literally as barmerge.gaps_on or barmerge.gaps_off, the only forms PineForge reads; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1085": {"severity": "warning", "area": "support", "message": "request.security lookahead must be barmerge.lookahead_on or barmerge.lookahead_off.", "hint": "Codegen only recognizes the barmerge.lookahead_* literal; other values are silently treated as lookahead_off.", "explanation": "The lookahead argument of request.security must be written literally as barmerge.lookahead_on or barmerge.lookahead_off, the only forms PineForge reads; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {}}, + "PF-W1086": {"severity": "warning", "area": "support", "message": "request.security: {kw_name}={object_name}.{val_member} is not supported. The engine ignores this kwarg, which would silently produce different prices from TradingView.", "hint": "Allowed values: {allowed}.", "explanation": "PineForge ignores request.security's price-adjustment settings, so only no-op values are accepted; others would silently give prices unlike TradingView's; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"kw_name": {"kind": "identifier"}, "object_name": {"kind": "identifier"}, "val_member": {"kind": "identifier"}, "allowed": {"kind": "identifier"}}}, + "PF-W1087": {"severity": "warning", "area": "support", "message": "request.security: {kw_name}=... must be a constant member access of the form {kw_name}. (got a non-constant expression).", "hint": "Allowed values: {allowed}.", "explanation": "A request.security price-adjustment setting must be a plain constant of the form name.value (like adjustment.none), not a computed expression; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"kw_name": {"kind": "identifier"}, "allowed": {"kind": "identifier"}}}, + "PF-W1088": {"severity": "warning", "area": "support", "message": "{name} {message} (TradingView: {spelled}).", "hint": "Use the parameters of TradingView''s signature.", "explanation": "A nz or fixnan call whose arguments match none of TradingView's signatures (unknown name, too many or missing arguments) is refused, as TradingView refuses it; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}, "message": {"kind": "text"}, "spelled": {"kind": "identifier"}}}, + "PF-W1089": {"severity": "warning", "area": "support", "message": "ta.{name} {message} (TradingView: {signature}).", "hint": "Use the parameters of TradingView''s signature.", "explanation": "A ta.* call whose arguments match none of TradingView's signatures (unknown or repeated parameter, too many or missing arguments) is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"name": {"kind": "identifier"}, "message": {"kind": "text"}, "signature": {"kind": "identifier"}}}, + "PF-W1090": {"severity": "warning", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "empty timeframe literal", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-W1091": {"severity": "warning", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "non-integer timeframe magnitude ''{digits}''", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}, "digits": {"kind": "identifier"}}}, + "PF-W1092": {"severity": "warning", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "timeframe magnitude must be positive", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-W1093": {"severity": "warning", "area": "support", "message": "request.security: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "unknown timeframe suffix ''{suffix}''", "explanation": "The timeframe string given to request.security is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}, "suffix": {"kind": "identifier"}}}, + "PF-W1094": {"severity": "warning", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "empty timeframe literal", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-W1095": {"severity": "warning", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "non-integer timeframe magnitude ''{digits}''", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}, "digits": {"kind": "identifier"}}}, + "PF-W1096": {"severity": "warning", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "timeframe magnitude must be positive", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}}}, + "PF-W1097": {"severity": "warning", "area": "support", "message": "request.security_lower_tf: invalid timeframe literal ''{timeframe}''. Expected Pine TF format like ''1'', ''15'', ''1H'', ''1D'', ''15S''.", "hint": "unknown timeframe suffix ''{suffix}''", "explanation": "The timeframe string given to request.security_lower_tf is not a valid Pine timeframe such as 1, 15, 1H, 1D or 15S, so it is refused; inside a switch arm PineForge warns instead and keeps the arm's lowering.", "args": {"timeframe": {"kind": "identifier"}, "suffix": {"kind": "identifier"}}}, + "PF-W1500": {"severity": "warning", "area": "support", "message": "{call}: request.security symbol can select an alternate symbol, but PineForge always loads the current chart symbol.", "hint": "It reads no feed of another symbol: {reasons}. Every reachable symbol value must resolve to syminfo.tickerid or syminfo.ticker for exact results.", "explanation": "A request.security whose symbol can select another symbol is approximated by the chart's own symbol, because no other-symbol feed can be registered for it.", "args": {"call": {"kind": "identifier"}, "reasons": {"kind": "text"}}}, + "PF-W1501": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "PineForge reads another symbol''s feed only for a symbol and timeframe registration computes before the first bar; {reasons}.", "explanation": "A request.security of another symbol has no pinned data, so the run stops with an error where its value is read; its symbol and timeframe must be known up front.", "args": {"call": {"kind": "identifier"}, "reasons": {"kind": "text"}}}, + "PF-W1502": {"severity": "warning", "area": "support", "message": "color(...) cast has no effect in PineForge backtests (visual only); it emits a default color.", "hint": null, "explanation": "A color(...) cast is visual only and has no effect on a backtest, so PineForge ignores it and uses a default color.", "args": {}}, + "PF-W1503": {"severity": "warning", "area": "support", "message": "strategy.risk.{name}(...) has partial PineForge runtime support.", "hint": "Verify risk behavior against PineForge results; unsupported risk edge cases may diverge from TradingView.", "explanation": "A strategy.risk.* call has only partial runtime support in PineForge, so check that your risk limits behave as they do on TradingView.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1504": {"severity": "warning", "area": "support", "message": "strategy.{name} parameter ''{param_name}'' is not supported by PineForge and is ignored.", "hint": null, "explanation": "A strategy order call passes a parameter PineForge does not support, so the parameter is ignored and the order runs without it.", "args": {"name": {"kind": "identifier"}, "param_name": {"kind": "identifier"}}}, + "PF-W1505": {"severity": "warning", "area": "support", "message": "ta.ema initial warmup is approximated: PineForge may return a finite value before TradingView does.", "hint": "A covered length-20 TradingView tape first returns a finite EMA at bar 19; standalone PineForge EMA is finite at bar 0. Its established lowering stays in place pending per-call-site population parity.", "explanation": "ta.ema is approximated during warmup: PineForge may return a finite value on early bars where TradingView still returns na, so early results can differ.", "args": {}}, + "PF-W1506": {"severity": "warning", "area": "support", "message": "color.{name}(...) has no effect in PineForge backtests (visual only); it evaluates its arguments and emits a default color.", "hint": null, "explanation": "A cosmetic color function has no effect on a backtest, so PineForge evaluates its arguments and uses a default color.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1507": {"severity": "warning", "area": "support", "message": "{ns}.{name}(...) is a visual no-op in PineForge backtests (drawing geometry is data; color/style/size are dropped).", "hint": null, "explanation": "A drawing setter for color, style or size is a visual no-op in PineForge, which keeps only the drawing's geometry as data.", "args": {"ns": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-W1508": {"severity": "warning", "area": "support", "message": "{name}(...) has no effect in PineForge backtests (visual only).", "hint": null, "explanation": "A call into a visual-only namespace such as table or polyline has no effect on backtest results, so PineForge ignores it.", "args": {"name": {"kind": "identifier"}}}, + "PF-W1509": {"severity": "warning", "area": "support", "message": "{full}(...) has no effect in PineForge backtests (visual only).", "hint": null, "explanation": "A call into a visual-only namespace such as table or polyline has no effect on backtest results, so PineForge ignores it.", "args": {"full": {"kind": "identifier"}}}, + "PF-W1510": {"severity": "warning", "area": "support", "message": "{chain} is approximated in PineForge.", "hint": "In direct batch chart-scope evaluation, barstate.islast is true only on the final bar of PineForge''s fed chart-data window. Inside a request.security() history index, PineForge currently selects the false branch; requested-context last-bar state is not modeled.", "explanation": "barstate.islast is true only on the last bar of PineForge's fed data, and inside a request.security history index it selects the false branch.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1511": {"severity": "warning", "area": "support", "message": "{chain} is approximated in PineForge.", "hint": "In direct historical batch chart-scope evaluation, PineForge approximates barstate.islastconfirmedhistory as true only on the final bar of the fed chart-data window. Inside a request.security() history index, PineForge currently selects the false branch; TradingView''s requested-context and realtime-boundary semantics are not modeled.", "explanation": "barstate.islastconfirmedhistory is approximated as true only on the final bar of the fed data window, and as false inside a request.security history index.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1512": {"severity": "warning", "area": "support", "message": "{chain} is approximated in PineForge.", "hint": "barstate.isconfirmed follows PineForge last-tick execution state.", "explanation": "barstate.isconfirmed follows PineForge's last-tick execution state, so it can differ from TradingView's confirmation behavior.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1513": {"severity": "warning", "area": "support", "message": "{chain} is approximated in PineForge.", "hint": "barstate.ishistory is always true in PineForge batch backtests.", "explanation": "barstate.ishistory is always true in PineForge batch backtests, because there is no real-time bar.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1514": {"severity": "warning", "area": "support", "message": "{chain} is approximated in PineForge.", "hint": "barstate.isnew follows PineForge first-tick execution state.", "explanation": "barstate.isnew is only approximated in PineForge, following its first-tick execution state, so it may behave differently from TradingView.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1515": {"severity": "warning", "area": "support", "message": "{chain} is approximated in PineForge.", "hint": "barstate.isrealtime is always false in PineForge batch backtests.", "explanation": "barstate.isrealtime is always false because PineForge runs batch backtests on historical bars only, so real-time-only logic never runs.", "args": {"chain": {"kind": "identifier"}}}, + "PF-W1516": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: chart.bg_color has no meaning in a batch backtest (no chart theme); emits a default color.", "hint": null, "explanation": "chart.bg_color depends on the chart theme, which a batch backtest does not have, so PineForge substitutes a default color.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1517": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: chart.fg_color has no meaning in a batch backtest (no chart theme); emits a default color.", "hint": null, "explanation": "chart.fg_color depends on the chart theme, which a batch backtest does not have, so PineForge substitutes a default color.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1518": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: chart.left_visible_bar_time has no meaning in a batch backtest (no viewport); emits 0.", "hint": null, "explanation": "chart.left_visible_bar_time depends on the chart viewport, which a batch backtest does not have, so PineForge substitutes 0.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1519": {"severity": "warning", "area": "support", "message": "{object_name}.{member}: chart.right_visible_bar_time has no meaning in a batch backtest (no viewport); emits 0.", "hint": null, "explanation": "chart.right_visible_bar_time depends on the chart viewport, which a batch backtest does not have, so PineForge substitutes 0.", "args": {"object_name": {"kind": "identifier"}, "member": {"kind": "identifier"}}}, + "PF-W1520": {"severity": "warning", "area": "support", "message": "syminfo.{member} is na unless the run declares the symbol''s {member} (syminfo metadata \"{member}\", a lane fact).", "hint": null, "explanation": "This syminfo field has no built-in value in PineForge: it is na unless the run supplies the symbol's value as metadata, so anything computed from it is na.", "args": {"member": {"kind": "identifier"}}}, + "PF-W1521": {"severity": "warning", "area": "support", "message": "syminfo.{member} returns na in current PineForge; any expression using it will be na. Will be backfilled by pineforge-data product.", "hint": null, "explanation": "This syminfo field is not provided by PineForge yet and always reads na, so any expression using it is na.", "args": {"member": {"kind": "identifier"}}}, + "PF-W1522": {"severity": "warning", "area": "support", "message": "syminfo.{member} returns na in current PineForge; condition will always be false. Will be backfilled by pineforge-data product.", "hint": null, "explanation": "This syminfo field is not provided by PineForge yet and always reads na, so a condition built on it is always false.", "args": {"member": {"kind": "identifier"}}}, + "PF-W1523": {"severity": "warning", "area": "support", "message": "request.security symbol can select an alternate symbol, but PineForge always loads the current chart symbol.", "hint": "Every reachable symbol value must resolve to syminfo.tickerid or syminfo.ticker for exact results.", "explanation": "The request.security symbol can select another symbol, but PineForge always loads the chart's symbol; resolve every value to syminfo.tickerid for exact results.", "args": {}}, + "PF-W1524": {"severity": "warning", "area": "support", "message": "request.security lookahead_on changes HTF timing: the completed higher-timeframe value is exposed from the bucket''s first chart bar. PineForge emits this (engine-supported) but results differ from lookahead_off and, with a 0-offset HTF expression, repaint future data.", "hint": "The safe non-repainting form pairs lookahead_on with a [1] offset (e.g. close[1]) to read only completed prior HTF bars.", "explanation": "request.security with lookahead_on exposes higher-timeframe values early and can repaint future data; pair it with a [1] offset such as close[1] to stay safe.", "args": {}}, + "PF-W1525": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "External corporate-action data not available in PineForge. A recorded series is read when {blocker}. The value it lowers to reaches alerts, plots and tables only.", "explanation": "No recorded series applies to this earnings, dividends or splits request, but its value only feeds plots, alerts or tables, so it becomes na; trades are unaffected.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "text"}}}, + "PF-W1526": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "External corporate-action data not available in PineForge. The value it lowers to reaches alerts, plots and tables only.", "explanation": "PineForge has no earnings, dividends or splits data; this request's value only feeds plots, alerts or tables, so it becomes na and trades are unaffected.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1527": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "External fundamentals data not available in PineForge. A recorded series is read when {blocker}. The value it lowers to reaches alerts, plots and tables only.", "explanation": "No recorded series applies to this request.financial call, but its value only feeds plots, alerts or tables, so it becomes na and trades are unaffected.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "text"}}}, + "PF-W1528": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "External fundamentals data not available in PineForge. The value it lowers to reaches alerts, plots and tables only.", "explanation": "PineForge has no fundamentals data for request.financial; its value only feeds plots, alerts or tables, so it becomes na and trades are unaffected.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1529": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "Footprint (bid/ask volume) data not available in PineForge. A recorded series is read when {blocker}. The value it lowers to reaches alerts, plots and tables only.", "explanation": "No recorded series applies to this request.footprint call, but its value only feeds plots, alerts or tables, so it becomes na and trades are unaffected.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "text"}}}, + "PF-W1530": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "Footprint (bid/ask volume) data not available in PineForge. The value it lowers to reaches alerts, plots and tables only.", "explanation": "PineForge has no footprint (bid/ask volume) data for request.footprint; its value only feeds plots, alerts or tables, so it becomes na and trades are unaffected.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1531": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "PineForge backtests load the chart''s symbol only (syminfo.tickerid, syminfo.ticker), and reads another symbol''s feed only when {blocker}. The value it lowers to reaches alerts, plots and tables only.", "explanation": "Another symbol's feed is read only in the stated case; here the request's value only feeds plots, alerts or tables, so it becomes na and trades are unaffected.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "vocab", "values": ["it is outside another request's expression", "it is request.security", "its expression holds no request of its own", "its gaps and lookahead are barmerge constants", "its request.footprint states ticks_per_row and va_percent as literal whole numbers", "registration computes its ignore_invalid_symbol before the first bar", "registration computes its symbol before the first bar", "registration computes its timeframe before the first bar"]}}}, + "PF-W1532": {"severity": "warning", "area": "support", "message": "{call}: value reaches only display/alert sinks; lowered to na; trades are unaffected.", "hint": "PineForge backtests load the chart''s symbol only (syminfo.tickerid, syminfo.ticker). The value it lowers to reaches alerts, plots and tables only.", "explanation": "PineForge loads only the chart's symbol; this request for another symbol only feeds plots, alerts or tables, so it becomes na and trades are unaffected.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1533": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "External corporate-action data not available in PineForge. A recorded series is read when {blocker}. Its value can reach a trade: {reason}.", "explanation": "No recorded series applies to this earnings, dividends or splits request and its value can reach a trade, so the run stops with an error where the value is read.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "text"}, "reason": {"kind": "text"}}}, + "PF-W1534": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "External corporate-action data not available in PineForge. Its value can reach a trade: {reason}.", "explanation": "PineForge has no earnings, dividends or splits data and this request's value can reach a trade, so the run stops with an error where the value is read.", "args": {"call": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-W1535": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "External fundamentals data not available in PineForge. A recorded series is read when {blocker}. Its value can reach a trade: {reason}.", "explanation": "No recorded series applies to this request.financial call and its value can reach a trade, so the run stops with an error where the value is read.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "text"}, "reason": {"kind": "text"}}}, + "PF-W1536": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "External fundamentals data not available in PineForge. Its value can reach a trade: {reason}.", "explanation": "PineForge has no fundamentals data for request.financial and its value can reach a trade, so the run stops with an error where the value is read.", "args": {"call": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-W1537": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "Footprint (bid/ask volume) data not available in PineForge. A recorded series is read when {blocker}. Its value can reach a trade: {reason}.", "explanation": "No recorded series applies to this request.footprint call and its value can reach a trade, so the run stops with an error where the value is read.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "text"}, "reason": {"kind": "text"}}}, + "PF-W1538": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "Footprint (bid/ask volume) data not available in PineForge. Its value can reach a trade: {reason}.", "explanation": "PineForge has no footprint (bid/ask volume) data and this request's value can reach a trade, so the run stops with an error where the value is read.", "args": {"call": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-W1539": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "PineForge backtests load the chart''s symbol only (syminfo.tickerid, syminfo.ticker), and reads another symbol''s feed only when {blocker}. Its value can reach a trade: {reason}.", "explanation": "PineForge reads another symbol's feed only in the stated case, and this request's value can reach a trade, so the run stops with an error where it is read.", "args": {"call": {"kind": "identifier"}, "blocker": {"kind": "vocab", "values": ["it is outside another request's expression", "it is request.security", "its expression holds no request of its own", "its gaps and lookahead are barmerge constants", "its request.footprint states ticks_per_row and va_percent as literal whole numbers", "registration computes its ignore_invalid_symbol before the first bar", "registration computes its symbol before the first bar", "registration computes its timeframe before the first bar"]}, "reason": {"kind": "text"}}}, + "PF-W1540": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where its value is read.", "hint": "PineForge backtests load the chart''s symbol only (syminfo.tickerid, syminfo.ticker). Its value can reach a trade: {reason}.", "explanation": "PineForge loads only the chart's symbol, and this request for another symbol can reach a trade, so the run stops with an error where its value is read.", "args": {"call": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-W1541": {"severity": "warning", "area": "support", "message": "{call}: another symbol''s bars, read from the feed the requests manifest pins for it; with none installed, the run stops with an error where its value is read.", "hint": "PineForge runs the expression on that symbol''s own bars (history, ta.* and syminfo.* in its context) and merges them by time as TradingView does; a symbol equal to the chart''s reads the chart.", "explanation": "request.security on another symbol reads that symbol's pinned feed; if none is installed, the run stops with an error where the value is read.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1542": {"severity": "warning", "area": "support", "message": "{call}: its symbol can select another symbol: registered by the string the run computes, a footprint reads the feed the requests manifest pins for each symbol, the chart''s too (the chart''s bars carry no footprint); with none installed, the run stops with an error where its value is read.", "hint": "It read the chart''s bars for every symbol: another symbol''s value never comes from the chart.", "explanation": "The footprint symbol can vary: every symbol, the chart's too, reads its own pinned feed, and a missing feed stops the run where the value is read.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1543": {"severity": "warning", "area": "support", "message": "{call}: its symbol can select another symbol: registered by the string the run computes, the chart''s reads the chart and another symbol''s the feed the requests manifest pins for it; with none installed, the run stops with an error where its value is read.", "hint": "It read the chart''s bars for every symbol: another symbol''s value never comes from the chart.", "explanation": "The request.security symbol can be the chart's or another symbol: the chart's reads the chart, another reads its pinned feed, and a missing feed stops the run.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1544": {"severity": "warning", "area": "support", "message": "{call}: TradingView''s values per chart bar, read from the series the requests manifest records under {parts}||{parts2}|{parts3}|gaps_{parts4}|lookahead_{parts5}; with none installed, the run stops with an error where its value is read.", "hint": "PineForge replays the values TradingView returned on the chart''s own bars (chart_open_ms,value): a bar the tape has no row for reads na.", "explanation": "This request replays the values TradingView returned on each chart bar, from the requests manifest; with no recording installed the run stops where it is read.", "args": {"call": {"kind": "identifier"}, "parts": {"kind": "identifier"}, "parts2": {"kind": "identifier"}, "parts3": {"kind": "identifier"}, "parts4": {"kind": "identifier"}, "parts5": {"kind": "identifier"}}}, + "PF-W1545": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where it is evaluated.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Its value can reach a trade: it decides a loop''s break or continue.", "explanation": "PineForge loads no other symbol's lower-timeframe bars, and this request's value can reach a trade, so the run stops with an error where it is evaluated.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1546": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where it is evaluated.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Its value can reach a trade: it is a history offset.", "explanation": "PineForge loads no other symbol's lower-timeframe bars, and this request's value can reach a trade, so the run stops with an error where it is evaluated.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1547": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where it is evaluated.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Its value can reach a trade: it is written to a field or element.", "explanation": "PineForge loads no other symbol's lower-timeframe bars, and this request's value can reach a trade, so the run stops with an error where it is evaluated.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1548": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where it is evaluated.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Its value can reach a trade: it reaches {label}.", "explanation": "PineForge loads no other symbol's lower-timeframe bars, and this request's value can reach a trade, so the run stops with an error where it is evaluated.", "args": {"call": {"kind": "identifier"}, "label": {"kind": "text"}}}, + "PF-W1549": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where it is evaluated.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Its value can reach a trade: its expression calls {label}.", "explanation": "PineForge loads no other symbol's lower-timeframe bars, and this request's value can reach a trade, so the run stops with an error where it is evaluated.", "args": {"call": {"kind": "identifier"}, "label": {"kind": "text"}}}, + "PF-W1550": {"severity": "warning", "area": "support", "message": "{call}: no data is pinned for this request; the run stops with an error where it is evaluated.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Its value can reach a trade: its expression calls {ns}.{name}.", "explanation": "PineForge loads no other symbol's lower-timeframe bars, and this request's value can reach a trade, so the run stops with an error where it is evaluated.", "args": {"call": {"kind": "identifier"}, "ns": {"kind": "identifier"}, "name": {"kind": "identifier"}}}, + "PF-W1551": {"severity": "warning", "area": "support", "message": "{call}: its symbol can be another symbol''s, whose lower-timeframe bars PineForge reads from the chart.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Every reachable symbol value must resolve to syminfo.tickerid or syminfo.ticker for exact results.", "explanation": "The request.security_lower_tf symbol can be another symbol, but PineForge only has the chart's lower-timeframe bars and reads those, so results can differ.", "args": {"call": {"kind": "identifier"}}}, + "PF-W1552": {"severity": "warning", "area": "support", "message": "{call}: its symbol can be another symbol''s, whose lower-timeframe bars PineForge reads from the chart; its value reaches only display/alert sinks, so trades are unaffected.", "hint": "PineForge loads no other symbol''s lower-timeframe bars. Every reachable symbol value must resolve to syminfo.tickerid or syminfo.ticker for exact results.", "explanation": "The lower-timeframe request may name another symbol but reads the chart's bars; its value only feeds plots, alerts or tables, so trades are unaffected.", "args": {"call": {"kind": "identifier"}}}, + "PF-W2001": {"severity": "warning", "area": "analysis", "message": "Untyped parameter ''{param}'' of callable ''{callee}'' receives {shared} and {incoming} at its written calls; a copy per call path would exceed {max_family_variants} copies and four per written call, so PineForge types it {shared}, as its first call, and converts the other argument. Declare the parameter type to choose it.", "hint": null, "explanation": "An untyped parameter receives two argument types and one copy per call would be too many, so PineForge types it as the first call's; declare the type to choose.", "args": {"param": {"kind": "identifier"}, "callee": {"kind": "identifier"}, "shared": {"kind": "type"}, "incoming": {"kind": "type"}, "max_family_variants": {"kind": "number"}}}, + "PF-W2002": {"severity": "warning", "area": "analysis", "message": "Untyped parameter ''{param}'' of callable ''{callee}'' receives {current} and {candidate} through calls that share one written-call variant (cs{cs_idx}); PineForge types it {current}, so the other argument is converted. Declare the parameter type to choose it.", "hint": null, "explanation": "An untyped parameter receives two argument types through calls sharing one variant; PineForge types it by the first and converts the other, so declare the type.", "args": {"param": {"kind": "identifier"}, "callee": {"kind": "identifier"}, "current": {"kind": "type"}, "candidate": {"kind": "type"}, "cs_idx": {"kind": "number"}}}, + "PF-W2003": {"severity": "warning", "area": "analysis", "message": "(...)[...] reads an element of the selected current array in PineForge: no history of a selection is kept, where TradingView reads the array it selected that many bars back.", "hint": null, "explanation": "Indexing a selected array with [] reads the current array, since PineForge keeps no history of selections; TradingView reads the array from that many bars back.", "args": {}}, + "PF-W2004": {"severity": "warning", "area": "analysis", "message": "input.source defval is not a native chart series (open, high, low, close, …); complex indicators or expressions are not supported in PineForge.", "hint": null, "explanation": "input.source needs a built-in chart series such as close as its default; indicators or other expressions are not supported in PineForge.", "args": {}}, + "PF-W2005": {"severity": "warning", "area": "analysis", "message": "input.timeframe defval ''{defval}'' is not a typical Pine timeframe string.", "hint": null, "explanation": "The default of input.timeframe is not a usual Pine timeframe string such as 15, 1D or W; check its spelling.", "args": {"defval": {"kind": "identifier"}}}, + "PF-W2006": {"severity": "warning", "area": "analysis", "message": "input.session defval ''{defval}'' may be invalid (expected e.g. ''24x7'', ''0930-1600'', or weekday flags).", "hint": null, "explanation": "The default of input.session may not be a valid session string; use forms like 24x7 or 0930-1600, optionally with weekday flags.", "args": {"defval": {"kind": "identifier"}}}, + "PF-W2007": {"severity": "warning", "area": "analysis", "message": "input.string defval is not among the options list values.", "hint": null, "explanation": "The default of input.string is not among its listed options; choose a default that appears in the options list.", "args": {}}, + "PF-W2008": {"severity": "warning", "area": "analysis", "message": "input.enum defval {ename}.{emem} is not a member of enum {ename}.", "hint": null, "explanation": "The default of input.enum names a member the enum does not declare; use one of the enum's own members.", "args": {"ename": {"kind": "identifier"}, "emem": {"kind": "identifier"}}}, + "PF-W2009": {"severity": "warning", "area": "analysis", "message": "input defval ''{name}'' is not a known chart series (open, high, low, close, …); verify spelling or use a series variable.", "hint": null, "explanation": "The default of this input is not a known chart series such as close; check the spelling or use a series variable.", "args": {"name": {"kind": "identifier"}}}, + "PF-W3001": {"severity": "warning", "area": "request-security", "message": "request.security timeframe reads ''{name}'', which the script reassigns: PineForge registers every request before the first bar, where it holds its initial value, and cannot compute it there (''{where}'' {reason})", "hint": null, "explanation": "The request.security timeframe reads a reassigned variable PineForge cannot compute before the first bar, so the request uses its initial value.", "args": {"name": {"kind": "identifier"}, "where": {"kind": "identifier"}, "reason": {"kind": "vocab", "values": ["is assigned a value it cannot compute there", "is assigned after the first request", "is not a scalar int, float, bool or string", "is not declared at the top level"]}}}, + "PF-W3002": {"severity": "warning", "area": "request-security", "message": "request.security payload reads the history of ''{name}'', a parameter of ''{helper}'' whose argument PineForge does not recompute on the requested bars: it reads na", "hint": null, "explanation": "A request.security expression reads the history of a function parameter PineForge does not recompute on the requested bars, so the read gives na.", "args": {"name": {"kind": "identifier"}, "helper": {"kind": "identifier"}}}, + "PF-W3003": {"severity": "warning", "area": "request-security", "message": "request.security payload reads the history of ''{name}'', a parameter of ''{helper}'' whose argument PineForge does not recompute on the requested bars: it reads the global ''{name}'' instead", "hint": null, "explanation": "A request.security expression reads the history of a function parameter PineForge does not recompute on requested bars, so it reads the same-named global instead.", "args": {"name": {"kind": "identifier"}, "helper": {"kind": "identifier"}}}, + "PF-W3004": {"severity": "warning", "area": "request-security", "message": "request.security payload calls function ''{callee_name}'' on the chart''s bar: a payload inlines a function under a builtin call only when its body is a single expression and so is every user call it makes, directly or through a global''s value; TradingView evaluates it on the requested bar.", "hint": null, "explanation": "A function called in a request.security expression runs on the chart's bar, since under a builtin call PineForge inlines only single-expression functions and calls.", "args": {"callee_name": {"kind": "identifier"}}}, + "PF-W3005": {"severity": "warning", "area": "request-security", "message": "request.security payload calls function ''{callee_name}'' on the chart''s bar: a payload inlines a method on the requested bar only for a scalar receiver and arguments and a single-expression body reading no mutable global, whose user calls, directly or through a global''s value, are single expressions too; TradingView evaluates it on the requested bar.", "hint": null, "explanation": "A user call in a request.security expression runs on the chart's bar, since PineForge inlines a method on the requested bar only for scalar, single-expression cases.", "args": {"callee_name": {"kind": "identifier"}}}, + "PF-W3006": {"severity": "warning", "area": "request-security", "message": "request.security payload calls function ''{callee_name}'' on the chart''s bar: the evaluator cannot inline it ({reason}); TradingView evaluates it on the requested bar.", "hint": null, "explanation": "A function in a request.security expression runs on the chart's bar, not the requested one, because PineForge's evaluator cannot inline it for the stated reason.", "args": {"callee_name": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-W3007": {"severity": "warning", "area": "request-security", "message": "request.security payload calls method ''{callee_member}'' on the chart''s bar: a payload inlines a function under a builtin call only when its body is a single expression and so is every user call it makes, directly or through a global''s value; TradingView evaluates it on the requested bar.", "hint": null, "explanation": "A method called in a request.security expression runs on the chart's bar, since under a builtin call PineForge inlines only single-expression functions and calls.", "args": {"callee_member": {"kind": "identifier"}}}, + "PF-W3008": {"severity": "warning", "area": "request-security", "message": "request.security payload calls method ''{callee_member}'' on the chart''s bar: a payload inlines a method on the requested bar only for a scalar receiver and arguments and a single-expression body reading no mutable global, whose user calls, directly or through a global''s value, are single expressions too; TradingView evaluates it on the requested bar.", "hint": null, "explanation": "A method called in a request.security expression runs on the chart's bar, since only scalar, single-expression methods are inlined on the requested bar.", "args": {"callee_member": {"kind": "identifier"}}}, + "PF-W3009": {"severity": "warning", "area": "request-security", "message": "request.security payload calls method ''{callee_member}'' on the chart''s bar: the evaluator cannot inline it ({reason}); TradingView evaluates it on the requested bar.", "hint": null, "explanation": "A method in a request.security expression runs on the chart's bar, not the requested one, because PineForge's evaluator cannot inline it for the stated reason.", "args": {"callee_member": {"kind": "identifier"}, "reason": {"kind": "text"}}}, + "PF-W3010": {"severity": "warning", "area": "request-security", "message": "request.security payload keeps its user calls under builtin calls and its methods on the chart''s bar, as before: {message} (line {line}); TradingView evaluates them on the requested bar.", "hint": null, "explanation": "PineForge keeps this request.security payload's user calls under builtin calls and its methods on the chart's bar, for the stated reason, unlike TradingView.", "args": {"message": {"kind": "text"}, "line": {"kind": "number"}}}, + "PF-W3011": {"severity": "warning", "area": "request-security", "message": "request.security payload keeps its user calls under builtin calls and its methods on the chart''s bar, as before: {message}; TradingView evaluates them on the requested bar.", "hint": null, "explanation": "PineForge keeps this request.security payload's user calls under builtin calls and its methods on the chart's bar, for the stated reason, unlike TradingView.", "args": {"message": {"kind": "text"}}}, + "PF-W3012": {"severity": "warning", "area": "request-security", "message": "request.security payload reads the history of ''{name}'', an element of a tuple declaration, on the chart''s bar; TradingView reads it on the requested bar.", "hint": null, "explanation": "A request.security expression reads the history of a tuple-declared variable on the chart's bar, where TradingView reads it on the requested bar.", "args": {"name": {"kind": "identifier"}}}, + "PF-W3013": {"severity": "warning", "area": "request-security", "message": "request.security payload reads the history of ''{object_name}'' under a builtin call on the chart''s bar; TradingView evaluates it on the requested bar.", "hint": null, "explanation": "A request.security expression reads a variable's history inside a builtin call on the chart's bar, where TradingView evaluates it on the requested bar.", "args": {"object_name": {"kind": "identifier"}}}, + "PF-W5001": {"severity": "warning", "area": "codegen", "message": "strategy(use_bar_magnifier=...) is not a literal bool: the generated strategy does not declare the bar magnifier, so a host runs it without one.", "hint": "Write use_bar_magnifier = true or false.", "explanation": "Write use_bar_magnifier as a literal true or false; any other expression is ignored, so the strategy declares no bar magnifier and the host runs without one.", "args": {}}, + "PF-W5002": {"severity": "warning", "area": "codegen", "message": "input key ''{key}'' is shared by the inputs at {spots} and {spots2}: PineForge sets an input override by its title, else by the name of the declaration holding it, so one override sets all of them.", "hint": "Give each input its own title to override them apart.", "explanation": "Several inputs share one override key (their title, else their declaration's name), so one override sets all of them; give each input its own title.", "args": {"key": {"kind": "identifier"}, "spots": {"kind": "text"}, "spots2": {"kind": "text"}}}, + "PF-W5003": {"severity": "warning", "area": "codegen", "message": "array.slice returns a copy in PineForge; TradingView slices share source elements, so writes through either array can diverge.", "hint": "Avoid mutating a slice or its source while the slice is used.", "explanation": "array.slice returns an independent copy in PineForge, while TradingView's slice shares elements, so avoid mutating a slice or its source while both are used.", "args": {}}, + "PF-W5004": {"severity": "warning", "area": "codegen", "message": "A {kind} is stored as a 32-bit int in PineForge; this value can exceed int32, where TradingView''s int is 64-bit, and is truncated (or read as na) there.", "hint": "Declare the values float to keep every digit.", "explanation": "This collection element is stored as a 32-bit int, so a value beyond int32 is truncated or read as na, unlike TradingView's 64-bit int; declare the values float.", "args": {"kind": {"kind": "vocab", "values": ["map<..., int> value", "matrix element"]}}}, + "PF-W5005": {"severity": "warning", "area": "codegen", "message": "An {kind} is stored as a 32-bit int in PineForge; this value can exceed int32, where TradingView''s int is 64-bit, and is truncated (or read as na) there.", "hint": "Declare the values float to keep every digit.", "explanation": "This collection element is stored as a 32-bit int, so a value beyond int32 is truncated or read as na, unlike TradingView's 64-bit int; declare the values float.", "args": {"kind": {"kind": "vocab", "values": ["array element"]}}}, + "PF-W5006": {"severity": "warning", "area": "codegen", "message": "na() of a string reads the empty string as na: PineForge stores a string na as \"\", so an authored empty string is na here, while TradingView tells the two apart.", "hint": null, "explanation": "na() of a string treats the empty string as na because PineForge stores a string na as an empty string, so an authored empty string reads as na.", "args": {}}, + "PF-W5007": {"severity": "warning", "area": "codegen", "message": "str.repeat is missing its count argument; PineForge emits an empty string for this invalid TradingView call.", "hint": null, "explanation": "str.repeat was called without its count argument, which TradingView rejects; PineForge emits an empty string instead.", "args": {}}, + "PF-W5008": {"severity": "warning", "area": "codegen", "message": "str.repeat count can be na: PineForge returns an empty string for that value, while TradingView returns na string. The engine has no nullable string value.", "hint": "Check na(count) before calling str.repeat when the result affects strategy logic.", "explanation": "str.repeat's count can be na; PineForge then returns an empty string where TradingView returns na, so check na(count) first if the result drives logic.", "args": {}}, + "PF-W5009": {"severity": "warning", "area": "codegen", "message": "session.{member} inside request.security keeps the time-of-day predicate at the security bar''s open time, which can differ from TradingView: {opens}a D/W/M bar, {daily} on TradingView, reads its open''s time of day. The chart''s own session flags read the engine''s session facts.", "hint": null, "explanation": "A session flag inside request.security is tested at the security bar's open time, which can differ from TradingView, notably for D/W/M bars.", "args": {"member": {"kind": "identifier"}, "opens": {"kind": "vocab", "values": ["", "a bar that opens in a session break and holds the reopen reads as out of market, and "]}, "daily": {"kind": "vocab", "values": ["always in market", "never post-market", "never pre-market"]}}}, + "PF-W5010": {"severity": "warning", "area": "codegen", "message": "{object_name}[...] reads the current {kind} in PineForge: no history of this parameter is kept, where TradingView reads the copy the call that many calls back left (fixtures/array_history_tv ahist_fn).", "hint": null, "explanation": "Indexing a function parameter's array or matrix with [] reads the current collection in PineForge, while TradingView reads the copy from that many calls back.", "args": {"object_name": {"kind": "identifier"}, "kind": {"kind": "vocab", "values": ["array", "matrix"]}}}, + "PF-W5011": {"severity": "warning", "area": "codegen", "message": "{object_name}[...] reads the current {name} reference in PineForge: no history of this variable is kept here, where TradingView reads the reference it held that many bars back.", "hint": null, "explanation": "Indexing an object or drawing variable with [] reads its current reference in PineForge, while TradingView reads the reference it held that many bars back.", "args": {"object_name": {"kind": "identifier"}, "name": {"kind": "type"}}}, + "PF-W5012": {"severity": "warning", "area": "codegen", "message": "{kind} history indexing uses the current collection element in PineForge; the engine does not retain per-bar collection IDs, so this result can differ from TradingView and a missing index is not represented faithfully.", "hint": null, "explanation": "History indexing of an array or map reads the current element, as PineForge keeps no per-bar collection history, so results can differ from TradingView.", "args": {"kind": {"kind": "vocab", "values": ["array", "map"]}}} + }} diff --git a/pineforge_codegen/errors.py b/pineforge_codegen/errors.py index 6978c38e..dc62d9d1 100644 --- a/pineforge_codegen/errors.py +++ b/pineforge_codegen/errors.py @@ -32,6 +32,29 @@ class Diagnostic: message: str hint: str | None = None + # The stable code (``PF-E1203`` / ``PF-W0412``) and named arguments of the + # catalog template the English ``message`` and ``hint`` render from + # (``diagnostic_codes``, ``diagnostics_catalog.json``). Both are read off + # the text when first asked for, after the transpile: the text and the + # C++ never depend on them. + @property + def code(self) -> str: + return self._coded()[0] + + @property + def args(self) -> dict: + return self._coded()[1] + + def _coded(self) -> tuple[str, dict]: + severity = getattr(self.level, "value", self.level) + key = (severity, self.message, self.hint) + cached = self.__dict__.get("_pf_coded") + if cached is None or cached[0] != key: + from .diagnostic_codes import classify + cached = (key, classify(severity, self.message, self.hint)) + self.__dict__["_pf_coded"] = cached + return cached[1] + class CompileError(Exception): def __init__(self, diagnostics: list[Diagnostic]): diff --git a/scripts/gen_diagnostics_catalog.py b/scripts/gen_diagnostics_catalog.py new file mode 100644 index 00000000..a5f7f0bc --- /dev/null +++ b/scripts/gen_diagnostics_catalog.py @@ -0,0 +1,1035 @@ +#!/usr/bin/env python3 +"""Find every diagnostic template the transpiler spells, and keep +``pineforge_codegen/diagnostics_catalog.json`` in step with them. + +The emitters spell their English text in place (f-strings, string tables, +helper arguments). This script reads the package's source with ``ast`` and +turns each spelling into an ICU MessageFormat template: + +* the message and hint arguments of every diagnostic emitter + (``_err``/``_warn``/``_error``/``_codegen_error``/``_codegen_warning``/ + ``Diagnostic(...)``/the exception types the transpiler converts, ...); +* a placeholder that is a constant (``chr(34) * 3``) becomes its text; +* a placeholder that looks a key up in a module-level table + (``HARD_REJECT_FUNC[full]``) becomes one template per distinct value; +* a placeholder (or a whole message) naming a local the function assigns + string spellings to, or a parameter its callers pass string spellings for, + becomes one template per spelling; +* every other placeholder becomes a named argument. + +``--write`` adds a code for every template the catalog lacks (the next free +number of its area and severity) and never renumbers or removes one; the +default ``--check`` exits 1 naming each template without a code. +""" + +from __future__ import annotations + +import argparse +import ast +import importlib +import json +import re +import sys +from dataclasses import dataclass, field +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +PKG = ROOT / "pineforge_codegen" +sys.path.insert(0, str(ROOT)) + +from pineforge_codegen.diagnostic_codes import ( # noqa: E402 + CATALOG_PATH, CATALOG_SCHEMA, UNCATALOGUED, escape_literal, +) + +ERR, WARN = "error", "warning" +MAX_VARIANTS = 48 + +# Area digit of a code, by the module that spells the template. +AREAS = [ + ("lexer.py", 0), ("parser.py", 0), ("limits.py", 0), ("pragmas.py", 0), + ("support_checker.py", 1), ("external_requests.py", 1), + ("analyzer/", 2), ("method_binding.py", 2), ("block_locals.py", 2), + ("finite_ta_length.py", 7), ("security_contexts.py", 3), ("codegen/security.py", 3), + ("library_inline.py", 4), ("library_modules.py", 4), ("library_v5.py", 4), + ("pine_libraries.py", 4), + ("collection_history.py", 6), ("codegen/collection_history.py", 6), + ("codegen/ta.py", 7), + ("codegen/", 5), +] +AREA_NAMES = { + 0: "source", 1: "support", 2: "analysis", 3: "request-security", 4: "libraries", + 5: "codegen", 6: "collection-history", 7: "ta", +} +# The support checker reports what it refuses inside a switch arm as a +# warning (``SupportChecker._err``): PF-W1nnn (nnn < 500) is PF-E1nnn there. +SWITCH_ARM_TWIN_LIMIT = 500 + + +def area_of(path: str) -> int: + rel = path.replace("\\", "/").split("pineforge_codegen/", 1)[-1] + best = None + for suffix, area in AREAS: + if rel == suffix or rel.endswith("/" + suffix) or (suffix.endswith("/") and rel.startswith(suffix)): + if best is None or len(suffix) > len(best[0]): + best = (suffix, area) + elif rel.endswith(suffix) and suffix.endswith(".py"): + if best is None or len(suffix) > len(best[0]): + best = (suffix, area) + return best[1] if best else 5 + + +# callee -> (severity, message position, hint position); a position is an +# index of a positional argument, its keyword being "message" / "hint". +def emitter(name: str, path: str): + table = { + "_err": (ERR, 1, 2), "_codegen_error": (ERR, 1, 2), "_codegen_warning": (WARN, 1, 2), + "_codegen_error_diagnostic": (ERR, 1, 2), "_reject": (ERR, 1, 2), + "_feed_warning": (WARN, 2, 3), "pass_warning": (WARN, 1, 2), + "limit_error": (ERR, 0, None), "_module_error": (ERR, 1, None), + "_emit_diagnostic": (ERR, 0, 4), "LibraryResolveError": (ERR, 0, None), + "MethodBindError": (ERR, 0, None), "ParseError": (ERR, 0, None), + "_refused_session_read": (ERR, 2, None), + } + if name in table: + return table[name] + if name == "_warn": + return (WARN, 1, 2) if path.endswith("support_checker.py") else (WARN, 0, None) + if name == "_error": + if "analyzer/" in path or path.endswith("library_inline.py"): + return (ERR, 0, None) + return (ERR, 1, None) + if name == "refuse" and path.endswith("security_contexts.py"): + return (ERR, 1, None) + if name == "Diagnostic": + return ("level", None, None) + if name == "Decision": + return (ERR, None, None) + if name == "_reject_if_in" and path.endswith("support_checker.py"): + return (ERR, None, None) + if name == "Use" and path.endswith("collection_history.py"): + # A use the collection-history checker refuses carries its text; + # ``Decision(REFUSED, message=...)`` raises it. + return (ERR, 2, 3) + return None + + +def _fixed_hint(mod, name: str, depth: int = 0): + """The constant hint an emitter defined in ``mod`` always passes + (``security_contexts._error``, and ``refuse`` through it).""" + if depth > 2: + return None + for owner, func in FUNCS.get(name, ()): + if owner is not mod: + continue + for node in ast.walk(func): + if not isinstance(node, ast.Call): + continue + callee = callee_name(node) + if callee == "Diagnostic": + hint = call_arg(node, None, "hint") + if isinstance(hint, ast.Constant) and isinstance(hint.value, str): + return hint + elif callee and callee != name and any(o is mod for o, _ in FUNCS.get(callee, ())): + found = _fixed_hint(mod, callee, depth + 1) + if found is not None: + return found + return None + + +class _Substituted(ast.NodeTransformer): + def __init__(self, mapping: dict): + self.mapping = mapping + + def visit_Name(self, node): + return self.mapping.get(node.id, node) + + def visit_Subscript(self, node): + if isinstance(node.value, ast.Name) and node.value.id in self.mapping \ + and isinstance(node.slice, ast.Constant) and isinstance(node.slice.value, int): + target = self.mapping[node.value.id] + if isinstance(target, ast.Tuple): + return target.elts[node.slice.value] + return self.generic_visit(node) + + +def _reject_if_in_message(mod, call): + """``_reject_if_in(table, key, node, lambda k, v: f"...", hint=...)``: the + lambda's text with ``k`` the key's spelling and ``v`` the table's value.""" + table, key, fmt = call.args[0], call.args[1], call.args[3] + hint = call_arg(call, 4, "hint") + k_name, v_name = fmt.args.args[0].arg, fmt.args.args[1].arg + value = ast.Subscript(value=table, slice=key, ctx=ast.Load()) + body = _Substituted({k_name: key, v_name: value}).visit( + ast.parse(ast.unparse(fmt.body), mode="eval").body) + # Spell the substituted body back into the module so placeholders name + # the key's own expression and the table lookup expands. + src = ast.unparse(body) + mod.src_extra = getattr(mod, "src_extra", {}) + expr = ast.parse(src, mode="eval").body + for sub in ast.walk(expr): + sub.lineno = getattr(call, "lineno", 1) + _SYNTH_KEEP.append(expr) + _SYNTH[id(expr)] = src + for sub in ast.walk(expr): + if sub is not expr and hasattr(sub, "col_offset"): + _SYNTH[id(sub)] = ast.unparse(sub) + return expr, hint + + +_SYNTH: dict = {} +_SYNTH_KEEP: list = [] + + +class Arg: + """A placeholder: an argument named from its expression.""" + + def __init__(self, src: str, quoted: bool = False): + self.src = src + self.quoted = quoted + + def __repr__(self) -> str: + return f"Arg({self.src!r})" + + +@dataclass +class Template: + severity: str + message: list + hint: list | None + path: str + line: int + sites: list = field(default_factory=list) + + +class Module: + def __init__(self, path: Path): + self.path = path + self.rel = str(path.relative_to(ROOT)) + self.src = path.read_text(encoding="utf-8") + self.tree = ast.parse(self.src) + self.parents: dict = {} + for node in ast.walk(self.tree): + for child in ast.iter_child_nodes(node): + self.parents[child] = node + mod_name = self.rel[:-3].replace("/", ".") + try: + self.module = importlib.import_module(mod_name) + except Exception: # pragma: no cover - every module imports + self.module = None + + def seg(self, node) -> str: + if id(node) in _SYNTH: + return _SYNTH[id(node)] + return ast.get_source_segment(self.src, node) or "" + + def enclosing(self, node): + while node in self.parents: + node = self.parents[node] + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)): + return node + return None + + +MODULES: dict[str, Module] = {} +FUNCS: dict[str, list] = {} # function name -> [(module, FunctionDef)] +CALLS: dict[str, list] = {} # callee name -> [(module, Call)] + + +def load_modules() -> None: + for path in sorted(PKG.rglob("*.py")): + mod = Module(path) + MODULES[mod.rel] = mod + for node in ast.walk(mod.tree): + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): + FUNCS.setdefault(node.name, []).append((mod, node)) + elif isinstance(node, ast.Call): + name = callee_name(node) + if name: + CALLS.setdefault(name, []).append((mod, node)) + + +def callee_name(call: ast.Call) -> str | None: + fn = call.func + if isinstance(fn, ast.Attribute): + return fn.attr + if isinstance(fn, ast.Name): + return fn.id + return None + + +def call_arg(call: ast.Call, pos, kw): + if isinstance(pos, int) and pos < len(call.args): + return call.args[pos] + for keyword in call.keywords: + if keyword.arg == kw: + return keyword.value + return None + + +def _const_value(node): + """The value of a constant spelling (``chr(34) * 3``), else raise.""" + allowed = (ast.Constant, ast.BinOp, ast.Call, ast.Name, ast.Load, ast.Mult, ast.Add) + for sub in ast.walk(node): + if not isinstance(sub, allowed): + raise ValueError + if isinstance(sub, ast.Name) and sub.id != "chr": + raise ValueError + if isinstance(sub, ast.Call) and not (isinstance(sub.func, ast.Name) and sub.func.id == "chr"): + raise ValueError + value = eval(compile(ast.Expression(node), "", "eval"), {"chr": chr}) # noqa: S307 + if not isinstance(value, str): + raise ValueError + return value + + +def _assigned_values(func, name: str) -> list | None: + values = [] + for node in ast.walk(func): + if isinstance(node, ast.Assign): + for target in node.targets: + if isinstance(target, ast.Name) and target.id == name: + values.append(node.value) + elif isinstance(target, (ast.Tuple, ast.List)) and any( + isinstance(e, ast.Name) and e.id == name for e in target.elts): + return None + elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name) \ + and node.target.id == name and node.value is not None: + values.append(node.value) + elif isinstance(node, (ast.AugAssign,)) and isinstance(node.target, ast.Name) \ + and node.target.id == name: + return None + elif isinstance(node, (ast.For, ast.comprehension)) and isinstance(node.target, ast.Name) \ + and node.target.id == name: + return None + elif isinstance(node, ast.NamedExpr) and node.target.id == name: + return None + return values + + +def _param_index(func, name: str): + args = func.args + params = [a.arg for a in args.posonlyargs + args.args] + if name in params: + return params.index(name) + if name in [a.arg for a in args.kwonlyargs]: + return name + return None + + +def _caller_values(mod: Module, func, name: str) -> list | None: + """The spellings every call of ``func`` passes for parameter ``name``.""" + index = _param_index(func, name) + if index is None: + return None + is_method = bool(func.args.args) and func.args.args[0].arg == "self" + values = [] + found = False + for other, node in CALLS.get(func.name, ()): + if True: + if func.name in ("refuse",) and other is not mod: + continue + found = True + pos = index + if isinstance(pos, int) and is_method and isinstance(node.func, ast.Attribute): + pos -= 1 + value = call_arg(node, pos if isinstance(pos, int) else None, name) + if value is None: + default = _default(func, name) + if default is None: + return None + value = default + values.append((other, value)) + return values if found else None + + +def _default(func, name: str): + args = func.args + positional = args.posonlyargs + args.args + defaults = args.defaults + offset = len(positional) - len(defaults) + for i, a in enumerate(positional): + if a.arg == name and i >= offset: + return defaults[i - offset] + for a, d in zip(args.kwonlyargs, args.kw_defaults): + if a.arg == name: + return d + return None + + +def _table_values(mod: Module, node: ast.Subscript) -> list | None: + if not isinstance(node.value, ast.Name) or mod.module is None: + return None + table = getattr(mod.module, node.value.id, None) + if not isinstance(table, dict): + return None + if not table: + return [] # an empty table: the lookup never yields a text + values = sorted({v for v in table.values()}) + if not all(isinstance(v, str) for v in values): + return None + return values + + +class Flattener: + """Turn a string expression into variants: lists of str | Arg.""" + + def __init__(self, mod: Module, origin, depth: int = 0): + self.mod = mod + self.origin = origin + self.depth = depth + + def flatten(self, node) -> list[list]: + mod = self.mod + if node is None: + return [None] + if isinstance(node, ast.Constant): + if isinstance(node.value, str): + return [[node.value]] + if node.value is None: + return [None] + return [[Arg(mod.seg(node))]] + if isinstance(node, ast.JoinedStr): + variants = [[]] + for value in node.values: + if isinstance(value, ast.Constant): + options = [[value.value]] + else: + options = self.placeholder(value) + variants = [a + b for a in variants for b in options] + variants = variants[:MAX_VARIANTS * 4] + return variants + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.Add): + left, right = self.flatten(node.left), self.flatten(node.right) + return [a + b for a in left for b in right if a is not None and b is not None] + if isinstance(node, ast.IfExp): + return self.flatten(node.body) + self.flatten(node.orelse) + if isinstance(node, ast.BoolOp) and isinstance(node.op, ast.Or): + out = [] + for value in node.values: + out += [v for v in self.flatten(value) if v is not None] + return out + if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) \ + and node.func.attr == "strip" and not node.args: + return [_strip(v) for v in self.flatten(node.func.value)] + resolved = self.resolve(node) + if resolved is not None: + return resolved + return [[Arg(mod.seg(node))]] + + def placeholder(self, value: ast.FormattedValue) -> list[list]: + mod = self.mod + inner = value.value + if value.format_spec is not None: + return [[Arg(mod.seg(value))]] + if value.conversion == ord("r"): + resolved = self.resolve(inner, quoted=True) + if resolved is not None: + return resolved + return [[Arg(mod.seg(inner), quoted=True)]] + if isinstance(inner, ast.IfExp): + options = self.flatten(inner.body) + self.flatten(inner.orelse) + if all(o is not None for o in options): + return options + if isinstance(inner, (ast.JoinedStr, ast.BinOp)): + options = self.flatten(inner) + if all(o is not None for o in options): + return options + resolved = self.resolve(inner) + if resolved is not None: + return resolved + return [[Arg(mod.seg(inner))]] + + def resolve(self, node, quoted: bool = False) -> list[list] | None: + """Constant, table, local or caller spellings of ``node``, or None.""" + mod = self.mod + if quoted: + return None + try: + return [[_const_value(node)]] + except (ValueError, SyntaxError, TypeError, NameError): + pass + if self.depth > 3: + return None + if isinstance(node, ast.Subscript): + values = _table_values(mod, node) + if values is not None and len(values) <= MAX_VARIANTS: + return [[v] for v in values] + return None + if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == "str" \ + and len(node.args) == 1: + return self.resolve(node.args[0]) + if isinstance(node, ast.Call): + returned = _returned_texts(callee_name(node), self.origin, self.depth) + if returned is not None: + return returned + return None + if isinstance(node, ast.Name): + caught = _caught_exception_texts(mod, node, self.origin, self.depth) + if caught is not None: + return caught + func = mod.enclosing(node) + if func is None or isinstance(func, ast.Lambda): + return None + assigned = _assigned_values(func, node.id) + if assigned is None: + return None + if assigned and _param_index(func, node.id) is None: + out = [] + for value in assigned: + sub = Flattener(mod, self.origin, self.depth + 1).flatten(value) + if any(v is None for v in sub): + return None + if any(len(v) == 1 and isinstance(v[0], Arg) and v[0].src == node.id for v in sub): + return None + out += sub + if 0 < len(out) <= MAX_VARIANTS and _is_textual(out): + return out + return None + if not assigned: + key = (id(func), node.id) + if key in _CALLER_TEXTS: + return _CALLER_TEXTS[key] + _CALLER_TEXTS[key] = None + _CALLER_TEXTS[key] = self._caller_texts(mod, func, node.id) + return _CALLER_TEXTS[key] + return None + + def _caller_texts(self, mod, func, name): + """The spellings the callers of ``func`` pass for parameter ``name``.""" + callers = _caller_values(mod, func, name) + if callers is None: + return None + out = [] + for other, value in callers: + sub = Flattener(other, self.origin, self.depth + 1).flatten(value) + out += [v for v in sub if v is not None] if all(v is not None for v in sub) else [] + if 0 < len(out) <= MAX_VARIANTS and _is_textual(out): + return out + return None + + +def _caught_exception_texts(mod, node: ast.Name, origin, depth: int): + """``except LibraryResolveError as exc: ... f"...{exc}"``: the texts every + raise of that exception type spells.""" + current = node + while current in mod.parents: + current = mod.parents[current] + if isinstance(current, ast.ExceptHandler) and current.name == node.id: + kind = current.type + name = kind.id if isinstance(kind, ast.Name) else ( + kind.attr if isinstance(kind, ast.Attribute) else None) + if name is None or name in ("Exception", "ValueError", "KeyError", "TypeError"): + return None + out = [] + for other, call in CALLS.get(name, ()): + if not call.args: + continue + sub = Flattener(other, origin, depth + 1).flatten(call.args[0]) + out += [v for v in sub if v is not None and not _is_catch_all(v)] + return out if 0 < len(out) <= MAX_VARIANTS else None + if isinstance(current, (ast.FunctionDef, ast.AsyncFunctionDef)): + return None + return None + + +_RETURNED: dict = {} +_CALLER_TEXTS: dict = {} + + +def _returned_texts(name: str | None, origin, depth: int): + """A helper's text: every string its ``return`` statements spell.""" + if not name or depth > 3 or name in ("next", "join", "format", "get", "pop"): + return None + if name not in _RETURNED: + _RETURNED[name] = None # a recursive helper reads as no text + _RETURNED[name] = _returned_texts_uncached(name, origin, depth) + return _RETURNED[name] + + +def _returned_texts_uncached(name: str, origin, depth: int): + defs = FUNCS.get(name, ()) + if len(defs) != 1: + return None + mod, func = defs[0] + out = [] + for node in ast.walk(func): + if isinstance(node, ast.Return) and node.value is not None: + if isinstance(node.value, ast.Constant) and node.value.value is None: + continue + sub = Flattener(mod, origin, depth + 1).flatten(node.value) + out += [v for v in sub if v is not None] + if not out or not _is_textual(out) or len(out) > MAX_VARIANTS: + return None + return out + + +def _is_textual(variants: list) -> bool: + """Expansion pays off only when every variant spells some text.""" + return all(any(isinstance(p, str) and p.strip() for p in v) for v in variants) + + +def _strip(parts): + if parts is None: + return None + parts = list(parts) + if parts and isinstance(parts[0], str): + parts[0] = parts[0].lstrip() + if parts and isinstance(parts[-1], str): + parts[-1] = parts[-1].rstrip() + return parts + + +def normalize(parts): + if parts is None: + return None + out: list = [] + for p in parts: + if isinstance(p, str): + if not p: + continue + if out and isinstance(out[-1], str): + out[-1] += p + else: + out.append(p) + else: + out.append(p) + return out + + +# --------------------------------------------------------------------------- +# Argument names +# --------------------------------------------------------------------------- + +_NAME_OVERRIDES = { + "spell_call(node)": "call", "spell_call(request)": "call", + "self._expr_to_str(node)": "expr", + "type(stmt).__name__": "statement", + "_a(kind)": "kind", + "import_spelling(node)": "import_path", "import_spelling(stmt)": "import_path", + "self._ta_signature_text(name)": "signature", + "info.node.params[index]": "param", + "cur.value": "token", "cur.type.name": "token_type", "tt.name": "expected_token", + "tf_node.value": "timeframe", "seen[0][:12]": "found_sha", "sha[:12]": "sha", +} + + +def arg_name(src: str) -> str: + src = src.strip() + if src in _NAME_OVERRIDES: + return _NAME_OVERRIDES[src] + m = re.fullmatch(r"type\((.*)\)\.__name__", src) + if m: + return "node_type" + m = re.fullmatch(r"sorted\((.*)\)(?:\[\d+\])?", src, re.S) + if m: + return arg_name(m.group(1).split("&")[0].strip()) + m = re.fullmatch(r"getattr\([^,]+,\s*['\"](\w+)['\"].*\)", src, re.S) + if m: + return m.group(1) + m = re.fullmatch(r"(?:self\.)?_spell\((.*)\)", src) + if m: + return "expr" + m = re.fullmatch(r"self\._type_spec_to_cpp\((\w+)\)", src) + if m: + return m.group(1).replace("_spec", "") + "_type" + m = re.fullmatch(r"len\((.*)\)", src) + if m: + return _base(m.group(1)) + "_count" + m = re.fullmatch(r"""(?:"[^"]*"|'[^']*')\.join\((.*)\)""", src, re.S) + if m: + inner = m.group(1) + inner = re.sub(r"^sorted\((.*)\)$", r"\1", inner.strip(), flags=re.S) + return _base(inner) + m = re.fullmatch(r"str\((.*)\)", src) + if m: + return _base(m.group(1)) + return _base(src) + + +def _base(src: str) -> str: + src = re.sub(r"\[[^\[\]]*\]", "", src) # drop subscripts + src = re.sub(r"\((?:[^()]|\([^()]*\))*\)", "", src) # drop call arguments + tokens = re.findall(r"[A-Za-z_][A-Za-z0-9_]*", src) + tokens = [t for t in tokens if t not in ("self", "node", "value", "split", "get", "strip")] or tokens + if not tokens: + return "value" + name = tokens[-1].lstrip("_") + if name in ("name", "kind", "member") and len(tokens) >= 2: + prev = tokens[-2].lstrip("_") + if prev not in ("self", "node", "expr_node", "n", "info", "stmt", "site", "spec", "decl", + "target", "obj", "field", "mod", "lib", "tt", "error", "sig", "signature"): + name = f"{prev}_{name}" + name = re.sub(r"[^A-Za-z0-9_]", "_", name) or "value" + if name[0].isdigit(): + name = "v" + name + return name.lower() if name.isupper() else name + + +def to_template(message: list, hint: list | None) -> tuple[str, str | None, dict]: + """ICU templates of a variant pair and the source of each argument.""" + names: dict[str, str] = {} # expression source -> argument name + used: set[str] = set() + + def name_for(arg: Arg) -> str: + if arg.src in names: + return names[arg.src] + base = arg_name(arg.src) + candidate, n = base, 2 + while candidate in used: + candidate = f"{base}{n}" + n += 1 + used.add(candidate) + names[arg.src] = candidate + return candidate + + def render(parts): + if parts is None: + return None + out = [] + for p in parts: + if isinstance(p, str): + out.append(escape_literal(p)) + else: + ph = "{" + name_for(p) + "}" + out.append("''" + ph + "''" if p.quoted else ph) + return "".join(out) + + msg = render(message) + hnt = render(hint) + sources = {v: k for k, v in names.items()} + return msg, hnt, sources + + +# --------------------------------------------------------------------------- +# Extraction +# --------------------------------------------------------------------------- + +def _level_of(mod: Module, call: ast.Call) -> list[str]: + level = call_arg(call, 0, "level") + src = mod.seg(level) if level is not None else "" + out = [] + if "ERROR" in src: + out.append(ERR) + if "WARNING" in src: + out.append(WARN) + return out + + +def _is_catch_all(parts) -> bool: + """A text that is one argument alone: its spellings are sites of their own.""" + return len(parts) == 1 and isinstance(parts[0], Arg) + + +def _is_passthrough(variants) -> bool: + return all(v is not None and len(v) == 1 and isinstance(v[0], Arg) for v in variants) + + +def extract() -> list[dict]: + """Every (severity, message, hint) template the source spells.""" + if not MODULES: + load_modules() + found: dict[tuple, dict] = {} + for mod in MODULES.values(): + for call in ast.walk(mod.tree): + if not isinstance(call, ast.Call): + continue + name = callee_name(call) + spec = emitter(name, mod.rel) if name else None + severity_choices = None + if spec is None and isinstance(call.func, ast.Name): + # ``emit = self._err if ... else self._warn``; ``emit(...)``. + spec, severity_choices = _local_emitter(mod, call) + if spec is None: + continue + severity, mpos, hpos = spec + message = call_arg(call, mpos, "message") + hint = call_arg(call, hpos, "hint") + if hint is None: + hint = _fixed_hint(mod, name) + if name == "_reject_if_in": + message, hint = _reject_if_in_message(mod, call) + if message is None or _forwards_parameter(mod, message): + continue + severities = [severity] if severity in (ERR, WARN) else _level_of(mod, call) + if severity_choices: + severities = severity_choices + if name == "ParseError" or name == "MethodBindError" or name == "LibraryResolveError": + severities = [ERR] + flattener = Flattener(mod, call) + mvars = [normalize(v) for v in flattener.flatten(message)] + mvars = [v for v in mvars if v is not None and not _is_catch_all(v)] + if not mvars or _is_passthrough(mvars): + continue + hvars = [normalize(v) for v in flattener.flatten(hint)] if hint is not None else [None] + if hint is not None and not (isinstance(hint, ast.Constant) and hint.value is None): + # A hint that can be None at run time keeps a None variant. + if _may_be_none(mod, hint): + hvars.append(None) + for sev in severities: + for m in mvars[:MAX_VARIANTS]: + for h in hvars[:MAX_VARIANTS]: + if h is not None and len(h) == 0: + h = None + msg, hnt, sources = to_template(m, h) + key = (sev, msg, hnt) + entry = found.setdefault(key, { + "severity": sev, "message": msg, "hint": hnt, + "sources": sources, "sites": []}) + entry["sites"].append(f"{mod.rel}:{call.lineno}") + for parse_site in _parser_consume_templates(): + key = (ERR, parse_site["message"], None) + entry = found.setdefault(key, dict(parse_site, sites=[])) + entry["sites"] += parse_site["sites"] + return list(found.values()) + + +def _local_emitter(mod: Module, call: ast.Call): + """A call of a local bound to one emitter or another.""" + func = mod.enclosing(call) + if func is None or isinstance(func, ast.Lambda): + return None, None + values = _assigned_values(func, call.func.id) or [] + specs = [] + for value in values: + options = [value.body, value.orelse] if isinstance(value, ast.IfExp) else [value] + for option in options: + name = option.attr if isinstance(option, ast.Attribute) else None + spec = emitter(name, mod.rel) if name else None + if spec is None: + return None, None + specs.append(spec) + if not specs or len({(s[1], s[2]) for s in specs}) != 1: + return None, None + return specs[0], sorted({s[0] for s in specs}) + + +def _forwards_parameter(mod: Module, message) -> bool: + """An emitter's body handing on its own ``message`` parameter: the text + is spelled where the emitter is called, which is a site of its own.""" + if not isinstance(message, ast.Name): + return False + func = mod.enclosing(message) + return (func is not None and not isinstance(func, ast.Lambda) + and _param_index(func, message.id) is not None) + + +def _may_be_none(mod: Module, hint) -> bool: + if isinstance(hint, ast.Name): + func = mod.enclosing(hint) + if func is not None and not isinstance(func, ast.Lambda): + if _param_index(func, hint.id) is not None: + default = _default(func, hint.id) + if isinstance(default, ast.Constant) and default.value is None: + return True + for value in _assigned_values(func, hint.id) or []: + if isinstance(value, ast.Constant) and value.value is None: + return True + if isinstance(hint, ast.IfExp): + return any(isinstance(b, ast.Constant) and b.value is None for b in (hint.body, hint.orelse)) + return False + + +def _parser_consume_templates() -> list[dict]: + """``Parser._consume(tt, msg)``: "Expected {tt}, got {type}({value!r}). {msg}".""" + mod = MODULES["pineforge_codegen/parser.py"] + out = [] + for call in ast.walk(mod.tree): + if not isinstance(call, ast.Call) or callee_name(call) != "_consume": + continue + tt = call_arg(call, 0, "tt") + msg = call_arg(call, 1, "msg") + expected = mod.seg(tt).split(".")[-1] if isinstance(tt, ast.Attribute) else None + text = msg.value if isinstance(msg, ast.Constant) and isinstance(msg.value, str) else "" + parts = ["Expected ", expected if expected else Arg("tt.name"), ", got ", Arg("cur.type.name"), + "(", Arg("cur.value", quoted=True), "). " + text] + parts = normalize(_strip(parts)) + msg_t, _, sources = to_template(parts, None) + out.append({"severity": ERR, "message": msg_t, "hint": None, "sources": sources, + "sites": [f"{mod.rel}:{call.lineno}"]}) + return out + + +# --------------------------------------------------------------------------- +# Catalog maintenance +# --------------------------------------------------------------------------- + +def _guess_kind(name: str, src: str) -> str: + low = name.lower() + if low.endswith("_count") or low in ("count", "n", "cs_idx", "tuple_size", "max_family_variants", + "max_nesting_depth", "max_source_chars", + "max_transpile_seconds", "line") or src.startswith("len("): + return "number" + if "type" in low or low in ("t", "elem_str", "element_label", "inferred_types", "spec_name"): + return "type" + if low in ("op", "kw_name", "keyword", "statement"): + return "keyword" + if low in ("what", "why", "reason", "kind", "form", "problem", "found", "where", "reads", + "opens", "daily", "listed", "extra", "exc", "err", "hint", "message", "detail", + "allowed_hint", "chart_read", "via", "through", "label", "function", "code"): + return "text" + return "identifier" + + +def load_catalog() -> dict: + if CATALOG_PATH.exists(): + return json.loads(CATALOG_PATH.read_text(encoding="utf-8")) + return {"schema": CATALOG_SCHEMA, "codes": {}} + + +def _next_code(codes: dict, severity: str, area: int) -> str: + letter = "E" if severity == ERR else "W" + used = {int(c[4:]) for c in codes if c.startswith(f"PF-{letter}{area}")} + start = area * 1000 + 1 + if area == 1 and severity == WARN: + start = 1000 + SWITCH_ARM_TWIN_LIMIT + if area == 1 and severity == ERR: + limit = 1000 + SWITCH_ARM_TWIN_LIMIT + else: + limit = area * 1000 + 1000 + for number in range(start, limit): + if number not in used: + return f"PF-{letter}{number:04d}" + raise SystemExit(f"area {area} {severity} codes exhausted") + + +def merge(catalog: dict, templates: list[dict]) -> list[str]: + """Add codes for templates the catalog lacks; returns the new codes.""" + codes = catalog["codes"] + by_key = {(e["severity"], e["message"], e.get("hint")): c for c, e in codes.items()} + added = [] + ordered = sorted(templates, key=lambda t: (area_of(t["sites"][0].split(":")[0]), + t["sites"][0].split(":")[0], + int(t["sites"][0].split(":")[1]), + t["severity"], t["message"], t["hint"] or "")) + for t in ordered: + key = (t["severity"], t["message"], t["hint"]) + if key in by_key: + continue + area = area_of(t["sites"][0].split(":")[0]) + code = _next_code(codes, t["severity"], area) + codes[code] = { + "severity": t["severity"], "area": AREA_NAMES[area], + "message": t["message"], "hint": t["hint"], + "explanation": "", + "args": {name: {"kind": _guess_kind(name, src)} for name, src in t["sources"].items()}, + } + by_key[key] = code + added.append(code) + if area == 1 and t["severity"] == ERR: + twin = "PF-W" + code[4:] + twin_key = (WARN, t["message"], t["hint"]) + if twin not in codes and twin_key not in by_key: + codes[twin] = dict(codes[code], severity=WARN) + codes[twin]["args"] = {k: dict(v) for k, v in codes[code]["args"].items()} + by_key[twin_key] = twin + added.append(twin) + return added + + +PIN_PATH = ROOT / "tests" / "fixtures" / "diagnostic_codes_pin.json" + + +def pin_digest(entry: dict) -> str: + """What a code means: its severity, templates and argument names + (``tests/test_diagnostic_codes.py`` computes the same).""" + import hashlib + meaning = json.dumps([entry["severity"], entry["message"], entry.get("hint"), + sorted(entry.get("args", {}))], ensure_ascii=False) + return hashlib.sha256(meaning.encode("utf-8")).hexdigest() + + +def load_pin() -> dict: + if PIN_PATH.exists(): + return json.loads(PIN_PATH.read_text(encoding="utf-8"))["codes"] + return {} + + +def write_pin(catalog: dict) -> None: + """Pin every new code; a pinned code's digest never changes here.""" + pinned = load_pin() + for code, entry in catalog["codes"].items(): + pinned.setdefault(code, pin_digest(entry)) + body = {"note": ("Each code's meaning, pinned: a code is never removed or repurposed " + "(tests/test_diagnostic_codes.py). scripts/gen_diagnostics_catalog.py " + "--write pins new codes; never edit a line by hand."), + "codes": dict(sorted(pinned.items()))} + PIN_PATH.write_text(json.dumps(body, indent=1) + "\n", encoding="utf-8") + + +def prune(catalog: dict, templates: list[dict]) -> list[str]: + """Drop codes no source spells any more, while they are not pinned.""" + pinned = load_pin() + spelled = {(t["severity"], t["message"], t["hint"]) for t in templates} + codes = catalog["codes"] + gone = [] + for code, entry in list(codes.items()): + if code in pinned or code in UNCATALOGUED.values(): + continue + key = (entry["severity"], entry["message"], entry.get("hint")) + if key in spelled: + continue + if code.startswith("PF-W1") and int(code[4:]) < 1000 + SWITCH_ARM_TWIN_LIMIT: + twin = codes.get("PF-E" + code[4:]) + if twin is not None and (twin["severity"] == ERR) and \ + (ERR, twin["message"], twin.get("hint")) in spelled: + continue + gone.append(code) + for code in gone: + del codes[code] + return gone + + +def ensure_uncatalogued(catalog: dict) -> None: + for severity, code in UNCATALOGUED.items(): + catalog["codes"].setdefault(code, { + "severity": severity, "area": "uncatalogued", + "message": "{message}", "hint": "{hint}", + "explanation": ("A diagnostic whose text no catalog template renders; the " + "test suite refuses it, so a release never emits it."), + "args": {"message": {"kind": "text"}, "hint": {"kind": "text"}}, + }) + + +def dump(catalog: dict) -> str: + """One code per line: compact for the Pyodide bundle, readable in a diff.""" + codes = sorted(catalog["codes"].items()) + lines = [f'{{"schema": {json.dumps(CATALOG_SCHEMA)},', ' "codes": {'] + for i, (code, entry) in enumerate(codes): + ordered = {k: entry[k] for k in ("severity", "area", "message", "hint", "explanation", "args") + if k in entry} + tail = "," if i < len(codes) - 1 else "" + lines.append(f" {json.dumps(code)}: {json.dumps(ordered, ensure_ascii=False)}{tail}") + lines.append(" }}") + return "\n".join(lines) + "\n" + + +def main(argv=None) -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--write", action="store_true", help="add codes for new templates") + parser.add_argument("--list", action="store_true", help="print every extracted template") + args = parser.parse_args(argv) + templates = extract() + if args.list: + for t in templates: + print(t["severity"], t["message"], "||", t["hint"], t["sites"][:2]) + return 0 + catalog = load_catalog() + if args.write: + ensure_uncatalogued(catalog) + added = merge(catalog, templates) + pruned = prune(catalog, templates) + if pruned: + print(f"{len(pruned)} unpinned code(s) no source spells removed: {', '.join(pruned)}") + write_pin(catalog) + CATALOG_PATH.write_text(dump(catalog), encoding="utf-8") + print(f"{len(added)} code(s) added; {len(catalog['codes'])} in the catalog") + return 0 + have = {(e["severity"], e["message"], e.get("hint")) for e in catalog["codes"].values()} + missing = [t for t in templates if (t["severity"], t["message"], t["hint"]) not in have] + for t in missing: + print(f"no code: [{t['severity']}] {t['message']!r} hint={t['hint']!r} at {', '.join(t['sites'])}") + return 1 if missing else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/fixtures/diagnostic_codes_pin.json b/tests/fixtures/diagnostic_codes_pin.json new file mode 100644 index 00000000..506b8079 --- /dev/null +++ b/tests/fixtures/diagnostic_codes_pin.json @@ -0,0 +1,633 @@ +{ + "note": "Each code's meaning, pinned: a code is never removed or repurposed (tests/test_diagnostic_codes.py). scripts/gen_diagnostics_catalog.py --write pins new codes; never edit a line by hand.", + "codes": { + "PF-E0000": "3303a72fb4a697c60229aa4df7bae3acd712f6b37461a667ad0d2a052375ea40", + "PF-E0001": "29c9dd2bfdf64fc925e41a81a5fb07db9502500ea30c2e61ac44d5f39901acc1", + "PF-E0002": "36990d22db401d89c7a815e8e77e617b82f4651d78703a2a93956c9d879e87da", + "PF-E0003": "b83fd5bb5cc41388d7f1c11c05d179619e37462a7a2c8542a97e0f63a2ade00e", + "PF-E0004": "1616ea93f84b452761852af4961044b0232cb94b540873e5d069d34ce31455b5", + "PF-E0005": "abcd916fe7d3e16854554c841d8b9436e9572c17d8ea4a2b2861257e5f2ad1ff", + "PF-E0006": "f81600b8577abc42c8a858dc5b6b791c2d374f58c372e85ec532d5c3f3a1b53c", + "PF-E0007": "210b5660f1f992d71c31990a21e595095cb58e5e54bcd039cb619c126860ba51", + "PF-E0008": "6d9f5393c4534eb181f85afb34c5874705badab92a72fc34151223b70c50893d", + "PF-E0009": "f32e34c0a0a97a54299840e781ea7751c56ead6082f67e0df522391e170302b0", + "PF-E0010": "2234e279fdd806dfe1c97ebca47788ffd544b9d4ae3bdfeded8f615053498f87", + "PF-E0011": "4a72e9264dd3f89defd2e150ce9a8d8d9fdeae13b4277e202ed3b69d542b4777", + "PF-E0012": "ffc14241b3262c862d27d0f869918a20145bdf6b31b456f221dadcdcaaaaba2c", + "PF-E0013": "ee19b8fd08fd017a1a0d7d00fac32d8a2bef1b0b31d25fa91acc32aebd8f50e6", + "PF-E0014": "4c6420930cd06757e390b7714f48dd78d4e6a3528fc4d6114cd84da4aa05bf78", + "PF-E0015": "2300fb466d7ee168e3ea3de5d3eb19c45d239cd2b6b5503b169201c9528ae7a0", + "PF-E0016": "3049ec1ad1c8981dbeaa6024a2cff418c845c7bd21171c9e8ee0c80d349266ab", + "PF-E0017": "c8ae91a95af3d8136f020b8f177d9fde9938b6ec377ad380cc66883aaefaa596", + "PF-E0018": "507fd91137005a49351ba64609c9810ced13f0c94ece57b7dbf699bb50f358b6", + "PF-E0019": "ad1b95bbde239b797e173e5836712db42224ac99e724a7e6d829bf59e2824dd3", + "PF-E0020": "c4552d1d5b68b83429ebe51ccc784d51330a8ad7e48f0b5fd027012ea0b8d51b", + "PF-E0021": "372b5c00cbe1588b2e9fc043ea1cb78b99873b0e4c3a0385fb0ca22275807f68", + "PF-E0022": "ef27748eb4f5dcfc5bd2afddc24d53a08f16909943024efc88f96910447c9099", + "PF-E0023": "099aa2cc655d3e567b8a24510e359143fe64b7b9426fc7b098d94d1d6745134a", + "PF-E0024": "1fb1c8e85e86cfce0e7005a991b086fcb58d9a4e1f387d6b493b0212a98f2007", + "PF-E0025": "f6a6e747efb4556ba5eec94bf0311b319164b89617d1032fcdfd17dc1a7b125e", + "PF-E0026": "e16a5cc563fc3de1ed9676bac5f9499331b65299b8f14f37b1753291fd627a0f", + "PF-E0027": "d01364c87572de29e4b12d6845e4df24ad6ba46bd5087dfb458cc68f8f20ab29", + "PF-E0028": "822d6e1a6fed818f03de1b962dc9710eeae3099908b705306cfa77d7d9e5066d", + "PF-E0029": "fa4fde3e86d94d3d7c67a9d6cd4e4dbef184e5ccc8fca3bef285985d8f795db1", + "PF-E0030": "b7e6be364706546d82908ec49b6eb7a890ff7a0fc5dc358924e93f4f21c5f108", + "PF-E0031": "e7dc8694d8e2ce048d0de8e9ffb1b8e3439282c7554ce1b4a35161f74a4c863f", + "PF-E0032": "3157b077ee2856ad64a16ce89d182b43862ca59e9ebf233786d90e26d828ff81", + "PF-E0033": "06a36eb14950b1385c3d083d8940d38ad288c74531f845fa825d9134892d7de1", + "PF-E0034": "6b77657d71442fd9723f72856cd6fdc1a7b9e2d868ea83d8d06b83361f4ab073", + "PF-E0035": "c161306f62b0446d8e296dce48030c5831a6263bac67031e9ea0469fdf7c70a0", + "PF-E0036": "9796a21f482d814a51886c4b64e6cd069c409fb95997b2398c76afef78b6f4f5", + "PF-E0037": "2b0c8a85e42b7c601dd8d581793ea66b2aa43d421b63bc040e1b06d6d79ec97b", + "PF-E1001": "1bed9afb69614235acc3e9508a5191e19494bf664a4e2936298eb7f2e7a69957", + "PF-E1002": "9d6ed241629fbbc3efc7d3968246ee246974c294e727713df03a6c8284c0508f", + "PF-E1003": "b5bb7f7fab047bff1014739e2f9154986a69f325c936adc81c9d70606f21ab98", + "PF-E1004": "51b3e5484f965c5d956ad93f6fbc48e953dbbd8d82998a651ef64a35a13085e1", + "PF-E1005": "22e8be2a13c7cf5c3afa1b7c60983965a633b1baa0aa34f8ef0596a02294d849", + "PF-E1006": "437f348f804e641a56477fdc5a74faf47a331f6e96c15e32fd9720dcbb26a630", + "PF-E1007": "1b6402b558b5487ea6c418596ba923d30af47022a725b8b56adb421dbb12d482", + "PF-E1008": "33ff0698e0004b33429da9c831170e16019686aac8c1b422402ee12fded36960", + "PF-E1009": "173b4dfba927a43e065cf2fcb1dd7db6aa12f4e077e65a3c257aaf90ce70933a", + "PF-E1010": "4d4cda0a6b41e201ec1ff3c7006466e3b7b014735a39b275057a787b7ca3abf3", + "PF-E1011": "fa17a79d979caa9ca025e07278bf66c3c29fe81ee8d115c20aad3e118e06d8ec", + "PF-E1012": "c39586601bb38ada0cec8ef66ff83c370d5b5b6125d7647ff6933484407f097c", + "PF-E1013": "e301533861f3354b2e2cd2a82a7cfe9c952841a37ccf94d269096ad1f2d12fc8", + "PF-E1014": "70fa8e94a796e070b45801f40e8e501f08118e00fd92735fb176521e52aa6d7a", + "PF-E1015": "fd490d92ad548a814db8edf6082b0ed7bc275666c1ae8aebd4df4c1570042d07", + "PF-E1016": "458e9536182df4330f09348eae00b5ac70a9e2af69842a82157406cd3b6f590e", + "PF-E1017": "858385946e624c55bd0e59955329f8a141bb6a88ce780f61d5fd2367eb6deeac", + "PF-E1018": "64b1465d3acdca716809e388a3aeb1400cb6f1aae761c298ced07072bfecfcef", + "PF-E1019": "48f02152ba040e1266e242389f3ed03941340fe674c86d11e932ac0042572467", + "PF-E1020": "a1f7e47fd2465c00984bee8e1527e659e3e249916aa2e658d184bd792a4d14a7", + "PF-E1021": "3698fa26cf92549fc38ceb4982c8b2d4d0e42f8c938be4022311188476a478b7", + "PF-E1022": "8588b893f175392e0b7eb9e24f5a56ae2bea040e0996e6456ee215205de896cc", + "PF-E1023": "bce1bb8175fe931513ced732855122dbc46b96fac5141c100599d5b77c8969af", + "PF-E1024": "679188aac383acfdc5162b1ce3d9ac78aadad347a2340c6281c318c373c9b897", + "PF-E1025": "5bc73b96e7e3b4a9783d7d183f2d9900a1080d024a679000c3aecb24e6d2ac81", + "PF-E1026": "764919ee132b32e651d1a38e5e8f98ea7a0196339fffb1e225401b91d54bf54d", + "PF-E1027": "5664466bca10822dc7efae605d6b53bd3b934e092ff000df6950eff7acf63688", + "PF-E1028": "20b465aa8b748c16cf87f240819a58bb8e1708781e56d2d3d822b47553ad4457", + "PF-E1029": "9aa2efd2266155b64432feb1adbf72af692a7ebf3e70cc61077911ec05f1c7d1", + "PF-E1030": "37069bc589799b7d203a2e45d87849467ba044ec9752e859def214278db1f1de", + "PF-E1031": "404c4a0c840768896e5cc8c0fc77927e7adeda8175e78612f8a31b078eafd130", + "PF-E1032": "c2d1f32850bce4e5e400d3495682cb7662ab9efb67b16fde62da57a8bfcfbcc5", + "PF-E1033": "d94a27292287e167797cdf87e3aa73d7242e293df553ccb9db6fa3e417866b1b", + "PF-E1034": "535f42ca9296137c6cc570654ccd6ba30d0f3a5105cc730efd6a863b40f8cab6", + "PF-E1035": "3c57912dbd899cd6e922f08843ae1d24e642ec132dd7932a0be2ebaccff517f3", + "PF-E1036": "15f9bd1f1d29b0fd9302f581bb6cfff4e9bdf8a4b256974fdd3ead3b8f83a4a6", + "PF-E1037": "b76e22f251a0cb1d7ab39d5d073611fb05559a54b0546e206cfae4dc0fc203f6", + "PF-E1038": "8e6bef18dc20184c696fc0bab1fbd3cfc60abaabc64f2528f00605b4f4844ffd", + "PF-E1039": "2476b79e61e40a6685433f3bd4f76dc0570e1432366ce219f8036573e13ba10f", + "PF-E1040": "cb3a20c4bb51a88303ae9d49e2a5ac81cb3b6b5e5f7ca8c39f3ce08a8ebfb3cb", + "PF-E1041": "ff9e464d9a2c652f54db5b7567b77727c9e9c2818c7430a9c457f5aef96d94d2", + "PF-E1042": "bc3847b2cb22490d3480bd0139eb86a549bccde7d87f112bab75f16eb9655fb1", + "PF-E1043": "f36786bbbb28805e6a0551837851e7e76dae525b774c2277079077d4f42a3302", + "PF-E1044": "77b75f585c908c82ecb2efd1e32d6f22285f25500129a7676d8312c678b6902f", + "PF-E1045": "3a200af246d0b0ced5e6b59498efff32b462a0a79ccde83131af2c51ff4b3ac9", + "PF-E1046": "bf065b22d86c924f17c13b29f32b4aabdd65fe01d1f475559f54e17ebce06cae", + "PF-E1047": "a40d392da18f8fe6a15ab2e6bf752789501701638e729619e4d29f4a3442e724", + "PF-E1048": "929a1e9c5608d25cda73c60af38ca72115bb0fedb4e746a95d49dc87b10878d1", + "PF-E1049": "ae892e48c09c3ed4cc1ad29311d133bcfa9736fbe6042d1455fc1ce2640330e3", + "PF-E1050": "b5dbf9eb16770628b035d6a352be4c18eb32b4106cad185af2b87a65d6360d37", + "PF-E1051": "d20276d20e738e46baaa339e413fd92516e831673a0128963514702df4cc9b6f", + "PF-E1052": "0eead5cd442efea5f23a1ad5c7ac658bc1b440dc488b205ae960ab111d3b0f37", + "PF-E1053": "9c08971e4ca1bf7318cd1741c26f8766f0c2cac3a107000fcf6d5e78750da26a", + "PF-E1054": "d9aebb93769ff9f111f081cef1373923613f9f06e24dedc4f224dff68ed8313f", + "PF-E1055": "145414ca24f9caff188be99fde48927c67481434397ddffc081156e10fffdcc4", + "PF-E1056": "e105f547ca0ffa7e3df825f5a715bc1d05252166435e8ae0a1a97c2dbfd635bd", + "PF-E1057": "bdb97a4cd5ac96bdc11c862b6c9a2e4e70a7db2a4f963b26e785a16e5b54cab9", + "PF-E1058": "56dd32f3829d5385dde5244a1a90aeda233032dd5a06724dc8150763b9cf4f99", + "PF-E1059": "1179765dfc36619a0510270fe598186de9330af8534444cf13bb1ca8b4901b84", + "PF-E1060": "90862bd9768a41c6b07c66dc2670cc8e9930cd77a366e2ec6122d129919262a2", + "PF-E1061": "5553514226b4e30917f3dc1fffc22ebbf7d5dff30efdfcfde514a8021a5e489b", + "PF-E1062": "72a442b2ffcff2a108a32f4587e776c1ecdf45df039f7ed828d5375323ec675e", + "PF-E1063": "5c640b6d92bd3ec34f6e99e7f7e678fa8d54201665a46d80c77c1a6a946bd14f", + "PF-E1064": "59198c7b49e30690b69c087331d1c4f5d178c8711fb8f868715dfeefe0caec84", + "PF-E1065": "8b1b041e967baef61789ba92168063ef212e97de06ddc233291993cee36123c8", + "PF-E1066": "42dbc247b2b77d8b49f55bd358c06f6bbadb8ed6e517f63f84f061c60b399ee6", + "PF-E1067": "a1f9c954532f20f7e762e6998be2a98b43ddf9ed261c4e7c6dfffdf8aeedee54", + "PF-E1068": "2e7a534c1082989cbe4645f4257e6e58e77f4675fc5489e78d79ed7f83da14c9", + "PF-E1069": "3f215b252d9479aeb7a710778294258360a9b8cffc7da5631f60432da3b830b6", + "PF-E1070": "b6831c4fd31600e9aecf5540afb5362f68318ca3aef0789248fae3ff020e343f", + "PF-E1071": "ccdf791c46e739e190597e6f2b2e433098a597d10e55d378f69eb2c8c1c3a484", + "PF-E1072": "27d7e531c1a6b4ad4ddd794ce1a150e57abb55053e271596abd357b3a33fa864", + "PF-E1073": "b6599c5e23e9de1a60590ddbe4de0a1d4ba5a4ef36cc267a3933d0c62352aa26", + "PF-E1074": "73e41717c8b7630d8132691cf5867ddac80fb008c31630fb71ad765ebe3fe010", + "PF-E1075": "d0062fb698e43045a8c6866ef2b57436aff835b08c841fa842694d59ec1a5911", + "PF-E1076": "290880d06826cc1edb9ea055c4331f5cbf48789d2a41b33de3ec2b78c694f548", + "PF-E1077": "5d72fb258c8977b05f4675b0bf403fd9d444b193a40a6e2fbf81f122b20f1935", + "PF-E1078": "41e0d6d76295257c06ffde6e4597290ce685d83c062b1d2284be72c038d603cb", + "PF-E1079": "c332589a012c6abf43d1fe975caa6b7280fde4c2342b94635a7828cb73a495d1", + "PF-E1080": "d8498a80cbc979d85813f0b4dd7e235779fbc1e9390c590acb012276c175a5e1", + "PF-E1081": "3509dcaefa46ea1397a3082ead0f0ac8aee5ea9798a85d95998b5e01219744f8", + "PF-E1082": "def7e36f522cf9a1444b22493040fdd43b04a5b85e8ee2723764f0ea788533d2", + "PF-E1083": "92a73c19f401e96e028dad397421e6ab5ecc3fb29c9b20e353bb144151771fa8", + "PF-E1084": "34a5509dcff63e3f60db49caa603e3998f436dcb9a955e23121c46d1aa583aca", + "PF-E1085": "a19299b5d7cc970dd325a7a4063a14ee67ea3b890e1b3508ad04d3cb8036769f", + "PF-E1086": "413662092933423f190920300b0fda36c90cf155925f505c7744941085483988", + "PF-E1087": "684d95fc2b64d892837a557753d51c09ae3efc22ef26d5909bcf77e61f616c32", + "PF-E1088": "44d462e966b0e13484b2a90ec78080342773249d29ae2d01f83c298a8149b24c", + "PF-E1089": "874465bf1340ce9975cc461a896157178e6322a1eb5de2701529e1f7299dfb88", + "PF-E1090": "d9918762788990ac9654cf27faad21ef01ea76a951332fca0bccad79970b5517", + "PF-E1091": "21f37b95b0ea5b60015cfcf0146d8637ac82781ed823a2984ce08bc1ecb4b66e", + "PF-E1092": "bb6d80f38d438415b2c97f14bdb1f2b53789062c5df00584c247fe055c7d2671", + "PF-E1093": "25f723dd14de607e9d4043e132eede221a95fec1fc82f15399cffee435af6c5a", + "PF-E1094": "422815b4e44dd125dcfee488472288f116938a442404594623d1f19151b8f1ed", + "PF-E1095": "2ddeba7d392fb7ec5a8604554ad2513dc611f3c4ae80d1018433984c52bc6c81", + "PF-E1096": "d79acecc8126afe5f42b06ea07b2831a66e60caa44e958a22a9b4767de0c26ba", + "PF-E1097": "43c81f56957a39ecffde08c686c24d0534279ef22d031d1c1493a8920820337e", + "PF-E2001": "fa5a3e66b03da2eb1e43410c56925b3b3279009ce9f5dacd9bd0d57687f21c00", + "PF-E2002": "db6538bbf69995ea3d5c5c502f44820ff19a43d57bbd5c148ff975a00596c184", + "PF-E2003": "4b389b9f153243dedd087ae7c4c7aa009f9c3c8ec80bc12572e6fd477b48485d", + "PF-E2004": "d1283530f053a45311f1f9fecdd48f1c019b0c77d74591f8ccde64422ca70583", + "PF-E2005": "17be7493735ae53a7f0187a852b4d8944f97b326be3e05a0a27f0761960f06b3", + "PF-E2006": "71f69c37fd3e02047aefc8d261802ab09630d3518e3e0b84f5a35e79faabdf94", + "PF-E2007": "cfe579ed93ebb0bd4043168a8a781cc3bfad8f773205a95b34e6a4d17bd9b253", + "PF-E2008": "daa1fa9753ab6c66cb044156a4c680da03ebb4232e95ad60c239a5ce0b3d5578", + "PF-E2009": "3b881f66bc60ed536c0df01f2b230f1942d99db4fbdd733bc7a073871880bb4b", + "PF-E2010": "d1fe014b3699158ef4c1dd8cece1e3d420f221e835a7bb6bf75c709168e785ab", + "PF-E2011": "5936dde0794e96b6ab8597b67473266afc41e73fda2517a155214d82765783f0", + "PF-E2012": "a624c4ddcfbd48e57b56328d89cb4108c958d396b6ddd63deed1f982b54caf9c", + "PF-E2013": "7ab67198d640b26abbb6f4986f1414829a95571d93900c0ebea98e1b6b8e3f06", + "PF-E2014": "9718d91092ca36df191c533a3a7e7559bc6d3252964617294dd648d2b4f081fc", + "PF-E2015": "87fe6f364e055e9005fb5dd420c2297000bfc171148a5ac81e660b2864951433", + "PF-E2016": "17c05596dc90f912218c0592d3243f3f5330083a828d896abc2760ea54d23fb6", + "PF-E2017": "f588cd1b987f90331573f9faccd913d07ccd01434da07de3b0ea7954365c10e0", + "PF-E2018": "f2562b41b8639bb7b3d68199dd18ca91517ac2931862304b9631ecc21ee1ab51", + "PF-E2019": "85aac7b45d2dc36bec00e7e3f0a6656c772603bab8a15918f0c84d814317af28", + "PF-E2020": "f29c8e63d7717094f37fa288da9ccc9c9d5afe0fac8027c300dbc0188ac44b13", + "PF-E2021": "0e4e8a3d48069fca02d0ad72ed468a36f3265d70f70eda2dee01162acc1b93f0", + "PF-E2022": "61c8cd9ea7a63e8c3ae303da9b4004f3a77b90a9ee2c6e1245dd45fa4d435177", + "PF-E2023": "0a3a72379e6d10a44382fecd3c1e871eb258926707362525ec27db5f6a456ff7", + "PF-E2024": "9d9d1d4c1e2a2cf3d5c2bc6ea5fde3ae61aecac28a24b9078726b652186b9896", + "PF-E2025": "0e56b50a4612a96e7bb1c57b10c406f11287ab6c81172533ad9ca15f3372b603", + "PF-E2026": "25efdb79e27561c66b201f530352e7ce5604770de4baf4d0e5771935de7f6fc9", + "PF-E2027": "97d497fb95ae41955206393a4e2ef7b816710f3c10480b93180d6c312459517a", + "PF-E2028": "89b597d48b73067a478336b754a6acd0664f45a42d97f6e40dcb3850920c3022", + "PF-E2029": "122dcb39d7fe0a5df448c1cf5c3f73025ebc4c6965ce18e6386b65a5c2bfe131", + "PF-E2030": "4ab4347203caf6d00258fb58782f2e7b80420dd523cd06df5598af14be996f47", + "PF-E2031": "eaa4dac3780ade5ee62eef9ee9b4ec056999ddf30d308918e5ab32d4013a469d", + "PF-E2032": "3d329fe8079b275e840c39272afb11e4aaa5a52505188b9b48abf4071f09484b", + "PF-E2033": "efbc7a86f3a9da674c796caeff4da7434480197d9c45a2f33459480baa0cbe0d", + "PF-E2034": "ef22f5d432f03a2dc566b1463685bbcca81466c3bba5ea998f659e0435d61997", + "PF-E2035": "a511375c29f85bfedd42fc3f5cf74ae82b71af2c194ea8034427574eb15fe291", + "PF-E2036": "41c444c5c720835aaa53b4142c4b6d34a808fc973521e1ac2d692e1f72cddf71", + "PF-E2037": "ebb86c0878d80dbf8bec308117bef93307a94d744c4938d1ea1f315b38e76ce2", + "PF-E2038": "075d265e09731bb954bd0d672d7d5b96accf55eb6212c21f9d34691377162806", + "PF-E2039": "4ba31bc50ef3982caeb131158bb9662c540e51ef4bfc87df20fd910a6eab6a99", + "PF-E3001": "585dad07e797bbe2cfffa9f45e14dee040be5570cc13f8e46fa4c31e953fc92a", + "PF-E3002": "db089893825afe5ad1d91934c21107fc58451cadf3d71de2539b9c5805549433", + "PF-E3003": "02571beee5163d1596d8a11fe49336dfcf65f86d4fed13254bac6b36023c3c79", + "PF-E3004": "30c92a4a2423ed23782509fdfa0d02682d40af159a89fd3f5ec30e52b9831cea", + "PF-E3005": "b27512de5b1e16f6de9c66b3af380f73cb2d00ff33fea04aae0124b1f86797fc", + "PF-E3006": "d515e41a6f5ca835e7c97ed36fe6e8f7035306caee4f2960a85d32b10cebf2cc", + "PF-E3007": "adc607a7be6f667a101d92f62e94673fcbe703ab350554475cee90d714013446", + "PF-E3008": "0c54e68ff0f24134fdd3c11ba612fd9f4b4aa9deb7aa9bad52097de20f9b21c3", + "PF-E3009": "93e2089d2f6b1166da22d7c535568cbc88054611cec98588e3316ce7e1aa130a", + "PF-E3010": "7ab392e86dd2e2af525f99dcdf4b0131c1ed7e04b46065456eca59b28c2f2f6a", + "PF-E3011": "50d58e7ae776e4e2742ae84d9b30ee4f0012635f63a6bd3925a05415cfb326ed", + "PF-E3012": "3025b79d440418a9a44b90af29fbaaa6271e6b1aa9a753c485672333bc93c8be", + "PF-E3013": "1c61bb5993c55e628d49bc2fcc74ddb70d0fe5ec99241e61d559a5679413f0e9", + "PF-E3014": "6e713393159fa4e055261a4bce2c51acd786bfa8983d99a7c9a41621834e8793", + "PF-E3015": "4fe4e0ce8cb7c74474bc150a3cf30945fbdb61a59d58fcd729abde947c5271ea", + "PF-E3016": "41ea29f6848941aba248ccd8758b5e7c8a3d59d16eb1156111b466308328d0ee", + "PF-E3017": "711540c06238816942a20884b19400e90a570c4522a2e8c5899627fcda185c78", + "PF-E3018": "7693ce91626e624cd7b34f9e1bafd4cb1eecc2870555ed042684bd8820f1894c", + "PF-E3019": "c9d042c5909224e235bc14d58dc5c72e169353f1fd4a33e1a3b37116eb15adb5", + "PF-E3020": "5b0f01cf980da850ff611849d6955308b5dde333e2f0158146c5d1cb6fda6d44", + "PF-E3021": "983e12fe1a725658bfad9d4cd2089c698e8e46883105bbc7c073ba220cc1085e", + "PF-E3022": "4ee5f80af914cb40f95e337d143d79155b26346a29243deaa8ce067c4825245a", + "PF-E3023": "4bd1707430d44d1482f488aad0bdd7e5dff51eb111c7cd0ed13bcd758a551592", + "PF-E3024": "bd7431d9bc2d8fc144c2829c452d3afcec4decd0e7b508ff527d3347069af871", + "PF-E3025": "9881b90b40c2461e95fce3dca594b447fc1e42c3ba777eb56f8cca55c4dd66f6", + "PF-E3026": "240540f1d9868496939346b81d8fa3c720d1fbb2baa1a0a27107cb7ed24db4a1", + "PF-E3027": "776c925cfe85f760df1e2d81de2c353452d0e021d4f73e963b6f3fcfddf21141", + "PF-E3028": "7c20dd3863c65fed5dec63c03a7d9b0934a8f391fc3fa187d1fe2ed620ce6c78", + "PF-E3029": "1be44481457f8bcf76e6676c491daf5a246c457cf00ec8b886453769ba1190f4", + "PF-E3030": "04c36e5e99e078fc3bc6a957245ce75d8c5a8482f873d85240863f0bd8f7cc2e", + "PF-E3031": "4e910f3b499eba5a7a7edb162f8920afde0829772050ff14d3f2434f56b2ec68", + "PF-E3032": "7538d36582dc957756555221c69053ac465a6d5e902b010fd282384b8d21e969", + "PF-E3033": "b8e9d8e06458eb719a636856867c319f60fa9f1fb477c4c3d056e4223a491a40", + "PF-E3034": "24a68838c7ca78e4379e7748584fa0fc95ef691ce12c30b911971d8d0d3b3b5a", + "PF-E3035": "ff9b23c8ec0b11931c80ab757cfdf86f6a5e049844525bfef2a915ebd329c16a", + "PF-E3036": "379e3ba364a2257d4fe7c4ab33b969692a8d2a9124aea32ecb23b8b61be2cd2f", + "PF-E3037": "d24782cc7e4059c7904cec3fcf1277d54dac1d3f0e3883237e1dfcd28b481026", + "PF-E3038": "dea3cd644df59a17e6b1491c9de32bde1bf8cea839697e0d186fa73ad8ae4342", + "PF-E3039": "eeb033eaa1b1b0e1939083665ff51fb2f7bcf955aa72d6b9c95e962303d28973", + "PF-E3040": "57dca44dc50e2114d70a51b47706757a9556e7a3cd2ad8b7e243b5740da6b96a", + "PF-E3041": "36c80fb2a5b1b16722243b9569c598e7e7e87c11de53b7b5dfc69b4ecbde8d55", + "PF-E3042": "1032bd408c44b2fd63032cd1b8f373a59f48247a35555ad61b26612cc8017638", + "PF-E3043": "a293bad272705e6372d64b989d12aaf2095fdad958493845261b725e2aaf9471", + "PF-E3044": "68431710d5accc37798cf8f9afe0979d07818dcc9ccdbf24f1819ac9f09f5bf4", + "PF-E3045": "d686a941d65041bf613b024c84fa88b3fb00638311dd78c72ca7dd84f76e600a", + "PF-E3046": "0d0d7ce8d2a671f1ee6416ec5ed8ad65d165e2528c84d421a0449a9d37dbbd2e", + "PF-E3047": "88d13163942c51a33ebc911f2b1dc0d636c9366ee733842f6ca6934574156100", + "PF-E3048": "48efb37648f440d32f7a637816a3634bea9762cf713614137d2da14f2901d0e6", + "PF-E3049": "cfc66c64550821d23910f6f4c24b484d7842ca14fc37b61841dd79d161ba34e9", + "PF-E3050": "8ed4310529d2c09507a487a80fc0c9ce074d2492895683ffba8c33462c3b92fd", + "PF-E3051": "73a4c7907bfecf50e16e4fc69e0d5c12094bef6d69e578b316c1da06971990c2", + "PF-E3052": "02341847a530a199ac6ea78297f0ddb7f6142573b4e30cee15611c4d172edabb", + "PF-E3053": "05b3cae0f8db6c6363d4de7aff1f7efc99313b1a7a46f4ea3db0d6fd8be515b1", + "PF-E3054": "70e845dd172c9f8e89b8c2c07067685a40ea0015c3dd3125769f43ad56dc8e6f", + "PF-E3055": "f3532d0dcf66c9e5e2de10120568da28e6421b8bab9e25f96a5c1a44e1c15423", + "PF-E3056": "0f65bc68665b101cb594b89f0b192172277b54d84749885f22b4df0313ca5201", + "PF-E3057": "0cf35717f2db3b2ad03512968f22b2e38443ddec2cbeb1d4870908c7ed026358", + "PF-E3058": "8877da23dac5a0512daf5ba443caa52bdebcc51109609dc4fb7bb6577f0210c8", + "PF-E3059": "7b0d7eec835355b530d8c4acab5cd2f285ed25a5dc6ba58e0e6a4d7028ebea70", + "PF-E3060": "faf673d59c3bb1155bd0c697a59f714a8c508aebb0ecf18faf1244f113693610", + "PF-E3061": "56b82b70a64a499049ab49966d091f05ca2847fa4567a90bfd9b5b5446728ac0", + "PF-E3062": "2e3fef0b29a5654fe9aa94dd63e809305867d75e1cec6b7c22fda9ff73fa7e12", + "PF-E3063": "dd827b422b6beed8a362ed4d701f0b332c1313128f4fa6314225bd59762ce40a", + "PF-E3064": "3e55a1aa079d8ef66a670dcfbc98fe25f6dbd313e500ac92e1c573ca8ce45eff", + "PF-E3065": "b1199a376f35682e6045569f411d57715a70ab4bc292536d3ae11e40aec66e73", + "PF-E3066": "888ea9891258cf61257b539f4c837a801fc8c1affcb93caf73baebc7f3939dc6", + "PF-E3067": "4d050afccb8b8bd64256238a4e83c8ae32e4249a66d33d977b88611ec5b18a00", + "PF-E3068": "31b5428ab11778685066ab9085c3dbbc1aa5cc6c034babbca578bfcbb4da9da6", + "PF-E3069": "2c927584dd73c18b9f72388cfe833090b7b18053883278d3ab1ae6aefb86e90c", + "PF-E3070": "89f2bbbdfc1c6b62d275d168f782a3169d74266b90405633cf088a629294b3e4", + "PF-E3071": "1c3b76ed0cafad7c7a49cf6977bf8ddcc226f25d19fdc3601ca04c95a2c3ac36", + "PF-E3072": "f5ab203002eae57f227494228a2c096c8935f45dc43b146355826180ad1eefd3", + "PF-E3073": "db3ed98dcc439d7cac19ac14a4e719ef765706783635a7387a93121606532dbc", + "PF-E3074": "311accab9caa19401417639c92f9b336c7631266b500ae862a5f67c17bb23a66", + "PF-E3075": "1cfb2fa455c10d22fbb230ba062d25fd55027a555cd4fd15d9c98c4b1018657b", + "PF-E3076": "65f199f6133fe6fe03df22d6d33eb2a522616c2676de35d486029a4ce3111bfe", + "PF-E3077": "ed731dd2a1d3b1044e72b12e0a10cfe303cfc359a6a655453ec9487bdd5260d9", + "PF-E3078": "24d4fbfdc26d18fa606d1afeac138ef9546035249958c7d363ede349a4bf6d2d", + "PF-E3079": "ec7cc428c444dced4bed3e25dc4e37278c7ad8a2f659290d11f6ee355b48f0fb", + "PF-E3080": "59e78716bafd85494987e59884ccac02803d82e3482733b14f333dba5bcd9e73", + "PF-E3081": "709456204e38b0e972819db0d9e85ffefdcd20ab67d937c2284fcceb81dcfc82", + "PF-E3082": "fdd85a7923b61e8a61367b9aacccd6b43eab99b291e9c606dfb5d2421bb93292", + "PF-E3083": "947d155627263c6d7417146733d064eccc9fec32e653eaac6a252654e89aa9ad", + "PF-E3084": "666902f8371b1764df2dce2ba69af06cc43206aceef5dac223c85a62561170a2", + "PF-E3085": "e4e5981e4a41c4c6fcba7388bcaad0669758cc1aad095e4be523a588360fe5d4", + "PF-E3086": "eb5c7e9bd4283eea3823a937bd0ae1259e357586b1786c9293022afc3d238347", + "PF-E3087": "90ccb7ee991945e3233b409354e8f7b6cf9ea8439105ccb1469588ca98f03411", + "PF-E3088": "938373f4ceabe600e7a0e403a4f1ef3e90cbf74b522c761e0bea25d26d0a4da8", + "PF-E3089": "4e37fb4a30227e4a2b0162a9792059684b833819a4f51d2daee8dbd439b4cbcf", + "PF-E3090": "9f826e60755d3c5aa7cb956403a81b62f5395dac54f04e019c913476f4992870", + "PF-E3091": "3d56a8c1b46a3b0d16b43e5a6fb2cc0cd581d62a8ababef3931dc92a8691da4a", + "PF-E3092": "557c84b19c5680edcd1ec9807341611cddb8d5d035b221f9dbe5300d9d132827", + "PF-E4001": "f488e6af6b2b4f79cd67174b1e20c64a341f2662890bf94fc0238548bb2ffb32", + "PF-E4002": "9e14403bc1e30a4a59b40f55fa0be4f45d27cf31bea9adc97aa71cf599d39ab0", + "PF-E4003": "a29480e8883ce324fab677201938a847c6c51ac817c9f6be9d2173f2d7e0c530", + "PF-E4004": "2d1f7222de792bf9da7c4117f826e251a24256f7215c58aeeac84a63e6314a47", + "PF-E4005": "682221de055e538dfcbb9cd4428db77767f437ee864dddcbab812252059af3bc", + "PF-E4006": "18776bdf7ecefb78c2f66fb997af5761d56fa62ab65b65548d8636f936ea8d1c", + "PF-E4007": "d60606d10795ab11cf644eeff30f601300f3bc8e31197ab933fa9e24fe4f2193", + "PF-E4008": "7cbac16f5fc9c50c8ae841f067f843ba0162cfd370a491553d456cc7d16514d2", + "PF-E4009": "b2c5ef94ddb284004cf13bd78d30dde603395c5addb757b8a5dad05a9a48a076", + "PF-E4010": "af39b934f1e15c6dcf70a3ddbabf73a2befa7c5790d24df274d4153ffe882dcd", + "PF-E4011": "55750bb97e776607662ecd192af2b15dce424dfb18c3e273cd08b438e68a7c71", + "PF-E4012": "df2a6ab9c7364bd8b01a7ff481d2f17c9d14f16922dca7007c6d77fa319b871b", + "PF-E4013": "0566b5cebf055d8bb3dfac83ab33c0d309f0451badf055e4cea4906d6727b7ca", + "PF-E4014": "7866740c5ff6ff5b7ffd5113b12fb329ac060b0c9170df668b990cd3e6a4054a", + "PF-E4015": "9518640e1cb3181331426ce5c31d1125b2bfe150d95db78bf190eab155861bf2", + "PF-E4016": "552b4d836cf83b773847fdae010b4794bd946cd9931cf00d308482666bf914c3", + "PF-E4017": "1388cd20dddb1f3ad5540082c643a2c03954917e9508bdb65d84d50e1905291c", + "PF-E4018": "ed25566ffaa80d09d3b92d69a01c73e7551bc5a3365aefdc676a0ea7f422dd05", + "PF-E4019": "937b171075ba543e84ed71ff9b7115626169eda2500066479c94baef4fec3232", + "PF-E4020": "9d15066301851d08f2c8d849ef623530a38d54d6e25b425f399ac0da2088307f", + "PF-E4021": "e605234907c183c48a916a70b7db6a33f69aecfa8cd8aeeee1071baae334b61b", + "PF-E4022": "1d372faf58013c48d90a412b0d562e7868fd99d9f4b5cdcbdaba4ca4bc6bcc40", + "PF-E4023": "f68a4b1f9686b9f9532a8036e9bb6924e8dbaabcb908e98d52b2a5b62500ae4f", + "PF-E4024": "966c481aed947817713e3095525e8966395562d828ea7dc779b0ae676032d27f", + "PF-E4025": "187a2208ebf37784688785aae87dc90dd7b1e1ae760f450e7fd434bbb7eb2168", + "PF-E4026": "95816d33bae90b8680cefb34bef1232e2664771b14ccfc22ba29eaa344192c00", + "PF-E4027": "10ef01625abfd0380c0d6b7f4200c544ee954cd3db76f0b5b37340681f64e190", + "PF-E4028": "ad86f34f27b9641be2b8f3a065b7da6702530f88594b49fd977c9db5c0ac3356", + "PF-E4029": "a6124a0e3e1a4c5ff0fa640b5cac8a5bc096637ff9542503b9045c8cdfc499a8", + "PF-E4030": "b5e7647566355817676ee5b02cfe1aeb1ff2628484e9725d13fc07c9a35ca99e", + "PF-E4031": "54375fa2e19043fd9bb941b1ce444169e7797dafff91d58142fcd71a8e41fb41", + "PF-E4032": "c8ab521539784786f2eb3d398efe8ff0f14fbbeb2c40664562a7ea55883f6e9a", + "PF-E4033": "f9da466aff44be8a4227c45596b89320c35b3bf2d672abbb8b47498a51f3b3ce", + "PF-E4034": "36f9a37eafc908fbbe48a89bd3549978008dcdcb8613a765affb4df1c99e25c5", + "PF-E4035": "46fb8fa1739e4203053f5d5e0f22202e5d71f281bbb40620c7e77b6546bd9a95", + "PF-E4036": "4425ff00810f89e55be7ee7eddeb873a25f5f4a37ac6b65ba80f015b497b5133", + "PF-E4037": "c8cdbd9fdc3e3106e2ea79e646b0b4d1124d01d1bd778286349666e590b80af0", + "PF-E4038": "39dfc830adbd1b09db8aee60928439c4dbedc552cc32d6b27b696893b071e162", + "PF-E4039": "47c1a304fa37e4d1557fb6d08e892cd045dddc1553031cb7495f58a7176d41bc", + "PF-E4040": "ff1e347a6b9d2e36d2df9fa67488ebcfbdff768df88f9e65da86db81c41dbc85", + "PF-E5001": "04e2058982eb91b24fa9fcd9b34e87606b9ebe055310db68959330ac4f0ffaa9", + "PF-E5002": "b7ae068582d018dc2c7cb9adb652a8104fc5eb1cc18586d1f85005149087adee", + "PF-E5003": "e4210864adaed289355b23f7ec5d3ea575487bc557b8c7245111227899fafd72", + "PF-E5004": "d3bc99e3f0f94871dddd9547078bb668ddba7fe40bde89dfa8d305216a8d00b4", + "PF-E5005": "204eb55fe807f4736f0aca9c34be460d0763e8c02b93bd831402f7a12c4303c2", + "PF-E5006": "4a5c5ef12e9b969fab905900be479d89ba2281a2f65b41fcbfaa5dc8b9d181af", + "PF-E5007": "10ce4504551b8cb335d1694deed9f2495d796bbeabcbd369527a90a39bd7c872", + "PF-E5008": "665c6b7933dad5d098a83008ae473604ed03e4ec143543ebd1d11ac18212d69d", + "PF-E5009": "07116bf8df21a5148b6ac62df823500b4415de4ff2acf64b43181088257b84c5", + "PF-E5010": "405bfa5289883d26290252f4677cff8a3d1b59453e2fe1ded0dd8c8ea5d63290", + "PF-E5011": "f5d0893cfaf3c6901f95a12ae4dee63e1e97b73b757e80e2a219ebfedf2ba1c0", + "PF-E5012": "e0617aee147c8cd97850ee3c54609a5960710504423217c71504888172b6496c", + "PF-E5013": "6fd31d44cfa20046024611014aa701dfa5cf0f3bde6c4d2a6f181a28fbb98879", + "PF-E5014": "863d618ac9fef42b3de06f295df1a1ad00119abee6dfead7bcee84c445b71bd7", + "PF-E5015": "b915ae75b0a131301a37b99cec950f40841c1371185763ba0ae65a2aefe16bca", + "PF-E5016": "f6d5884fcfee5fddd9c3ca5f81a3dd4375b2a898545dd43bcf180f7b68742cf6", + "PF-E5017": "6f9c3a691ad59bf4e9fc1e98dd2cd477eece44b050e5b0b20b388816241eb6ab", + "PF-E5018": "84268b01b55420bd5e62a35f1d0fdb446e11c928ad344b939524e3e170003d38", + "PF-E5019": "5f11b33a15d19e08d12cfd9873e13923bef3ed78af8c677cacdbad8fc877a1d3", + "PF-E5020": "39ca44687806d7a17dbba6eb7cabef6a33880be8afa256677d56d0d6f6668c6b", + "PF-E5021": "58afbc952cef2bce7cd77a74eb9b5073fe8749bcd37c5c7b830d26c8b0bd4e8c", + "PF-E5022": "6a457ff496001807cb555f5070c6838758095c531ac0f36cf266ff863fd87c76", + "PF-E5023": "5fb07b636df4d93bbd81e67a6632362ba66796e8d26a8f6f8b5d41a4b47a9425", + "PF-E5024": "c8bea2b0778c43595418e16e1c656b66347667d362c0e83ecddfa0b56cd886a3", + "PF-E5025": "2ce9d266a1b40c65fe147697de35c4180903e25708eeb3b594baa12995ed5a53", + "PF-E5026": "0b2666a4475d52908d7392e3bccf732d7e5513f1eb1554757385cc5aeebf5da3", + "PF-E5027": "45fce1e9cba07b431f5430f97fb828b3a9beb540345f5bfe4f9914a0bee6e53f", + "PF-E5028": "9624dfe8451b9ec78df8bdd6cb20f136520135b46baba2898c23c365885dbba5", + "PF-E5029": "f7440d96eb7df08cbef389812a8a78f1a48f5bde6c6fac8bf24fbd61264d8cc7", + "PF-E5030": "9292925cd16913cc6a693697c7636491c455bf798d6504cf518f00afe66bd19e", + "PF-E5031": "e73daf5aed4a5ce67b624a4f1ad8acbebe050b3a422c30d56034992dbb1c6a64", + "PF-E5032": "989222460925cefc468f409537361e9a739a72349e36b63414f2989b3da812a3", + "PF-E5033": "501f91c1408149cbcdea5c8f8b53f7489afb543cb1e411c6d5afffc6136c04af", + "PF-E5034": "976c651cfd3e9f826f2ff26f92abd9d5a943c4942e5ba4a273927c044a2ec0ed", + "PF-E5035": "ea85ccb044c93f4e9329a6f882d33b4b737c33258d787ecf027c5286f1459e90", + "PF-E5036": "6146395b1dea5a398553f2a6960cb20a07fe384ddeebdeb1699ff87a61bf7ab1", + "PF-E5037": "494d9d549e10168477d768e2ed52f7171fcf045a17821a7a69919ac7edc59e7a", + "PF-E5038": "f4c447d252efdc61dbb5f3b74c9b9b58ba4b27be14102fca64a9e7abf530409b", + "PF-E5039": "27fd87deefc6f35aa11148653114a8ad6746a7da52025c8bbd2a9d4e82e827e1", + "PF-E5040": "4e25ecaaa4c2ee6bd69000fe29f16effe048ba0c95279ff03c9c11f466ea359b", + "PF-E5041": "fb8be86ab36e2d281326e6a67adc6cbdf1789deff4e6f93677b8a8d8abf9b02f", + "PF-E5042": "d1cba262c0b3f4de761593f7b2249c15afc212a5dd9a0df8b869ca84544df276", + "PF-E5043": "dfb8dbb703ad12a22bc5b74484ff987e590b342a8672fec78dc7b4053984f407", + "PF-E5044": "cebbe9a4cd473d6061052b4b078649f02b2cf3dc813a22e773fa43c5e154ae3e", + "PF-E5045": "ce94f3f93788b32f392b9a7a6688adbece65e01a48064be2894be9452e6781ce", + "PF-E5046": "d4dd00e326d28d6af215bd61a9cf97315265a37cdbeb07ce99ba2d5cc1d6909a", + "PF-E5047": "93c3ae8727904c6a4411f694508c280f801b8c0994213f7618482784e205fac0", + "PF-E5048": "34167e8b4381fbd6e0568d5cec5e13cce82f87fad7f17e2b2799a239de7b1d54", + "PF-E5049": "324fcec1de2fe836a4936f0117e215267ee54ca841539d9a754391f6fa629a29", + "PF-E5050": "4df3e307482c6d28cec9fd53682643f14df1645497da8f726bdd85baf066122d", + "PF-E5051": "951afeb314989372a68feb444c42acb6048a23da7b7143596fa25a7bdcac3447", + "PF-E6001": "62ad4d403a565609c34596b1c5d3982b990b137e255b3a83a97d92699ebe67bb", + "PF-E6002": "655927199576b7c06dae674bcfc6f5750c801f1af0564e862894c1e47a211038", + "PF-E6003": "8e9601e1627f343fada36b306aa9ecdd3239161eb3dc6a0716a664dc77e32b1b", + "PF-E6004": "ca9cb31a91aae0b4af0a6e37e137d12ba98146fc50e27768df6711e5e04b711a", + "PF-E6005": "5972b6278ffe2e4287aeec29112f93f92ff4b8016e3e886c200e98d0bb4b0c6f", + "PF-E6006": "200248af4b91de9c4be5391d828a4148fc05d594b5176c0b549548c18444ab5b", + "PF-E6007": "5614e696159ba2e71699eb8a53b3dfffc31bc1d3ec995eabadec32b80e8a6976", + "PF-E6008": "829032604cb717cfb53d832a8f88f24e7c0c833367cbec0e96097cadf8f69830", + "PF-E6009": "65b87ff5f1ff98ad28933218a6c424b5d88a44b2d10fa7cc7eeda0bd7524312b", + "PF-E6010": "b253302f63d44a2e561b0ceabdb6bbf345df839cbedcb9310556936cbb5ef2c2", + "PF-E6011": "bbf9a3ad1d1d60af7e6b2b62649cd4a37f795c033d41b1140a5d7cf09a9f3e41", + "PF-E6012": "969171f1eaf55ad370d752c32723232b84e96f2031f209fe756b715f64752f24", + "PF-E6013": "5ac43627a5ef99857754f9448fcbe24cb7fa3d79f26baaf4b423f0663cb0eb84", + "PF-E6014": "583d103570ceb892ee470a889f26c113745cc283b8f9061cdcbf27cc2d741342", + "PF-E6015": "f6c0e557ca3f1950ebba25e317978b52f0ba3a5a4c4c1edd668687b75e451656", + "PF-E6016": "04e35e80da2d34de9bb5230ead53de73d5728f06e547f75daaf7783b8e8f8ae4", + "PF-E6017": "3779b7d37851d76c9098cec76f3d7b2ec2002046548ad62ad11bfba3bc6d203d", + "PF-E6018": "6aefea9dd569e689b135b1f37a973b6e111dddd557d10a7fd0084d81acccf861", + "PF-E6019": "e94c6ce6de61583c455e625b6c78ef79b453efc6292fa601fa1400ec31bca7b6", + "PF-E6020": "a3c34182a2cd26f73d832c3ac97c1bc812fd9fa992f61019bda5ac50a74fa5b2", + "PF-E6021": "b14a65e21d0417ffd17f8d3ca4fb0417309af0bef4e73d12da91d7e51f8876c7", + "PF-E6022": "d6a05a4d09b426f6ec97751bd631cf690514e288cdf971d912063c8091e7e7ac", + "PF-E6023": "a155c6d5e72aebd0098e9d9ad69e4a20a6018453f1a93a35b8e91c7efeab423b", + "PF-E6024": "9cc312f293cfca01cbf7f6d4431b91b3d57bebae7394f15093ceab7932abfce3", + "PF-E6025": "ea5ad100f8a103eeecac6811e51d5e7616ee2d0e70cbf761a44b26bd3360be62", + "PF-E6026": "dff1f35e05559ac29553db95487021b6cfdf3e706e7dc207f8046e1e4b624462", + "PF-E6027": "cfd2ee75240683c804cccb895a51b679d35bc3276e34d10d0c032e4afa42c346", + "PF-E6028": "c0a3d82ffe92a1de0e5807616372f6133a64c59b25c7d41ce311e2f4b567d871", + "PF-E6029": "2d5438da4f2f94a1209f8c0f28dea07031e1b9f58f66e20c2d902fe59c523588", + "PF-E6030": "ee9c97a183b9db36b5b9e84f87a1331d03c8e7c90361707ff458dc010d6608f3", + "PF-E6031": "e2017709dd3089a5cadca80667d748914888b961932e1d21dc541d08225e1677", + "PF-E6032": "ade97008471b06d9b8243950fb0a2d35a03b4eb3876f1c358678da1170efde47", + "PF-E6033": "6199126cddaba0722cf62336b37c9887b1fd7250b38d4790965b6a444ad9a6f9", + "PF-E6034": "4394afe31b0004546ecf6b1ac1f1f0404faffd240d2efecf62835334b23050c2", + "PF-E6035": "9ad90a8374eb52b526000b4ff52a01d46e74dcce527637edc845d090486b8f0f", + "PF-E6036": "364d57d37af4d528ab3bf77efde83ba0b1b986a4efb3e6749459b69f37f402dc", + "PF-E6037": "3445e26f2cc4757069ccad0743cfee05cdd435267780ad5c6cd32be93fde6c4b", + "PF-E6038": "f1b432d1f37b943f87088e6377cd02f5db308d3ff3421fe4d96d1c6b7c4ea75c", + "PF-E6039": "e5c41a3431ddbf51ec6afbcd4d3dba42eaee3ba8483c74df89a0344cf64275dd", + "PF-E6040": "7893412edc7c7d3247d2ce8778fb0dfc59a8aae9ee40ea37451eff20618f8d65", + "PF-E6041": "ef405600ac0f7abebf36d25d6860f81e995fe1b97a661b3ce0a06b2b49a9861b", + "PF-E6042": "a81947fdb8c44f9576f3eb96a938796f57a069a1602187f3bf8cd6e9b7b1036d", + "PF-E6043": "a2b0e93bb65804205b715cd976b74837344058844887724913584955b1ffb150", + "PF-E6044": "b71984d7df9f1d0b4b9f64f50eb264548ed4a23d9c1eb832233923feea9c456c", + "PF-E6045": "83352ac09287010e7d43a64f802c8d42f26495a4bd528ef3b1fee2a29daafa81", + "PF-E6046": "35a1afc1871d257df1f4c02d18a244913192ca7e962311327270aade49181486", + "PF-E6047": "b2182faca0b5572d59ad9cb3ea5001d11f0116d0e500960d1dee5c158abc577a", + "PF-E6048": "805ce49eb04119d760e68bffbb22bad5b4b75968b243e4794a725700d9e2551c", + "PF-E6049": "98b80f47308ab54f439260d9e01cef201fd53b487f0b2dbc5ad191b32d984ade", + "PF-E6050": "b683d41f27a593560d0738477da76b74de0011f0d79b68bca36c6cd05013fc7f", + "PF-E6051": "2c1d8b51b6fdeebf33928d1c43aa0de96c92552f3e7e3067de1d48d82724a88a", + "PF-E6052": "f2d9b8311dba1285b023c6acc8bffeb990565a8dd8b0bb87d9bafba265ac0a4a", + "PF-E6053": "b97e941cab43e1a060311be74fc3dc45b4a988cf7d74d03bea15b234f50c362f", + "PF-E6054": "02a0e5049125602b6151b55a1cc132747381358b7036740d7bb3bfc497da9b1e", + "PF-E6055": "2136cdaabbb52e4e3cc52d6b1a05d06184b0eaa04ec357105787a6334cbbd007", + "PF-E6056": "b3a1b53a42062c311698a90d9d63d1ce5f18b46c7491b6d595029071db8a916a", + "PF-E6057": "e72f5e5628bdbc03701121156b498787bf6f2f55897184c1217400b5a8668933", + "PF-E6058": "814945420c3e42c79094ce37c0993c588b97cc94edd15b7a49731124c65b8e01", + "PF-E6059": "ddf160edda66996a5223434bb1d888d22a1b05862b4f2e7c6ff9be15ef693b15", + "PF-E6060": "afacc4dedd9eb39ab83a580ec7d2f81881d82f586000d330e473cb947354ba40", + "PF-E6061": "009fcb99a223fe1938d4f22457134091de127ce55b16a53918fc07baaa8228f0", + "PF-E6062": "b5d3dce8878ae83e50c99eeb05b32e3ed3fafb5ae0a02f535fd0992a6ed1dfb0", + "PF-E6063": "2513f9c2e3f7e968d1a9823630fd003033699c01cd7871f06b9031f335f17c46", + "PF-E6064": "97d1eb11d24cad3c2603079b1a85232c7073be677e8df925015856ddc2ddbd6a", + "PF-E6065": "342f7805ca1aa8205634ca956d73c1f2468f3deaec388f9572dfd85d94c43085", + "PF-E6066": "58840efee0a526f9d2a46ace2d847d8f5b0b53bf8ddef017e8e1e76c48ca27f9", + "PF-E6067": "1c89feb7accacad9bceb84f97fcb197fc2b4ae48783182e7d851278c779c9e5a", + "PF-E6068": "e2059672991f969d82e146f7227deab160959baae5c6833efc6d6a5baba69012", + "PF-E6069": "3ba8f6bf1019bc7762a219c3eece52b8b595b0d423d4bdd32ba9922d5cb713c0", + "PF-E6070": "aad05a3d0adc2d6d477ca539d0b6e94f7879bd889927ed9e1912cc223889dafa", + "PF-E6071": "b703c64f091dedd6174c3dfe9f7948afa0396baf64661d69286031a87419a6c1", + "PF-E6072": "e3635393fd9ac3638e3a025dcca91466a8e108afab18c4a0650339cedf56da1d", + "PF-E6073": "f6238ca281cb032b5fcedb9f8ca4f9e01ee96606377d8b79a4b7a5a02808c216", + "PF-E6074": "00937d8d72d30a81287f621132bc7eb01c236435fc71b5bdb27a9f586c0cf1cf", + "PF-E6075": "0f46198c3c4c81b3e92ba41954d614808ad380db34427287bc99a596fecc4c7d", + "PF-E6076": "c8bba3db26b3172028973a7b3754b7efad1c113c955a8626c84d7c624a08e614", + "PF-E6077": "99ebf94157bc99faac148e8786ce77af3857f20dea9d627955abfa6d970e3f4f", + "PF-E6078": "fd6178f44f7cebe4dac1c2db0009e8fdd3cc3611db2d66d4a9f4ee9c25beb336", + "PF-E6079": "bde36a0ba8f97cf5c48a339f93f1ece20e4d6afff2ae7a1884419faa1b230bb0", + "PF-E6080": "e930f5ff5fa26954485cbc0cbef6f7f56d1c66542a34f7e3025cf52b99bff523", + "PF-E6081": "24aa448c9cb20ef226aa3c2081ebee41ed0941f6281e658c1aab39b1fec0733b", + "PF-E6082": "605983784926e135ab5f41456c85c55ea68391d12774d5aa3b72d39e0b0750f8", + "PF-E7001": "233c520405eb6e3dda004c28c313fc77875fd7de8392af94c0ce5bd8367f4717", + "PF-E7002": "26993d470cbd1804937d72c282186c29c5f375059372276d3a9f52d6c0a39878", + "PF-E7003": "20f8958cd0e1dc67bb5dabacf0f7ced1e32a6233b79a2a69d1ca98eaee9bd366", + "PF-E7004": "084f19119896bd908db1d45322e6f8d89e3d01c9a9d76c6d8065c863b387cda2", + "PF-W0000": "7421c978182c16430cc009ca2a7449e607384eefbdc1aaa278fc5337146b3526", + "PF-W1001": "93247da40121bcea58c8c43e7b898685a6f12ebaeed2cbbdeb957a1d023fc34d", + "PF-W1002": "2ada4236c2f1bfdb4d62e734b64e13703a085329ce11a20df09458d8a891f49a", + "PF-W1003": "aa49c991dd37f11f31f5b847bc18c45bcba2e71efec65d0059997438d9ff6dca", + "PF-W1004": "07d3fd39d1388933f426e97cf7453fa3ac79b2fa9e8f87e21fdbe3b72e3a6a6d", + "PF-W1005": "95e14107e2c6bc6f802aa51c03234ea0b89452ae962fbc15b884855e9f3240a4", + "PF-W1006": "86878b51df714ca47451da2ce647b28ada9b0adce7ad288221efa866b32d4733", + "PF-W1007": "c662aa1cce95f062b82ba4d845081457e02951140332be5e0a8878b82a285a94", + "PF-W1008": "858b1448d6448f4e39bfecfefa62b993ef479ecc86bb0d7c6bac5b2aa0481d73", + "PF-W1009": "56c44a87d07cd60e86e02d2072415a0126179a44d9bfc891164b9033d1d207e7", + "PF-W1010": "86255f80abd859283a3a707a4b4bb6bc0dff474aac85bac88ed5c8093670426b", + "PF-W1011": "74d4c7e94f884165fe0b09aeb1786bf920899951eca8797c15da1245434e42e1", + "PF-W1012": "bce98a1335bc788aa77a903f1e2012e1ef8f03903a4146edd3422c3dd6189637", + "PF-W1013": "65d2e4c763c8b47aa081baaa661d9b2b66915a85e118013dc8f9f84e1f35121d", + "PF-W1014": "b3821009d1167627a0771981eefed44231dd222c40364938ac3a101ebceeb7c1", + "PF-W1015": "861f8971389b73de5d823bac5aa6d538356a2df793507130da745953203881e1", + "PF-W1016": "5f036c8234ed86a680f98559e9e706dd15456efe6666ee9617ca2f1e6296715a", + "PF-W1017": "068ef37cee1d1c895e75a1803af48fca2fb36d5fcdcff3fd4c6b5d98bf305fb5", + "PF-W1018": "2bc502b1f786e867a19520bd32ee77d88295e65baa64866ccc131eb4a84c241b", + "PF-W1019": "127c13304e6332f0d86b80c1f8f13660f00dddee122ac306b6c803ddf80be1da", + "PF-W1020": "f4b2c96e9a76f0ecedc59d301f5ddd0bb11ed5ea6a79ede6cd086d7484bda9f3", + "PF-W1021": "31b93326d878800a90830403bd6d5341c6921b2793793f1acc18ea39485a6d08", + "PF-W1022": "250c0b060e425f508e15a1e339423cb32743207b35faa7367b5559d221e2bb00", + "PF-W1023": "05c00b40a088c35f5cad483619bafbc83e91f0899deb53d654d968e598776054", + "PF-W1024": "51aa8638b0834a668cc9fc2b6dcaa4e9145b1cae8abb6fa3f61ca2e2e6df3d67", + "PF-W1025": "95d3664957a886cbe29a52f49466a41769150a71405aa4736b7fd4e900fd7381", + "PF-W1026": "5dac6a6591da8337312b2af19cf0f259edefefe79c82474728971b296614347c", + "PF-W1027": "0ce6b40a0c67d7ed14ad25e63bc3d9d44e0fe10b911221fbc03b392a2f131588", + "PF-W1028": "50d2df17c0d7641efc08621157bd50c38e2c568df5681b54cea2036f8bde3391", + "PF-W1029": "78ab49390a6c18761778a5caf0e6bc9060b31951c86cc74c49b4367e3f3c7ce4", + "PF-W1030": "63a79bd5c6a418137c60f97a538a74f8fd71009b0800a0a2be923b43e8042cf8", + "PF-W1031": "2cf4e6750071dfc6176e3a0aba0b4e84f34952db8bd0ac9370908af914ac8627", + "PF-W1032": "9cac4824ebc0657913e21d476aad66fc431f573c53b13b915bf6e413399e3e55", + "PF-W1033": "e569bf0431ebe863479fb6fed1b6209db2f70d92c94fdabf72191d83f2462c31", + "PF-W1034": "c3555e3429657790e5b99756fb1853df693807793839ece439e01827b85c26eb", + "PF-W1035": "d8442523cd1a9f4f14aa6d07f083aaf5eb105391f387f001ae24a952570ca8c5", + "PF-W1036": "fffdba49adb40c4d16801e7b2e4d55af34dc6c571d01c6058f6b48436b417732", + "PF-W1037": "5318dba34bec0d53c2457d750b944d60879a301188a39459733364d9e7eac383", + "PF-W1038": "0508c42d6ea84adfcc9d553fc189d4d96c61b9e416fad94fbb4f5f2623ec2784", + "PF-W1039": "c10cffe8f581ecd48bb5b2b8975ba487776d1f68c2155191b56d4976c260854f", + "PF-W1040": "2bb166e0b2d0df866c1b1e3dab389319781926bf5d61d870d3450c57c86a04b5", + "PF-W1041": "85dd2db20f4cfe95f374a5b7d1a20924f2f627b0e503a5aa2a00a077ccd239de", + "PF-W1042": "bd9db32a813d9cf5d9d79c4817174fc1e01ec75553e742cd4cc5dc79425c91fe", + "PF-W1043": "625a76246fff5c74368533e2b5516482834f0efbd4a45f91ced7334ab1a44189", + "PF-W1044": "9003820b931b01b3f8bc92eac8fe647cad126d1459c48b510da072c652e65133", + "PF-W1045": "560983a7123ddd1a2c3daefc9ad713a040d43b07cae8ae47069e6f81dcc2a6b9", + "PF-W1046": "f05663823503aafe68873e5fc8d864945b01d5cb8978e14a102038199a1a34b2", + "PF-W1047": "0296cfa2b46d67727d2f9dee18160ac9a7e079cd11b4c7e7bdceaaa5dcace4cc", + "PF-W1048": "d29953f131fa2e4df91dacf0b1a780342e027e9211febc153296ee20fe396667", + "PF-W1049": "b2da9c183f88d308e4715bdd7b62046fb3226faf6c5ee17f5ac7bcca32dccbbf", + "PF-W1050": "f9e54b91f6507ef6d95a1804e247b8ca7b08120a80a453fec11a227530263b11", + "PF-W1051": "5345255b13de28015511f26e324ce92ba4cb56777e3d0537b55581cebc50a006", + "PF-W1052": "39324af6060618f183568526eb29b346c79f055129ec9853c075f3524e2b727e", + "PF-W1053": "d1c27468a68ad70da01bc602afd7a52cf94199c6a640b73375d70caf4b599373", + "PF-W1054": "320e44c381eca970c001925d150513dc17943a9445c6eae334e9a8ff1f952f91", + "PF-W1055": "2b8e3c148b72b5888de56714c3c1258fd26a186d633e63ef06230af7ac753020", + "PF-W1056": "3b38438df0ba0ac764028e5cecdcff712c7557b828f4d10a4dd3505958644bc9", + "PF-W1057": "cf48d4f0ad54259de222c1db7f0f81bc37d96fd9e0bf88dfe1c8d29d82310727", + "PF-W1058": "90f8afacd46169aeabf07f734e67f1b665e58ad7374dffbc9bf35b21714d5ed4", + "PF-W1059": "08d7f32cd223a0c570e0cf2c13a68f9986527e457ecaafe5d3fb401fac726cb9", + "PF-W1060": "ca0f6ba51b1ad6417abd4acb1e7b416719aeae1533fcbf3782a8de9d45d2d2f6", + "PF-W1061": "011c7e28c32d44c26b539e05d57e4b256b9d2381acfcec595e32b59576390fae", + "PF-W1062": "46b53f4f1a68c87bf2e7d508dc078228af9cd8235b6f1a5d00c892d5b3f2afff", + "PF-W1063": "a627a93ebdc270c3f61dd60581a956974441a55d9f54ea9fb2e0291d0826ff33", + "PF-W1064": "a1a289d2ef01c51b75775bd636e90affd8f68190168a340f34728001302e1b06", + "PF-W1065": "95293a6131f3500f529c88e35a4b6875dc2c117afbb30c25b0de8b6c096a9085", + "PF-W1066": "ce3eedfa360b6ec4858b13b28e4017752aaac16846d53fb4b503485de14a0cb3", + "PF-W1067": "1a1168bfcfd2005d9939e289c06a7cff26380f4b0bb2010d42c699749de59e7c", + "PF-W1068": "bdb47827b1d92a83fbbade01e8c2b8c7e26eac6699d09a32a4f5cbb2e6fd55c5", + "PF-W1069": "32ce7ff427cecf36d5e08f348a70fdc83cc55a39d9d511ea0487f582e6ecabda", + "PF-W1070": "8fac83110d1b1b76f005866eb00bf7ea0e094847ef79d47edb11998531ea63f1", + "PF-W1071": "47599b98b6c95d56097656281f2cce2d21118d71d2db0f1359ebbd5d2f3c5b96", + "PF-W1072": "ecb27b1f85da4b882f4cdf7d158d31a2b630d17b39c4bd3408d31a7643aea34f", + "PF-W1073": "da25faf9e5e0d06f93997cbf8dfdcb4172d2de661fe6a1335ed727514d9ea025", + "PF-W1074": "455f83227fe6ded19acf783545e6b959e5c8b5edb0b00ef18ab90f117e4f869f", + "PF-W1075": "bd2eff8895e744170cbd821d30966ca8e9050f073e01fc67fe38e2ba4d3ba909", + "PF-W1076": "b6ded44b0603e7b43a7ae009ad187498c05cca066cc6b0f48061d84b973301ac", + "PF-W1077": "48a891e61786cbee0c049259a699fe12ffe6c7f09d04feb2b7652940654e9cb8", + "PF-W1078": "a8b2c968ffb503de85e81a3e7d9873848179f4c66ac24e83d71b337b6013cd1e", + "PF-W1079": "840f9a5e5ca420b3e394271b921ba27607a0e4538b06d5e1b151b1654af6119f", + "PF-W1080": "acca2adefb4532f03e60e15ee43ea2568286bc05d0ab6e0d5537a00287f7a89a", + "PF-W1081": "17fd525f8ff769383b7f499af22dcbb215180b5fe81d3e94d860ff5225befd85", + "PF-W1082": "d4955f41ae92c063aa4624b289b4beefa6f1e5ce7b3ec15d05ccb6446ac04bf0", + "PF-W1083": "9625ef7e15f462451010a611ba0e5f86517617e793e4d72dc59b478102c8131c", + "PF-W1084": "86fcdda06690b603b7df5aebf784024d938c6c12de5c4a5b45425745c95513c5", + "PF-W1085": "cfcdd6ea0cf9bf22715934e7836cabd54688eca5a0e76c518733a62fef4ddbf7", + "PF-W1086": "d94fade49915c9d45998369bdc31a3ed1b4ae08094ed9cfd4ebda19ba7e0f24e", + "PF-W1087": "09f809e15fc3c7f876feb714fb6e80fd78ae7e62b1147051ffaf0ec1771a101f", + "PF-W1088": "9e8e55fab34e5c09417a4248cd77c805c3e86673694aa917eca1a9a81eeb1904", + "PF-W1089": "bb18286df7edf7cc64ec9fe67346e1c597c86c5133bf4e8840b89fa50f0cff1b", + "PF-W1090": "441e4e371f5186cd535b3295007af1050ec240920c3a3c1125e16e46cd7d70d7", + "PF-W1091": "8156829538596b3a2dc315e8a79d33f65f6a8304a1884210cdcdf34e47787d8c", + "PF-W1092": "f9a2ad4d5462b771eac860cdd29336e6db1aab0f7619fef6d7f31041dea06453", + "PF-W1093": "3b77b0b47f4f9cdcaf811c3404d171f417a47ccc9d4d3d2b5ee40071ab75d924", + "PF-W1094": "c04f0b17db3f9a4fc6228b4895fdf8d78d422d4823e7ddc39340a1ef99ad934a", + "PF-W1095": "88ed0e6b483c3458d57caaa78f295e6e2e0f311b1638ae982f68bb5438d94e43", + "PF-W1096": "3d6e62130f9cca02a3b3cc144c68942bef1434dae675ed6bd7040cb144e22f7f", + "PF-W1097": "a889558560d36b89dc2fc566cdc9c5f9c322f169ac68bbc41bf4208a368bbb0c", + "PF-W1500": "c75a5672704911176a2a4325bc17f79d8d56191b92c87f670a663a32c604a038", + "PF-W1501": "1b3135d61f5cd94b670a85a1037ea4be636a7f9db9532f6bcda08faf314bf1c9", + "PF-W1502": "7414dde57f8560fef4a235df1712edcdd104dabb912301c0b7955cd6180806e2", + "PF-W1503": "d01282d4267e74bee4f2410d627a53659dfb8ef4d3a7da52aa6d2472ca3cdd44", + "PF-W1504": "a47b0c03eca361d8efc488ad9978d80981fa62ece90917d644e652f526965ec2", + "PF-W1505": "787177596255e23d0b59c8aa9892f69d71a1a745c89982b96610389c129f4735", + "PF-W1506": "4a3de9263a6aee53db84e33bdc89120475693bc33f8817897c5e3b0c4f600e70", + "PF-W1507": "6abcc1fbd882466757a9c052cefccec32d0ea79551eafc1b2dd8418a68ecae08", + "PF-W1508": "e6a55746d8cd3e273e1a160f8d40005667d7276f14e43679802b7acea59eb8a5", + "PF-W1509": "14a7dc566b33c9ac37dbaddff8ec88284778798cb6ed2c6b82e734f741e2db64", + "PF-W1510": "2c8994cfc4ca7de7a63f18306b1b25147d9ed0fccb13799fb24e01b5aaae1b1e", + "PF-W1511": "7a7077a3ea2c89a607a74bbba0fa197b193af52a8d2dbbb10c186a97e562e6e0", + "PF-W1512": "621ae32351ea33c51a2f12e668f0314341354fef423a4e02e272d03874080dce", + "PF-W1513": "b09f7956345ce2d4e6b14e424c902aaaffbfb2321d27467dd352cb75efe2b212", + "PF-W1514": "d149dae283204e35bdde9e02154893465e6f4262e610c9ef2457ae3e4dd7e42b", + "PF-W1515": "0302bdcd62c655929f28d5d27e3c724e0e28438203f8f22f011dfae1910a4949", + "PF-W1516": "f539d4116c39db982437cda31d3c36b56dbb82a8a05dc2f7896a356d2fb12af8", + "PF-W1517": "f2c6311163b88497028915a764a25f35d3affddd9c29c8233d33212e9b965393", + "PF-W1518": "eb9a54268ae3b991de36ca03295ab71ab3df79772433632562adb45ae241128d", + "PF-W1519": "0a95fbc03da2cc532c9af8a99e5afdcea426fc00f8ba7ab5673b76b0457212c1", + "PF-W1520": "bb7a8a5164bc0b732c70079b2911e85b8fd5f5f92377ce8b1a45b4679d49c1e9", + "PF-W1521": "44c7cc7abf42bf6934dc591f7cb7bbefc9c226e7404d8e7f15288ab0330e3db1", + "PF-W1522": "ef8bdb005216265ab866cfe24f869b04bc7b76187776f51ee326e3d124799646", + "PF-W1523": "6048f792bbe012075b1f1af01ba2a4a7e92ed31471adaae94a3b4fcdff9294e0", + "PF-W1524": "eb43a104276e90b07fd37ece812f5c1206dabc36943ef2bf56188744ff5ea6cd", + "PF-W1525": "7f05cf12e7274bf5ae4e4164f975fc4185864e3dc9658a128bd8f3413213d06b", + "PF-W1526": "9a7990cadb1fe7eda3d35cdd345836889d5e8a7a28d0279e2c2e3e8d8334b91d", + "PF-W1527": "6f7b920851e88a42f7a414060750870806bbab9209aa93e24d008affbba3360f", + "PF-W1528": "c7b73144ec5143b30f2914ea891277630110c77150aec2b766643e023bd6c15e", + "PF-W1529": "ccc27d2ce0c2216a63bde293f052cf39e913e8135a5d5df3b0ea19b428048912", + "PF-W1530": "095838c70d9f3e88f202c92312b649d717a4749e7b205f90f4b1e2e3f88d736b", + "PF-W1531": "75e41d964c941d0b16e7f1b74fe60aea944a2a24bcdd8f7438bd84263be55705", + "PF-W1532": "e844cd922c91555618673691479c7dc64d280d7621da59b4f2a6f9cfe83205c4", + "PF-W1533": "c244f2332d60b36aee58c5d46a62c73da9cfded5a8c4065821787dadaabaeab6", + "PF-W1534": "6f62f69665b802bf9f80cdeb10e2a720379b4f296b71d3c922b463cf1112c5d8", + "PF-W1535": "cb45ba282f87aae25883dedd8287263de9bfcb60c3ae9a97bbc5f32e872622f6", + "PF-W1536": "e8bc1a3ef7ba64afd0040b0aaf061e8f6cd4548e6613c8c3347523d3273087ff", + "PF-W1537": "7a105a660db12b6be736b258190630ae893cfd16fb21d52281a083d184613bda", + "PF-W1538": "d03767ee33236a7f64c6c37736f59e41966fac39c613100160299752e198512b", + "PF-W1539": "3d733379543ceae1f722106fa53a836485739fc99ae089f80c5f8623aecafe55", + "PF-W1540": "fbe702127d7fa1fcd8239824fd7d4701686f268dab705799965add653111e04c", + "PF-W1541": "84e314020f8b6616e0fff411dfc4e70d80fd72d677d95c201bd82c7ef88362f7", + "PF-W1542": "ab496915d9a08faf2aeb9d74be122ad34dc346822103574f61ddc97e5212f75b", + "PF-W1543": "9cf564aa1eeb4aa7b262ac30529cc1cc1a2de724656ec34e7a6e1d6131aa2e59", + "PF-W1544": "274e7f851b6f4e908b89b9a2a2a08d3c06857b0a17215585fa246b222e0d44a0", + "PF-W1545": "b843a59b8718436b234bd44b53f6e392b08a299104e289b923cc7028a68b329e", + "PF-W1546": "36c3af6f843fb4857509aac9c37f1eb18ecc2c76f0db6dcaa08932f348deca10", + "PF-W1547": "2001b472364a0543b471e49f5d6bde2e2d1645f7129aee65dc7d3bbfa8c052e8", + "PF-W1548": "76fa06b5bb6f1261b8727a0b38ae9fcc1ff1d338831fd1a9eba6df7c023ee3aa", + "PF-W1549": "3e6cadcf3e8c9aba8f4d680e2defed3342fed8e12a734277b5390c8ef658fa4a", + "PF-W1550": "0d73bb5d2a22ee6bc342499b16b7338abddb0d6c98f2237a92157812c4121aef", + "PF-W1551": "97261dabc66a05a5a5e14e4fe7e8865f5704e1f7289304aa45709e976a29fc07", + "PF-W1552": "1f0ecd367a2b16f724e5f17dc950054f06071925c8633dcd291ad37c1fdadcea", + "PF-W2001": "49fda8dee49a14e23193c02639093e2d8e2598279d36d910233de8395d996082", + "PF-W2002": "a0474e31462e4ee84e821c3f791c7be21db29e1e8c0bb67372119bf2547b3955", + "PF-W2003": "1aa350aaabc80de130be586528ebae1045ab9392c91f43d0f2757e5d37b7606d", + "PF-W2004": "03752b434d95a43b58b4586852c5a95bacb5c8159554b1ed9936e0c76b7a2b7c", + "PF-W2005": "6eaf80f389e63432fcbd43526756f2e2931214ddfc6fa035b2cbd50f1b7193ce", + "PF-W2006": "67e17e0e7cfebc2c92e62f98d2360da4e2c61b5572e000e596818bbe33363ed0", + "PF-W2007": "cd375f4dc0dba878b28ca0aff9e333e3b1107dba424ede74f14e6015c2c02b84", + "PF-W2008": "75f3960b09e8b899ed9d4135d5f663cf4795c4e8dce1f475d5ac670a0900a77b", + "PF-W2009": "624d1f21f72d2064394f4fbb29fda30f46f919535f35dacfb392cfdd14173072", + "PF-W3001": "26147be69f0b2246d64b05e05e4732d1a67f6d739a246df32f664d8a038f8e58", + "PF-W3002": "e79e17e4bfc6be42e3dc37eb5a9fea86d025db807b6a8731d9e4920b6dc43095", + "PF-W3003": "65aa628c54d4e6f49df436c0833481fc11091a6897363c189c01e5af9251c629", + "PF-W3004": "b743ede072aa5fdba2ffd8983e7715869046e17339a35c5e9928fa10023dfc5d", + "PF-W3005": "196e9c66ecfef9edb39bd367fc04c7905963b9339632ea3cc15f29e1b9714b5d", + "PF-W3006": "4132e24d31d76bcb7c0c2d57e509ecefd3cb740573f5917cb7b3dfce6818e1e7", + "PF-W3007": "02dac59a7b8bcff7ba97ef2e156f225501ab251eaa3d59a8666b2ab6c4a352c2", + "PF-W3008": "6610ccb2e0562d4e29b77c74e75d7d68ce31b7db1f97378223fad0ddd92be606", + "PF-W3009": "37041000c4e8846db5a1739ac6903ba8e109019baf858eafbcac6daeea2f21b4", + "PF-W3010": "a936d51d7f7f632e707923d2f4285e5dcf9566a9e387bf567c84cb1431281515", + "PF-W3011": "dc777ac59e3fdfd74d312e55397b096f8dc22acbd58c2315fed1a9b8beff947c", + "PF-W3012": "16a75b0fdede020dc9919f2230a0506744695e999e88b44676cdcda5c76a8594", + "PF-W3013": "5fbce67eec11e99de6f9f9dabdb95a63fda667a4d160832e8b7f396927c84582", + "PF-W5001": "0ef938afbfa02f4fede7cac1fee01dc61d46a588ef943096fcd545f359fcefe1", + "PF-W5002": "253a89e2f6b604376930c302d3139a8fbb221d93b86145a90df9a0af50e145d0", + "PF-W5003": "447fc43e819fdd3df7659d9471f9f3d1d25e9b0a19fe923ea3a5da98f2a63985", + "PF-W5004": "3284133adac0ce8e30f8ec0dce132afb53bf4d9d9c8a552cace40bc73968c18b", + "PF-W5005": "8d2b834899049991c5fac10b73ead2d5a68fcb52a556f0e710a304522bea0a5e", + "PF-W5006": "b227a773d40a86f4389759c49a2a3e4474a2ebcbaaec1c92d46ba431213b518c", + "PF-W5007": "7124a2fe3e882861873bf1f9ee02c516f995200822a20f2d01aed08516d1fdbb", + "PF-W5008": "007769d118b3c079d4f5c7a036ef29ebf7ee77b218a35cc1adfb34f4c1291147", + "PF-W5009": "7ff3059904161cab2a3bf1c400db319b89a48f5e36d27fc5fba976f122503d75", + "PF-W5010": "0eeaef26dc71232c3e3e3568e49c4b2b350ae11e3855b51ea623813ca57e9354", + "PF-W5011": "78355a934a2a30492f26e90c24425fa13d289abd687f35337b769b423c66dc48", + "PF-W5012": "b45b744807fd859880761b1c9966f84ec6811f101acb6f80d368106db72aee44" + } +} diff --git a/tests/test_diagnostic_codes.py b/tests/test_diagnostic_codes.py new file mode 100644 index 00000000..15b664b7 --- /dev/null +++ b/tests/test_diagnostic_codes.py @@ -0,0 +1,219 @@ +"""Stable diagnostic codes: the catalog, its pin, and every emitted diagnostic. + +Every diagnostic carries a ``code`` and named ``args``; the catalog +(``pineforge_codegen/diagnostics_catalog.json``) gives each code its severity, +English ICU MessageFormat templates and a one-line explanation, and the +rendered templates are the diagnostic's ``message`` and ``hint`` byte for +byte. ``tests/fixtures/diagnostic_codes_pin.json`` pins what each code means: +a code is never removed or repurposed, and a new code needs a catalog entry +(``scripts/gen_diagnostics_catalog.py --write`` adds both). +""" + +from __future__ import annotations + +import hashlib +import importlib.util +import json +import os +import re +import sys +from pathlib import Path + +import pytest + +from pineforge_codegen import diagnostics_catalog, transpile, transpile_full +from pineforge_codegen.diagnostic_codes import ( + UNCATALOGUED, classify, escape_literal, parse_template, render, render_diagnostic, +) +from pineforge_codegen.errors import CompileError, Diagnostic, Level, Phase, SourceLocation + +ROOT = Path(__file__).resolve().parent.parent +PIN = ROOT / "tests" / "fixtures" / "diagnostic_codes_pin.json" +FIXTURES = ROOT / "tests" / "fixtures" +KINDS = {"identifier", "type", "keyword", "number", "vocab", "text"} +CATALOG = diagnostics_catalog()["codes"] + + +def _placeholders(template: str | None) -> set[str]: + if template is None: + return set() + return {part[0] for part in parse_template(template) if isinstance(part, tuple)} + + +def pin_digest(entry: dict) -> str: + """What a code means: its severity, templates and argument names.""" + meaning = json.dumps([entry["severity"], entry["message"], entry.get("hint"), + sorted(entry.get("args", {}))], ensure_ascii=False) + return hashlib.sha256(meaning.encode("utf-8")).hexdigest() + + +# --------------------------------------------------------------------------- +# The catalog +# --------------------------------------------------------------------------- + +def test_catalog_entries_are_well_formed(): + assert diagnostics_catalog()["schema"] == "pineforge-diagnostics-catalog/v1" + for code, entry in CATALOG.items(): + assert re.fullmatch(r"PF-[EW][0-9]{4}", code), code + assert entry["severity"] == {"E": "error", "W": "warning"}[code[3]], code + assert entry["area"], code + explanation = entry["explanation"] + assert explanation and "\n" not in explanation and len(explanation) <= 300, code + names = _placeholders(entry["message"]) | _placeholders(entry.get("hint")) + assert names == set(entry["args"]), code + for name, spec in entry["args"].items(): + assert spec["kind"] in KINDS, (code, name) + if spec["kind"] == "vocab": + assert spec["values"] and all(isinstance(v, str) for v in spec["values"]), (code, name) + else: + assert "values" not in spec, (code, name) + + +def test_catalog_codes_are_pinned(): + """Removing or repurposing a code fails; a new code must be pinned too.""" + pinned = json.loads(PIN.read_text(encoding="utf-8"))["codes"] + removed = sorted(set(pinned) - set(CATALOG)) + assert not removed, f"codes are never removed: {removed}" + repurposed = sorted(c for c in pinned if pin_digest(CATALOG[c]) != pinned[c]) + assert not repurposed, ( + f"a changed meaning needs a new code, the old one kept: {repurposed}") + unpinned = sorted(set(CATALOG) - set(pinned)) + assert not unpinned, ( + f"new codes {unpinned} are not pinned: run scripts/gen_diagnostics_catalog.py --write") + + +def test_catalog_api_returns_a_copy(): + first = diagnostics_catalog() + first["codes"].clear() + assert diagnostics_catalog()["codes"] == CATALOG + + +def test_switch_arm_warnings_twin_support_checker_errors(): + """The support checker warns, inside a switch arm, what it refuses + elsewhere: PF-W1nnn (nnn < 500) is PF-E1nnn's text as a warning.""" + for code, entry in CATALOG.items(): + if code.startswith("PF-E1"): + twin = CATALOG["PF-W" + code[4:]] + assert (twin["message"], twin.get("hint")) == (entry["message"], entry.get("hint")) + assert twin["severity"] == "warning" + + +def _load_generator(): + spec = importlib.util.spec_from_file_location( + "gen_diagnostics_catalog", ROOT / "scripts" / "gen_diagnostics_catalog.py") + module = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = module + spec.loader.exec_module(module) + return module + + +def test_every_spelled_template_has_a_code(): + """A diagnostic text the source spells needs a catalog entry.""" + generator = _load_generator() + have = {(e["severity"], e["message"], e.get("hint")) for e in CATALOG.values()} + missing = [ + f"[{t['severity']}] {t['message']!r} (hint {t['hint']!r}) at {', '.join(t['sites'])}" + for t in generator.extract() + if (t["severity"], t["message"], t["hint"]) not in have + ] + assert not missing, ( + "templates without a code (run scripts/gen_diagnostics_catalog.py --write):\n" + + "\n".join(missing)) + + +# --------------------------------------------------------------------------- +# Rendering and classification +# --------------------------------------------------------------------------- + +def test_icu_quoting(): + assert render("it''s '{'x'}' {a}", {"a": "b"}) == "it's {x} b" + assert render("'{0}' and ''{name}''", {"name": "len"}) == "{0} and 'len'" + assert render("a lone ' stays", {}) == "a lone ' stays" + for text in ("{0,number,#}", "it's", "'{'", "''", "a}b{c"): + assert render(escape_literal(text), {}) == text + assert render("{n} bars", {"n": 1234}) == "1234 bars" + + +def test_classify_reads_arguments_raw(): + code, args = classify("error", "Undefined variable: 'rsiLen'") + assert CATALOG[code]["message"] == "Undefined variable: ''{name}''" + assert args == {"name": "rsiLen"} + assert render_diagnostic(code, args) == ("Undefined variable: 'rsiLen'", None) + + +def test_uncatalogued_text_keeps_a_code(): + diagnostic = Diagnostic(Level.ERROR, Phase.ANALYZER, + SourceLocation("t.pine", 1, 1, 1), "boom") + assert diagnostic.code == UNCATALOGUED["error"] + assert diagnostic.args == {"message": "boom"} + + +def test_number_arguments_are_numbers(): + with pytest.raises(CompileError) as err: + transpile("//@version=6\nstrategy('t')\nplot(close)\n" + "x = " + "(" * 600 + "1" + ")" * 600) + diagnostic = err.value.diagnostics[0] + entry = CATALOG[diagnostic.code] + numbers = [n for n, spec in entry["args"].items() if spec["kind"] == "number"] + assert numbers and all(isinstance(diagnostic.args[n], int) for n in numbers) + assert render(entry["message"], diagnostic.args) == diagnostic.message + + +# --------------------------------------------------------------------------- +# Every emitted diagnostic renders back to its text +# --------------------------------------------------------------------------- + +def _corpus_dir() -> Path | None: + env = os.environ.get("PINEFORGE_ENGINE_CORPUS") + candidates = [Path(env)] if env else [] + candidates.append(ROOT.parent / "pineforge-engine" / "corpus") + return next((c for c in candidates if c.is_dir()), None) + + +def _scripts() -> list[Path]: + scripts = sorted(FIXTURES.rglob("*.pine")) + corpus = _corpus_dir() + if corpus is not None: + scripts += sorted(corpus.rglob("*.pine")) + return scripts + + +def _assert_coded(diagnostic: Diagnostic, where: str) -> None: + code, args = diagnostic.code, diagnostic.args + assert code not in UNCATALOGUED.values(), f"{where}: no template renders {diagnostic.message!r}" + entry = CATALOG[code] + assert entry["severity"] == diagnostic.level.value, where + assert render(entry["message"], args) == diagnostic.message, where + assert render(entry.get("hint"), args) == diagnostic.hint, where + for name, spec in entry["args"].items(): + value = args[name] + assert isinstance(value, (int, float) if spec["kind"] == "number" else str) \ + or (spec["kind"] == "number" and isinstance(value, str)), (where, name) + + +@pytest.mark.parametrize("path", _scripts(), ids=lambda p: str(p.relative_to(p.parents[2]))) +def test_emitted_diagnostics_render_their_text(path: Path): + source = path.read_text(encoding="utf-8") + try: + diagnostics = transpile_full(source)["diagnostics"] + except CompileError as err: + diagnostics = err.diagnostics + for diagnostic in diagnostics: + _assert_coded(diagnostic, str(path)) + + +def test_glue_envelope_carries_codes(): + namespace: dict = {} + glue = (ROOT / "gate" / "glue.py").read_text(encoding="utf-8") + exec(compile(glue.replace('"/codegen"', repr(str(ROOT))), "glue.py", "exec"), namespace) + source = ("//@version=6\nstrategy('t')\nx = bar_index\n" + "if close > open\n strategy.entry('L', strategy.long)\n") + envelope = json.loads(namespace["transpile_json"](source)) + assert envelope["ok"] and envelope["diagnostics"] + for entry in envelope["diagnostics"]: + spec = CATALOG[entry["code"]] + message = render(spec["message"], entry["args"]) + hint = render(spec.get("hint"), entry["args"]) + assert entry["message"] == (message + " — " + hint if hint else message) + failed = json.loads(namespace["transpile_json"]("//@version=6\nstrategy('t')\ny = nope + 1\n")) + assert not failed["ok"] + assert all(entry["code"].startswith("PF-E") for entry in failed["diagnostics"]) diff --git a/tests/test_settings_error_order.py b/tests/test_settings_error_order.py new file mode 100644 index 00000000..a679bed2 --- /dev/null +++ b/tests/test_settings_error_order.py @@ -0,0 +1,40 @@ +"""The settings metadata visits every input's arguments (defval, options, +minval, maxval, step) in the constructor, which is emitted ahead of the +script body. An error it finds is held until the body is generated, so the +error raised is the script's first in source order, as before 1.1.0 added +that metadata (an unknown name on an earlier line used to lose to one in a +later input's minval).""" + +import pytest + +from pineforge_codegen import transpile +from pineforge_codegen.errors import CompileError + +HEAD = '//@version=6\nstrategy("t")\n' + + +def _first_error(source: str): + with pytest.raises(CompileError) as err: + transpile(HEAD + source) + diagnostic = err.value.diagnostics[0] + return diagnostic.location.line, diagnostic.message + + +@pytest.mark.parametrize("argument", [ + "minval = uu", "maxval = uu", "step = uu", "options = [1, uu]", +]) +def test_an_earlier_body_error_comes_first(argument): + line, message = _first_error( + f'x = zz2 + 1\nlen = input.int(1, "Len", {argument})\nplot(close)\n') + assert line == 3 and "'zz2'" in message + + +def test_an_earlier_input_error_comes_first(): + line, message = _first_error( + 'len = input.int(10, "Len", minval = uu)\nx = zz2 + 1\nplot(close)\n') + assert line == 3 and "'uu'" in message + + +def test_an_input_error_alone_is_still_raised(): + line, message = _first_error('len = input.int(10, "Len", maxval = uu)\nplot(close)\n') + assert line == 3 and message.startswith("Unknown variable 'uu'")