uslap-query / Code_files /amr_cli.py
uslap's picture
Upload folder using huggingface_hub
7cc8e29 verified
Raw
History Blame Contribute Delete
9.72 kB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ุฃูŽู…ู’ุฑ CLI โ€” Command Line Interface
Entry point: python3 amr_cli.py program.ุฃู…ุฑ
Modes:
run (default) โ€” parse, emit Python, execute
compile โ€” parse, emit Python to stdout
check โ€” parse only, report errors
"""
import sys
import os
import argparse
import tempfile
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from amr_lexer import tokenize_file, tokenize_source, LexerError
from amr_parser import parse_source, parse_file, print_ast, ParseError
from amr_emitter import emit_source, emit_file, EmitterError
# Arabic translations for common Python runtime errors
RUNTIME_ERROR_MAP = {
'NameError': 'ุงูุณู’ู… ุบูŽูŠู’ุฑ ู…ูุนูŽุฑูŽู‘ู', # undefined name
'TypeError': 'ุฎูŽุทูŽุฃ ูููŠ ุงู„ู†ูŽู‘ูˆู’ุน', # type error
'ValueError': 'ุฎูŽุทูŽุฃ ูููŠ ุงู„ู‚ููŠู…ูŽุฉ', # value error
'IndexError': 'ููู‡ู’ุฑูุณ ุฎูŽุงุฑูุฌ ุงู„ู…ูŽุฏูŽู‰', # index out of range
'KeyError': 'ู…ููู’ุชูŽุงุญ ุบูŽูŠู’ุฑ ู…ูŽูˆู’ุฌููˆุฏ', # key not found
'ZeroDivisionError': 'ู‚ูุณู’ู…ูŽุฉ ุนูŽู„ูŽู‰ ุตููู’ุฑ', # division by zero
'FileNotFoundError': 'ู…ูู„ูŽูู‘ ุบูŽูŠู’ุฑ ู…ูŽูˆู’ุฌููˆุฏ', # file not found
'AttributeError': 'ุตูููŽุฉ ุบูŽูŠู’ุฑ ู…ูŽูˆู’ุฌููˆุฏูŽุฉ', # attribute not found
'RecursionError': 'ุนูู…ู’ู‚ ุงู„ุชูŽู‘ูƒู’ุฑูŽุงุฑ ุชูŽุฌูŽุงูˆูŽุฒูŽ ุงู„ุญูŽุฏู‘', # recursion limit
'OperationalError': 'ุฎูŽุทูŽุฃ ูููŠ ุงู„ู„ูŽู‘ูˆู’ุญ', # sqlite operational error
'ุฎูŽุทูŽุฃ_ู„ูŽูˆู’ุญ': 'ุฎูŽุทูŽุฃ ูููŠ ุงู„ู„ูŽู‘ูˆู’ุญ', # LAWH error
'ุฎูŽุทูŽุฃ_ุฃูŽุฑู’ุถ': 'ุฎูŽุทูŽุฃ ูููŠ ุงู„ุฃูŽุฑู’ุถ', # ARD error
'ุฎูŽุทูŽุฃ_ุชูŽุฑู’ุฌูŽู…ูŽุฉ': 'ุฎูŽุทูŽุฃ ูููŠ ุงู„ุชูŽู‘ุฑู’ุฌูŽู…ูŽุฉ', # Translation error
}
def format_runtime_error(e):
"""Format a Python exception with Arabic error type."""
err_type = type(e).__name__
arabic_type = RUNTIME_ERROR_MAP.get(err_type, err_type)
return f'{arabic_type}: {e}'
def run_file(filepath):
"""Parse, emit Python, and execute an ุฃูŽู…ู’ุฑ file."""
if not os.path.exists(filepath):
print(f'ู…ูู„ูŽูู‘ ุบูŽูŠู’ุฑ ู…ูŽูˆู’ุฌููˆุฏ: {filepath}', file=sys.stderr)
return 1
try:
python_code = emit_file(filepath)
except (LexerError, ParseError, EmitterError) as e:
print(f'ุฎูŽุทูŽุฃ: {e}', file=sys.stderr)
return 1
# Write to temp file and execute
code_dir = os.path.dirname(os.path.abspath(__file__))
with tempfile.NamedTemporaryFile(
mode='w', suffix='.py', dir=code_dir,
delete=False, encoding='utf-8'
) as tmp:
tmp.write(python_code)
tmp_path = tmp.name
try:
# Execute the generated Python
exec_globals = {'__name__': '__main__', '__file__': tmp_path}
exec(compile(python_code, filepath, 'exec'), exec_globals)
return 0
except Exception as e:
print(f'ุฎูŽุทูŽุฃ ุชูŽู†ู’ูููŠุฐ: {format_runtime_error(e)}', file=sys.stderr)
return 1
finally:
try:
os.unlink(tmp_path)
except OSError:
pass
def run_string(source):
"""Parse, emit, and execute ุฃูŽู…ู’ุฑ source from string."""
try:
python_code = emit_source(source)
except (LexerError, ParseError, EmitterError) as e:
print(f'ุฎูŽุทูŽุฃ: {e}', file=sys.stderr)
return 1
try:
exec_globals = {'__name__': '__main__', '__file__': '<string>'}
exec(compile(python_code, '<string>', 'exec'), exec_globals)
return 0
except Exception as e:
print(f'ุฎูŽุทูŽุฃ ุชูŽู†ู’ูููŠุฐ: {format_runtime_error(e)}', file=sys.stderr)
return 1
def compile_file(filepath):
"""Parse and emit Python to stdout."""
if not os.path.exists(filepath):
print(f'ู…ูู„ูŽูู‘ ุบูŽูŠู’ุฑ ู…ูŽูˆู’ุฌููˆุฏ: {filepath}', file=sys.stderr)
return 1
try:
python_code = emit_file(filepath)
print(python_code)
return 0
except (LexerError, ParseError, EmitterError) as e:
print(f'ุฎูŽุทูŽุฃ: {e}', file=sys.stderr)
return 1
def check_file(filepath):
"""Parse only, report errors or success."""
if not os.path.exists(filepath):
print(f'ู…ูู„ูŽูู‘ ุบูŽูŠู’ุฑ ู…ูŽูˆู’ุฌููˆุฏ: {filepath}', file=sys.stderr)
return 1
try:
tokens = tokenize_file(filepath)
print(f'ุชูŽุญู’ู„ููŠู„: {len(tokens)} tokens')
from amr_parser import Parser
parser = Parser(tokens)
ast = parser.parse()
print(f'ุชูŽุญู’ู„ููŠู„: {len(ast.body)} statements')
print('ู†ูŽุฌูŽุงุญ โ€” no errors found') # success
return 0
except (LexerError, ParseError) as e:
print(f'ุฎูŽุทูŽุฃ: {e}', file=sys.stderr)
return 1
def repl():
"""Interactive ุฃูŽู…ู’ุฑ REPL (Read-Evaluate-Print Loop)."""
print('ุจูุณู’ู…ู ุงู„ู„ูŽู‘ู‡ู ุงู„ุฑูŽู‘ุญู’ู…ูŽูฐู†ู ุงู„ุฑูŽู‘ุญููŠู…ู')
print('ุฃูŽู…ู’ุฑ v1.0 โ€” ุงู‚ู’ุฑูŽุฃู’')
print('ุงููƒู’ุชูุจู’ "ุฎูุฑููˆุฌ" ู„ูู„ู’ุฎูุฑููˆุฌ')
print()
# Persistent execution environment
exec_globals = {'__name__': '__main__', '__file__': '<repl>'}
# Pre-load runtime
runtime_code = (
'import sys, os\n'
'sys.path.insert(0, os.path.dirname(os.path.abspath("' +
os.path.dirname(os.path.abspath(__file__)).replace('\\', '\\\\') +
'")))\n'
'sys.path.insert(0, "' +
os.path.dirname(os.path.abspath(__file__)).replace('\\', '\\\\') +
'")\n'
'from amr_runtime import *\n'
)
exec(compile(runtime_code, '<repl-init>', 'exec'), exec_globals)
# Multiline input state
buffer = []
in_block = False
while True:
try:
prompt = '... ' if in_block else 'ุฃู…ุฑ> '
line = input(prompt)
except (EOFError, KeyboardInterrupt):
print('\nูˆูŽุฏูŽุงุนู‹ุง')
break
# Exit commands
if line.strip() in ('ุฎูุฑููˆุฌ', 'exit', 'quit'):
print('ูˆูŽุฏูŽุงุนู‹ุง')
break
# Empty line ends a block
if not line.strip() and in_block:
source = '\n'.join(buffer)
buffer = []
in_block = False
elif line.strip().endswith(':'):
buffer.append(line)
in_block = True
continue
elif in_block:
buffer.append(line)
continue
else:
source = line
if not source.strip():
continue
try:
python_code = emit_source(source)
# Strip the boilerplate (already loaded in exec_globals)
lines = python_code.split('\n')
# Remove the import/setup lines
code_lines = []
skip = True
for l in lines:
if skip and (l.startswith('#') or l.startswith('import ') or
l.startswith('sys.') or l.startswith('from amr_') or
l.strip() == ''):
continue
skip = False
code_lines.append(l)
clean_code = '\n'.join(code_lines)
if clean_code.strip():
exec(compile(clean_code, '<repl>', 'exec'), exec_globals)
except (LexerError, ParseError, EmitterError) as e:
print(f'ุฎูŽุทูŽุฃ: {e}', file=sys.stderr)
except Exception as e:
print(f'ุฎูŽุทูŽุฃ ุชูŽู†ู’ูููŠุฐ: {format_runtime_error(e)}', file=sys.stderr)
def main():
parser = argparse.ArgumentParser(
description='ุฃูŽู…ู’ุฑ โ€” Root-Derived Programming Language CLI',
epilog='ุจูุณู’ู…ู ุงู„ู„ูŽู‘ู‡ู ุงู„ุฑูŽู‘ุญู’ู…ูŽูฐู†ู ุงู„ุฑูŽู‘ุญููŠู…ู'
)
parser.add_argument('file', nargs='?', help='Path to .ุฃู…ุฑ source file')
parser.add_argument('-c', '--compile', action='store_true',
help='Emit Python code to stdout (do not execute)')
parser.add_argument('--check', action='store_true',
help='Parse only, report errors')
parser.add_argument('-e', '--exec', dest='exec_str', metavar='CODE',
help='Execute ุฃูŽู…ู’ุฑ code from string')
parser.add_argument('--ast', action='store_true',
help='Print AST (debug)')
parser.add_argument('-i', '--interactive', action='store_true',
help='Start interactive REPL')
args = parser.parse_args()
# REPL mode
if args.interactive:
return repl()
# Execute from string
if args.exec_str:
if args.compile:
try:
python_code = emit_source(args.exec_str)
print(python_code)
return 0
except (LexerError, ParseError, EmitterError) as e:
print(f'ุฎูŽุทูŽุฃ: {e}', file=sys.stderr)
return 1
return run_string(args.exec_str)
# No file and no other mode โ†’ REPL
if not args.file:
return repl()
# AST debug mode
if args.ast:
try:
ast = parse_file(args.file)
print_ast(ast)
return 0
except (LexerError, ParseError) as e:
print(f'ุฎูŽุทูŽุฃ: {e}', file=sys.stderr)
return 1
# Check mode
if args.check:
return check_file(args.file)
# Compile mode
if args.compile:
return compile_file(args.file)
# Default: run
return run_file(args.file)
if __name__ == '__main__':
sys.exit(main())