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,247 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The members of each pynecore.lib namespace, as the runtime defines them.
|
|
3
|
+
|
|
4
|
+
GENERATED by tools/collect_namespace_members.py from opencode-pyneruntime 6.9.4; do not
|
|
5
|
+
edit by hand. A binding named like a namespace uses it to tell `N.m` on the
|
|
6
|
+
binding from `N.m` on the namespace (card #9).
|
|
7
|
+
"""
|
|
8
|
+
from typing import Dict, FrozenSet
|
|
9
|
+
|
|
10
|
+
NAMESPACE_MEMBERS: Dict[str, FrozenSet[str]] = {
|
|
11
|
+
'adjustment': frozenset({
|
|
12
|
+
'dividends', 'none', 'splits',
|
|
13
|
+
}),
|
|
14
|
+
'alert': frozenset({
|
|
15
|
+
'alert', 'freq_all', 'freq_once_per_bar', 'freq_once_per_bar_close',
|
|
16
|
+
}),
|
|
17
|
+
'array': frozenset({
|
|
18
|
+
'abs', 'avg', 'binary_search', 'binary_search_leftmost', 'binary_search_rightmost',
|
|
19
|
+
'clear', 'concat', 'copy', 'covariance', 'every', 'fill', 'first', 'from_items', 'get',
|
|
20
|
+
'includes', 'indexof', 'insert', 'join', 'last', 'lastindexof', 'max', 'median', 'min',
|
|
21
|
+
'mode', 'na_float', 'new', 'new_bool', 'new_box', 'new_color', 'new_float', 'new_int',
|
|
22
|
+
'new_label', 'new_line', 'new_linefill', 'new_string', 'new_table',
|
|
23
|
+
'percentile_linear_interpolation', 'percentile_nearest_rank', 'percentrank', 'pop',
|
|
24
|
+
'push', 'range', 'remove', 'reverse', 'set', 'shift', 'size', 'slice', 'some', 'sort',
|
|
25
|
+
'sort_indices', 'standardize', 'stdev', 'sum', 'unshift', 'variance',
|
|
26
|
+
}),
|
|
27
|
+
'barmerge': frozenset({
|
|
28
|
+
'gaps_off', 'gaps_on', 'lookahead_last_closed', 'lookahead_off', 'lookahead_on',
|
|
29
|
+
}),
|
|
30
|
+
'barstate': frozenset({
|
|
31
|
+
'isconfirmed', 'isfirst', 'ishistory', 'islast', 'islastconfirmedhistory', 'isnew',
|
|
32
|
+
'isrealtime',
|
|
33
|
+
}),
|
|
34
|
+
'box': frozenset({
|
|
35
|
+
'all', 'copy', 'delete', 'get_bottom', 'get_left', 'get_right', 'get_top', 'na_float',
|
|
36
|
+
'new', 'set_bgcolor', 'set_border_color', 'set_border_style', 'set_border_width',
|
|
37
|
+
'set_bottom', 'set_bottom_right_point', 'set_extend', 'set_left', 'set_lefttop',
|
|
38
|
+
'set_right', 'set_rightbottom', 'set_text', 'set_text_color', 'set_text_font_family',
|
|
39
|
+
'set_text_formatting', 'set_text_halign', 'set_text_size', 'set_text_valign',
|
|
40
|
+
'set_text_wrap', 'set_top', 'set_top_left_point', 'set_xloc',
|
|
41
|
+
}),
|
|
42
|
+
'chart': frozenset({
|
|
43
|
+
'bg_color', 'fg_color', 'is_heikinashi', 'is_kagi', 'is_linebreak', 'is_pnf',
|
|
44
|
+
'is_range', 'is_renko', 'is_standard', 'left_visible_bar_time', 'point',
|
|
45
|
+
'right_visible_bar_time',
|
|
46
|
+
}),
|
|
47
|
+
'color': frozenset({
|
|
48
|
+
'aqua', 'b', 'black', 'blue', 'from_gradient', 'fuchsia', 'g', 'gray', 'green', 'lime',
|
|
49
|
+
'maroon', 'navy', 'new', 'olive', 'orange', 'purple', 'r', 'red', 'rgb', 'silver', 't',
|
|
50
|
+
'teal', 'white', 'yellow',
|
|
51
|
+
}),
|
|
52
|
+
'currency': frozenset({
|
|
53
|
+
'AED', 'ARS', 'AUD', 'BDT', 'BHD', 'BRL', 'BTC', 'CAD', 'CHF', 'CLP', 'CNY', 'COP',
|
|
54
|
+
'CZK', 'DKK', 'EGP', 'ETH', 'EUR', 'GBP', 'HKD', 'HUF', 'IDR', 'ILS', 'INR', 'ISK',
|
|
55
|
+
'JPY', 'KES', 'KRW', 'KWD', 'LKR', 'MAD', 'MXN', 'MYR', 'NGN', 'NOK', 'NONE', 'NZD',
|
|
56
|
+
'PEN', 'PHP', 'PKR', 'PLN', 'QAR', 'RON', 'RSD', 'RUB', 'SAR', 'SEK', 'SGD', 'THB',
|
|
57
|
+
'TND', 'TRY', 'TWD', 'USD', 'USDT', 'VES', 'VND', 'ZAR',
|
|
58
|
+
}),
|
|
59
|
+
'dayofweek': frozenset({
|
|
60
|
+
'dayofweek', 'friday', 'monday', 'saturday', 'sunday', 'thursday', 'tuesday',
|
|
61
|
+
'wednesday',
|
|
62
|
+
}),
|
|
63
|
+
'display': frozenset({
|
|
64
|
+
'all', 'data_window', 'none', 'pane', 'price_scale', 'status_line',
|
|
65
|
+
}),
|
|
66
|
+
'dividends': frozenset({
|
|
67
|
+
'future_amount', 'future_ex_date', 'future_pay_date', 'gross', 'na_float', 'net',
|
|
68
|
+
}),
|
|
69
|
+
'earnings': frozenset({
|
|
70
|
+
'actual', 'estimate', 'future_eps', 'future_period_end_time', 'future_revenue',
|
|
71
|
+
'future_time', 'na_float', 'standardized',
|
|
72
|
+
}),
|
|
73
|
+
'extend': frozenset({
|
|
74
|
+
'both', 'left', 'none', 'right',
|
|
75
|
+
}),
|
|
76
|
+
'font': frozenset({
|
|
77
|
+
'family_default', 'family_monospace',
|
|
78
|
+
}),
|
|
79
|
+
'footprint': frozenset({
|
|
80
|
+
'buy_volume', 'delta', 'poc', 'sell_volume', 'total_volume', 'vah', 'val',
|
|
81
|
+
}),
|
|
82
|
+
'format': frozenset({
|
|
83
|
+
'inherit', 'mintick', 'percent', 'price', 'volume',
|
|
84
|
+
}),
|
|
85
|
+
'hline': frozenset({
|
|
86
|
+
'hline', 'style_dashed', 'style_dotted', 'style_solid',
|
|
87
|
+
}),
|
|
88
|
+
'label': frozenset({
|
|
89
|
+
'all', 'copy', 'delete', 'get_text', 'get_x', 'get_y', 'na_float', 'new', 'set_color',
|
|
90
|
+
'set_point', 'set_size', 'set_style', 'set_text', 'set_text_font_family',
|
|
91
|
+
'set_text_formatting', 'set_textalign', 'set_textcolor', 'set_tooltip', 'set_x',
|
|
92
|
+
'set_xloc', 'set_xy', 'set_y', 'set_yloc', 'style_arrowdown', 'style_arrowup',
|
|
93
|
+
'style_circle', 'style_cross', 'style_diamond', 'style_flag', 'style_label_center',
|
|
94
|
+
'style_label_down', 'style_label_left', 'style_label_lower_left',
|
|
95
|
+
'style_label_lower_right', 'style_label_right', 'style_label_up',
|
|
96
|
+
'style_label_upper_left', 'style_label_upper_right', 'style_none', 'style_square',
|
|
97
|
+
'style_text_outline', 'style_triangledown', 'style_triangleup', 'style_xcross',
|
|
98
|
+
}),
|
|
99
|
+
'line': frozenset({
|
|
100
|
+
'all', 'copy', 'delete', 'get_price', 'get_x1', 'get_x2', 'get_y1', 'get_y2',
|
|
101
|
+
'na_float', 'new', 'set_color', 'set_extend', 'set_first_point', 'set_second_point',
|
|
102
|
+
'set_style', 'set_width', 'set_x1', 'set_x2', 'set_xloc', 'set_xy1', 'set_xy2',
|
|
103
|
+
'set_y1', 'set_y2', 'style_arrow_both', 'style_arrow_left', 'style_arrow_right',
|
|
104
|
+
'style_dashed', 'style_dotted', 'style_solid',
|
|
105
|
+
}),
|
|
106
|
+
'linefill': frozenset({
|
|
107
|
+
'all', 'delete', 'get_line1', 'get_line2', 'new', 'set_color',
|
|
108
|
+
}),
|
|
109
|
+
'location': frozenset({
|
|
110
|
+
'abovebar', 'absolute', 'belowbar', 'bottom', 'top',
|
|
111
|
+
}),
|
|
112
|
+
'log': frozenset({
|
|
113
|
+
'broker_debug', 'broker_error', 'broker_info', 'broker_warning', 'error', 'handler',
|
|
114
|
+
'info', 'logger', 'ohlcv_info', 'setup_security_file_log', 'sim_info', 'warning',
|
|
115
|
+
}),
|
|
116
|
+
'map': frozenset({
|
|
117
|
+
'clear', 'contains', 'copy', 'get', 'keys', 'new', 'put', 'put_all', 'remove', 'size',
|
|
118
|
+
'values',
|
|
119
|
+
}),
|
|
120
|
+
'math': frozenset({
|
|
121
|
+
'abs', 'acos', 'asin', 'atan', 'avg', 'ceil', 'cos', 'e', 'exp', 'floor', 'log',
|
|
122
|
+
'log10', 'max', 'min', 'na_float', 'phi', 'pi', 'pow', 'random', 'round',
|
|
123
|
+
'round_to_mintick', 'rphi', 'sign', 'sin', 'sqrt', 'sum', 'tan', 'todegrees',
|
|
124
|
+
'toradians',
|
|
125
|
+
}),
|
|
126
|
+
'matrix': frozenset({
|
|
127
|
+
'add_col', 'add_row', 'all', 'annotations', 'avg', 'col', 'columns', 'concat', 'copy',
|
|
128
|
+
'delete', 'det', 'diff', 'eigenvalues', 'eigenvectors', 'elements_count', 'fill', 'get',
|
|
129
|
+
'inv', 'is_antidiagonal', 'is_antisymmetric', 'is_binary', 'is_diagonal', 'is_identity',
|
|
130
|
+
'is_square', 'is_stochastic', 'is_symmetric', 'is_triangular', 'is_zero', 'kron', 'max',
|
|
131
|
+
'median', 'min', 'mode', 'mult', 'na_float', 'new', 'pinv', 'pow', 'rank', 'remove_col',
|
|
132
|
+
'remove_row', 'reshape', 'reverse', 'row', 'rows', 'set', 'sort', 'submatrix', 'sum',
|
|
133
|
+
'swap_columns', 'swap_rows', 'trace', 'transpose',
|
|
134
|
+
}),
|
|
135
|
+
'order': frozenset({
|
|
136
|
+
'ascending', 'descending',
|
|
137
|
+
}),
|
|
138
|
+
'pivotpointtype': frozenset({
|
|
139
|
+
'camarilla', 'classic', 'dm', 'fibonacci', 'traditional', 'woodie',
|
|
140
|
+
}),
|
|
141
|
+
'plot': frozenset({
|
|
142
|
+
'linestyle_dashed', 'linestyle_dotted', 'linestyle_solid', 'plot', 'style_area',
|
|
143
|
+
'style_areabr', 'style_circles', 'style_columns', 'style_cross', 'style_histogram',
|
|
144
|
+
'style_line', 'style_linebr', 'style_stepline', 'style_stepline_diamond',
|
|
145
|
+
'style_steplinebr',
|
|
146
|
+
}),
|
|
147
|
+
'polyline': frozenset({
|
|
148
|
+
'all', 'delete', 'new', 'style_arrow_both', 'style_arrow_left', 'style_arrow_right',
|
|
149
|
+
'style_dashed', 'style_dotted', 'style_solid',
|
|
150
|
+
}),
|
|
151
|
+
'position': frozenset({
|
|
152
|
+
'bottom_center', 'bottom_left', 'bottom_right', 'middle_center', 'middle_left',
|
|
153
|
+
'middle_right', 'top_center', 'top_left', 'top_right',
|
|
154
|
+
}),
|
|
155
|
+
'request': frozenset({
|
|
156
|
+
'annotations', 'currency_rate', 'dividends', 'earnings', 'economic', 'financial',
|
|
157
|
+
'footprint', 'nan', 'quandl', 'security', 'security_lower_tf', 'seed', 'splits',
|
|
158
|
+
}),
|
|
159
|
+
'runtime': frozenset({
|
|
160
|
+
'error',
|
|
161
|
+
}),
|
|
162
|
+
'scale': frozenset({
|
|
163
|
+
'left', 'none', 'right',
|
|
164
|
+
}),
|
|
165
|
+
'session': frozenset({
|
|
166
|
+
'extended', 'isfirstbar', 'isfirstbar_regular', 'islastbar', 'islastbar_regular',
|
|
167
|
+
'ismarket', 'ispostmarket', 'ispremarket', 'regular',
|
|
168
|
+
}),
|
|
169
|
+
'shape': frozenset({
|
|
170
|
+
'arrowdown', 'arrowup', 'circle', 'cross', 'diamond', 'flag', 'labeldown', 'labelup',
|
|
171
|
+
'square', 'triangledown', 'triangleup', 'xcross',
|
|
172
|
+
}),
|
|
173
|
+
'size': frozenset({
|
|
174
|
+
'auto', 'huge', 'large', 'normal', 'small', 'tiny',
|
|
175
|
+
}),
|
|
176
|
+
'splits': frozenset({
|
|
177
|
+
'denominator', 'numerator',
|
|
178
|
+
}),
|
|
179
|
+
'strategy': frozenset({
|
|
180
|
+
'account_currency', 'avg_losing_trade', 'avg_losing_trade_percent', 'avg_trade',
|
|
181
|
+
'avg_trade_percent', 'avg_winning_trade', 'avg_winning_trade_percent', 'cancel',
|
|
182
|
+
'cancel_all', 'cash', 'close', 'close_all', 'closedtrades', 'commission',
|
|
183
|
+
'convert_to_account', 'convert_to_symbol', 'default_entry_qty', 'direction', 'entry',
|
|
184
|
+
'equity', 'eventrades', 'exit', 'fixed', 'grossloss', 'grossloss_percent',
|
|
185
|
+
'grossprofit', 'grossprofit_percent', 'initial_capital', 'long', 'losstrades',
|
|
186
|
+
'margin_liquidation_price', 'max_contracts_held_all', 'max_contracts_held_long',
|
|
187
|
+
'max_contracts_held_short', 'max_drawdown', 'max_drawdown_percent', 'max_runup',
|
|
188
|
+
'max_runup_percent', 'na_float', 'netprofit', 'netprofit_percent', 'oca', 'openprofit',
|
|
189
|
+
'openprofit_percent', 'opentrades', 'order', 'percent_of_equity', 'position_avg_price',
|
|
190
|
+
'position_entry_name', 'position_size', 'risk', 'short', 'wintrades',
|
|
191
|
+
}),
|
|
192
|
+
'string': frozenset({
|
|
193
|
+
'contains', 'endswith', 'format', 'format_time', 'length', 'lower', 'match', 'na_float',
|
|
194
|
+
'pos', 'repeat', 'replace', 'replace_all', 'split', 'startswith', 'substring',
|
|
195
|
+
'tonumber', 'tostring', 'trim', 'upper',
|
|
196
|
+
}),
|
|
197
|
+
'syminfo': frozenset({
|
|
198
|
+
'basecurrency', 'country', 'currency', 'current_contract', 'description', 'employees',
|
|
199
|
+
'expiration_date', 'industry', 'isin', 'main_tickerid', 'mincontract', 'minmove',
|
|
200
|
+
'mintick', 'na_float', 'period', 'pointvalue', 'prefix', 'pricescale',
|
|
201
|
+
'recommendations_buy', 'recommendations_buy_strong', 'recommendations_date',
|
|
202
|
+
'recommendations_hold', 'recommendations_sell', 'recommendations_sell_strong',
|
|
203
|
+
'recommendations_total', 'regular', 'root', 'sector', 'session', 'shareholders',
|
|
204
|
+
'shares_outstanding_float', 'shares_outstanding_total', 'target_price_average',
|
|
205
|
+
'target_price_date', 'target_price_estimates', 'target_price_high', 'target_price_low',
|
|
206
|
+
'target_price_median', 'ticker', 'tickerid', 'timezone', 'type', 'volumetype',
|
|
207
|
+
}),
|
|
208
|
+
'ta': frozenset({
|
|
209
|
+
'accdist', 'alma', 'atr', 'barssince', 'bb', 'bbw', 'cci', 'change', 'cmo', 'cog',
|
|
210
|
+
'correlation', 'cross', 'crossover', 'crossunder', 'cum', 'dev', 'dmi', 'ema',
|
|
211
|
+
'falling', 'highest', 'highestbars', 'hma', 'iii', 'kc', 'kcw', 'linreg', 'lowest',
|
|
212
|
+
'lowestbars', 'macd', 'max', 'median', 'mfi', 'min', 'mode', 'mom', 'na_float', 'nvi',
|
|
213
|
+
'obv', 'percentile_linear_interpolation', 'percentile_nearest_rank', 'percentrank',
|
|
214
|
+
'pivot_point_levels', 'pivothigh', 'pivotlow', 'pvi', 'pvt', 'range', 'rci', 'rising',
|
|
215
|
+
'rma', 'roc', 'rsi', 'sar', 'sma', 'stdev', 'stoch', 'supertrend', 'swma', 'tr', 'tsi',
|
|
216
|
+
'valuewhen', 'variance', 'vwap', 'vwma', 'wad', 'wma', 'wpr', 'wvad',
|
|
217
|
+
}),
|
|
218
|
+
'table': frozenset({
|
|
219
|
+
'all', 'cell', 'cell_set_bgcolor', 'cell_set_height', 'cell_set_text',
|
|
220
|
+
'cell_set_text_color', 'cell_set_text_font_family', 'cell_set_text_formatting',
|
|
221
|
+
'cell_set_text_halign', 'cell_set_text_size', 'cell_set_text_valign',
|
|
222
|
+
'cell_set_tooltip', 'cell_set_width', 'clear', 'delete', 'merge_cells', 'new',
|
|
223
|
+
'set_bgcolor', 'set_border_color', 'set_border_width', 'set_frame_color',
|
|
224
|
+
'set_frame_width', 'set_position',
|
|
225
|
+
}),
|
|
226
|
+
'text': frozenset({
|
|
227
|
+
'align_bottom', 'align_center', 'align_left', 'align_right', 'align_top', 'format_bold',
|
|
228
|
+
'format_italic', 'format_none', 'wrap_auto', 'wrap_none',
|
|
229
|
+
}),
|
|
230
|
+
'ticker': frozenset({
|
|
231
|
+
'heikinashi', 'inherit', 'kagi', 'linebreak', 'modify', 'new', 'pointfigure', 'renko',
|
|
232
|
+
'standard',
|
|
233
|
+
}),
|
|
234
|
+
'timeframe': frozenset({
|
|
235
|
+
'change', 'from_seconds', 'in_seconds', 'isdaily', 'isdwm', 'isintraday', 'isminutes',
|
|
236
|
+
'ismonthly', 'isseconds', 'isticks', 'isweekly', 'main_period', 'multiplier', 'period',
|
|
237
|
+
}),
|
|
238
|
+
'volume_row': frozenset({
|
|
239
|
+
'buy_volume', 'delta', 'down_price', 'sell_volume', 'total_volume', 'up_price',
|
|
240
|
+
}),
|
|
241
|
+
'xloc': frozenset({
|
|
242
|
+
'bar_index', 'bar_time',
|
|
243
|
+
}),
|
|
244
|
+
'yloc': frozenset({
|
|
245
|
+
'abovebar', 'belowbar', 'price',
|
|
246
|
+
}),
|
|
247
|
+
}
|
pine2pyne/node_ids.py
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""The numbers PyneComp gives the blocks of a script: the suffix of a renamed local.
|
|
2
|
+
|
|
3
|
+
A local that shadows a name, or is named like a function of the script, is
|
|
4
|
+
spelled ``<name>__<n>__`` by PyneComp, ``n`` eight hex digits. ``n`` is the id
|
|
5
|
+
its parser gave the block the local is declared in. The parser numbers some
|
|
6
|
+
nodes, from 1, as it finishes them (post-order, in source order):
|
|
7
|
+
|
|
8
|
+
* a call, except a cast (``int(x)``, ``label(na)``) and Pine v4's ``iff()``,
|
|
9
|
+
which is parsed as a conditional;
|
|
10
|
+
* a history read ``x[n]``;
|
|
11
|
+
* every block: a function body (a one-line body too), each branch of an
|
|
12
|
+
``if``/``else if``/``else``, each case of a ``switch``, a loop body;
|
|
13
|
+
* a ``type`` or ``enum`` declaration.
|
|
14
|
+
|
|
15
|
+
Pine v4 is converted while it is parsed and the nodes the conversion creates
|
|
16
|
+
are numbered too: a constant colour merged with ``transp`` (or with v4's
|
|
17
|
+
default transparency) is a ``color.new()`` call. (The session conversion of
|
|
18
|
+
``time()``, two more calls, is in the tree already: :mod:`.legacy_sessions`.)
|
|
19
|
+
|
|
20
|
+
Measured with probe scripts compiled by PyneComp v6.0.80 (``tmp/probes``):
|
|
21
|
+
a meter function ``m(x) => m = x`` between two constructs reads how many ids
|
|
22
|
+
the construct takes. On the reference corpus the numbering names 87 of the 92
|
|
23
|
+
modules with such locals that pine2pyne parses.
|
|
24
|
+
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import dataclasses
|
|
28
|
+
from typing import Dict, Optional
|
|
29
|
+
|
|
30
|
+
from .legacy_sessions import SESSION_HELPER
|
|
31
|
+
from .ast_nodes import (
|
|
32
|
+
ASTNode, Assignment, EnumDecl, ExpressionStatement, ForInLoop, ForLoop, FuncDecl, FunctionCall, Identifier,
|
|
33
|
+
IfExpression, IfStatement, IndexAccess, InputDecl, Literal, MemberAccess, MethodCall, Script, SwitchExpression,
|
|
34
|
+
SwitchStatement, TupleDestructure, TypeDecl, WhileLoop,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
#: calls that are casts: no node of their own
|
|
38
|
+
_CASTS = frozenset({'int', 'float', 'bool', 'string', 'color', 'line', 'label', 'box', 'table', 'linefill',
|
|
39
|
+
'polyline', 'iff'})
|
|
40
|
+
_NAMED_COLOURS = frozenset({
|
|
41
|
+
'aqua', 'black', 'blue', 'fuchsia', 'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'orange',
|
|
42
|
+
'purple', 'red', 'silver', 'teal', 'white', 'yellow'})
|
|
43
|
+
#: Pine v4 calls whose colour takes ``transp``: the colour keywords, (colour, transp) positions
|
|
44
|
+
_V4_COLOUR_KEYWORDS = {'plot': ('color',), 'plotshape': ('color', 'textcolor'), 'plotchar': ('color',),
|
|
45
|
+
'plotarrow': ('colorup', 'colordown'), 'fill': ('color',)}
|
|
46
|
+
_V4_COLOUR_POSITIONS = {'plot': (2, None), 'plotshape': (4, 5), 'plotchar': (4, 5), 'fill': (2, 3)}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def hex_suffixed(name: str, block_id: int) -> str:
|
|
50
|
+
"""PyneComp's spelling of a renamed local of block ``block_id``."""
|
|
51
|
+
return f'{name}__{block_id:08x}__'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class BlockNumbers:
|
|
55
|
+
"""The id of every block of a script, by the identity of its statement list
|
|
56
|
+
(or of the function, for a one-line body). Built once per script."""
|
|
57
|
+
|
|
58
|
+
def __init__(self, script: Script) -> None:
|
|
59
|
+
version_text = getattr(script.version, 'version', '') if script.version else ''
|
|
60
|
+
self._version = int(version_text) if str(version_text).isdigit() else 6
|
|
61
|
+
self._count = 0
|
|
62
|
+
self._ids: Dict[int, int] = {}
|
|
63
|
+
items = sorted(list(script.declarations) + list(script.body),
|
|
64
|
+
key=lambda item: (getattr(item, 'line', 0), getattr(item, 'column', 0)))
|
|
65
|
+
self._constant_colour_names = self._constant_colours(items) if self._version <= 4 else frozenset()
|
|
66
|
+
if script.script_decl is not None:
|
|
67
|
+
for value in script.script_decl.kwargs.values():
|
|
68
|
+
self._expression(value)
|
|
69
|
+
self._take()
|
|
70
|
+
for item in items:
|
|
71
|
+
self._statement(item)
|
|
72
|
+
|
|
73
|
+
def of(self, block) -> int:
|
|
74
|
+
"""The id of a statement list (or of a FuncDecl's body); 0 when unknown."""
|
|
75
|
+
return self._ids.get(id(block), 0)
|
|
76
|
+
|
|
77
|
+
# ------------------------------------------------------------ numbering
|
|
78
|
+
|
|
79
|
+
def _take(self) -> int:
|
|
80
|
+
self._count += 1
|
|
81
|
+
return self._count
|
|
82
|
+
|
|
83
|
+
def _block(self, statements, owner: Optional[object] = None) -> None:
|
|
84
|
+
if isinstance(statements, list):
|
|
85
|
+
for statement in statements:
|
|
86
|
+
self._statement(statement)
|
|
87
|
+
else:
|
|
88
|
+
self._expression(statements)
|
|
89
|
+
number = self._take()
|
|
90
|
+
self._ids[id(statements)] = number
|
|
91
|
+
if owner is not None:
|
|
92
|
+
self._ids[id(owner)] = number
|
|
93
|
+
|
|
94
|
+
def _statement(self, node) -> None:
|
|
95
|
+
if isinstance(node, FuncDecl):
|
|
96
|
+
if node.name == SESSION_HELPER:
|
|
97
|
+
return # PyneComp's own helper
|
|
98
|
+
for parameter in node.params:
|
|
99
|
+
self._expression(parameter.default)
|
|
100
|
+
self._block(node.body, owner=node)
|
|
101
|
+
elif isinstance(node, IfStatement):
|
|
102
|
+
self._expression(node.condition)
|
|
103
|
+
self._block(node.body)
|
|
104
|
+
for condition, body in node.elseifs:
|
|
105
|
+
self._expression(condition)
|
|
106
|
+
self._block(body)
|
|
107
|
+
if node.else_body is not None:
|
|
108
|
+
self._block(node.else_body)
|
|
109
|
+
elif isinstance(node, ForLoop):
|
|
110
|
+
for value in (node.from_val, node.to_val, node.step):
|
|
111
|
+
self._expression(value)
|
|
112
|
+
self._block(node.body)
|
|
113
|
+
elif isinstance(node, ForInLoop):
|
|
114
|
+
self._expression(node.iterable)
|
|
115
|
+
self._block(node.body)
|
|
116
|
+
elif isinstance(node, WhileLoop):
|
|
117
|
+
self._expression(node.condition)
|
|
118
|
+
self._block(node.body)
|
|
119
|
+
elif isinstance(node, (SwitchStatement, SwitchExpression)):
|
|
120
|
+
self._switch(node)
|
|
121
|
+
elif isinstance(node, InputDecl):
|
|
122
|
+
for value in list(node.args) + list(node.kwargs.values()):
|
|
123
|
+
self._expression(value)
|
|
124
|
+
self._take()
|
|
125
|
+
elif isinstance(node, (TypeDecl, EnumDecl)):
|
|
126
|
+
self._take()
|
|
127
|
+
else:
|
|
128
|
+
self._expression(node)
|
|
129
|
+
|
|
130
|
+
def _switch(self, node) -> None:
|
|
131
|
+
self._expression(node.expr)
|
|
132
|
+
for case, body in node.cases:
|
|
133
|
+
self._expression(case)
|
|
134
|
+
self._block(body)
|
|
135
|
+
if node.default is not None:
|
|
136
|
+
self._block(node.default)
|
|
137
|
+
|
|
138
|
+
def _expression(self, node) -> None:
|
|
139
|
+
if node is None or not isinstance(node, (ASTNode, list)):
|
|
140
|
+
return
|
|
141
|
+
if isinstance(node, list):
|
|
142
|
+
for item in node:
|
|
143
|
+
self._statement(item)
|
|
144
|
+
return
|
|
145
|
+
if isinstance(node, TupleDestructure):
|
|
146
|
+
return # the names only: its value is the assignment's
|
|
147
|
+
if isinstance(node, FunctionCall):
|
|
148
|
+
if not isinstance(node.func, str):
|
|
149
|
+
self._expression(node.func)
|
|
150
|
+
for value in list(node.args) + list(node.kwargs.values()):
|
|
151
|
+
self._expression(value)
|
|
152
|
+
if isinstance(node.func, str) and node.func in _CASTS:
|
|
153
|
+
return
|
|
154
|
+
if self._version <= 4 and isinstance(node.func, str):
|
|
155
|
+
self._v4_conversion(node)
|
|
156
|
+
self._take()
|
|
157
|
+
return
|
|
158
|
+
if isinstance(node, MethodCall):
|
|
159
|
+
self._expression(node.object)
|
|
160
|
+
for value in list(node.args) + list(node.kwargs.values()):
|
|
161
|
+
self._expression(value)
|
|
162
|
+
self._take()
|
|
163
|
+
return
|
|
164
|
+
if isinstance(node, IndexAccess):
|
|
165
|
+
self._expression(node.object)
|
|
166
|
+
self._expression(node.index)
|
|
167
|
+
self._take()
|
|
168
|
+
return
|
|
169
|
+
if isinstance(node, IfExpression):
|
|
170
|
+
self._expression(node.condition)
|
|
171
|
+
self._block(node.true_expr)
|
|
172
|
+
if node.false_expr is not None:
|
|
173
|
+
self._block(node.false_expr)
|
|
174
|
+
return
|
|
175
|
+
if isinstance(node, SwitchExpression):
|
|
176
|
+
self._switch(node)
|
|
177
|
+
return
|
|
178
|
+
if isinstance(node, (Assignment, ExpressionStatement)) or dataclasses.is_dataclass(node):
|
|
179
|
+
for field in dataclasses.fields(node):
|
|
180
|
+
if field.name in ('line', 'column'):
|
|
181
|
+
continue
|
|
182
|
+
self._child(getattr(node, field.name))
|
|
183
|
+
|
|
184
|
+
def _child(self, value) -> None:
|
|
185
|
+
if isinstance(value, ASTNode):
|
|
186
|
+
self._expression(value)
|
|
187
|
+
elif isinstance(value, (list, tuple)):
|
|
188
|
+
for item in value:
|
|
189
|
+
self._child(item)
|
|
190
|
+
elif isinstance(value, dict):
|
|
191
|
+
for item in value.values():
|
|
192
|
+
self._child(item)
|
|
193
|
+
|
|
194
|
+
# ------------------------------------------------------------ Pine v4 conversion
|
|
195
|
+
|
|
196
|
+
def _v4_conversion(self, call: FunctionCall) -> None:
|
|
197
|
+
"""The calls Pine v4's conversion adds around ``call``."""
|
|
198
|
+
if call.func in _V4_COLOUR_KEYWORDS:
|
|
199
|
+
for _ in range(self._merged_colours(call)):
|
|
200
|
+
self._take() # color.new(c, transp)
|
|
201
|
+
|
|
202
|
+
def _merged_colours(self, call: FunctionCall) -> int:
|
|
203
|
+
function = call.func
|
|
204
|
+
transparency = call.kwargs.get('transp')
|
|
205
|
+
colour_index, transp_index = _V4_COLOUR_POSITIONS.get(function, (None, None))
|
|
206
|
+
if transp_index is not None and len(call.args) > transp_index:
|
|
207
|
+
transparency = call.args[transp_index]
|
|
208
|
+
colours = [call.kwargs[key] for key in _V4_COLOUR_KEYWORDS[function] if key in call.kwargs]
|
|
209
|
+
if colour_index is not None and len(call.args) > colour_index:
|
|
210
|
+
colours.append(call.args[colour_index])
|
|
211
|
+
merged = 0
|
|
212
|
+
for colour in colours:
|
|
213
|
+
if self._is_constant_colour(colour):
|
|
214
|
+
merged += 1
|
|
215
|
+
elif transparency is not None and function == 'fill' and not isinstance(colour, Literal):
|
|
216
|
+
merged += 1
|
|
217
|
+
return merged
|
|
218
|
+
|
|
219
|
+
def _is_constant_colour(self, value) -> bool:
|
|
220
|
+
if isinstance(value, Literal):
|
|
221
|
+
return value.literal_type == 'color'
|
|
222
|
+
if isinstance(value, Identifier):
|
|
223
|
+
return value.name in self._constant_colour_names or (
|
|
224
|
+
value.name.startswith('color.') and value.name[len('color.'):] in _NAMED_COLOURS)
|
|
225
|
+
return isinstance(value, MemberAccess) and value.object == 'color' and value.member in _NAMED_COLOURS
|
|
226
|
+
|
|
227
|
+
def _constant_colours(self, items) -> frozenset:
|
|
228
|
+
"""Top-level names bound once, to a constant colour."""
|
|
229
|
+
bindings: Dict[str, list] = {}
|
|
230
|
+
for item in items:
|
|
231
|
+
if isinstance(item, Assignment) and isinstance(item.target, str):
|
|
232
|
+
bindings.setdefault(item.target, []).append(item.value)
|
|
233
|
+
self._constant_colour_names = frozenset()
|
|
234
|
+
return frozenset(name for name, values in bindings.items()
|
|
235
|
+
if len(values) == 1 and self._is_constant_colour(values[0]))
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`once` lowering: Pine v6's `once` structure as a persistent flag plus an `if`.
|
|
3
|
+
|
|
4
|
+
once close > mySMA var bool once_fired1 = false
|
|
5
|
+
printLabel(...) -> if not once_fired1 and close > mySMA
|
|
6
|
+
once_fired1 := true
|
|
7
|
+
printLabel(...)
|
|
8
|
+
|
|
9
|
+
This is the equivalent code the Pine v6 User Manual gives for `once`
|
|
10
|
+
("Conditional structures", section "`once` structure"): the block runs the
|
|
11
|
+
first time its condition is true and never again. The condition is optional
|
|
12
|
+
and `true` by default, so a bare `once` checks only its flag. `and`
|
|
13
|
+
short-circuits, so the condition is not evaluated once the structure fired
|
|
14
|
+
("evaluated only once ... and then never again after that"). The flag is set
|
|
15
|
+
before the block, so a `break` or `continue` in it cannot skip that.
|
|
16
|
+
|
|
17
|
+
The flag is a `var`, so it has a `var`'s scope: one per function call site,
|
|
18
|
+
one for all iterations of a loop, initialised the first time its block runs.
|
|
19
|
+
The lowering runs at the end of parsing, so no later stage sees a `once`
|
|
20
|
+
(card #59).
|
|
21
|
+
"""
|
|
22
|
+
import dataclasses
|
|
23
|
+
|
|
24
|
+
from .ast_nodes import (
|
|
25
|
+
BinaryOp, Identifier, IfStatement, Literal, OnceStatement, Reassignment,
|
|
26
|
+
Script, UnaryOp, VarDecl,
|
|
27
|
+
)
|
|
28
|
+
from .ast_walk import contains, is_node
|
|
29
|
+
from .scope_renamer import collect_names, fresh_name
|
|
30
|
+
|
|
31
|
+
FLAG_STEM = 'once_fired'
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def lower_once_structures(script: Script) -> Script:
|
|
35
|
+
"""Return a copy of `script` with every `once` structure lowered to a
|
|
36
|
+
`var` flag and an `if`. A script without one is returned unchanged."""
|
|
37
|
+
if not contains(script, lambda node: isinstance(node, OnceStatement)):
|
|
38
|
+
return script
|
|
39
|
+
return _OnceLowering(collect_names(script)).rebuild(script)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class _OnceLowering:
|
|
43
|
+
def __init__(self, used_names):
|
|
44
|
+
self.used_names = used_names
|
|
45
|
+
|
|
46
|
+
def rebuild(self, value):
|
|
47
|
+
"""`value` with each statement list's `once` structures expanded in place."""
|
|
48
|
+
if isinstance(value, list):
|
|
49
|
+
lowered = []
|
|
50
|
+
for item in value:
|
|
51
|
+
rebuilt = self.rebuild(item)
|
|
52
|
+
lowered.extend(self.flag_and_if(rebuilt) if isinstance(rebuilt, OnceStatement) else [rebuilt])
|
|
53
|
+
return lowered
|
|
54
|
+
if isinstance(value, tuple):
|
|
55
|
+
return tuple(self.rebuild(item) for item in value)
|
|
56
|
+
if isinstance(value, dict):
|
|
57
|
+
return {key: self.rebuild(item) for key, item in value.items()}
|
|
58
|
+
if not is_node(value):
|
|
59
|
+
return value
|
|
60
|
+
children = {field.name: self.rebuild(getattr(value, field.name))
|
|
61
|
+
for field in dataclasses.fields(value) if field.name not in ('line', 'column')}
|
|
62
|
+
return dataclasses.replace(value, **children)
|
|
63
|
+
|
|
64
|
+
def flag_and_if(self, once: OnceStatement) -> list:
|
|
65
|
+
position = {'line': once.line, 'column': once.column}
|
|
66
|
+
flag = fresh_name(FLAG_STEM, self.used_names)
|
|
67
|
+
not_fired = UnaryOp(op='not', operand=Identifier(name=flag, **position), **position)
|
|
68
|
+
condition = not_fired if once.condition is None else BinaryOp(
|
|
69
|
+
left=not_fired, op='and', right=once.condition, **position)
|
|
70
|
+
fired = Reassignment(target=flag, value=Literal(value=True, literal_type='bool', **position), **position)
|
|
71
|
+
return [
|
|
72
|
+
VarDecl(name=flag, value=Literal(value=False, literal_type='bool', **position), type_hint='bool',
|
|
73
|
+
**position),
|
|
74
|
+
IfStatement(condition=condition, body=[fired] + once.body, **position),
|
|
75
|
+
]
|