forked from DevlopRishi/Gen-Alpha-Programming-Language-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlang.py
More file actions
141 lines (97 loc) · 3.27 KB
/
lang.py
File metadata and controls
141 lines (97 loc) · 3.27 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
import re
import sys
import os
import csv
def get_strings(original_program: str) -> list[tuple[int, int]]:
"""
Searches through entire file program, saves indexes of double/single
quotes in a list of tuples, returns that list.
Uses list to avoid translations within quotes.
:param original_program: non-translated program in string format
:return: list of start and end positions of quotes
"""
string_locations: list[tuple[int, int]] = []
inside: str | None = None
pointer: int = -1
for i, char in enumerate(original_program):
if inside is None:
if char in ("'", '"'):
inside = char
pointer = i
elif char == inside:
inside = None
string_locations.append((pointer, i))
return string_locations
def is_in_string(idx: int, string_positions: list[tuple[int, int]]) -> bool:
"""
Checks if index of keyword is within start and end index of single/double quotes
Returns bool based on result
:param idx: index of translatable keyword
:param string_positions: list of start and end positions of quotes
:return: ``True`` if index of keyword is within string indexes, ``False`` otherwise
"""
for start, end in string_positions:
if start < idx < end:
return True
return False
def get_translations() -> dict[str, str]:
"""
Reads translatable keywords from a csv file.
:return: a dictionary containing python keywords and translatable keyword
"""
translations: dict[str, str] = {}
# second command line argument is a dictionary path
with open(sys.argv[2], encoding='utf-8', newline='') as f:
reader = csv.reader(f)
for row in reader:
translations[row[0]] = row[1]
return translations
def translate_program(program: str) -> str:
"""
Replaces all translatable keywords in program with python keywords.
:param program: python-like program with translatable keywords in string format
:return: translated python program
"""
def replacer(match) -> str:
"""Replaces translatable keywords if they are not located in a string"""
idx = match.start()
strings: list[tuple[int, int]] = get_strings(program)
return py_word \
if not is_in_string(idx, strings) \
else match.group(0)
translations: dict[str, str] = get_translations()
for py_word in translations.keys():
pattern: str = re.escape(translations[py_word])
program: str = re.sub(pattern, replacer, program)
return program
def run_program(program: str) -> None:
"""
Executes the python program
:param program: fully translated python program
:raises Exception: if any error occurs
"""
try:
exec(program, {'__return_value__': None})
except Exception as e:
raise Exception(e)
def main() -> None:
"""Main function: handles file input."""
if len(sys.argv) < 3:
raise IOError('Must Provide Additional Arguments')
# Read code from file
filename: str = sys.argv[1]
if not filename.endswith('.tpy'):
raise FileNotFoundError('Your Chosen File Is Not A .tpy File')
with open(filename, 'r', encoding='utf-8') as f:
code = f.read()
python_program: str = translate_program(code)
if len(sys.argv) == 3:
run_program(python_program)
return
if not os.path.exists('debug'):
os.makedirs('debug')
with open(f'debug/debug.py', 'w', encoding='utf-8') as f:
f.write(python_program)
run_program(python_program)
if __name__ == '__main__':
main()