pine2pyne 0.2.4__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.
- pine2pyne/__init__.py +84 -0
- pine2pyne/__main__.py +12 -0
- pine2pyne/ast_nodes.py +405 -0
- pine2pyne/ast_walk.py +93 -0
- pine2pyne/block_value_lowering.py +694 -0
- pine2pyne/bool_builtins.py +42 -0
- pine2pyne/bool_value_typing.py +580 -0
- pine2pyne/cli.py +247 -0
- pine2pyne/codegen.py +886 -0
- pine2pyne/compat/__init__.py +19 -0
- pine2pyne/compat/__main__.py +6 -0
- pine2pyne/compat/cli.py +114 -0
- pine2pyne/compat/comparison.py +105 -0
- pine2pyne/compat/corpus.py +73 -0
- pine2pyne/compat/report.py +95 -0
- pine2pyne/compat/runner.py +63 -0
- pine2pyne/condition_typing.py +260 -0
- pine2pyne/conditional_history_calls.py +96 -0
- pine2pyne/core/__init__.py +26 -0
- pine2pyne/core/contracts.py +125 -0
- pine2pyne/di.py +173 -0
- pine2pyne/emit/__init__.py +5 -0
- pine2pyne/emit/legacy.py +14 -0
- pine2pyne/emit/pynecomp/__init__.py +20 -0
- pine2pyne/emit/pynecomp/banner.py +30 -0
- pine2pyne/emit/pynecomp/blank_lines.py +69 -0
- pine2pyne/emit/pynecomp/emitter.py +61 -0
- pine2pyne/emit/pynecomp/imports.py +65 -0
- pine2pyne/emit/pynecomp/passes/__init__.py +84 -0
- pine2pyne/emit/pynecomp/passes/annotations.py +422 -0
- pine2pyne/emit/pynecomp/passes/base.py +69 -0
- pine2pyne/emit/pynecomp/passes/builtins.py +169 -0
- pine2pyne/emit/pynecomp/passes/hoisting.py +205 -0
- pine2pyne/emit/pynecomp/passes/imports.py +112 -0
- pine2pyne/emit/pynecomp/passes/legacy_colors.py +101 -0
- pine2pyne/emit/pynecomp/passes/library.py +205 -0
- pine2pyne/emit/pynecomp/passes/rewrites.py +215 -0
- pine2pyne/emit/pynecomp/printer.py +288 -0
- pine2pyne/emit/pynecomp/unparser.py +186 -0
- pine2pyne/emitted_names.py +152 -0
- pine2pyne/errors.py +69 -0
- pine2pyne/for_loop_end_bound.py +172 -0
- pine2pyne/grouped_history_lowering.py +310 -0
- pine2pyne/import_resolver.py +469 -0
- pine2pyne/input_hoisting.py +195 -0
- pine2pyne/legacy_function_names.py +74 -0
- pine2pyne/legacy_sessions.py +68 -0
- pine2pyne/lexer.py +630 -0
- pine2pyne/library_collision.py +434 -0
- pine2pyne/namespace_members.py +247 -0
- pine2pyne/node_ids.py +235 -0
- pine2pyne/once_lowering.py +75 -0
- pine2pyne/overload_resolution.py +475 -0
- pine2pyne/parse_repair.py +398 -0
- pine2pyne/parser.py +1873 -0
- pine2pyne/pine_builtins.py +394 -0
- pine2pyne/pine_semantics.py +604 -0
- pine2pyne/pipeline/__init__.py +18 -0
- pine2pyne/pipeline/service.py +70 -0
- pine2pyne/pipeline/stages.py +73 -0
- pine2pyne/scope_renamer.py +965 -0
- pine2pyne/strategy_when_lowering.py +101 -0
- pine2pyne/strict_boolean.py +101 -0
- pine2pyne/symbol_table.py +166 -0
- pine2pyne/tokens.py +143 -0
- pine2pyne/transformer.py +2510 -0
- pine2pyne/type_inference.py +422 -0
- pine2pyne/udt_field_defaults.py +149 -0
- pine2pyne/value_blocks.py +357 -0
- pine2pyne-0.2.4.dist-info/METADATA +99 -0
- pine2pyne-0.2.4.dist-info/RECORD +75 -0
- pine2pyne-0.2.4.dist-info/WHEEL +5 -0
- pine2pyne-0.2.4.dist-info/entry_points.txt +3 -0
- pine2pyne-0.2.4.dist-info/licenses/LICENSE +201 -0
- pine2pyne-0.2.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""The transpile use case, composed from injected stages."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Sequence
|
|
5
|
+
|
|
6
|
+
from ..core.contracts import (
|
|
7
|
+
AstNormalizer,
|
|
8
|
+
CodeEmitter,
|
|
9
|
+
CompilationUnit,
|
|
10
|
+
ScriptTransformer,
|
|
11
|
+
SemanticGuard,
|
|
12
|
+
SourceFilter,
|
|
13
|
+
SourceParser,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TranspileService:
|
|
18
|
+
"""Pine source -> Python source.
|
|
19
|
+
|
|
20
|
+
The service only orders the stages; it knows nothing about how any of
|
|
21
|
+
them works (S and D in SOLID). Swap a stage by registering another
|
|
22
|
+
implementation of its contract in the container.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
source_filter: SourceFilter,
|
|
28
|
+
parser: SourceParser,
|
|
29
|
+
normalizers: Sequence[AstNormalizer],
|
|
30
|
+
guard: SemanticGuard,
|
|
31
|
+
transformer: ScriptTransformer,
|
|
32
|
+
emitter: CodeEmitter,
|
|
33
|
+
) -> None:
|
|
34
|
+
self._source_filter = source_filter
|
|
35
|
+
self._parser = parser
|
|
36
|
+
self._normalizers = tuple(normalizers)
|
|
37
|
+
self._guard = guard
|
|
38
|
+
self._transformer = transformer
|
|
39
|
+
self._emitter = emitter
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def emitter(self) -> CodeEmitter:
|
|
43
|
+
return self._emitter
|
|
44
|
+
|
|
45
|
+
def _front_end(self, source: str):
|
|
46
|
+
script = self._parser.parse(source)
|
|
47
|
+
for normalizer in self._normalizers:
|
|
48
|
+
script = normalizer.normalize(script)
|
|
49
|
+
self._guard.check(script)
|
|
50
|
+
return script
|
|
51
|
+
|
|
52
|
+
def transpile(self, source: str) -> str:
|
|
53
|
+
"""Python source for ``source``; an empty string for a comment-only source.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
Pine2PyneError: if any stage refuses the script.
|
|
57
|
+
"""
|
|
58
|
+
if self._source_filter.is_blank(source):
|
|
59
|
+
return ''
|
|
60
|
+
script = self._front_end(source)
|
|
61
|
+
transformed = self._transformer.transform(script)
|
|
62
|
+
return self._emitter.emit(CompilationUnit(pine_source=source, pine_script=script, transformed=transformed))
|
|
63
|
+
|
|
64
|
+
def validate(self, source: str) -> None:
|
|
65
|
+
"""Parse and run the semantic guard without generating code (``--validate``).
|
|
66
|
+
|
|
67
|
+
Unlike :meth:`transpile`, the legacy name pass is skipped, as the CLI's
|
|
68
|
+
``--validate`` always did: it checks the script as written.
|
|
69
|
+
"""
|
|
70
|
+
self._guard.check(self._parser.parse(source))
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Concrete pipeline stages: thin adapters over the transpiler engine.
|
|
2
|
+
|
|
3
|
+
Each class implements one contract from :mod:`pine2pyne.core.contracts` and
|
|
4
|
+
delegates to the engine module that already does the work, so the engine
|
|
5
|
+
keeps its own tests while the application layer sees only abstractions.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ..ast_nodes import Script
|
|
10
|
+
from ..input_hoisting import hoist_inputs
|
|
11
|
+
from ..legacy_function_names import qualify_legacy_function_names
|
|
12
|
+
from ..legacy_sessions import qualify_legacy_sessions
|
|
13
|
+
from ..parse_repair import parse_source
|
|
14
|
+
from ..pine_semantics import enforce
|
|
15
|
+
from ..transformer import PyneTransformedScript, Transformer
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CommentOnlySourceFilter:
|
|
19
|
+
"""A source made of comments and whitespace has nothing to transpile."""
|
|
20
|
+
|
|
21
|
+
def is_blank(self, source: str) -> bool:
|
|
22
|
+
if not source:
|
|
23
|
+
return True
|
|
24
|
+
for line in source.splitlines():
|
|
25
|
+
stripped = line.strip()
|
|
26
|
+
if stripped and not stripped.startswith('//'):
|
|
27
|
+
return False
|
|
28
|
+
return True
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class RepairingSourceParser:
|
|
32
|
+
"""Lex and parse; a rejected known spelling of valid Pine is repaired (card #55)."""
|
|
33
|
+
|
|
34
|
+
def parse(self, source: str) -> Script:
|
|
35
|
+
script, _repairs = parse_source(source)
|
|
36
|
+
return script
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class LegacyFunctionNameNormalizer:
|
|
40
|
+
"""Pine v1-v4 call names are spelled the way Pine v5 spells them (card #116)."""
|
|
41
|
+
|
|
42
|
+
def normalize(self, script: Script) -> Script:
|
|
43
|
+
return qualify_legacy_function_names(script)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class LegacySessionNormalizer:
|
|
47
|
+
"""Pine v4 sessions of time()/time_close() get v4's default days (see :mod:`pine2pyne.legacy_sessions`)."""
|
|
48
|
+
|
|
49
|
+
def normalize(self, script: Script) -> Script:
|
|
50
|
+
return qualify_legacy_sessions(script)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class InputHoistingNormalizer:
|
|
54
|
+
"""Every top-level input call becomes a main() parameter (see :mod:`pine2pyne.input_hoisting`)."""
|
|
55
|
+
|
|
56
|
+
def normalize(self, script: Script) -> Script:
|
|
57
|
+
return hoist_inputs(script)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class PineSemanticGuard:
|
|
61
|
+
"""Refuse what TradingView's compiler refuses, at the Pine line (card #28)."""
|
|
62
|
+
|
|
63
|
+
def check(self, script: Script) -> None:
|
|
64
|
+
enforce(script)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class FreshTransformer:
|
|
68
|
+
""":class:`~pine2pyne.transformer.Transformer` is single-use (card #83):
|
|
69
|
+
this stage builds a fresh one for every script, so the stage itself is
|
|
70
|
+
stateless and safe to share."""
|
|
71
|
+
|
|
72
|
+
def transform(self, script: Script) -> PyneTransformedScript:
|
|
73
|
+
return Transformer().transform(script)
|