@pineforge/codegen-pyodide 1.0.0-rc.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/pineforge_codegen/analyzer/base.py +189 -1
- package/pineforge_codegen/analyzer/contracts.py +3 -0
- package/pineforge_codegen/analyzer/types.py +16 -5
- package/pineforge_codegen/ast_nodes.py +7 -0
- package/pineforge_codegen/codegen/base.py +136 -14
- package/pineforge_codegen/codegen/collection_history.py +200 -0
- package/pineforge_codegen/codegen/emit_top.py +32 -5
- package/pineforge_codegen/codegen/helpers.py +5 -1
- package/pineforge_codegen/codegen/security.py +56 -1
- package/pineforge_codegen/codegen/ta.py +65 -1
- package/pineforge_codegen/codegen/types.py +136 -8
- package/pineforge_codegen/codegen/visit_call.py +92 -3
- package/pineforge_codegen/codegen/visit_expr.py +202 -3
- package/pineforge_codegen/codegen/visit_stmt.py +19 -4
- package/pineforge_codegen/collection_history.py +1595 -0
- package/pineforge_codegen/parser.py +19 -4
- package/pineforge_codegen/support_checker.py +37 -0
- package/pineforge_codegen-1.0.1.tar.gz +0 -0
- package/release.json +2 -2
- package/tables.json +1 -1
- package/pineforge_codegen-1.0.0-rc.1.tar.gz +0 -0
|
@@ -18,6 +18,7 @@ from .lexer import Token, TokenType
|
|
|
18
18
|
from .errors import CompileError, Diagnostic, Level, Phase, SourceLocation
|
|
19
19
|
from .limits import MAX_NESTING_DEPTH, TimeBudget, limit_error, syntax_children
|
|
20
20
|
from .ast_nodes import (
|
|
21
|
+
HISTORY_MEMBER_ANNOTATION,
|
|
21
22
|
ASTNode, ArgOrder,
|
|
22
23
|
Program, StrategyDecl, ImportStmt,
|
|
23
24
|
VarDecl, Assignment, TupleAssign,
|
|
@@ -1482,6 +1483,11 @@ class Parser:
|
|
|
1482
1483
|
def _parse_postfix(self):
|
|
1483
1484
|
chain_tok = self._current()
|
|
1484
1485
|
expr = self._parse_primary()
|
|
1486
|
+
# Whether ``expr`` is a history reference this chain wrote, not one in
|
|
1487
|
+
# parentheses: TradingView refuses a member straight after it
|
|
1488
|
+
# (``c[1].v``, CE10011; ``b[1].get_top()``, CE10010), which the
|
|
1489
|
+
# support checker reports (HISTORY_MEMBER_ANNOTATION).
|
|
1490
|
+
after_subscript = False
|
|
1485
1491
|
while True:
|
|
1486
1492
|
# Subscript: expr[index]
|
|
1487
1493
|
if self._check(TokenType.LBRACKET):
|
|
@@ -1491,6 +1497,9 @@ class Parser:
|
|
|
1491
1497
|
self._consume(TokenType.RBRACKET)
|
|
1492
1498
|
expr = Subscript(object=expr, index=index)
|
|
1493
1499
|
self._set_loc(expr, start_tok)
|
|
1500
|
+
after_subscript = True
|
|
1501
|
+
self._check_chain(expr, chain_tok)
|
|
1502
|
+
continue
|
|
1494
1503
|
|
|
1495
1504
|
# Member access: expr.member or expr.member(args)
|
|
1496
1505
|
elif self._check(TokenType.DOT):
|
|
@@ -1501,24 +1510,30 @@ class Parser:
|
|
|
1501
1510
|
if self._looks_like_call_template_args():
|
|
1502
1511
|
template_args = self._parse_template_args()
|
|
1503
1512
|
|
|
1513
|
+
annotations = {}
|
|
1514
|
+
if template_args:
|
|
1515
|
+
annotations["template_args"] = template_args
|
|
1516
|
+
if after_subscript:
|
|
1517
|
+
annotations[HISTORY_MEMBER_ANNOTATION] = True
|
|
1504
1518
|
if self._check(TokenType.LPAREN):
|
|
1505
1519
|
# Build callee as MemberAccess, then parse call
|
|
1506
1520
|
callee = MemberAccess(object=expr, member=member_tok.value)
|
|
1507
1521
|
self._set_loc(callee, member_tok)
|
|
1508
|
-
if
|
|
1509
|
-
callee.annotations =
|
|
1522
|
+
if annotations:
|
|
1523
|
+
callee.annotations = annotations
|
|
1510
1524
|
expr = self._parse_call_with_callee(callee)
|
|
1511
1525
|
else:
|
|
1512
1526
|
expr = MemberAccess(object=expr, member=member_tok.value)
|
|
1513
1527
|
self._set_loc(expr, member_tok)
|
|
1514
|
-
if
|
|
1515
|
-
expr.annotations =
|
|
1528
|
+
if annotations:
|
|
1529
|
+
expr.annotations = annotations
|
|
1516
1530
|
|
|
1517
1531
|
# Direct call: expr(args) — needed for identifiers followed by (
|
|
1518
1532
|
elif self._check(TokenType.LPAREN) and self._is_call_position(expr):
|
|
1519
1533
|
expr = self._parse_call_with_callee(expr)
|
|
1520
1534
|
else:
|
|
1521
1535
|
break
|
|
1536
|
+
after_subscript = False
|
|
1522
1537
|
self._check_chain(expr, chain_tok)
|
|
1523
1538
|
return expr
|
|
1524
1539
|
|
|
@@ -36,6 +36,7 @@ import re
|
|
|
36
36
|
from typing import Callable
|
|
37
37
|
|
|
38
38
|
from .ast_nodes import (
|
|
39
|
+
HISTORY_MEMBER_ANNOTATION,
|
|
39
40
|
ASTNode,
|
|
40
41
|
Program, StrategyDecl, ImportStmt, TypeField,
|
|
41
42
|
VarDecl, Assignment, TupleAssign,
|
|
@@ -1482,6 +1483,40 @@ class SupportChecker:
|
|
|
1482
1483
|
)
|
|
1483
1484
|
self._visit_children(node)
|
|
1484
1485
|
|
|
1486
|
+
def _refuse_history_member(self, node: MemberAccess) -> None:
|
|
1487
|
+
"""A field read or a method call written straight after the
|
|
1488
|
+
history-referencing operator: TradingView refuses ``c[1].v``
|
|
1489
|
+
("User variable identifiers should not contain '.'", CE10011) and
|
|
1490
|
+
``b[1].get_top()`` (CE10010), and takes the history reference in
|
|
1491
|
+
parentheses, ``(c[1]).v``, which reads the field of the object the
|
|
1492
|
+
variable held (fixtures/udt_history_tv)."""
|
|
1493
|
+
history = node.object
|
|
1494
|
+
receiver = "x[k]"
|
|
1495
|
+
if (isinstance(history, Subscript)
|
|
1496
|
+
and isinstance(history.object, Identifier)
|
|
1497
|
+
and isinstance(history.index, (NumberLiteral, Identifier))):
|
|
1498
|
+
index = (history.index.name if isinstance(history.index, Identifier)
|
|
1499
|
+
else history.index.value)
|
|
1500
|
+
receiver = f"{history.object.name}[{index}]"
|
|
1501
|
+
if id(node) in self._callee_node_ids:
|
|
1502
|
+
self._err(
|
|
1503
|
+
node,
|
|
1504
|
+
f"{receiver}.{node.member}(): TradingView refuses a method "
|
|
1505
|
+
"call straight after the history-referencing operator "
|
|
1506
|
+
"(CE10010; CE10011 after an array's or a matrix's history).",
|
|
1507
|
+
hint=f"Call the method on the history reference in "
|
|
1508
|
+
f"parentheses: ({receiver}).{node.member}().",
|
|
1509
|
+
)
|
|
1510
|
+
return
|
|
1511
|
+
self._err(
|
|
1512
|
+
node,
|
|
1513
|
+
f"{receiver}.{node.member}: TradingView refuses a field read "
|
|
1514
|
+
"straight after the history-referencing operator (CE10011: "
|
|
1515
|
+
"\"User variable identifiers should not contain '.'\").",
|
|
1516
|
+
hint=f"Read the field of the history reference in parentheses: "
|
|
1517
|
+
f"({receiver}).{node.member}.",
|
|
1518
|
+
)
|
|
1519
|
+
|
|
1485
1520
|
def _visit_FuncCall(self, node: FuncCall) -> None:
|
|
1486
1521
|
ns, name = _qualified_name(node.callee)
|
|
1487
1522
|
|
|
@@ -1976,6 +2011,8 @@ class SupportChecker:
|
|
|
1976
2011
|
self._visit(node.false_val)
|
|
1977
2012
|
|
|
1978
2013
|
def _visit_MemberAccess(self, node: MemberAccess) -> None:
|
|
2014
|
+
if (node.annotations or {}).get(HISTORY_MEMBER_ANNOTATION):
|
|
2015
|
+
self._refuse_history_member(node)
|
|
1979
2016
|
chain = _resolve_member_chain(node)
|
|
1980
2017
|
if (
|
|
1981
2018
|
chain is not None
|
|
Binary file
|
package/release.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"codegen": "1.0.
|
|
2
|
+
"codegen": "1.0.1",
|
|
3
3
|
"pyodide": "314.0.0",
|
|
4
4
|
"python": "3.14.0",
|
|
5
5
|
"emscripten": "emscripten_5_0_3",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "2ad9a8595850ce2c485dcddb049fd738097d9149d2136ce83a951a506541a113"
|
|
7
7
|
}
|
package/tables.json
CHANGED
|
Binary file
|