|
| 1 | +# Experimental ES module emitter |
| 2 | + |
| 3 | +The development checkout exposes `JavaScript.emitter.compile_source`. It |
| 4 | +validates source through the python-browser/1 front end, lowers the immutable IR |
| 5 | +and returns a CompiledArtifact without executing input or writing files. The |
| 6 | +published 0.1.0 package predates this compiler implementation. |
| 7 | + |
| 8 | +```python |
| 9 | +from JavaScript.emitter import compile_source |
| 10 | + |
| 11 | +artifact = compile_source( |
| 12 | + "def count(text):\n return len(text)", |
| 13 | + filename="counter.py", |
| 14 | +) |
| 15 | +print(artifact.manifest["application_exports"]) # ['count'] |
| 16 | +``` |
| 17 | + |
| 18 | +`files` is a tuple of immutable OutputFile(path, data, role) values. The caller |
| 19 | +can inspect or pass those bytes to the future pocket-python application builder. |
| 20 | +The manifest bytes are separate from their own file/hash closure and can be |
| 21 | +saved as PYTHON-JAVASCRIPT.json. Every recorded file has exact size, SHA-256 and |
| 22 | +role; imports, notices and selected helper dependencies are explicit. Current |
| 23 | +single-module output has no static imports. The compiler ABI is |
| 24 | +python-browser-esm/1, independently of package and application-profile versions. |
| 25 | + |
| 26 | +The emitted entrypoint is app.mjs by default, with a named `createModule` export: |
| 27 | + |
| 28 | +```javascript |
| 29 | +import {createModule} from './app.mjs'; |
| 30 | +const app = createModule({write: text => console.log(text)}); |
| 31 | +console.log(app.count('A😀')); // 2n |
| 32 | +``` |
| 33 | + |
| 34 | +Each factory call initializes a fresh module in Python source order. Top-level |
| 35 | +print/call statements execute at that time. Functions are assigned when their |
| 36 | +definition executes; immutable literal defaults are created once per definition, |
| 37 | +including tuple identity across calls. Function-local unbound values and global |
| 38 | +use before definition raise source-located Python errors. Imports/aliases resolve |
| 39 | +through the validated JavaScript registry; only Array.of/length are adopted. |
| 40 | +The default output sink uses console.log with the print newline removed. |
| 41 | + |
| 42 | +External function arguments accept BigInt, bool, null and native JavaScript |
| 43 | +strings. Number is rejected to avoid ambiguous rounded integers. An explicit |
| 44 | +`{type:'str', codepoints:[...]}` preserves Python surrogate/code-point distinctions; |
| 45 | +`{type:'tuple', items:[...]}` constructs a Python tuple. Cycles, arbitrary host |
| 46 | +objects and input depth over 64 fail explicitly. Native string input iterates |
| 47 | +Unicode code points at the boundary. Exported strings/tuples retain their frozen |
| 48 | +str/codepoints or tuple/items wrappers; they are not JavaScript arrays. The host |
| 49 | +protocol adapter will serialize these values separately. |
| 50 | + |
| 51 | +Python integers use BigInt, including signed floor division/modulo and numeric |
| 52 | +bool behavior. Strings retain code points, negative indexing, membership and |
| 53 | +lexicographic ordering. Tuples retain truthiness, iteration, equality/order and |
| 54 | +alias identity. Chained comparisons and boolean operators evaluate each operand |
| 55 | +once, in order, with short-circuiting and original operand results. |
| 56 | + |
| 57 | +Print formats supported values using Python spelling and tuple/string repr. |
| 58 | +The compiler generates a compact nonprintable-range table from its CPython |
| 59 | +Unicode database and records that database version, so a newer JavaScript |
| 60 | +Unicode database cannot silently change repr. This is build-time data, not |
| 61 | +runtime Python delegation. Raw surrogate text output requires a separately |
| 62 | +adopted sink and fails explicitly; escaped surrogate tuple repr is supported. |
| 63 | +Integer/string interning identity remains outside the profile. Dynamic values |
| 64 | +outside an adopted operation fail with a source-located TypeError rather than |
| 65 | +coercing to native JavaScript behavior. |
| 66 | + |
| 67 | +Compiled calls use an explicit depth limit of 128 and report RecursionError |
| 68 | +before depending on host stack exhaustion. This is a profile resource limit, |
| 69 | +not CPython's configurable recursion limit. Arbitrary compiled applications are |
| 70 | +not instruction/memory sandboxed; the independent VM has its own budget model. |
| 71 | +Unsupported syntax/imports fail compilation before an artifact is returned. |
| 72 | +Ordinary error classes are preserved; argument-count wording is profile-specific. |
| 73 | + |
| 74 | +Source maps use version 3 and original logical filename, lines/columns and |
| 75 | +sourcesContent. Runtime errors also carry original location records. Pass |
| 76 | +source_map=False to omit map bytes and their sourceMappingURL together. Use a |
| 77 | +logical filename when artifacts are intended for distribution; maps intentionally |
| 78 | +include the selected source. module_name must be a portable .mjs basename. |
| 79 | + |
| 80 | +Only selected helpers and their declared dependency closure enter the output. |
| 81 | +NOTICES.txt records original helper provenance; no third-party interpreter or |
| 82 | +runtime is embedded. The repository has no declared code license; this notice |
| 83 | +does not choose or grant one. Redistribution licensing remains a release decision. |
| 84 | + |
| 85 | +Run `python -m unittest discover -s tests -p 'test_compiler*.py' -v` with the |
| 86 | +installed development checkout and Node 24.19.0. Tests compare CPython and emitted |
| 87 | +Node output/errors/evaluation order, the single-module text_metrics application, |
| 88 | +precision/Unicode/tuple/default behavior and an independent Node source-map |
| 89 | +consumer. Local modules, async browser capabilities and the final browser parity |
| 90 | +gate remain MOD-01, ASYNC-01/BROWSER-01 and QA-03. This compiler executes only |
| 91 | +ahead-of-time approved source; it does not parse new source in the browser. |
0 commit comments