multilingualprogramming 0.2.0__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.
- multilingualprogramming/__init__.py +74 -0
- multilingualprogramming/__main__.py +194 -0
- multilingualprogramming/codegen/__init__.py +12 -0
- multilingualprogramming/codegen/executor.py +215 -0
- multilingualprogramming/codegen/python_generator.py +592 -0
- multilingualprogramming/codegen/repl.py +489 -0
- multilingualprogramming/codegen/runtime_builtins.py +308 -0
- multilingualprogramming/core/__init__.py +12 -0
- multilingualprogramming/core/ir.py +29 -0
- multilingualprogramming/core/lowering.py +24 -0
- multilingualprogramming/datetime/__init__.py +11 -0
- multilingualprogramming/datetime/date_parser.py +190 -0
- multilingualprogramming/datetime/mp_date.py +210 -0
- multilingualprogramming/datetime/mp_datetime.py +153 -0
- multilingualprogramming/datetime/mp_time.py +147 -0
- multilingualprogramming/datetime/resource_loader.py +18 -0
- multilingualprogramming/exceptions.py +158 -0
- multilingualprogramming/imports.py +150 -0
- multilingualprogramming/keyword/__init__.py +13 -0
- multilingualprogramming/keyword/keyword_registry.py +249 -0
- multilingualprogramming/keyword/keyword_validator.py +59 -0
- multilingualprogramming/keyword/language_pack_validator.py +110 -0
- multilingualprogramming/lexer/__init__.py +11 -0
- multilingualprogramming/lexer/lexer.py +570 -0
- multilingualprogramming/lexer/source_reader.py +91 -0
- multilingualprogramming/lexer/token.py +54 -0
- multilingualprogramming/lexer/token_types.py +38 -0
- multilingualprogramming/numeral/__init__.py +11 -0
- multilingualprogramming/numeral/abstract_numeral.py +232 -0
- multilingualprogramming/numeral/complex_numeral.py +190 -0
- multilingualprogramming/numeral/fraction_numeral.py +165 -0
- multilingualprogramming/numeral/mp_numeral.py +243 -0
- multilingualprogramming/numeral/numeral_converter.py +151 -0
- multilingualprogramming/numeral/roman_numeral.py +301 -0
- multilingualprogramming/numeral/unicode_numeral.py +292 -0
- multilingualprogramming/parser/__init__.py +28 -0
- multilingualprogramming/parser/ast_nodes.py +459 -0
- multilingualprogramming/parser/ast_printer.py +677 -0
- multilingualprogramming/parser/error_messages.py +75 -0
- multilingualprogramming/parser/parser.py +1796 -0
- multilingualprogramming/parser/semantic_analyzer.py +689 -0
- multilingualprogramming/parser/surface_normalizer.py +282 -0
- multilingualprogramming/resources/datetime/eras.json +23 -0
- multilingualprogramming/resources/datetime/formats.json +32 -0
- multilingualprogramming/resources/datetime/months.json +150 -0
- multilingualprogramming/resources/datetime/weekdays.json +90 -0
- multilingualprogramming/resources/parser/error_messages.json +310 -0
- multilingualprogramming/resources/repl/commands.json +636 -0
- multilingualprogramming/resources/usm/builtins_aliases.json +731 -0
- multilingualprogramming/resources/usm/keywords.json +1063 -0
- multilingualprogramming/resources/usm/operators.json +532 -0
- multilingualprogramming/resources/usm/schema.json +34 -0
- multilingualprogramming/resources/usm/surface_patterns.json +1523 -0
- multilingualprogramming/unicode_string.py +140 -0
- multilingualprogramming/version.py +9 -0
- multilingualprogramming-0.2.0.dist-info/METADATA +350 -0
- multilingualprogramming-0.2.0.dist-info/RECORD +61 -0
- multilingualprogramming-0.2.0.dist-info/WHEEL +5 -0
- multilingualprogramming-0.2.0.dist-info/entry_points.txt +3 -0
- multilingualprogramming-0.2.0.dist-info/licenses/LICENSE +674 -0
- multilingualprogramming-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#
|
|
2
|
+
# SPDX-FileCopyrightText: 2022 John Samuel <johnsamuelwrites@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
"""multilingualprogramming is an application for multilingual programming."""
|
|
8
|
+
|
|
9
|
+
from multilingualprogramming.numeral.mp_numeral import MPNumeral
|
|
10
|
+
from multilingualprogramming.numeral.unicode_numeral import UnicodeNumeral
|
|
11
|
+
from multilingualprogramming.numeral.roman_numeral import RomanNumeral
|
|
12
|
+
from multilingualprogramming.numeral.complex_numeral import ComplexNumeral
|
|
13
|
+
from multilingualprogramming.numeral.fraction_numeral import FractionNumeral
|
|
14
|
+
from multilingualprogramming.numeral.numeral_converter import NumeralConverter
|
|
15
|
+
from multilingualprogramming.keyword.keyword_registry import KeywordRegistry
|
|
16
|
+
from multilingualprogramming.keyword.keyword_validator import KeywordValidator
|
|
17
|
+
from multilingualprogramming.keyword.language_pack_validator import (
|
|
18
|
+
LanguagePackValidator,
|
|
19
|
+
)
|
|
20
|
+
from multilingualprogramming.datetime.mp_date import MPDate
|
|
21
|
+
from multilingualprogramming.datetime.mp_time import MPTime
|
|
22
|
+
from multilingualprogramming.datetime.mp_datetime import MPDatetime
|
|
23
|
+
from multilingualprogramming.lexer.lexer import Lexer
|
|
24
|
+
from multilingualprogramming.lexer.token import Token
|
|
25
|
+
from multilingualprogramming.lexer.token_types import TokenType
|
|
26
|
+
from multilingualprogramming.parser.parser import Parser
|
|
27
|
+
from multilingualprogramming.parser.ast_printer import ASTPrinter
|
|
28
|
+
from multilingualprogramming.parser.semantic_analyzer import (
|
|
29
|
+
Symbol, Scope, SymbolTable, SemanticAnalyzer,
|
|
30
|
+
)
|
|
31
|
+
from multilingualprogramming.parser.error_messages import ErrorMessageRegistry
|
|
32
|
+
from multilingualprogramming.codegen.python_generator import PythonCodeGenerator
|
|
33
|
+
from multilingualprogramming.codegen.runtime_builtins import RuntimeBuiltins
|
|
34
|
+
from multilingualprogramming.codegen.executor import ProgramExecutor, ExecutionResult
|
|
35
|
+
from multilingualprogramming.codegen.repl import REPL
|
|
36
|
+
from multilingualprogramming.core.ir import CoreIRProgram
|
|
37
|
+
from multilingualprogramming.core.lowering import lower_to_core_ir
|
|
38
|
+
from multilingualprogramming.imports import (
|
|
39
|
+
enable_multilingual_imports, disable_multilingual_imports,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"MPNumeral",
|
|
44
|
+
"UnicodeNumeral",
|
|
45
|
+
"RomanNumeral",
|
|
46
|
+
"ComplexNumeral",
|
|
47
|
+
"FractionNumeral",
|
|
48
|
+
"NumeralConverter",
|
|
49
|
+
"KeywordRegistry",
|
|
50
|
+
"KeywordValidator",
|
|
51
|
+
"LanguagePackValidator",
|
|
52
|
+
"MPDate",
|
|
53
|
+
"MPTime",
|
|
54
|
+
"MPDatetime",
|
|
55
|
+
"Lexer",
|
|
56
|
+
"Token",
|
|
57
|
+
"TokenType",
|
|
58
|
+
"Parser",
|
|
59
|
+
"ASTPrinter",
|
|
60
|
+
"Symbol",
|
|
61
|
+
"Scope",
|
|
62
|
+
"SymbolTable",
|
|
63
|
+
"SemanticAnalyzer",
|
|
64
|
+
"ErrorMessageRegistry",
|
|
65
|
+
"PythonCodeGenerator",
|
|
66
|
+
"RuntimeBuiltins",
|
|
67
|
+
"ProgramExecutor",
|
|
68
|
+
"ExecutionResult",
|
|
69
|
+
"REPL",
|
|
70
|
+
"CoreIRProgram",
|
|
71
|
+
"lower_to_core_ir",
|
|
72
|
+
"enable_multilingual_imports",
|
|
73
|
+
"disable_multilingual_imports",
|
|
74
|
+
]
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#
|
|
2
|
+
# SPDX-FileCopyrightText: 2024 John Samuel <johnsamuelwrites@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
CLI entry point for the multilingual programming language.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python -m multilingualprogramming # Start REPL
|
|
12
|
+
python -m multilingualprogramming run <file> # Execute a file
|
|
13
|
+
python -m multilingualprogramming repl [--lang XX] # Start REPL
|
|
14
|
+
python -m multilingualprogramming compile <file> # Show generated Python
|
|
15
|
+
python -m multilingualprogramming smoke --lang fr # Validate one language pack
|
|
16
|
+
python -m multilingualprogramming smoke --all # Validate all language packs
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
from multilingualprogramming.codegen.executor import ProgramExecutor
|
|
23
|
+
from multilingualprogramming.codegen.python_generator import PythonCodeGenerator
|
|
24
|
+
from multilingualprogramming.codegen.repl import REPL
|
|
25
|
+
from multilingualprogramming.keyword.language_pack_validator import (
|
|
26
|
+
LanguagePackValidator,
|
|
27
|
+
)
|
|
28
|
+
from multilingualprogramming.exceptions import UnsupportedLanguageError
|
|
29
|
+
from multilingualprogramming.lexer.lexer import Lexer
|
|
30
|
+
from multilingualprogramming.parser.parser import Parser
|
|
31
|
+
from multilingualprogramming.version import __version__
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def cmd_run(args):
|
|
35
|
+
"""Execute a multilingual source file."""
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
with open(args.file, encoding="utf-8") as f:
|
|
39
|
+
source = f.read()
|
|
40
|
+
except FileNotFoundError:
|
|
41
|
+
print(f"Error: file not found: {args.file}", file=sys.stderr)
|
|
42
|
+
sys.exit(1)
|
|
43
|
+
except OSError as e:
|
|
44
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
45
|
+
sys.exit(1)
|
|
46
|
+
|
|
47
|
+
executor = ProgramExecutor(language=args.lang)
|
|
48
|
+
result = executor.execute(source)
|
|
49
|
+
|
|
50
|
+
if result.output:
|
|
51
|
+
sys.stdout.write(result.output)
|
|
52
|
+
|
|
53
|
+
if not result.success:
|
|
54
|
+
for err in result.errors:
|
|
55
|
+
print(err, file=sys.stderr)
|
|
56
|
+
sys.exit(1)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def cmd_repl(args):
|
|
60
|
+
"""Start the interactive REPL."""
|
|
61
|
+
repl = REPL(language=args.lang, show_python=args.show_python)
|
|
62
|
+
repl.run()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def cmd_compile(args):
|
|
66
|
+
"""Compile a source file and print the generated Python."""
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
with open(args.file, encoding="utf-8") as f:
|
|
70
|
+
source = f.read()
|
|
71
|
+
except FileNotFoundError:
|
|
72
|
+
print(f"Error: file not found: {args.file}", file=sys.stderr)
|
|
73
|
+
sys.exit(1)
|
|
74
|
+
except OSError as e:
|
|
75
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
76
|
+
sys.exit(1)
|
|
77
|
+
|
|
78
|
+
lang = args.lang
|
|
79
|
+
lexer = Lexer(source, language=lang)
|
|
80
|
+
tokens = lexer.tokenize()
|
|
81
|
+
detected_lang = lexer.language or lang or "en"
|
|
82
|
+
|
|
83
|
+
parser = Parser(tokens, source_language=detected_lang)
|
|
84
|
+
program = parser.parse()
|
|
85
|
+
|
|
86
|
+
generator = PythonCodeGenerator()
|
|
87
|
+
python_source = generator.generate(program)
|
|
88
|
+
print(python_source)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def cmd_smoke(args):
|
|
92
|
+
"""Run language-pack smoke validation checks."""
|
|
93
|
+
registry_validator = LanguagePackValidator()
|
|
94
|
+
languages = (
|
|
95
|
+
sorted(registry_validator.get_supported_languages())
|
|
96
|
+
if args.all
|
|
97
|
+
else [args.lang]
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
failed = False
|
|
101
|
+
for language in languages:
|
|
102
|
+
try:
|
|
103
|
+
errors = registry_validator.validate(language)
|
|
104
|
+
except UnsupportedLanguageError as exc:
|
|
105
|
+
failed = True
|
|
106
|
+
print(f"[FAIL] {language}: {exc}", file=sys.stderr)
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
if errors:
|
|
110
|
+
failed = True
|
|
111
|
+
print(f"[FAIL] {language}", file=sys.stderr)
|
|
112
|
+
for error in errors:
|
|
113
|
+
print(f" - {error}", file=sys.stderr)
|
|
114
|
+
else:
|
|
115
|
+
print(f"[PASS] {language}")
|
|
116
|
+
|
|
117
|
+
if failed:
|
|
118
|
+
sys.exit(1)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def main():
|
|
122
|
+
"""Run the CLI entry point and dispatch subcommands."""
|
|
123
|
+
parser = argparse.ArgumentParser(
|
|
124
|
+
prog="multilingual",
|
|
125
|
+
description="Multilingual Programming Language CLI",
|
|
126
|
+
)
|
|
127
|
+
parser.add_argument(
|
|
128
|
+
"--version", action="version",
|
|
129
|
+
version=f"%(prog)s {__version__}",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
133
|
+
|
|
134
|
+
# run subcommand
|
|
135
|
+
run_parser = subparsers.add_parser("run", help="Execute a source file")
|
|
136
|
+
run_parser.add_argument("file", help="Path to the source file")
|
|
137
|
+
run_parser.add_argument(
|
|
138
|
+
"--lang", default=None,
|
|
139
|
+
help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# repl subcommand
|
|
143
|
+
repl_parser = subparsers.add_parser("repl", help="Start interactive REPL")
|
|
144
|
+
repl_parser.add_argument(
|
|
145
|
+
"--lang", default=None,
|
|
146
|
+
help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
|
|
147
|
+
)
|
|
148
|
+
repl_parser.add_argument(
|
|
149
|
+
"--show-python", action="store_true",
|
|
150
|
+
help="Display generated Python code before execution",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# compile subcommand
|
|
154
|
+
compile_parser = subparsers.add_parser(
|
|
155
|
+
"compile", help="Show generated Python code"
|
|
156
|
+
)
|
|
157
|
+
compile_parser.add_argument("file", help="Path to the source file")
|
|
158
|
+
compile_parser.add_argument(
|
|
159
|
+
"--lang", default=None,
|
|
160
|
+
help="Source language code (e.g., en, fr, hi). Auto-detect if omitted.",
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# smoke subcommand
|
|
164
|
+
smoke_parser = subparsers.add_parser(
|
|
165
|
+
"smoke", help="Validate language pack(s)"
|
|
166
|
+
)
|
|
167
|
+
smoke_parser.add_argument(
|
|
168
|
+
"--lang", default="en",
|
|
169
|
+
help="Language code to validate (default: en)",
|
|
170
|
+
)
|
|
171
|
+
smoke_parser.add_argument(
|
|
172
|
+
"--all", action="store_true",
|
|
173
|
+
help="Validate all supported languages",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
args = parser.parse_args()
|
|
177
|
+
|
|
178
|
+
if args.command == "run":
|
|
179
|
+
cmd_run(args)
|
|
180
|
+
elif args.command == "repl":
|
|
181
|
+
cmd_repl(args)
|
|
182
|
+
elif args.command == "compile":
|
|
183
|
+
cmd_compile(args)
|
|
184
|
+
elif args.command == "smoke":
|
|
185
|
+
cmd_smoke(args)
|
|
186
|
+
else:
|
|
187
|
+
# Default: start REPL
|
|
188
|
+
args.lang = None
|
|
189
|
+
args.show_python = False
|
|
190
|
+
cmd_repl(args)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
if __name__ == "__main__":
|
|
194
|
+
main()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#
|
|
2
|
+
# SPDX-FileCopyrightText: 2024 John Samuel <johnsamuelwrites@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
"""Code generation and runtime subpackage for the multilingual programming language."""
|
|
8
|
+
|
|
9
|
+
from multilingualprogramming.codegen.python_generator import PythonCodeGenerator
|
|
10
|
+
from multilingualprogramming.codegen.runtime_builtins import RuntimeBuiltins
|
|
11
|
+
from multilingualprogramming.codegen.executor import ProgramExecutor, ExecutionResult
|
|
12
|
+
from multilingualprogramming.codegen.repl import REPL
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#
|
|
2
|
+
# SPDX-FileCopyrightText: 2024 John Samuel <johnsamuelwrites@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Program executor: full pipeline from multilingual source to execution.
|
|
9
|
+
|
|
10
|
+
source (any language) -> Lexer -> Parser -> SemanticAnalyzer
|
|
11
|
+
-> PythonCodeGenerator -> compile + exec
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import io
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
from multilingualprogramming.lexer.lexer import Lexer
|
|
18
|
+
from multilingualprogramming.parser.parser import Parser
|
|
19
|
+
from multilingualprogramming.parser.semantic_analyzer import SemanticAnalyzer
|
|
20
|
+
from multilingualprogramming.codegen.python_generator import PythonCodeGenerator
|
|
21
|
+
from multilingualprogramming.codegen.runtime_builtins import RuntimeBuiltins
|
|
22
|
+
from multilingualprogramming.core.lowering import lower_to_core_ir
|
|
23
|
+
from multilingualprogramming.imports import enable_multilingual_imports
|
|
24
|
+
from multilingualprogramming.exceptions import (
|
|
25
|
+
RuntimeExecutionError,
|
|
26
|
+
CodeGenerationError,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ExecutionResult:
|
|
31
|
+
"""Result of executing a multilingual program."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, output="", return_value=None, python_source="",
|
|
34
|
+
errors=None, success=True):
|
|
35
|
+
self.output = output
|
|
36
|
+
self.return_value = return_value
|
|
37
|
+
self.python_source = python_source
|
|
38
|
+
self.errors = errors or []
|
|
39
|
+
self.success = success
|
|
40
|
+
|
|
41
|
+
def __repr__(self):
|
|
42
|
+
status = "OK" if self.success else "FAILED"
|
|
43
|
+
return (f"ExecutionResult({status}, "
|
|
44
|
+
f"output={self.output!r}, "
|
|
45
|
+
f"errors={self.errors!r})")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ProgramExecutor:
|
|
49
|
+
"""
|
|
50
|
+
Executes multilingual source code through the full pipeline.
|
|
51
|
+
|
|
52
|
+
Usage:
|
|
53
|
+
executor = ProgramExecutor(language="fr")
|
|
54
|
+
result = executor.execute(french_source)
|
|
55
|
+
print(result.output) # captured stdout
|
|
56
|
+
print(result.success) # True/False
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(self, language=None, check_semantics=True):
|
|
60
|
+
"""
|
|
61
|
+
Initialize the executor.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
language: Source language code (e.g., "en", "fr", "hi").
|
|
65
|
+
If None, auto-detect from keywords.
|
|
66
|
+
check_semantics: Whether to run semantic analysis before
|
|
67
|
+
code generation. Default True.
|
|
68
|
+
"""
|
|
69
|
+
self.language = language
|
|
70
|
+
self.check_semantics = check_semantics
|
|
71
|
+
|
|
72
|
+
def execute(self, source, capture_output=True, globals_dict=None):
|
|
73
|
+
"""
|
|
74
|
+
Execute multilingual source code.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
source: Multilingual source code string.
|
|
78
|
+
capture_output: If True, capture stdout to result.output.
|
|
79
|
+
If False, print to actual stdout.
|
|
80
|
+
globals_dict: Optional dict to merge into execution globals.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
ExecutionResult with output, generated Python source, and errors.
|
|
84
|
+
"""
|
|
85
|
+
try:
|
|
86
|
+
# Step 1-3: Frontend to typed core representation
|
|
87
|
+
core_program = self.to_core_ir(source)
|
|
88
|
+
detected_language = core_program.source_language
|
|
89
|
+
|
|
90
|
+
# Step 4: Semantic analysis (optional)
|
|
91
|
+
if self.check_semantics:
|
|
92
|
+
analyzer = SemanticAnalyzer(
|
|
93
|
+
source_language=detected_language
|
|
94
|
+
)
|
|
95
|
+
# Pre-seed symbol table with runtime builtins so that
|
|
96
|
+
# names like print, range, len, etc. are not flagged
|
|
97
|
+
# as undefined.
|
|
98
|
+
builtins_ns = RuntimeBuiltins(detected_language).namespace()
|
|
99
|
+
for name in builtins_ns:
|
|
100
|
+
analyzer.symbol_table.define(
|
|
101
|
+
name, "variable", line=0, column=0
|
|
102
|
+
)
|
|
103
|
+
semantic_errors = analyzer.analyze(core_program.ast)
|
|
104
|
+
if semantic_errors:
|
|
105
|
+
return ExecutionResult(
|
|
106
|
+
errors=[str(e) for e in semantic_errors],
|
|
107
|
+
success=False,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Step 5: Lowered core to Python
|
|
111
|
+
generator = PythonCodeGenerator()
|
|
112
|
+
python_source = generator.generate(core_program)
|
|
113
|
+
|
|
114
|
+
# Step 6: Execute
|
|
115
|
+
return self._exec_python(
|
|
116
|
+
python_source, detected_language,
|
|
117
|
+
capture_output, globals_dict
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
except (CodeGenerationError, RuntimeExecutionError) as exc:
|
|
121
|
+
return ExecutionResult(
|
|
122
|
+
errors=[str(exc)],
|
|
123
|
+
success=False,
|
|
124
|
+
)
|
|
125
|
+
except Exception as exc:
|
|
126
|
+
return ExecutionResult(
|
|
127
|
+
errors=[f"{type(exc).__name__}: {exc}"],
|
|
128
|
+
success=False,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def transpile(self, source):
|
|
132
|
+
"""
|
|
133
|
+
Transpile multilingual source to Python without executing.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
source: Multilingual source code string.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Python source code string.
|
|
140
|
+
|
|
141
|
+
Raises:
|
|
142
|
+
Various exceptions on lex/parse/codegen errors.
|
|
143
|
+
"""
|
|
144
|
+
core_program = self.to_core_ir(source)
|
|
145
|
+
generator = PythonCodeGenerator()
|
|
146
|
+
return generator.generate(core_program)
|
|
147
|
+
|
|
148
|
+
def to_core_ir(self, source):
|
|
149
|
+
"""Compile source into the typed core representation."""
|
|
150
|
+
lexer = Lexer(source, language=self.language)
|
|
151
|
+
tokens = lexer.tokenize()
|
|
152
|
+
detected_language = lexer.language or self.language or "en"
|
|
153
|
+
|
|
154
|
+
parser = Parser(tokens, source_language=detected_language)
|
|
155
|
+
program = parser.parse()
|
|
156
|
+
return lower_to_core_ir(
|
|
157
|
+
program, detected_language, frontend_name="lexer_parser"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
def _exec_python(self, python_source, language,
|
|
161
|
+
capture_output, globals_dict):
|
|
162
|
+
"""Compile and execute generated Python code."""
|
|
163
|
+
enable_multilingual_imports()
|
|
164
|
+
|
|
165
|
+
# Build execution namespace with builtins
|
|
166
|
+
builtins_ns = RuntimeBuiltins(language).namespace()
|
|
167
|
+
exec_globals = dict(builtins_ns)
|
|
168
|
+
|
|
169
|
+
if globals_dict:
|
|
170
|
+
exec_globals.update(globals_dict)
|
|
171
|
+
|
|
172
|
+
# Compile for better error reporting
|
|
173
|
+
try:
|
|
174
|
+
code = compile(python_source, "<multilingual>", "exec")
|
|
175
|
+
except SyntaxError as exc:
|
|
176
|
+
return ExecutionResult(
|
|
177
|
+
python_source=python_source,
|
|
178
|
+
errors=[f"Generated Python has syntax error: {exc}"],
|
|
179
|
+
success=False,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Execute with optional output capture
|
|
183
|
+
output = ""
|
|
184
|
+
if capture_output:
|
|
185
|
+
captured = io.StringIO()
|
|
186
|
+
old_stdout = sys.stdout
|
|
187
|
+
try:
|
|
188
|
+
sys.stdout = captured
|
|
189
|
+
exec(code, exec_globals) # pylint: disable=exec-used
|
|
190
|
+
output = captured.getvalue()
|
|
191
|
+
except Exception as exc:
|
|
192
|
+
output = captured.getvalue()
|
|
193
|
+
return ExecutionResult(
|
|
194
|
+
output=output,
|
|
195
|
+
python_source=python_source,
|
|
196
|
+
errors=[f"{type(exc).__name__}: {exc}"],
|
|
197
|
+
success=False,
|
|
198
|
+
)
|
|
199
|
+
finally:
|
|
200
|
+
sys.stdout = old_stdout
|
|
201
|
+
else:
|
|
202
|
+
try:
|
|
203
|
+
exec(code, exec_globals) # pylint: disable=exec-used
|
|
204
|
+
except Exception as exc:
|
|
205
|
+
return ExecutionResult(
|
|
206
|
+
python_source=python_source,
|
|
207
|
+
errors=[f"{type(exc).__name__}: {exc}"],
|
|
208
|
+
success=False,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
return ExecutionResult(
|
|
212
|
+
output=output,
|
|
213
|
+
python_source=python_source,
|
|
214
|
+
success=True,
|
|
215
|
+
)
|