-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathuniversalpython.py
More file actions
183 lines (149 loc) · 6.61 KB
/
universalpython.py
File metadata and controls
183 lines (149 loc) · 6.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# ------------------------------------------------------------
# universalpython.py
#
# Main driver file.
# - Arguments are captured here
# - The parsing mode is called from here with the same args as this file
# ------------------------------------------------------------
import importlib
import inspect
import sys
import os
import re
import yaml
SCRIPTDIR = os.path.dirname(__file__)
LANGUAGES_DIR = os.path.join(SCRIPTDIR, 'languages')
def build_language_map():
"""Build language map in the format {lang: {filename: fullpath}}"""
language_map = {}
if not os.path.exists(LANGUAGES_DIR):
return language_map
for lang_dir in os.listdir(LANGUAGES_DIR):
lang_path = os.path.join(LANGUAGES_DIR, lang_dir)
if not os.path.isdir(lang_path):
continue
lang_files = {}
for filename in os.listdir(lang_path):
if filename.endswith('.yaml'):
filepath = os.path.join(lang_path, filename)
if os.path.isfile(filepath):
name = os.path.splitext(filename)[0] # Remove .yaml
lang_files[name] = filepath
if lang_files: # Only add if we found YAML files
language_map[lang_dir] = lang_files
return language_map
# Build language map at module load
DEFAULT_LANGUAGE_MAP = build_language_map()
def detect_language_from_filename(filename):
"""Detect language from file extension (e.g., my-program.de.py -> german)
Returns tuple: (filepath, two_letter_code) or None"""
parts = filename.split('.')
if len(parts) > 2: # Has language code in extension
lang_code = parts[-2].lower()
if lang_code in DEFAULT_LANGUAGE_MAP:
# Return first filepath found and the language code
lang_files = DEFAULT_LANGUAGE_MAP[lang_code]
first_file = next(iter(lang_files.values())) if lang_files else None
return (first_file, lang_code)
return None
def detect_language_from_comment(code):
"""Detect language from comment (e.g., # language:fr)
Returns tuple: (filepath, two_letter_code) or None"""
first_lines = code.split('\n')[:5] # Check first 5 lines for comment
for line in first_lines:
match = re.search(r'^#\s*language\s*:\s*(\w+)', line, re.IGNORECASE)
if match:
lang_code = match.group(1).lower()
if lang_code in DEFAULT_LANGUAGE_MAP:
# Return first filepath found and the language code
lang_files = DEFAULT_LANGUAGE_MAP[lang_code]
first_file = next(iter(lang_files.values())) if lang_files else None
return (first_file, lang_code)
return None
def determine_language(args, filename, code):
"""Determine target language based on priority rules"""
detected_dictionary = None
detected_lang = None
# Check detection methods in priority order
if args.get('dictionary'):
detected_dictionary = args['dictionary']
elif args.get('source_language'):
detected_dictionary = DEFAULT_LANGUAGE_MAP.get(args['source_language'], {})['default']
else:
detected_dictionary, detected_lang = (detect_language_from_comment(code) or
detect_language_from_filename(filename) or
(None, None))
# Update source_language with the detected language if not explicitly set
# if not args.get('source_language') and detected_lang:
if detected_lang:
args['source_language'] = detected_lang
return detected_dictionary or ""
def run_module(
mode,
code,
args={
'translate': False,
'dictionary': "",
'source_language': "",
'reverse': False,
'keep': False,
'keep_only': False,
'return': True,
},
):
# Determine language and update source_language
filename = ""
if args["file"]:
filename = args["file"][0]
args['dictionary'] = determine_language(args, filename, code)
# Default mode is 'lex' if not specified
mode = args.get('mode', 'lex')
mod = importlib.import_module(".modes."+mode, package='universalpython')
return mod.run(args, code)
def main():
import argparse
# construct the argument parser and parse the argument
ap = argparse.ArgumentParser()
ap.add_argument('file', metavar='F', type=str, nargs='+',
help='File to compile.')
ap.add_argument("-t", "--translate",
choices=["", "argostranslate", "unidecode"],
const="", # Default when --translate is used without value
default=None, # Default when --translate is not used at all
nargs='?', # Makes the argument optional
required=False,
help="Translate variables and functions. Options: "
"no value (unidecode), 'argostranslate', or 'unidecode'")
ap.add_argument("-d", "--dictionary",
default="", required=False,
help="The dictionary to use to translate the code.")
ap.add_argument("-sl", "--source-language",
default="", required=False,
dest="source_language",
help="The source language of the code (for translation).")
ap.add_argument("-r", "--reverse",
action='store_true',
default=False, required=False,
help="Translate English code to the language of your choice.")
ap.add_argument("-re", "--return",
action='store_false',
default=False, required=False,
help="Return the code instead of executing (used in module mode).")
group = ap.add_mutually_exclusive_group(required=False)
group.add_argument("-k", "--keep",
action='store_true',
default=False, required=False,
help="Save the compiled file to the specified location.")
group.add_argument("-ko", "--keep-only",
action='store_true',
default=False, required=False,
help="Save the compiled file to the specified location, but don't run the file.")
args = vars(ap.parse_args())
filename = args["file"][0]
with open(filename) as code_pyfile:
code = code_pyfile.read()
# Default mode is 'lex' if not specified
mode = args.get('mode', 'lex')
return run_module(mode, code, args)
if __name__ == "__main__":
sys.exit(main())