pineforge-codegen 0.6.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pineforge_codegen/__init__.py +53 -0
- pineforge_codegen/analyzer/__init__.py +60 -0
- pineforge_codegen/analyzer/base.py +1563 -0
- pineforge_codegen/analyzer/call_handlers.py +895 -0
- pineforge_codegen/analyzer/contracts.py +163 -0
- pineforge_codegen/analyzer/diagnostics.py +118 -0
- pineforge_codegen/analyzer/tables.py +204 -0
- pineforge_codegen/analyzer/types.py +250 -0
- pineforge_codegen/ast_nodes.py +293 -0
- pineforge_codegen/codegen/__init__.py +78 -0
- pineforge_codegen/codegen/base.py +1381 -0
- pineforge_codegen/codegen/emit_top.py +875 -0
- pineforge_codegen/codegen/helpers.py +163 -0
- pineforge_codegen/codegen/helpers_syminfo.py +134 -0
- pineforge_codegen/codegen/input.py +189 -0
- pineforge_codegen/codegen/security.py +1564 -0
- pineforge_codegen/codegen/ta.py +298 -0
- pineforge_codegen/codegen/tables.py +613 -0
- pineforge_codegen/codegen/types.py +573 -0
- pineforge_codegen/codegen/visit_call.py +1305 -0
- pineforge_codegen/codegen/visit_expr.py +701 -0
- pineforge_codegen/codegen/visit_stmt.py +729 -0
- pineforge_codegen/errors.py +98 -0
- pineforge_codegen/lexer.py +531 -0
- pineforge_codegen/parser.py +1198 -0
- pineforge_codegen/pragmas.py +117 -0
- pineforge_codegen/signatures.py +808 -0
- pineforge_codegen/support_checker.py +1111 -0
- pineforge_codegen/symbols.py +118 -0
- pineforge_codegen/tokens.py +406 -0
- pineforge_codegen/tv_input_choices.py +86 -0
- pineforge_codegen-0.6.5.dist-info/METADATA +462 -0
- pineforge_codegen-0.6.5.dist-info/RECORD +35 -0
- pineforge_codegen-0.6.5.dist-info/WHEEL +4 -0
- pineforge_codegen-0.6.5.dist-info/licenses/LICENSE +197 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Pre-lex pragma extraction for PineForge.
|
|
2
|
+
|
|
3
|
+
This module recognises ``// @pf-trace name=expr`` line comments in Pine
|
|
4
|
+
source and lifts them into a structured list the codegen consumes when
|
|
5
|
+
emitting the per-bar instrumentation hook at the bottom of every
|
|
6
|
+
``on_bar()``.
|
|
7
|
+
|
|
8
|
+
Why a pre-pass?
|
|
9
|
+
The :class:`Lexer` strips both block (``/* ... */``) and line
|
|
10
|
+
(``//``) comments before the parser ever sees them, so by the time
|
|
11
|
+
we have an AST the original pragma text is gone. We instead walk
|
|
12
|
+
the raw source once, regex-match each pragma line, then run the
|
|
13
|
+
expression body through the same :class:`Lexer` /
|
|
14
|
+
:class:`Parser` machinery used for normal Pine expressions. This
|
|
15
|
+
keeps a single source of truth for Pine syntax and ensures pragma
|
|
16
|
+
expressions support the full grammar (logical operators, member
|
|
17
|
+
access, function calls, ternaries, ...).
|
|
18
|
+
|
|
19
|
+
Pragma syntax (kept deliberately strict so unrelated comments are
|
|
20
|
+
untouched)::
|
|
21
|
+
|
|
22
|
+
// @pf-trace <id>=<expr>
|
|
23
|
+
|
|
24
|
+
* ``//`` followed by at least one space, then ``@pf-trace``.
|
|
25
|
+
* ``<id>`` matches ``[A-Za-z_][A-Za-z0-9_]*`` (the trace label).
|
|
26
|
+
* ``<expr>`` is any Pine expression evaluated at script-top scope.
|
|
27
|
+
|
|
28
|
+
Multiple pragmas may appear on consecutive (or non-consecutive) lines;
|
|
29
|
+
their source order is preserved in the output so the codegen emits the
|
|
30
|
+
matching ``trace(...)`` calls in the same order. Block comments and
|
|
31
|
+
line comments not starting with ``// @pf-trace`` are ignored. Mid-line
|
|
32
|
+
trailing pragmas (``x = 1 // @pf-trace ...``) are intentionally NOT
|
|
33
|
+
recognised — pragmas must occupy the whole line so they are
|
|
34
|
+
unambiguous to read by humans and trivial to grep.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
import re
|
|
40
|
+
from dataclasses import dataclass
|
|
41
|
+
from typing import Any
|
|
42
|
+
|
|
43
|
+
from .lexer import Lexer
|
|
44
|
+
from .parser import Parser
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Anchored to start/end of line so a stray ``// @pf-trace`` substring
|
|
48
|
+
# inside a string literal or block comment cannot match. ``\s+`` after
|
|
49
|
+
# ``//`` requires at least one space before ``@pf-trace`` (the spec is
|
|
50
|
+
# ``// @pf-trace ``, distinct from Pine's ``//@version=N``).
|
|
51
|
+
_PRAGMA_RE = re.compile(
|
|
52
|
+
r"^\s*//\s+@pf-trace\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+?)\s*$"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class PfTracePragma:
|
|
58
|
+
"""One ``// @pf-trace name=expr`` annotation extracted from Pine source.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
name: The trace label (left-hand side of ``=``); matches
|
|
62
|
+
``[A-Za-z_][A-Za-z0-9_]*`` so it can be safely embedded in
|
|
63
|
+
a C++ string literal without escaping.
|
|
64
|
+
expr_source: Raw Pine expression text (right-hand side of
|
|
65
|
+
``=``), retained for diagnostics and the test harness.
|
|
66
|
+
expr_node: AST node parsed from ``expr_source`` via the
|
|
67
|
+
standard Pine expression parser. Codegen feeds this through
|
|
68
|
+
``_visit_expr`` to obtain the C++ form.
|
|
69
|
+
line: 1-based source line where the pragma was found.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
name: str
|
|
73
|
+
expr_source: str
|
|
74
|
+
expr_node: Any
|
|
75
|
+
line: int
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def extract_pf_trace_pragmas(source: str) -> list[PfTracePragma]:
|
|
79
|
+
"""Scan ``source`` for ``// @pf-trace`` line comments.
|
|
80
|
+
|
|
81
|
+
Returns the pragmas in source order. The expression on the
|
|
82
|
+
right-hand side of ``=`` is run through the project's own
|
|
83
|
+
:class:`Lexer` followed by :meth:`Parser._parse_expression` so the
|
|
84
|
+
full Pine expression grammar is supported (binary / unary
|
|
85
|
+
operators, ternaries, member access, function calls, subscripts).
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
source: Raw Pine source text.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
A list of :class:`PfTracePragma` entries in source order. Empty
|
|
92
|
+
list when no pragmas are present (the common case for legacy
|
|
93
|
+
scripts) — callers should treat this as the zero-overhead
|
|
94
|
+
path.
|
|
95
|
+
"""
|
|
96
|
+
pragmas: list[PfTracePragma] = []
|
|
97
|
+
for lineno, raw in enumerate(source.splitlines(), start=1):
|
|
98
|
+
m = _PRAGMA_RE.match(raw)
|
|
99
|
+
if not m:
|
|
100
|
+
continue
|
|
101
|
+
name = m.group(1)
|
|
102
|
+
expr_source = m.group(2)
|
|
103
|
+
# Reuse the full Pine-source -> AST pipeline by lexing + parsing
|
|
104
|
+
# the expression body in isolation. ``Parser._parse_expression``
|
|
105
|
+
# is the same entry the statement parser uses for RHS values,
|
|
106
|
+
# so anything legal in ``x = <expr>`` is legal here.
|
|
107
|
+
tokens = Lexer(expr_source).tokenize()
|
|
108
|
+
expr_node = Parser(tokens, source=expr_source)._parse_expression()
|
|
109
|
+
pragmas.append(
|
|
110
|
+
PfTracePragma(
|
|
111
|
+
name=name,
|
|
112
|
+
expr_source=expr_source,
|
|
113
|
+
expr_node=expr_node,
|
|
114
|
+
line=lineno,
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
return pragmas
|