@pineforge/codegen-pyodide 1.1.0 → 1.3.0

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/LICENSE ADDED
@@ -0,0 +1,261 @@
1
+ PineForge Source License 1.2
2
+ ============================
3
+
4
+ Version 1.2, 2026-10-05. Compared with 1.1, two places change. In the
5
+ Personal Trading section, the last bullet now says that an account a
6
+ proprietary-trading firm or funded-trader program provides or allocates,
7
+ including a challenge, evaluation or simulated account, is not the
8
+ person's own account or capital. In the Commercial Use section, the
9
+ definition of investment capital now covers the capital in such an
10
+ account, real or simulated.
11
+
12
+ Copyright 2025-2026 pineforge, LLC
13
+
14
+ Required Notice: Copyright 2025-2026 pineforge, LLC (https://github.com/pineforge-4pass/pineforge-codegen-oss)
15
+
16
+ The software is free of charge for the permitted purposes below, including
17
+ Personal Trading. Commercial Use, defined below, needs a separate commercial
18
+ license from the licensor.
19
+
20
+
21
+ ## Acceptance
22
+
23
+ In order to get any license under these terms, you must agree to them as both
24
+ strict obligations and conditions to all your licenses.
25
+
26
+
27
+ ## Copyright License
28
+
29
+ The licensor grants you a copyright license for the software to do everything
30
+ you might do with the software that would otherwise infringe the licensor's
31
+ copyright in it for any permitted purpose. However, you may only distribute
32
+ the software according to the Distribution License section, and make changes
33
+ or new works based on the software according to the Changes and New Works
34
+ License section.
35
+
36
+
37
+ ## Distribution License
38
+
39
+ The licensor grants you an additional copyright license to distribute copies
40
+ of the software. Your license to distribute covers distributing the software
41
+ with changes and new works permitted by the Changes and New Works License
42
+ section. Unless it is a permitted purpose, distributing the software, changed
43
+ or not, embedded in or bundled with a product or service made available to
44
+ others is Commercial Use under (3) of the Commercial Use section, which your
45
+ license to distribute does not cover. Distributing copies under this section
46
+ is not Commercial Use, and it gives the people who get them no license beyond
47
+ these terms.
48
+
49
+
50
+ ## Notices
51
+
52
+ You must ensure that anyone who gets a copy of any part of the software from
53
+ you also gets a copy of these terms or a link to them, as well as copies of
54
+ any plain-text lines beginning with `Required Notice:` that the licensor
55
+ provided with the software. For example:
56
+
57
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
58
+
59
+
60
+ ## Changes and New Works License
61
+
62
+ The licensor grants you an additional copyright license to make changes and
63
+ new works based on the software for any permitted purpose.
64
+
65
+
66
+ ## Patent License
67
+
68
+ The licensor grants you a patent license for the software that covers patent
69
+ claims the licensor can license, or becomes able to license, that you would
70
+ infringe by using the software for a permitted purpose.
71
+
72
+
73
+ ## Permitted Purposes
74
+
75
+ Each of the following is a permitted purpose:
76
+
77
+ - **Noncommercial purposes.** Any noncommercial purpose.
78
+
79
+ - **Personal uses.** Personal use for research, experiment, and testing for
80
+ the benefit of public knowledge, personal study, private entertainment,
81
+ hobby projects, amateur pursuits, or religious observance, without any
82
+ anticipated commercial application.
83
+
84
+ - **Noncommercial organizations.** Use by any charitable organization,
85
+ educational institution, public research organization, public safety or
86
+ health organization, environmental protection organization, or government
87
+ institution for its teaching, research and other operations, regardless of
88
+ the source of funding or obligations resulting from the funding.
89
+
90
+ - **Personal Trading**, as defined in the next section.
91
+
92
+ Investment Management, defined in the Commercial Use section, is never a
93
+ permitted purpose, except as Personal Trading. That is so even when it is done
94
+ by a noncommercial organization or for a noncommercial purpose.
95
+
96
+
97
+ ## Personal Trading
98
+
99
+ **Personal Trading** means use of the software by a natural person to do any
100
+ of the following, solely for trades that meet conditions (a) and (b) below:
101
+ research, develop or backtest trading strategies, or execute trades in
102
+ securities, derivatives, currencies, crypto-assets, commodities or other
103
+ financial instruments.
104
+
105
+ (a) The trades are, or will be, placed for that person's own account.
106
+
107
+ (b) The trades are, or will be, funded solely by that person's own
108
+ capital.
109
+
110
+ For Personal Trading:
111
+
112
+ - A person's **household** is that person, their spouse or domestic
113
+ partner, and their dependants.
114
+
115
+ - A person's **own account** includes an account held by the person alone
116
+ or jointly with members of their household; an account of a member of
117
+ their household; and a retirement, pension, education-savings or other
118
+ tax-advantaged account, or an account of a revocable trust, held for the
119
+ benefit of the person or members of their household.
120
+
121
+ - A person's **own capital** includes capital belonging to members of
122
+ their household, and capital borrowed in the ordinary course from a
123
+ broker, bank or other lender, such as margin, leverage or credit on a
124
+ trading account, for which the person or their household is liable.
125
+ Money the person has received outright, such as pay, a gift or an
126
+ inheritance, is the person's own capital.
127
+
128
+ - Trading in the person's own name, for their own account and with their
129
+ own capital, is Personal Trading even when it is the person's business
130
+ or livelihood.
131
+
132
+ - Publishing or teaching about the person's own Personal Trading,
133
+ including its results, is part of Personal Trading even when the person
134
+ is paid for it, as long as they do not give Output to others.
135
+
136
+ - An account of a company, partnership, fund, trust or other
137
+ organization, other than an account described under own account above,
138
+ is not the person's own account, even if the person wholly owns or
139
+ controls it.
140
+
141
+ - Capital that an employer, a proprietary-trading firm, a funded-trader
142
+ program or anyone else outside the person's household provides or
143
+ allocates to the person to trade, and that the provider still owns or
144
+ whose losses the provider bears, is not the person's own capital, even
145
+ if the person shares in the profits. An account that a
146
+ proprietary-trading firm or a funded-trader program provides or
147
+ allocates to the person to trade, including a challenge, evaluation or
148
+ simulated account, whether the capital in it is real or simulated, is
149
+ likewise not the person's own account and is not funded by the
150
+ person's own capital.
151
+
152
+
153
+ ## Commercial Use
154
+
155
+ **Investment Management** means using the software to manage, advise on, or
156
+ trade investment capital; to research, develop or backtest strategies for
157
+ investment capital that you, or anyone you do the work for, manage, advise on
158
+ or trade; or to operate the software for others who do any of these things;
159
+ in each case whoever the capital belongs to and whether or not for a fee.
160
+
161
+ **Investment capital** means any money or other assets held for investment or
162
+ trading, including capital belonging to any other person or entity, such as a
163
+ friend or relative, clients or investors, an endowment, a pension or
164
+ retirement fund, a sovereign or other public fund, or the treasury or reserves
165
+ of a foundation or other organization. The capital in an account that a
166
+ proprietary-trading firm or a funded-trader program provides or allocates
167
+ to a person or entity to trade, including a challenge, evaluation or
168
+ simulated account, is investment capital whether it is real or simulated.
169
+
170
+ **Commercial Use** means any use of the software that is not a permitted
171
+ purpose, other than distributing copies under the Distribution License
172
+ section. Investment Management is Commercial Use for every individual and
173
+ every organization, including the noncommercial organizations listed under
174
+ Permitted Purposes, whatever its purpose, unless it is Personal Trading.
175
+ Unless it is a permitted purpose, each of the following is also Commercial
176
+ Use:
177
+
178
+ (1) managing, advising on, or trading capital belonging to any other person
179
+ or entity, whether or not for a fee;
180
+
181
+ (2) use by, for, or on behalf of any company, fund, partnership, or other
182
+ organization, including use by an individual in the course of work for
183
+ such an organization;
184
+
185
+ (3) embedding the software or its Output, changed or not, into any product
186
+ or service made available to others, or distributing either bundled
187
+ with such a product or service, including using the software to
188
+ generate Output for such a product or service; and
189
+
190
+ (4) operating any hosted, software-as-a-service, or otherwise public-facing
191
+ service through which others can run the software or receive its
192
+ Output.
193
+
194
+ Commercial Use requires a separate commercial license from the licensor. To
195
+ obtain one, contact: enterprise@pineforge.dev
196
+
197
+
198
+ ## Output
199
+
200
+ **Output** means code that the software generates, such as the C++ source
201
+ code it generates from PineScript, and any program or library built from that
202
+ code. Backtest results, charts, reports and trade signals are not Output.
203
+
204
+
205
+ ## Fair Use
206
+
207
+ You may have "fair use" rights for the software under the law. These terms do
208
+ not limit them.
209
+
210
+
211
+ ## No Other Rights
212
+
213
+ These terms do not allow you to sublicense or transfer any of your licenses
214
+ to anyone else, or prevent the licensor from granting licenses to anyone
215
+ else. These terms do not imply any other licenses.
216
+
217
+
218
+ ## Patent Defense
219
+
220
+ If you make any written claim that the software infringes or contributes to
221
+ infringement of any patent, your patent license for the software granted
222
+ under these terms ends immediately. If your company makes such a claim, your
223
+ patent license ends immediately for work on behalf of your company.
224
+
225
+
226
+ ## Violations
227
+
228
+ The first time you are notified in writing that you have violated any of
229
+ these terms, or done anything with the software not covered by your licenses,
230
+ your licenses can nonetheless continue if you come into full compliance with
231
+ these terms, and take practical steps to correct past violations, within 32
232
+ days of receiving notice. Otherwise, all your licenses end immediately.
233
+
234
+
235
+ ## No Liability
236
+
237
+ ***As far as the law allows, the software comes as is, without any warranty
238
+ or condition, and the licensor will not be liable to you for any damages
239
+ arising out of these terms or the use or nature of the software, under any
240
+ kind of legal claim.***
241
+
242
+
243
+ ## Definitions
244
+
245
+ The **licensor** is pineforge, LLC, and the **software** is the software the
246
+ licensor makes available under these terms.
247
+
248
+ **You** refers to the individual or entity agreeing to these terms.
249
+
250
+ **Your company** is any legal entity, sole proprietorship, or other kind of
251
+ organization that you work for, plus all organizations that have control
252
+ over, are under the control of, or are under common control with that
253
+ organization. **Control** means ownership of substantially all the assets of
254
+ an entity, or the power to direct its management and policies by vote,
255
+ contract, or otherwise. Control can be direct or indirect.
256
+
257
+ **Your licenses** are all the licenses granted to you for the software under
258
+ these terms.
259
+
260
+ **Use** means anything you do with the software requiring one of your
261
+ licenses.
package/README.md CHANGED
@@ -16,6 +16,11 @@ Stable releases are on the `latest` dist-tag. A prerelease (for example
16
16
  - `transpile.worker.mjs` — an ES module worker that runs the glue in Pyodide.
17
17
  - `index.mjs` — exports `release`, `tables`, `archivePath`, `sourceRoot`, `codegenSourceDir`,
18
18
  `workerPath` and `glue`.
19
+ - `pineforge_codegen/diagnostics_catalog.json` — the diagnostics catalog (since 1.2.0), also
20
+ importable as `@pineforge/codegen-pyodide/diagnostics_catalog.json`; the repository's
21
+ `docs/PUBLIC_CONTRACT.md` describes it.
22
+ - `LICENSE` — the PineForge Source License (since 1.2.0), which `package.json` names:
23
+ version 1.1 in release 1.2.0, version 1.2 from release 1.3.0 on.
19
24
 
20
25
  ## Publishing (maintainers)
21
26
  A `v*` tag push, which the release workflow makes, publishes through npm OIDC Trusted
package/glue.py CHANGED
@@ -23,6 +23,10 @@ def _diagnostic_entries(diagnostics) -> list:
23
23
  "col": loc.col if loc else 1,
24
24
  "message": message,
25
25
  "severity": getattr(d.level, "value", "error"),
26
+ # The stable code and named arguments of the catalog templates the
27
+ # message (and the hint after " — ") render from.
28
+ "code": d.code,
29
+ "args": d.args,
26
30
  }
27
31
  end_col = getattr(loc, "end_col", None) if loc else None
28
32
  if end_col is not None:
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@pineforge/codegen-pyodide",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Gate-validated Pyodide payload for the PineScript v6 -> C++ transpiler: archive (run in Pyodide), unpacked source, introspected tables, and release metadata.",
5
5
  "type": "module",
6
6
  "main": "index.mjs",
7
7
  "exports": {
8
8
  ".": "./index.mjs",
9
9
  "./tables.json": "./tables.json",
10
- "./release.json": "./release.json"
10
+ "./release.json": "./release.json",
11
+ "./diagnostics_catalog.json": "./pineforge_codegen/diagnostics_catalog.json"
11
12
  },
12
13
  "files": [
13
14
  "index.mjs",
@@ -16,7 +17,8 @@
16
17
  "tables.json",
17
18
  "release.json",
18
19
  "transpile.worker.mjs",
19
- "glue.py"
20
+ "glue.py",
21
+ "LICENSE"
20
22
  ],
21
23
  "engines": {
22
24
  "node": ">=20"
@@ -35,5 +37,5 @@
35
37
  "type": "git",
36
38
  "url": "git+https://github.com/pineforge-4pass/pineforge-codegen-oss.git"
37
39
  },
38
- "license": "PolyForm-Noncommercial-1.0.0"
40
+ "license": "SEE LICENSE IN LICENSE"
39
41
  }
@@ -6,6 +6,7 @@ from .lexer import Lexer
6
6
  from .parser import Parser
7
7
  from .analyzer import Analyzer
8
8
  from .codegen import CodeGen
9
+ from .diagnostic_codes import diagnostics_catalog, render_diagnostic
9
10
  from .errors import CompileError, Level, Phase
10
11
  from .external_requests import lower_no_data_requests
11
12
  from .builtin_keywords import bind_builtin_keywords
@@ -240,6 +240,9 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
240
240
  def __init__(self, ctx: AnalyzerContext,
241
241
  budget: TimeBudget | None = None) -> None:
242
242
  self.ctx = ctx
243
+ self._order_shape_calls = {}
244
+ self._order_shape_host_reads: set[str] = set()
245
+ self._order_shape_constructor: list[str] = []
243
246
  self._budget = budget
244
247
  self._budget_visit_count = 0
245
248
  self._initialise_safe_names(ctx.ast)
@@ -4414,7 +4417,44 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
4414
4417
  return None
4415
4418
 
4416
4419
  def generate(self) -> str:
4417
- """Generate C++ source from the AnalyzerContext."""
4420
+ """Generate C++ source from the AnalyzerContext.
4421
+
4422
+ An error the settings metadata finds in an input's arguments (emitted
4423
+ in the constructor, ahead of the body: ``checked_settings``) is held
4424
+ until the rest is generated; the error raised is the first in source
4425
+ order, as before that metadata visited the arguments."""
4426
+ self._deferred_settings_errors: list[CompileError] | None = []
4427
+ try:
4428
+ try:
4429
+ cpp = self._generate_cpp()
4430
+ except CompileError as error:
4431
+ first = self._first_settings_error_before(error)
4432
+ if first is None:
4433
+ raise
4434
+ raise first from None
4435
+ if self._deferred_settings_errors:
4436
+ raise self._deferred_settings_errors[0]
4437
+ return cpp
4438
+ finally:
4439
+ self._deferred_settings_errors = None
4440
+
4441
+ def _defer_settings_error(self, error: CompileError) -> None:
4442
+ held = getattr(self, "_deferred_settings_errors", None)
4443
+ if held is None: # outside generate(): nothing holds it
4444
+ raise error
4445
+ held.append(error)
4446
+
4447
+ def _first_settings_error_before(self, error: CompileError) -> CompileError | None:
4448
+ """A held settings error located before ``error``, else None."""
4449
+ def where(err: CompileError):
4450
+ loc = err.diagnostics[0].location if err.diagnostics else None
4451
+ return (loc.line, loc.col) if loc is not None else (float("inf"), 0)
4452
+ held = sorted(self._deferred_settings_errors, key=where)
4453
+ if held and where(held[0]) < where(error):
4454
+ return held[0]
4455
+ return None
4456
+
4457
+ def _generate_cpp(self) -> str:
4418
4458
  # Every input is keyed by its title: refuse a non-constant one first,
4419
4459
  # then flag inputs one override key would reach together.
4420
4460
  self._check_input_titles()
@@ -4453,7 +4493,8 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
4453
4493
  self._prepare_lazy_source_clock_sites()
4454
4494
  self.block_locals_needing_names = self._block_locals_needing_names()
4455
4495
 
4456
- lines: list[str] = []
4496
+ from .order_shapes import HostReadLines
4497
+ lines: list[str] = HostReadLines(self._order_shape_host_reads)
4457
4498
 
4458
4499
  # Series<T> ctor-arg suffix from any max_bars_back directive (empty when
4459
4500
  # absent, so directive-free output is byte-identical to before).
@@ -5413,7 +5454,12 @@ class CodeGen(CallVisitor, ExprVisitor, StmtVisitor, TopLevelEmitter, SecurityEm
5413
5454
  if self._uses_session_market:
5414
5455
  lines.insert(_session_market_member_at, SESSION_MARKET_MEMBER)
5415
5456
  lines.insert(_session_market_at, SESSION_MARKET_CPP)
5457
+ self._capabilities_export_at += 2
5416
5458
 
5459
+ from .capabilities import emit_capabilities_exports
5460
+ exports: list[str] = []
5461
+ emit_capabilities_exports(self, exports)
5462
+ lines[self._capabilities_export_at:self._capabilities_export_at] = exports
5417
5463
  cpp = "\n".join(lines)
5418
5464
  self._settle_session_reads(cpp)
5419
5465
  return cpp