multilingualprogramming 0.7.0__tar.gz → 0.8.0__tar.gz

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.
Files changed (136) hide show
  1. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/PKG-INFO +1 -1
  2. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/__main__.py +229 -1
  3. multilingualprogramming-0.8.0/multilingualprogramming/codegen/linear_manifest.py +96 -0
  4. multilingualprogramming-0.8.0/multilingualprogramming/codegen/midi_capture.py +156 -0
  5. multilingualprogramming-0.8.0/multilingualprogramming/codegen/midi_manifest.py +110 -0
  6. multilingualprogramming-0.8.0/multilingualprogramming/codegen/opcode_ontology.py +290 -0
  7. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_capabilities.py +140 -0
  8. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_core.py +1034 -0
  9. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_field_projection.py +257 -0
  10. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_graph_projection.py +295 -0
  11. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_migration.py +87 -0
  12. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_program.py +100 -0
  13. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_projection.py +279 -0
  14. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_sequence_projection.py +248 -0
  15. multilingualprogramming-0.8.0/multilingualprogramming/codegen/process_static_projection.py +200 -0
  16. multilingualprogramming-0.8.0/multilingualprogramming/codegen/projection_capabilities.py +37 -0
  17. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/runtime_builtins.py +123 -0
  18. multilingualprogramming-0.8.0/multilingualprogramming/codegen/semantic_core.py +213 -0
  19. multilingualprogramming-0.8.0/multilingualprogramming/codegen/sonic_capture.py +183 -0
  20. multilingualprogramming-0.8.0/multilingualprogramming/codegen/sonic_projection.py +134 -0
  21. multilingualprogramming-0.8.0/multilingualprogramming/codegen/spatial_capture.py +182 -0
  22. multilingualprogramming-0.8.0/multilingualprogramming/codegen/spatial_manifest.py +145 -0
  23. multilingualprogramming-0.8.0/multilingualprogramming/codegen/volumetric_manifest.py +104 -0
  24. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator.py +196 -5
  25. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_core.py +202 -24
  26. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_expression.py +110 -0
  27. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_manifest.py +39 -1
  28. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_orchestrator.py +20 -2
  29. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_runtime.py +715 -2
  30. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_support.py +11 -0
  31. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/lexer/lexer.py +46 -1
  32. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/parser/ast_nodes.py +7 -1
  33. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/usm/builtins_aliases.json +342 -0
  34. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/version.py +1 -1
  35. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming.egg-info/PKG-INFO +1 -1
  36. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming.egg-info/SOURCES.txt +20 -0
  37. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/LICENSE +0 -0
  38. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/README.md +0 -0
  39. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/__init__.py +0 -0
  40. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/__init__.py +0 -0
  41. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/build_orchestrator.py +0 -0
  42. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/encoding_guard.py +0 -0
  43. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/executor.py +0 -0
  44. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/python_generator.py +0 -0
  45. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/repl.py +0 -0
  46. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/ui_lowering.py +0 -0
  47. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wasm_generator.py +0 -0
  48. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_loop.py +0 -0
  49. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_match.py +0 -0
  50. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_oop.py +0 -0
  51. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_print.py +0 -0
  52. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_generator_sequence.py +0 -0
  53. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/codegen/wat_ir_adapter.py +0 -0
  54. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/core/__init__.py +0 -0
  55. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/core/effects.py +0 -0
  56. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/core/ir_nodes.py +0 -0
  57. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/core/semantic_analyzer.py +0 -0
  58. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/core/semantic_lowering.py +0 -0
  59. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/core/types.py +0 -0
  60. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/core/validators.py +0 -0
  61. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/datetime/__init__.py +0 -0
  62. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/datetime/date_parser.py +0 -0
  63. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/datetime/mp_date.py +0 -0
  64. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/datetime/mp_datetime.py +0 -0
  65. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/datetime/mp_time.py +0 -0
  66. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/datetime/resource_loader.py +0 -0
  67. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/exceptions.py +0 -0
  68. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/imports.py +0 -0
  69. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/keyword/__init__.py +0 -0
  70. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/keyword/keyword_registry.py +0 -0
  71. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/keyword/keyword_validator.py +0 -0
  72. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/keyword/language_pack_validator.py +0 -0
  73. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/lexer/__init__.py +0 -0
  74. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/lexer/source_reader.py +0 -0
  75. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/lexer/token.py +0 -0
  76. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/lexer/token_types.py +0 -0
  77. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/__init__.py +0 -0
  78. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/abstract_numeral.py +0 -0
  79. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/complex_numeral.py +0 -0
  80. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/fraction_numeral.py +0 -0
  81. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/mp_numeral.py +0 -0
  82. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/numeral_converter.py +0 -0
  83. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/roman_numeral.py +0 -0
  84. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/numeral/unicode_numeral.py +0 -0
  85. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/parser/__init__.py +0 -0
  86. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/parser/ast_printer.py +0 -0
  87. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/parser/error_messages.py +0 -0
  88. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/parser/lexer.py +0 -0
  89. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/parser/parser.py +0 -0
  90. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/parser/surface_normalizer.py +0 -0
  91. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/datetime/eras.json +0 -0
  92. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/datetime/formats.json +0 -0
  93. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/datetime/months.json +0 -0
  94. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/datetime/weekdays.json +0 -0
  95. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/parser/error_messages.json +0 -0
  96. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/repl/commands.json +0 -0
  97. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/usm/keywords.json +0 -0
  98. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/usm/operators.json +0 -0
  99. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/usm/schema.json +0 -0
  100. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/usm/surface_patterns.json +0 -0
  101. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/resources/usm/ui_lowering.json +0 -0
  102. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/__init__.py +0 -0
  103. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/ai_runtime.py +0 -0
  104. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/ai_types.py +0 -0
  105. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/anthropic_provider.py +0 -0
  106. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/backend_selector.py +0 -0
  107. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/channel.py +0 -0
  108. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/inference_cache.py +0 -0
  109. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/memory_store.py +0 -0
  110. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/model_registry.py +0 -0
  111. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/multimodal_runtime.py +0 -0
  112. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/numeric_primitives.py +0 -0
  113. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/observability.py +0 -0
  114. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/ollama_provider.py +0 -0
  115. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/openai_provider.py +0 -0
  116. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/placement.py +0 -0
  117. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/prompt_optimizer.py +0 -0
  118. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/python_fallbacks.py +0 -0
  119. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/reactive.py +0 -0
  120. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/retrieval_runtime.py +0 -0
  121. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/semantic_match.py +0 -0
  122. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/swarm.py +0 -0
  123. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/runtime/tool_runtime.py +0 -0
  124. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/source_extensions.py +0 -0
  125. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/unicode_string.py +0 -0
  126. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/wasm/loader.py +0 -0
  127. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/wasm/tuple_abi.py +0 -0
  128. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming/wasm/tuple_memory.py +0 -0
  129. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming.egg-info/dependency_links.txt +0 -0
  130. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming.egg-info/entry_points.txt +0 -0
  131. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming.egg-info/requires.txt +0 -0
  132. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/multilingualprogramming.egg-info/top_level.txt +0 -0
  133. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/pyproject.toml +0 -0
  134. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/setup.cfg +0 -0
  135. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/setup.py +0 -0
  136. {multilingualprogramming-0.7.0 → multilingualprogramming-0.8.0}/tests/tests.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multilingualprogramming
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: Python application for multilingual programming
5
5
  Author-email: John Samuel <johnsamuelwrites@example.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -49,6 +49,16 @@ from multilingualprogramming.source_extensions import (
49
49
  find_package_init,
50
50
  has_source_extension,
51
51
  )
52
+ from multilingualprogramming.codegen.linear_manifest import build_linear_manifest_file
53
+ from multilingualprogramming.codegen.midi_manifest import build_midi_manifest_file
54
+ from multilingualprogramming.codegen.opcode_ontology import write_ontology_manifest
55
+ from multilingualprogramming.codegen.semantic_core import build_semantic_core_file
56
+ from multilingualprogramming.codegen.process_program import build_process_core_file
57
+ from multilingualprogramming.codegen.sonic_projection import build_sonic_manifest_file
58
+ from multilingualprogramming.codegen.spatial_manifest import build_spatial_manifest_file
59
+ from multilingualprogramming.codegen.volumetric_manifest import (
60
+ build_volumetric_manifest_file,
61
+ )
52
62
  from multilingualprogramming.version import __version__
53
63
 
54
64
 
@@ -367,6 +377,101 @@ def cmd_build_ui_bundle(args):
367
377
  print(f"[WARN] {diag}")
368
378
 
369
379
 
380
+ def cmd_spatial_build(args):
381
+ """Build a spatial JSON manifest from a Multilingual source file."""
382
+ manifest = build_spatial_manifest_file(
383
+ args.file,
384
+ args.out,
385
+ language=args.lang or "en",
386
+ )
387
+ print(f"[PASS] {args.out}")
388
+ print(f"[spatial] {manifest['kind']} entities={len(manifest['entities'])}")
389
+
390
+
391
+ def cmd_polymodal_build(args):
392
+ """Build a modality-free semantic core manifest from Multilingual source."""
393
+ core = build_semantic_core_file(
394
+ args.file,
395
+ args.out,
396
+ language=args.lang or "en",
397
+ )
398
+ print(f"[PASS] {args.out}")
399
+ print(f"[polymodal] {core['kind']} entities={len(core['entities'])}")
400
+
401
+
402
+ def cmd_process_build(args):
403
+ """Build a semantic-core-v1 process manifest from Multilingual source."""
404
+ core = build_process_core_file(
405
+ args.file,
406
+ args.out,
407
+ language=args.lang or "en",
408
+ )
409
+ state = core.get("state", {})
410
+ # A lattice program stores loci; a sequence (string-rewriting) program
411
+ # stores an ordered sequence. Report whichever this core carries.
412
+ if "sequence" in state:
413
+ size = f"symbols={len(state['sequence'])}"
414
+ else:
415
+ size = f"loci={len(state.get('loci', []))}"
416
+ print(f"[PASS] {args.out}")
417
+ print(
418
+ f"[process] {core['kind']} "
419
+ f"topology={core['topology'].get('kind')} "
420
+ f"schedule={core['schedule'].get('kind')} {size}"
421
+ )
422
+
423
+
424
+ def cmd_sonic_build(args):
425
+ """Build a sonic JSON manifest from a Multilingual source file."""
426
+ manifest = build_sonic_manifest_file(
427
+ args.file,
428
+ args.out,
429
+ language=args.lang or "en",
430
+ )
431
+ print(f"[PASS] {args.out}")
432
+ print(f"[sonic] {manifest['kind']} voices={len(manifest['voices'])}")
433
+
434
+
435
+ def cmd_ontology_export(args):
436
+ """Write the shared opcode ontology as JSON for browser runtimes."""
437
+ manifest = write_ontology_manifest(args.out)
438
+ print(f"[PASS] {args.out}")
439
+ print(f"[ontology] {manifest['kind']} opcodes={len(manifest['opcodes'])}")
440
+
441
+
442
+ def cmd_linear_build(args):
443
+ """Build a 1D linear JSON manifest from a Multilingual source file."""
444
+ manifest = build_linear_manifest_file(
445
+ args.file,
446
+ args.out,
447
+ language=args.lang or "en",
448
+ )
449
+ print(f"[PASS] {args.out}")
450
+ print(f"[linear] {manifest['kind']} marks={len(manifest['marks'])}")
451
+
452
+
453
+ def cmd_volumetric_build(args):
454
+ """Build a 3D volumetric JSON manifest from a Multilingual source file."""
455
+ manifest = build_volumetric_manifest_file(
456
+ args.file,
457
+ args.out,
458
+ language=args.lang or "en",
459
+ )
460
+ print(f"[PASS] {args.out}")
461
+ print(f"[volumetric] {manifest['kind']} marks={len(manifest['marks'])}")
462
+
463
+
464
+ def cmd_midi_build(args):
465
+ """Build a MIDI JSON manifest from a Multilingual source file."""
466
+ manifest = build_midi_manifest_file(
467
+ args.file,
468
+ args.out,
469
+ language=args.lang or "en",
470
+ )
471
+ print(f"[PASS] {args.out}")
472
+ print(f"[midi] {manifest['kind']} events={len(manifest['events'])}")
473
+
474
+
370
475
  def cmd_ir(args):
371
476
  """Lower a source file to semantic IR and print a summary."""
372
477
  program = _parse_program_from_file(args.file, args.lang)
@@ -576,7 +681,7 @@ def _maybe_dispatch_direct_file_run(argv):
576
681
  return True
577
682
 
578
683
 
579
- def main(): # pylint: disable=too-many-statements
684
+ def main(): # pylint: disable=too-many-statements,too-many-locals,too-many-branches
580
685
  """Run the CLI entry point and dispatch subcommands."""
581
686
  argv = sys.argv[1:]
582
687
  if _maybe_dispatch_direct_file_run(argv):
@@ -739,6 +844,113 @@ def main(): # pylint: disable=too-many-statements
739
844
  help="Output directory for generated artifacts (default: build/ui)",
740
845
  )
741
846
 
847
+ spatial_build_parser = subparsers.add_parser(
848
+ "spatial-build",
849
+ help="Build a fixed-semantic spatial JSON manifest",
850
+ )
851
+ spatial_build_parser.add_argument("file", help="Path to the source file")
852
+ spatial_build_parser.add_argument(
853
+ "--lang", default=None,
854
+ help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
855
+ )
856
+ spatial_build_parser.add_argument(
857
+ "--out", default="program.spatial.json",
858
+ help="Output JSON manifest path (default: program.spatial.json)",
859
+ )
860
+
861
+ polymodal_build_parser = subparsers.add_parser(
862
+ "polymodal-build",
863
+ help="Build a modality-free semantic core manifest",
864
+ )
865
+ polymodal_build_parser.add_argument("file", help="Path to the source file")
866
+ polymodal_build_parser.add_argument(
867
+ "--lang", default=None,
868
+ help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
869
+ )
870
+ polymodal_build_parser.add_argument(
871
+ "--out", default="program.semantic.json",
872
+ help="Output JSON manifest path (default: program.semantic.json)",
873
+ )
874
+
875
+ process_build_parser = subparsers.add_parser(
876
+ "process-build",
877
+ help="Build a semantic-core-v1 process manifest (dynamics as data)",
878
+ )
879
+ process_build_parser.add_argument("file", help="Path to the source file")
880
+ process_build_parser.add_argument(
881
+ "--lang", default=None,
882
+ help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
883
+ )
884
+ process_build_parser.add_argument(
885
+ "--out", default="program.v1.json",
886
+ help="Output JSON manifest path (default: program.v1.json)",
887
+ )
888
+
889
+ sonic_build_parser = subparsers.add_parser(
890
+ "sonic-build",
891
+ help="Build a sonic projection JSON manifest",
892
+ )
893
+ sonic_build_parser.add_argument("file", help="Path to the source file")
894
+ sonic_build_parser.add_argument(
895
+ "--lang", default=None,
896
+ help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
897
+ )
898
+ sonic_build_parser.add_argument(
899
+ "--out", default="program.sonic.json",
900
+ help="Output JSON manifest path (default: program.sonic.json)",
901
+ )
902
+
903
+ ontology_export_parser = subparsers.add_parser(
904
+ "ontology-export",
905
+ help="Write the shared opcode ontology JSON (for browser runtimes)",
906
+ )
907
+ ontology_export_parser.add_argument(
908
+ "--out", default="ontology.json",
909
+ help="Output JSON path (default: ontology.json)",
910
+ )
911
+
912
+ linear_build_parser = subparsers.add_parser(
913
+ "linear-build",
914
+ help="Build a 1D linear timeline JSON manifest",
915
+ )
916
+ linear_build_parser.add_argument("file", help="Path to the source file")
917
+ linear_build_parser.add_argument(
918
+ "--lang", default=None,
919
+ help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
920
+ )
921
+ linear_build_parser.add_argument(
922
+ "--out", default="program.linear.json",
923
+ help="Output JSON manifest path (default: program.linear.json)",
924
+ )
925
+
926
+ volumetric_build_parser = subparsers.add_parser(
927
+ "volumetric-build",
928
+ help="Build a 3D volumetric JSON manifest",
929
+ )
930
+ volumetric_build_parser.add_argument("file", help="Path to the source file")
931
+ volumetric_build_parser.add_argument(
932
+ "--lang", default=None,
933
+ help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
934
+ )
935
+ volumetric_build_parser.add_argument(
936
+ "--out", default="program.volumetric.json",
937
+ help="Output JSON manifest path (default: program.volumetric.json)",
938
+ )
939
+
940
+ midi_build_parser = subparsers.add_parser(
941
+ "midi-build",
942
+ help="Build a MIDI event JSON manifest",
943
+ )
944
+ midi_build_parser.add_argument("file", help="Path to the source file")
945
+ midi_build_parser.add_argument(
946
+ "--lang", default=None,
947
+ help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
948
+ )
949
+ midi_build_parser.add_argument(
950
+ "--out", default="program.midi.json",
951
+ help="Output JSON manifest path (default: program.midi.json)",
952
+ )
953
+
742
954
  # ir subcommand
743
955
  ir_parser = subparsers.add_parser(
744
956
  "ir", help="Show the semantic IR for a source file"
@@ -805,6 +1017,22 @@ def main(): # pylint: disable=too-many-statements
805
1017
  cmd_build_wasm_bundle(args)
806
1018
  elif args.command == "build-ui-bundle":
807
1019
  cmd_build_ui_bundle(args)
1020
+ elif args.command == "spatial-build":
1021
+ cmd_spatial_build(args)
1022
+ elif args.command == "polymodal-build":
1023
+ cmd_polymodal_build(args)
1024
+ elif args.command == "process-build":
1025
+ cmd_process_build(args)
1026
+ elif args.command == "sonic-build":
1027
+ cmd_sonic_build(args)
1028
+ elif args.command == "ontology-export":
1029
+ cmd_ontology_export(args)
1030
+ elif args.command == "linear-build":
1031
+ cmd_linear_build(args)
1032
+ elif args.command == "volumetric-build":
1033
+ cmd_volumetric_build(args)
1034
+ elif args.command == "midi-build":
1035
+ cmd_midi_build(args)
808
1036
  elif args.command == "ir":
809
1037
  cmd_ir(args)
810
1038
  elif args.command == "explain":
@@ -0,0 +1,96 @@
1
+ #
2
+ # SPDX-FileCopyrightText: 2026 John Samuel <johnsamuelwrites@gmail.com>
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+
7
+ """Linear (1D timeline) projection of a polymodal program.
8
+
9
+ Peer of the spatial (2D) and sonic projections. Takes the modality-free
10
+ semantic core and produces a one-dimensional manifest: each entity
11
+ becomes a positioned mark along a single axis. Phase determines the
12
+ position; opcode determines the glyph and color.
13
+
14
+ Adding 1D as a peer projection (rather than a parameterization of the
15
+ 2D spatial projection) is deliberate. The 1D rendering primitives
16
+ (dot, segment, pulse, ramp, wave, fork, join, band, shift, double)
17
+ do not generalize from 2D shapes -- "ring" and "membrane" have no
18
+ natural 1D analog. Peer projections force the equivalence test to
19
+ exercise the dimensionality axis rather than silently treating
20
+ "spatial" as a monolith.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import json
26
+ from pathlib import Path
27
+ from typing import Any
28
+
29
+ from multilingualprogramming.codegen import opcode_ontology
30
+ from multilingualprogramming.codegen.projection_capabilities import capability_contract
31
+ from multilingualprogramming.codegen.semantic_core import build_semantic_core
32
+
33
+ MANIFEST_KIND = "linear-seed-v0"
34
+
35
+
36
+ def build_linear_manifest(
37
+ source: str,
38
+ language: str = "en",
39
+ source_path: str = "",
40
+ ) -> dict[str, Any]:
41
+ """Execute Multilingual source and return a validated linear manifest."""
42
+ core = build_semantic_core(source, language=language, source_path=source_path)
43
+ marks = [_mark_from_semantic_entity(entity) for entity in core["entities"]]
44
+ return {
45
+ "kind": MANIFEST_KIND,
46
+ "version": 0,
47
+ "source_language": language,
48
+ "source": source_path,
49
+ "capabilities": capability_contract(
50
+ projection=MANIFEST_KIND,
51
+ preserves=["id", "opcode", "intensity", "phase", "channel"],
52
+ derived=[],
53
+ lossy=["signal"],
54
+ ambiguous=[],
55
+ inverse="view-only",
56
+ ),
57
+ "tempo_bpm": 96,
58
+ "bar_seconds": 4.0,
59
+ "marks": marks,
60
+ }
61
+
62
+
63
+ def build_linear_manifest_file(
64
+ source_path: str | Path,
65
+ output_path: str | Path,
66
+ language: str = "en",
67
+ ) -> dict[str, Any]:
68
+ """Build and write a linear manifest from a Multilingual source file."""
69
+ src = Path(source_path)
70
+ out = Path(output_path)
71
+ manifest = build_linear_manifest(
72
+ src.read_text(encoding="utf-8"),
73
+ language=language,
74
+ source_path=str(src),
75
+ )
76
+ out.parent.mkdir(parents=True, exist_ok=True)
77
+ out.write_text(
78
+ json.dumps(manifest, ensure_ascii=False, indent=2) + "\n",
79
+ encoding="utf-8",
80
+ )
81
+ return manifest
82
+
83
+
84
+ def _mark_from_semantic_entity(entity: dict[str, Any]) -> dict[str, Any]:
85
+ op = opcode_ontology.get(entity["opcode"])
86
+ return {
87
+ "id": entity["id"],
88
+ "index": int(entity["index"]),
89
+ "opcode": op.code,
90
+ "name": op.name,
91
+ "glyph": op.linear.glyph,
92
+ "color": op.linear.color,
93
+ "position": round(float(entity["phase"]) % 1.0, 4),
94
+ "intensity": round(float(entity["intensity"]), 4),
95
+ "channel": int(entity["channel"]),
96
+ }
@@ -0,0 +1,156 @@
1
+ #
2
+ # SPDX-FileCopyrightText: 2026 John Samuel <johnsamuelwrites@gmail.com>
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+
7
+ """Inverse MIDI projection: observed MIDI events -> semantic core.
8
+
9
+ The forward MIDI projection emits identity labels for manifests, but a
10
+ real MIDI input stream does not carry ``opcode`` or ``name``. This
11
+ module recovers semantic identity from the observable MIDI fields the
12
+ ontology owns: role and pitch.
13
+
14
+ MIDI capture is deliberately partial:
15
+
16
+ - ``bus`` events are silent routing markers, not recoverable input.
17
+ - ``program`` events in the current ontology have base velocity 0, so
18
+ intensity cannot be recovered.
19
+ - events whose velocity has clipped to 127 cannot recover the original
20
+ intensity exactly.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ from dataclasses import dataclass
26
+ from typing import Any, Iterable
27
+
28
+ from multilingualprogramming.codegen import opcode_ontology
29
+ from multilingualprogramming.codegen.semantic_core import CORE_KIND
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class ObservedMidiEvent:
34
+ """A MIDI event as it would arrive from a MIDI input boundary."""
35
+
36
+ index: int
37
+ role: str
38
+ pitch: int
39
+ velocity: int
40
+ channel: int
41
+ start_offset: float
42
+
43
+
44
+ def _ontology_signature(op: opcode_ontology.Opcode) -> tuple[str, int]:
45
+ return (op.midi.role, op.midi.pitch)
46
+
47
+
48
+ def invertible_opcodes() -> set[int]:
49
+ """Opcodes whose identity can be recovered from MIDI observation."""
50
+ signature_counts: dict[tuple[str, int], int] = {}
51
+ for op in opcode_ontology.OPCODES:
52
+ signature = _ontology_signature(op)
53
+ signature_counts[signature] = signature_counts.get(signature, 0) + 1
54
+ return {
55
+ op.code
56
+ for op in opcode_ontology.OPCODES
57
+ if op.midi.role != "bus"
58
+ and op.midi.velocity > 0
59
+ and signature_counts[_ontology_signature(op)] == 1
60
+ }
61
+
62
+
63
+ def observe_event(event: dict[str, Any]) -> ObservedMidiEvent:
64
+ """Strip semantic identity labels from a forward-projected MIDI event."""
65
+ return ObservedMidiEvent(
66
+ index=int(event["index"]),
67
+ role=str(event["role"]),
68
+ pitch=int(event["pitch"]),
69
+ velocity=int(event["velocity"]),
70
+ channel=int(event["channel"]),
71
+ start_offset=float(event["start_offset"]),
72
+ )
73
+
74
+
75
+ def _opcode_from_observation(
76
+ observed: ObservedMidiEvent,
77
+ ) -> opcode_ontology.Opcode:
78
+ signature = (observed.role, observed.pitch)
79
+ matches = [
80
+ op for op in opcode_ontology.OPCODES if _ontology_signature(op) == signature
81
+ ]
82
+ if not matches:
83
+ raise ValueError(
84
+ f"No ontology opcode matches MIDI observation {signature!r} "
85
+ f"on event index {observed.index}"
86
+ )
87
+ if len(matches) > 1:
88
+ names = ", ".join(op.name for op in matches)
89
+ raise ValueError(
90
+ f"MIDI observation {signature!r} on event index {observed.index} is "
91
+ f"ambiguous: matches {names}."
92
+ )
93
+ op = matches[0]
94
+ if op.midi.role == "bus":
95
+ raise ValueError(
96
+ f"MIDI event index {observed.index} resolves to bus opcode {op.name!r}; "
97
+ "silent routing events are not recoverable authoring input."
98
+ )
99
+ if op.midi.velocity <= 0:
100
+ raise ValueError(
101
+ f"MIDI event index {observed.index} resolves to opcode {op.name!r} "
102
+ "with zero base velocity; intensity cannot be recovered."
103
+ )
104
+ return op
105
+
106
+
107
+ def _intensity_from_velocity(
108
+ op: opcode_ontology.Opcode,
109
+ observed: ObservedMidiEvent,
110
+ ) -> float:
111
+ if not 0 <= observed.velocity <= 127:
112
+ raise ValueError(
113
+ f"MIDI event index {observed.index} velocity must be in 0..127"
114
+ )
115
+ if observed.velocity == 127:
116
+ raise ValueError(
117
+ f"MIDI event index {observed.index} is clipped at velocity 127; "
118
+ "original intensity is lossy."
119
+ )
120
+ return observed.velocity / op.midi.velocity
121
+
122
+
123
+ def capture_semantic_core(
124
+ observed: Iterable[ObservedMidiEvent],
125
+ *,
126
+ source_language: str = "en",
127
+ source_path: str = "",
128
+ ) -> dict[str, Any]:
129
+ """Invert observed MIDI events into a semantic-core manifest."""
130
+ entities: list[dict[str, Any]] = []
131
+ for event in observed:
132
+ op = _opcode_from_observation(event)
133
+ intensity = _intensity_from_velocity(op, event)
134
+ entities.append(
135
+ {
136
+ "index": event.index,
137
+ "opcode": op.code,
138
+ "name": op.name,
139
+ "intensity": intensity,
140
+ "signal": 0.0,
141
+ "phase": event.start_offset,
142
+ "channel": event.channel,
143
+ }
144
+ )
145
+ return {
146
+ "kind": CORE_KIND,
147
+ "version": 0,
148
+ "source_language": source_language,
149
+ "source": source_path,
150
+ "ontology": [
151
+ {"code": op.code, "name": op.name}
152
+ for op in opcode_ontology.OPCODES
153
+ ],
154
+ "entities": entities,
155
+ "relations": [],
156
+ }
@@ -0,0 +1,110 @@
1
+ #
2
+ # SPDX-FileCopyrightText: 2026 John Samuel <johnsamuelwrites@gmail.com>
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+
7
+ """MIDI projection of a polymodal program.
8
+
9
+ Peer of the linear / spatial / volumetric / sonic projections. Where
10
+ those projections describe continuous shapes (along 1/2/3 spatial axes
11
+ or in audio), MIDI describes the program as a sequence of discrete
12
+ events: note on/off, control change, program change, percussion hits.
13
+
14
+ This is the modality that stress-tests whether the ontology is
15
+ genuinely modality-free. If our opcode primitives only mapped cleanly
16
+ to continuous-shape projections, MIDI would be where that cracked --
17
+ because MIDI's contract is fundamentally event-flavored rather than
18
+ field-flavored. Each opcode commits to a MIDI role
19
+ (``note``, ``drum``, ``cc``, ``program``, ``bus``) via its
20
+ :class:`MidiHint`, and the projection here turns the semantic core
21
+ into a flat list of MIDI events ready for a piano-roll renderer or
22
+ Web MIDI output.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import json
28
+ from pathlib import Path
29
+ from typing import Any
30
+
31
+ from multilingualprogramming.codegen import opcode_ontology
32
+ from multilingualprogramming.codegen.projection_capabilities import capability_contract
33
+ from multilingualprogramming.codegen.semantic_core import build_semantic_core
34
+
35
+ MANIFEST_KIND = "midi-seed-v0"
36
+
37
+
38
+ def build_midi_manifest(
39
+ source: str,
40
+ language: str = "en",
41
+ source_path: str = "",
42
+ ) -> dict[str, Any]:
43
+ """Execute Multilingual source and return a validated MIDI manifest."""
44
+ core = build_semantic_core(source, language=language, source_path=source_path)
45
+ events = [_event_from_semantic_entity(entity) for entity in core["entities"]]
46
+ return {
47
+ "kind": MANIFEST_KIND,
48
+ "version": 0,
49
+ "source_language": language,
50
+ "source": source_path,
51
+ "capabilities": capability_contract(
52
+ projection=MANIFEST_KIND,
53
+ preserves=["id", "opcode", "phase", "channel"],
54
+ derived=["intensity"],
55
+ lossy=["signal", "intensity when velocity clips or base velocity is zero"],
56
+ ambiguous=[],
57
+ inverse="partial",
58
+ ),
59
+ "tempo_bpm": 96,
60
+ "bar_seconds": 4.0,
61
+ "events": events,
62
+ "relations": core["relations"],
63
+ }
64
+
65
+
66
+ def build_midi_manifest_file(
67
+ source_path: str | Path,
68
+ output_path: str | Path,
69
+ language: str = "en",
70
+ ) -> dict[str, Any]:
71
+ """Build and write a MIDI manifest from a Multilingual source file."""
72
+ src = Path(source_path)
73
+ out = Path(output_path)
74
+ manifest = build_midi_manifest(
75
+ src.read_text(encoding="utf-8"),
76
+ language=language,
77
+ source_path=str(src),
78
+ )
79
+ out.parent.mkdir(parents=True, exist_ok=True)
80
+ out.write_text(
81
+ json.dumps(manifest, ensure_ascii=False, indent=2) + "\n",
82
+ encoding="utf-8",
83
+ )
84
+ return manifest
85
+
86
+
87
+ def _event_from_semantic_entity(entity: dict[str, Any]) -> dict[str, Any]:
88
+ op = opcode_ontology.get(entity["opcode"])
89
+ intensity = float(entity["intensity"])
90
+
91
+ # Bus voices are silent under the forward MIDI projection just as
92
+ # they are silent under sonic. The event is still emitted so peer
93
+ # projections agree on entity count and ordering -- runtimes simply
94
+ # do not transmit it.
95
+ if op.midi.role == "bus":
96
+ velocity = 0
97
+ else:
98
+ velocity = max(0, min(127, round(op.midi.velocity * intensity)))
99
+
100
+ return {
101
+ "id": entity["id"],
102
+ "index": int(entity["index"]),
103
+ "opcode": op.code,
104
+ "name": op.name,
105
+ "role": op.midi.role,
106
+ "pitch": op.midi.pitch,
107
+ "velocity": velocity,
108
+ "channel": int(entity["channel"]),
109
+ "start_offset": round(float(entity["phase"]) % 1.0, 4),
110
+ }