colon3 0.0.9__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.
- colon3/__init__.py +0 -0
- colon3/cli.py +47 -0
- colon3-0.0.9.dist-info/METADATA +5 -0
- colon3-0.0.9.dist-info/RECORD +15 -0
- colon3-0.0.9.dist-info/WHEEL +5 -0
- colon3-0.0.9.dist-info/entry_points.txt +2 -0
- colon3-0.0.9.dist-info/top_level.txt +2 -0
- modules/SETTINGS.py +29 -0
- modules/__init__.py +0 -0
- modules/evaulator.py +156 -0
- modules/functions/__init__.py +0 -0
- modules/functions/pointer_related.py +147 -0
- modules/functions/variable_parsing.py +220 -0
- modules/parser.py +135 -0
- modules/tokens.py +176 -0
colon3/__init__.py
ADDED
|
File without changes
|
colon3/cli.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from modules.evaulator import Ev
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
def print_error(prefix, string_reason):
|
|
6
|
+
print(f"{prefix}: {string_reason}")
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
args = sys.argv[1:]
|
|
10
|
+
|
|
11
|
+
if not args:
|
|
12
|
+
print("colon three,,, the programming language... Why did i make this language...")
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
if args[0] == "run":
|
|
16
|
+
if len(args) != 2:
|
|
17
|
+
print("Usage: colon-three run [FILE]...")
|
|
18
|
+
return
|
|
19
|
+
|
|
20
|
+
file_path = Path(args[1]).expanduser()
|
|
21
|
+
# print("FILE_PATH:", file_path)
|
|
22
|
+
|
|
23
|
+
if not file_path.exists():
|
|
24
|
+
print_error(sys.argv[1], f"cannot run '{file_path}': No such file or directory. (colon-three)")
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
if not file_path.is_file():
|
|
28
|
+
print_error(sys.argv[1], f"cannot run '{file_path}': Not a file. (colon-three)")
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
with file_path.open("r", encoding="utf-8") as file:
|
|
33
|
+
content = file.read()
|
|
34
|
+
|
|
35
|
+
except OSError as e:
|
|
36
|
+
print_error(sys.argv[:1], f"cannot read '{file_path}': {e}")
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
ev = Ev()
|
|
40
|
+
ev.ev(content)
|
|
41
|
+
|
|
42
|
+
else:
|
|
43
|
+
print(f"Unknown command: {args[0]}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
if __name__ == "__main__":
|
|
47
|
+
main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
colon3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
colon3/cli.py,sha256=vWdB95INxCSlh9rrU4IR5MiY0FOYqG_Pr2a3FuGJiAA,1234
|
|
3
|
+
modules/SETTINGS.py,sha256=Xv1VFl3MARK3gYrqTkHg2JQYlKN9m7_Vd1UhhkSFO-s,754
|
|
4
|
+
modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
modules/evaulator.py,sha256=lnycyvStCaeC0_I3oIgic26sTSaq9xEqjJMW3ct-nTQ,5162
|
|
6
|
+
modules/parser.py,sha256=OudnmJk2Gep74uSvRrfOmhGJmk5oZZSZYbNiSTEUmdg,4666
|
|
7
|
+
modules/tokens.py,sha256=7ELSjuehjbORyaSTmVrvPNWrz8HDu_S9CKUV6Xm6a5g,4947
|
|
8
|
+
modules/functions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
modules/functions/pointer_related.py,sha256=0FYwGmtmIRnOG6zRpQBbWyidKIcmG0xnmAOoP5WSTIY,4390
|
|
10
|
+
modules/functions/variable_parsing.py,sha256=9bThRl80plq5ADhSYsEu6jr1YbTI9fD_9FjEw_oW0o0,7366
|
|
11
|
+
colon3-0.0.9.dist-info/METADATA,sha256=375fObotcUC_Q9ZUGI8rqZqmJc2Pz43Yv-Z7nRNPpFQ,203
|
|
12
|
+
colon3-0.0.9.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
13
|
+
colon3-0.0.9.dist-info/entry_points.txt,sha256=VLABzUkYBdDCOYfiNllBVk8tJWrE-F7g-R4Hrb2FcPA,43
|
|
14
|
+
colon3-0.0.9.dist-info/top_level.txt,sha256=CzY29IQbUXXGD9vh77xH9G1bN0HKit0QV8K_Dl4mds0,15
|
|
15
|
+
colon3-0.0.9.dist-info/RECORD,,
|
modules/SETTINGS.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
settings = {
|
|
2
|
+
"debug": False,
|
|
3
|
+
"show_intent": True,
|
|
4
|
+
"returning_values": False,
|
|
5
|
+
"output_lines": False,
|
|
6
|
+
"show_tokenized_code": True
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if not settings["debug"]:
|
|
10
|
+
settings["show_intent"] = False
|
|
11
|
+
settings["returning_values"] = False
|
|
12
|
+
settings["output_lines"] = False
|
|
13
|
+
settings["show_tokenized_code"] = False
|
|
14
|
+
|
|
15
|
+
def debugPrint(*args):
|
|
16
|
+
if settings["debug"]:
|
|
17
|
+
print(*args)
|
|
18
|
+
|
|
19
|
+
def debugPrintIntent(*args):
|
|
20
|
+
if settings["debug"] and settings["show_intent"]:
|
|
21
|
+
print(*args)
|
|
22
|
+
|
|
23
|
+
def debugPrintReturn(*args):
|
|
24
|
+
if settings["debug"] and settings["returning_values"]:
|
|
25
|
+
print(*args)
|
|
26
|
+
|
|
27
|
+
def debugPrintOutput(*args):
|
|
28
|
+
if settings["debug"] and settings["output_lines"]:
|
|
29
|
+
print(*args)
|
modules/__init__.py
ADDED
|
File without changes
|
modules/evaulator.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from .parser import compute_action
|
|
3
|
+
from .tokens import lib_number_tokens, lib_syntax, lib_operators, lib_nest_up, lib_nest_down, lib_nest_ambiguous
|
|
4
|
+
from .SETTINGS import debugPrint, debugPrintOutput, settings
|
|
5
|
+
|
|
6
|
+
def callout_error(line, collumn, reason):
|
|
7
|
+
raise SyntaxError(f"Syntax error at ({line}:{collumn}): {reason}")
|
|
8
|
+
|
|
9
|
+
class Ev:
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.current_line = 0
|
|
13
|
+
self.current_collumn = 0
|
|
14
|
+
self.current_nest_level = 0
|
|
15
|
+
|
|
16
|
+
self.variables = {}
|
|
17
|
+
|
|
18
|
+
self.nest_info = []
|
|
19
|
+
self.loop_labels = []
|
|
20
|
+
|
|
21
|
+
self.recall_labels = []
|
|
22
|
+
|
|
23
|
+
def get_nest(self, converted_total):
|
|
24
|
+
nest = []
|
|
25
|
+
level = 0
|
|
26
|
+
|
|
27
|
+
for line_num, line in enumerate(converted_total):
|
|
28
|
+
line_info = {
|
|
29
|
+
"value": level,
|
|
30
|
+
"columns": {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for col, token in enumerate(line):
|
|
34
|
+
if token in lib_nest_ambiguous:
|
|
35
|
+
level -= 1
|
|
36
|
+
if level < 0:
|
|
37
|
+
callout_error(line_num + 1, col + 1, f"Unexpected '{token}.'")
|
|
38
|
+
|
|
39
|
+
line_info["columns"][col] = {"value": level}
|
|
40
|
+
|
|
41
|
+
level += 1
|
|
42
|
+
line_info["columns"][col + 1] = {"value": level}
|
|
43
|
+
|
|
44
|
+
elif token in lib_nest_up:
|
|
45
|
+
level += 1
|
|
46
|
+
line_info["columns"][col + 1] = {"value": level}
|
|
47
|
+
|
|
48
|
+
elif token in lib_nest_down:
|
|
49
|
+
level -= 1
|
|
50
|
+
if level < 0:
|
|
51
|
+
callout_error(line_num + 1, col + 1, f"Unexpected '{token}.'")
|
|
52
|
+
|
|
53
|
+
line_info["columns"][col] = {"value": level}
|
|
54
|
+
|
|
55
|
+
nest.append(line_info)
|
|
56
|
+
|
|
57
|
+
if level != 0:
|
|
58
|
+
raise callout_error(0, 0, f"One or more nesting blocks weren't closed properly.")
|
|
59
|
+
|
|
60
|
+
return nest
|
|
61
|
+
|
|
62
|
+
def map_syntax(self, token, use_new_parser=False):
|
|
63
|
+
if token in lib_number_tokens:
|
|
64
|
+
return lib_number_tokens[token]
|
|
65
|
+
|
|
66
|
+
if token in lib_syntax:
|
|
67
|
+
return lib_syntax[token]
|
|
68
|
+
|
|
69
|
+
if token in lib_operators:
|
|
70
|
+
return lib_operators[token]
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
def convert_token(self, tokens):
|
|
74
|
+
result = []
|
|
75
|
+
i = 0
|
|
76
|
+
|
|
77
|
+
while i < len(tokens):
|
|
78
|
+
output = None
|
|
79
|
+
|
|
80
|
+
# Try a three-token match
|
|
81
|
+
if i + 2 < len(tokens):
|
|
82
|
+
triple = f"{tokens[i]} {tokens[i + 1]} {tokens[i + 2]}"
|
|
83
|
+
output = self.map_syntax(triple)
|
|
84
|
+
|
|
85
|
+
if output is not None:
|
|
86
|
+
result.append(output)
|
|
87
|
+
i += 3
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
# Try a two-token match
|
|
91
|
+
if i + 1 < len(tokens):
|
|
92
|
+
pair = f"{tokens[i]} {tokens[i + 1]}"
|
|
93
|
+
output = self.map_syntax(pair)
|
|
94
|
+
|
|
95
|
+
if output is not None:
|
|
96
|
+
result.append(output)
|
|
97
|
+
i += 2
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
# Try a one-token match
|
|
101
|
+
output = self.map_syntax(tokens[i])
|
|
102
|
+
if output is not None:
|
|
103
|
+
result.append(output)
|
|
104
|
+
i += 1
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
# Welp im all out of options..
|
|
108
|
+
raise callout_error(self.current_line, i, f"{tokens[i]} is not a valid token!")
|
|
109
|
+
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
def ev(self, s: str):
|
|
113
|
+
lines = [x.strip() for x in re.split(r"\n|murrp", s) if x.strip()]
|
|
114
|
+
lines = [line for line in lines if not line.startswith("//")]
|
|
115
|
+
|
|
116
|
+
# hardmode
|
|
117
|
+
i = 0
|
|
118
|
+
for line in lines:
|
|
119
|
+
if not line.endswith("~"):
|
|
120
|
+
raise callout_error(len(line) - 1, i, "Expected a '~' at end of declaration.")
|
|
121
|
+
lines[i] = line[:-1]
|
|
122
|
+
i += 1
|
|
123
|
+
|
|
124
|
+
converted_lines = [] # Only used once wow how useful
|
|
125
|
+
for line in lines:
|
|
126
|
+
converted_lines.append(self.convert_token(line.split()))
|
|
127
|
+
|
|
128
|
+
if settings["show_tokenized_code"]:
|
|
129
|
+
debugPrint("Tokenized code:")
|
|
130
|
+
for line in converted_lines:
|
|
131
|
+
debugPrint(line)
|
|
132
|
+
|
|
133
|
+
self.nest_info = self.get_nest(converted_lines)
|
|
134
|
+
self.current_line = 0
|
|
135
|
+
|
|
136
|
+
while self.current_line < len(lines):
|
|
137
|
+
self.ev_expr(lines[self.current_line], lines)
|
|
138
|
+
self.current_line += 1
|
|
139
|
+
|
|
140
|
+
debugPrint("Code finished executing.")
|
|
141
|
+
debugPrint("Variables:", self.variables)
|
|
142
|
+
debugPrint("Nest data:", self.nest_info)
|
|
143
|
+
debugPrint("Loop data:", self.loop_labels)
|
|
144
|
+
|
|
145
|
+
def ev_expr(self, line: str, whole_code: str):
|
|
146
|
+
words = line.split()
|
|
147
|
+
token_array = self.convert_token(words)
|
|
148
|
+
|
|
149
|
+
debugPrintOutput(f"Line {self.current_collumn}:", token_array)
|
|
150
|
+
self.current_collumn = 0
|
|
151
|
+
|
|
152
|
+
while self.current_collumn < len(token_array):
|
|
153
|
+
token = token_array[self.current_collumn]
|
|
154
|
+
changed_collumn = compute_action(self, token, token_array, whole_code)
|
|
155
|
+
if changed_collumn != "IGNORE":
|
|
156
|
+
self.current_collumn = changed_collumn
|
|
File without changes
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from ..tokens import lib_operators, lib_reverse_search, lib_nest_down, lib_nest_ambiguous
|
|
2
|
+
from ..SETTINGS import debugPrintOutput, debugPrintReturn, debugPrint
|
|
3
|
+
from .variable_parsing import return_variable_referenced
|
|
4
|
+
|
|
5
|
+
def get_nest_at(nest_info, line, column):
|
|
6
|
+
if not (0 <= line < len(nest_info)):
|
|
7
|
+
return 0
|
|
8
|
+
|
|
9
|
+
line_info = nest_info[line]
|
|
10
|
+
nesting = line_info["value"]
|
|
11
|
+
|
|
12
|
+
for col in sorted(line_info["columns"]):
|
|
13
|
+
if col > column:
|
|
14
|
+
break
|
|
15
|
+
nesting = line_info["columns"][col]["value"]
|
|
16
|
+
|
|
17
|
+
return nesting
|
|
18
|
+
|
|
19
|
+
def find_next_else_or_end(self, total):
|
|
20
|
+
converted_lines = [
|
|
21
|
+
self.convert_token(line.split())
|
|
22
|
+
for line in total
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
current_nest = get_nest_at(
|
|
26
|
+
self.nest_info,
|
|
27
|
+
self.current_line,
|
|
28
|
+
self.current_collumn
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
pointer_line = self.current_line
|
|
32
|
+
pointer_collumn = self.current_collumn
|
|
33
|
+
|
|
34
|
+
while pointer_line < len(converted_lines):
|
|
35
|
+
|
|
36
|
+
# Move to next token
|
|
37
|
+
if pointer_collumn + 1 < len(converted_lines[pointer_line]):
|
|
38
|
+
pointer_collumn += 1
|
|
39
|
+
else:
|
|
40
|
+
pointer_line += 1
|
|
41
|
+
pointer_collumn = 0
|
|
42
|
+
|
|
43
|
+
if pointer_line >= len(converted_lines):
|
|
44
|
+
break
|
|
45
|
+
|
|
46
|
+
if pointer_collumn >= len(converted_lines[pointer_line]):
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
statement = converted_lines[pointer_line][pointer_collumn]
|
|
50
|
+
|
|
51
|
+
statement_nest = get_nest_at(
|
|
52
|
+
self.nest_info,
|
|
53
|
+
pointer_line,
|
|
54
|
+
pointer_collumn
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
debugPrint(
|
|
58
|
+
f"{pointer_line}:{pointer_collumn}",
|
|
59
|
+
statement,
|
|
60
|
+
"nest:",
|
|
61
|
+
statement_nest
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if statement_nest == current_nest:
|
|
65
|
+
if statement in lib_nest_down or statement in lib_nest_ambiguous:
|
|
66
|
+
return pointer_line, pointer_collumn
|
|
67
|
+
|
|
68
|
+
raise SyntaxError("Could not find matching else/end.")
|
|
69
|
+
|
|
70
|
+
def parse_if_statement(self, tokenized_text, total):
|
|
71
|
+
if len(tokenized_text) <= self.current_collumn + 1:
|
|
72
|
+
raise SyntaxError("Expected a value or variable.")
|
|
73
|
+
|
|
74
|
+
value = return_variable_referenced(
|
|
75
|
+
self,
|
|
76
|
+
tokenized_text[self.current_collumn + 1]
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if value > 0:
|
|
80
|
+
debugPrintReturn("check passed!")
|
|
81
|
+
|
|
82
|
+
self.current_nest_level += 1
|
|
83
|
+
return self.current_collumn + 1
|
|
84
|
+
|
|
85
|
+
debugPrintReturn("check failed!")
|
|
86
|
+
|
|
87
|
+
line, col = find_next_else_or_end(self, total)
|
|
88
|
+
|
|
89
|
+
self.current_line = line
|
|
90
|
+
self.current_collumn = col + 1
|
|
91
|
+
|
|
92
|
+
return "IGNORE"
|
|
93
|
+
|
|
94
|
+
def recall_back_to_start_of_loop(self, tokenized_text, total):
|
|
95
|
+
debugPrintOutput("currently recalling last loop in line", self.current_line, "collumn", self.current_collumn)
|
|
96
|
+
|
|
97
|
+
statement_nest = get_nest_at(
|
|
98
|
+
self.nest_info,
|
|
99
|
+
self.current_line,
|
|
100
|
+
self.current_collumn
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
advanceAmount = 1
|
|
104
|
+
if len(tokenized_text) >= 1:
|
|
105
|
+
advanceAmount = return_variable_referenced(self, tokenized_text[1])
|
|
106
|
+
|
|
107
|
+
debugPrintOutput("Tokenized text:", tokenized_text)
|
|
108
|
+
debugPrintOutput("current statement level:", statement_nest)
|
|
109
|
+
|
|
110
|
+
while self.loop_labels:
|
|
111
|
+
latest_loop = self.loop_labels[-1]
|
|
112
|
+
data = latest_loop["data"]
|
|
113
|
+
|
|
114
|
+
if "var_check" in data:
|
|
115
|
+
check_value = return_variable_referenced(self, data["var_check"])
|
|
116
|
+
if check_value <= 0:
|
|
117
|
+
# This loop is finished
|
|
118
|
+
self.loop_labels.pop()
|
|
119
|
+
self.current_nest_level -= 1
|
|
120
|
+
else:
|
|
121
|
+
self.current_line = latest_loop["line"]
|
|
122
|
+
self.current_collumn = latest_loop["collumn"]
|
|
123
|
+
|
|
124
|
+
break
|
|
125
|
+
|
|
126
|
+
if data["current"] < data["end"]:
|
|
127
|
+
data["current"] = min(data["current"] + advanceAmount, data["end"])
|
|
128
|
+
|
|
129
|
+
self.variables[data["var_name"]] = data["current"]
|
|
130
|
+
self.current_line = latest_loop["line"]
|
|
131
|
+
self.current_collumn = latest_loop["collumn"]
|
|
132
|
+
|
|
133
|
+
break
|
|
134
|
+
else:
|
|
135
|
+
# This loop is finished
|
|
136
|
+
self.loop_labels.pop()
|
|
137
|
+
self.current_nest_level -= 1
|
|
138
|
+
|
|
139
|
+
return self.current_collumn + 1
|
|
140
|
+
|
|
141
|
+
def skip_parts_of_code(self, tokenized_text, total):
|
|
142
|
+
line, col = find_next_else_or_end(self, total)
|
|
143
|
+
|
|
144
|
+
self.current_line = line
|
|
145
|
+
self.current_collumn = col + 1
|
|
146
|
+
|
|
147
|
+
return "IGNORE"
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from ..tokens import lib_operators, lib_reverse_search
|
|
2
|
+
from ..SETTINGS import debugPrintOutput, debugPrintReturn
|
|
3
|
+
|
|
4
|
+
def get_type(self, var_name):
|
|
5
|
+
if var_name not in self.variables:
|
|
6
|
+
return None
|
|
7
|
+
|
|
8
|
+
value = self.variables[var_name]
|
|
9
|
+
|
|
10
|
+
# Empty strings are treated as None
|
|
11
|
+
if isinstance(value, str) and len(value) == 0:
|
|
12
|
+
return None
|
|
13
|
+
|
|
14
|
+
return type(value)
|
|
15
|
+
|
|
16
|
+
def parse_statement(value1, value2, type):
|
|
17
|
+
# Strings are compared by their length
|
|
18
|
+
if isinstance(value1, str):
|
|
19
|
+
value1 = len(value1)
|
|
20
|
+
|
|
21
|
+
if isinstance(value2, str):
|
|
22
|
+
value2 = len(value2)
|
|
23
|
+
|
|
24
|
+
if type == lib_reverse_search["equal_to"]:
|
|
25
|
+
return 1 if value1 == value2 else 0
|
|
26
|
+
|
|
27
|
+
elif type == lib_reverse_search["more_than"]:
|
|
28
|
+
return 1 if value1 > value2 else 0
|
|
29
|
+
|
|
30
|
+
elif type == lib_reverse_search["less_than"]:
|
|
31
|
+
return 1 if value1 < value2 else 0
|
|
32
|
+
|
|
33
|
+
elif type == lib_reverse_search["more_or_equal_to"]:
|
|
34
|
+
return 1 if value1 >= value2 else 0
|
|
35
|
+
|
|
36
|
+
elif type == lib_reverse_search["less_or_equal_to"]:
|
|
37
|
+
return 1 if value1 <= value2 else 0
|
|
38
|
+
|
|
39
|
+
return 0
|
|
40
|
+
|
|
41
|
+
def parse_number(value):
|
|
42
|
+
# Already a number
|
|
43
|
+
if isinstance(value, (int, float)):
|
|
44
|
+
return value
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
return int(value)
|
|
48
|
+
except (ValueError, TypeError):
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
return float(value)
|
|
53
|
+
except (ValueError, TypeError):
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
return value
|
|
57
|
+
|
|
58
|
+
def convert_to_literal(value):
|
|
59
|
+
if value == "null":
|
|
60
|
+
|
|
61
|
+
debugPrintReturn("returning as null")
|
|
62
|
+
return None
|
|
63
|
+
else:
|
|
64
|
+
new = parse_number(value)
|
|
65
|
+
|
|
66
|
+
debugPrintReturn("returning as", type(new))
|
|
67
|
+
return new
|
|
68
|
+
|
|
69
|
+
def return_variable_referenced(self, value):
|
|
70
|
+
if value in self.variables:
|
|
71
|
+
old = self.variables[value]
|
|
72
|
+
|
|
73
|
+
debugPrintReturn("borrowing the value", old, "for", value)
|
|
74
|
+
return old
|
|
75
|
+
|
|
76
|
+
debugPrintReturn("returning literal", value)
|
|
77
|
+
# Convert literals if possible
|
|
78
|
+
value = convert_to_literal(value)
|
|
79
|
+
return value
|
|
80
|
+
|
|
81
|
+
def compute_variable(self, tokenized_text):
|
|
82
|
+
operators = lib_operators.values()
|
|
83
|
+
|
|
84
|
+
# Find the operator
|
|
85
|
+
operator_index = None
|
|
86
|
+
for j in range(self.current_collumn + 1, len(tokenized_text)):
|
|
87
|
+
if tokenized_text[j] in operators:
|
|
88
|
+
operator_index = j
|
|
89
|
+
break
|
|
90
|
+
|
|
91
|
+
if operator_index is None:
|
|
92
|
+
raise SyntaxError("Expected an assignment operator.")
|
|
93
|
+
|
|
94
|
+
# Everything before the operator is the variable name
|
|
95
|
+
var_name = "".join(tokenized_text[self.current_collumn + 1:operator_index])
|
|
96
|
+
|
|
97
|
+
# Find the separator
|
|
98
|
+
separator_index = None
|
|
99
|
+
for j in range(operator_index + 1, len(tokenized_text)):
|
|
100
|
+
if tokenized_text[j] == lib_reverse_search["add"]: # :3 would be more of a seperator
|
|
101
|
+
separator_index = j
|
|
102
|
+
break
|
|
103
|
+
|
|
104
|
+
if separator_index is None:
|
|
105
|
+
# No separator found
|
|
106
|
+
value = "".join(tokenized_text[operator_index + 1:])
|
|
107
|
+
value2 = ""
|
|
108
|
+
else:
|
|
109
|
+
value = "".join(tokenized_text[operator_index + 1:separator_index])
|
|
110
|
+
value2 = "".join(tokenized_text[separator_index + 1:])
|
|
111
|
+
|
|
112
|
+
# Variable reference
|
|
113
|
+
value = return_variable_referenced(self, value)
|
|
114
|
+
value2 = return_variable_referenced(self, value2)
|
|
115
|
+
|
|
116
|
+
operator = tokenized_text[operator_index]
|
|
117
|
+
travelled_index = len(tokenized_text)
|
|
118
|
+
|
|
119
|
+
# Get its existing type
|
|
120
|
+
existing_type = get_type(self, var_name)
|
|
121
|
+
debugPrintReturn("Existing type:", existing_type)
|
|
122
|
+
debugPrintReturn("Value1:", value, type(value))
|
|
123
|
+
debugPrintReturn("Value2:", value2, type(value2))
|
|
124
|
+
|
|
125
|
+
if operator == lib_reverse_search["equal_to"]:
|
|
126
|
+
self.variables[var_name] = parse_statement(value, value2, operator)
|
|
127
|
+
return travelled_index
|
|
128
|
+
|
|
129
|
+
elif operator == lib_reverse_search["more_than"]:
|
|
130
|
+
self.variables[var_name] = parse_statement(value, value2, operator)
|
|
131
|
+
return travelled_index
|
|
132
|
+
|
|
133
|
+
elif operator == lib_reverse_search["less_than"]:
|
|
134
|
+
self.variables[var_name] = parse_statement(value, value2, operator)
|
|
135
|
+
return travelled_index
|
|
136
|
+
|
|
137
|
+
elif operator == lib_reverse_search["more_or_equal_to"]:
|
|
138
|
+
self.variables[var_name] = parse_statement(value, value2, operator)
|
|
139
|
+
return travelled_index
|
|
140
|
+
|
|
141
|
+
elif operator == lib_reverse_search["less_or_equal_to"]:
|
|
142
|
+
self.variables[var_name] = parse_statement(value, value2, operator)
|
|
143
|
+
return travelled_index
|
|
144
|
+
|
|
145
|
+
# Assignment
|
|
146
|
+
if operator == lib_reverse_search["equal"]:
|
|
147
|
+
self.variables[var_name] = value
|
|
148
|
+
debugPrintOutput("setting", var_name, "to", value)
|
|
149
|
+
|
|
150
|
+
return travelled_index
|
|
151
|
+
|
|
152
|
+
# Addition
|
|
153
|
+
if operator == lib_reverse_search["add"]:
|
|
154
|
+
if var_name not in self.variables:
|
|
155
|
+
raise NameError(f"Variable '{var_name}' does not exist.")
|
|
156
|
+
|
|
157
|
+
current = self.variables[var_name]
|
|
158
|
+
|
|
159
|
+
# Number + Number
|
|
160
|
+
if isinstance(current, (int, float)):
|
|
161
|
+
debugPrintOutput("Adding", value, "to", var_name, "(current value:", current, ")")
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
if not isinstance(value, (int, float)):
|
|
165
|
+
value = parse_number(value)
|
|
166
|
+
|
|
167
|
+
self.variables[var_name] = current + value
|
|
168
|
+
except Exception:
|
|
169
|
+
# Fall back to string concatenation
|
|
170
|
+
|
|
171
|
+
debugPrintOutput(f"Failed to add as numbers, falling back to string concatenation for {var_name}.")
|
|
172
|
+
self.variables[var_name] = str(current) + str(value)
|
|
173
|
+
|
|
174
|
+
# String + Anything
|
|
175
|
+
elif isinstance(current, str):
|
|
176
|
+
self.variables[var_name] = current + str(value)
|
|
177
|
+
|
|
178
|
+
else:
|
|
179
|
+
raise TypeError(
|
|
180
|
+
f"Unsupported type '{type(current).__name__}' for variable '{var_name}'."
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return travelled_index
|
|
184
|
+
|
|
185
|
+
# Type checking because this is number special only...
|
|
186
|
+
if (existing_type is not None) and type(value) is not existing_type:
|
|
187
|
+
raise TypeError(
|
|
188
|
+
f"Expected {existing_type.__name__}, got {type(value).__name__}"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# Subtraction
|
|
192
|
+
elif operator == lib_reverse_search["subtract"]:
|
|
193
|
+
if not isinstance(value, (int, float)):
|
|
194
|
+
raise TypeError("Subtraction only works with numbers.")
|
|
195
|
+
|
|
196
|
+
debugPrintOutput(f"Subtracting {value} from {var_name} (current value: {self.variables.get(var_name, 0)})")
|
|
197
|
+
self.variables[var_name] -= value
|
|
198
|
+
|
|
199
|
+
# Multiplication
|
|
200
|
+
elif operator == lib_reverse_search["multiply"]:
|
|
201
|
+
if not isinstance(value, (int, float)):
|
|
202
|
+
raise TypeError("Multiplication only works with numbers.")
|
|
203
|
+
|
|
204
|
+
debugPrintOutput(f"Multiplying {var_name} by {value} (current value: {self.variables.get(var_name, 0)})")
|
|
205
|
+
self.variables[var_name] *= value
|
|
206
|
+
|
|
207
|
+
# Division
|
|
208
|
+
elif operator == lib_reverse_search["divide"]:
|
|
209
|
+
if not isinstance(value, (int, float)):
|
|
210
|
+
raise TypeError("Division only works with numbers.")
|
|
211
|
+
if value == 0:
|
|
212
|
+
raise ZeroDivisionError("Division by zero.")
|
|
213
|
+
|
|
214
|
+
debugPrintOutput(f"Dividing {var_name} by {value} (current value: {self.variables.get(var_name, 0)})")
|
|
215
|
+
self.variables[var_name] /= value
|
|
216
|
+
|
|
217
|
+
else:
|
|
218
|
+
raise SyntaxError("Not a valid operator.")
|
|
219
|
+
|
|
220
|
+
return travelled_index
|
modules/parser.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from .tokens import lib_operators, lib_reverse_search, lib_nest_up, lib_nest_down, lib_nest_ambiguous
|
|
2
|
+
from .SETTINGS import debugPrint, debugPrintOutput, debugPrintReturn
|
|
3
|
+
|
|
4
|
+
from .functions.pointer_related import parse_if_statement, recall_back_to_start_of_loop, skip_parts_of_code, find_next_else_or_end
|
|
5
|
+
from .functions.variable_parsing import convert_to_literal, return_variable_referenced, compute_variable
|
|
6
|
+
|
|
7
|
+
def print_object(self, tokenized_text):
|
|
8
|
+
variable = "".join(tokenized_text[self.current_collumn + 1:])
|
|
9
|
+
|
|
10
|
+
# Specifically prints whatevers in the variable, or <None> if it doesn't exist
|
|
11
|
+
if variable in self.variables:
|
|
12
|
+
print(self.variables[variable])
|
|
13
|
+
else:
|
|
14
|
+
print("<None>")
|
|
15
|
+
|
|
16
|
+
return len(tokenized_text)
|
|
17
|
+
|
|
18
|
+
def read_input(self, tokenized_text):
|
|
19
|
+
# Make sure there are enough tokens
|
|
20
|
+
if len(tokenized_text) < 2:
|
|
21
|
+
raise SyntaxError("Expected a variable name.")
|
|
22
|
+
|
|
23
|
+
left = tokenized_text[0]
|
|
24
|
+
right = tokenized_text[1]
|
|
25
|
+
|
|
26
|
+
# Ensure both sides exist
|
|
27
|
+
if not left or not right:
|
|
28
|
+
raise SyntaxError("Invalid input statement.")
|
|
29
|
+
|
|
30
|
+
value = input("")
|
|
31
|
+
|
|
32
|
+
self.variables[right] = convert_to_literal(value if len(value) > 0 else None)
|
|
33
|
+
|
|
34
|
+
# Return the next token index
|
|
35
|
+
return self.current_collumn + 2
|
|
36
|
+
|
|
37
|
+
def handle_loop_statement(self, tokenized_text, total, type="for_loop"):
|
|
38
|
+
add_token = lib_reverse_search["add"]
|
|
39
|
+
|
|
40
|
+
parts = []
|
|
41
|
+
current = []
|
|
42
|
+
|
|
43
|
+
# Skip the LOOP_STATEMENT token
|
|
44
|
+
for token in tokenized_text[1:]:
|
|
45
|
+
if token == add_token:
|
|
46
|
+
if current:
|
|
47
|
+
parts.append("".join(current))
|
|
48
|
+
current = []
|
|
49
|
+
else:
|
|
50
|
+
current.append(token)
|
|
51
|
+
|
|
52
|
+
if current:
|
|
53
|
+
parts.append("".join(current))
|
|
54
|
+
|
|
55
|
+
if type == "while_loop":
|
|
56
|
+
if len(parts) > 1:
|
|
57
|
+
raise SyntaxError("While loops only accept a single condition.")
|
|
58
|
+
|
|
59
|
+
check_value = return_variable_referenced(self, parts[0])
|
|
60
|
+
if check_value <= 0:
|
|
61
|
+
|
|
62
|
+
debugPrintOutput("while loop condition failed, skipping...")
|
|
63
|
+
|
|
64
|
+
line, col = find_next_else_or_end(self, total)
|
|
65
|
+
|
|
66
|
+
self.current_line = line
|
|
67
|
+
self.current_collumn = col + 1
|
|
68
|
+
|
|
69
|
+
return "IGNORE"
|
|
70
|
+
|
|
71
|
+
debugPrintOutput("while loop condition passed, continuing...")
|
|
72
|
+
|
|
73
|
+
self.loop_labels.append(
|
|
74
|
+
{
|
|
75
|
+
"line": self.current_line,
|
|
76
|
+
"collumn": self.current_collumn,
|
|
77
|
+
"data": {
|
|
78
|
+
"var_check": parts[0],
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return self.current_collumn + 2
|
|
84
|
+
|
|
85
|
+
if len(parts) < 2:
|
|
86
|
+
raise SyntaxError("Expected a start and end value.")
|
|
87
|
+
|
|
88
|
+
start = return_variable_referenced(self, parts[0])
|
|
89
|
+
end = return_variable_referenced(self, parts[1])
|
|
90
|
+
var = parts[2] if len(parts) > 2 else None
|
|
91
|
+
|
|
92
|
+
debugPrintOutput("Making a loop statement with the given values:")
|
|
93
|
+
debugPrintOutput(" start:", start)
|
|
94
|
+
debugPrintOutput(" end: ", end)
|
|
95
|
+
debugPrintOutput(" var: ", var)
|
|
96
|
+
|
|
97
|
+
self.variables[var] = start
|
|
98
|
+
|
|
99
|
+
print(self.loop_labels)
|
|
100
|
+
|
|
101
|
+
self.loop_labels.append(
|
|
102
|
+
{
|
|
103
|
+
"line": self.current_line,
|
|
104
|
+
"collumn": self.current_collumn,
|
|
105
|
+
"data": {
|
|
106
|
+
"start": start,
|
|
107
|
+
"end": end,
|
|
108
|
+
"var_name": var,
|
|
109
|
+
"current": start
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return self.current_collumn + (3 if var is not None else 2)
|
|
115
|
+
|
|
116
|
+
def compute_action(self, converted_token, tokenized_text, total):
|
|
117
|
+
if converted_token == lib_reverse_search["set_var"]:
|
|
118
|
+
return compute_variable(self, tokenized_text)
|
|
119
|
+
elif converted_token == lib_reverse_search["print"]:
|
|
120
|
+
return print_object(self, tokenized_text)
|
|
121
|
+
elif converted_token == lib_reverse_search["input"]:
|
|
122
|
+
return read_input(self, tokenized_text)
|
|
123
|
+
elif converted_token == lib_reverse_search["if"]:
|
|
124
|
+
return parse_if_statement(self, tokenized_text, total)
|
|
125
|
+
elif converted_token == lib_reverse_search["else"]:
|
|
126
|
+
return skip_parts_of_code(self, tokenized_text, total)
|
|
127
|
+
elif converted_token == lib_reverse_search["loop"]:
|
|
128
|
+
return handle_loop_statement(self, tokenized_text, total, type="for_loop")
|
|
129
|
+
elif converted_token == lib_reverse_search["while"]:
|
|
130
|
+
return handle_loop_statement(self, tokenized_text, total, type="while_loop")
|
|
131
|
+
elif converted_token == lib_reverse_search["next"]:
|
|
132
|
+
return recall_back_to_start_of_loop(self, tokenized_text, total)
|
|
133
|
+
|
|
134
|
+
# Basically does NOTHING
|
|
135
|
+
return self.current_collumn + 1
|
modules/tokens.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
this_special_identifier = "@1209310239_"
|
|
2
|
+
|
|
3
|
+
lib_number_tokens = {
|
|
4
|
+
"mrrm mrrp": '0',
|
|
5
|
+
"mrrm meow": '1',
|
|
6
|
+
"mrrm mrow": '2',
|
|
7
|
+
"mrrm merow": '3',
|
|
8
|
+
"mrrm maow": '4',
|
|
9
|
+
"mrrm miau": '5',
|
|
10
|
+
"mrrm meww": '6',
|
|
11
|
+
"mrrm mrau": '7',
|
|
12
|
+
"mrrm myraa": '8',
|
|
13
|
+
"mrrp mrrm": '9',
|
|
14
|
+
"mrrp meow": 'a',
|
|
15
|
+
"mrrp mrow": 'b',
|
|
16
|
+
"mrrp merow": 'c',
|
|
17
|
+
"mrrp maow": 'd',
|
|
18
|
+
"mrrp miau": 'e',
|
|
19
|
+
"mrrp meww": 'f',
|
|
20
|
+
"mrrp mrau": 'g',
|
|
21
|
+
"mrrp myraa": 'h',
|
|
22
|
+
"meow mrrm": 'i',
|
|
23
|
+
"meow mrrp": 'j',
|
|
24
|
+
"meow mrow": 'k',
|
|
25
|
+
"meow merow": 'l',
|
|
26
|
+
"meow maow": 'm',
|
|
27
|
+
"meow miau": 'n',
|
|
28
|
+
"meow meww": 'o',
|
|
29
|
+
"meow mrau": 'p',
|
|
30
|
+
"meow myraa": 'q',
|
|
31
|
+
"mrow mrrm": 'r',
|
|
32
|
+
"mrow mrrp": 's',
|
|
33
|
+
"mrow meow": 't',
|
|
34
|
+
"mrow merow": 'u',
|
|
35
|
+
"mrow maow": 'v',
|
|
36
|
+
"mrow miau": 'w',
|
|
37
|
+
"mrow meww": 'x',
|
|
38
|
+
"mrow mrau": 'y',
|
|
39
|
+
"mrow myraa": 'z',
|
|
40
|
+
"merow mrrm": 'A',
|
|
41
|
+
"merow mrrp": 'B',
|
|
42
|
+
"merow meow": 'C',
|
|
43
|
+
"merow mrow": 'D',
|
|
44
|
+
"merow maow": 'E',
|
|
45
|
+
"merow miau": 'F',
|
|
46
|
+
"merow meww": 'G',
|
|
47
|
+
"merow mrau": 'H',
|
|
48
|
+
"merow myraa": 'I',
|
|
49
|
+
"maow mrrm": 'J',
|
|
50
|
+
"maow mrrp": 'K',
|
|
51
|
+
"maow meow": 'L',
|
|
52
|
+
"maow mrow": 'M',
|
|
53
|
+
"maow merow": 'N',
|
|
54
|
+
"maow miau": 'O',
|
|
55
|
+
"maow meww": 'P',
|
|
56
|
+
"maow mrau": 'Q',
|
|
57
|
+
"maow myraa": 'R',
|
|
58
|
+
"miau mrrm": 'S',
|
|
59
|
+
"miau mrrp": 'T',
|
|
60
|
+
"miau meow": 'U',
|
|
61
|
+
"miau mrow": 'V',
|
|
62
|
+
"miau merow": 'W',
|
|
63
|
+
"miau maow": 'X',
|
|
64
|
+
"miau meww": 'Y',
|
|
65
|
+
"miau mrau": 'Z',
|
|
66
|
+
"miau myraa": '!',
|
|
67
|
+
"meww mrrm": '"',
|
|
68
|
+
"meww mrrp": '#',
|
|
69
|
+
"meww meow": '$',
|
|
70
|
+
"meww mrow": '%',
|
|
71
|
+
"meww merow": '&',
|
|
72
|
+
"meww maow": "'",
|
|
73
|
+
"meww miau": '(',
|
|
74
|
+
"meww mrau": ')',
|
|
75
|
+
"meww myraa": '*',
|
|
76
|
+
"mrau mrrm": '+',
|
|
77
|
+
"mrau mrrp": ',',
|
|
78
|
+
"mrau meow": '-',
|
|
79
|
+
"mrau mrow": '.',
|
|
80
|
+
"mrau merow": '/',
|
|
81
|
+
"mrau maow": ':',
|
|
82
|
+
"mrau miau": ';',
|
|
83
|
+
"mrau meww": '<',
|
|
84
|
+
"mrau myraa": '=',
|
|
85
|
+
"myraa mrrm": '>',
|
|
86
|
+
"myraa mrrp": '?',
|
|
87
|
+
"myraa meow": '@',
|
|
88
|
+
"myraa mrow": '[',
|
|
89
|
+
"myraa merow": '\\',
|
|
90
|
+
"myraa maow": ']',
|
|
91
|
+
"myraa miau": '^',
|
|
92
|
+
"myraa meww": '_',
|
|
93
|
+
"myraa mrau": '`',
|
|
94
|
+
|
|
95
|
+
"mya": " ", # whitespace
|
|
96
|
+
|
|
97
|
+
# special characters
|
|
98
|
+
"purrr": "BUFFER1",
|
|
99
|
+
"purrrr": "BUFFER2",
|
|
100
|
+
"purrrrr": "BUFFER3",
|
|
101
|
+
"purrrrrr": "BUFFER4",
|
|
102
|
+
"purrrrrrr": "BUFFER5"
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
lib_reverse_search = {
|
|
106
|
+
"set_var": this_special_identifier + "CODE_SET_VAR",
|
|
107
|
+
"equal": this_special_identifier + "CODE_EQUAL",
|
|
108
|
+
"add": this_special_identifier + "CODE_ADD",
|
|
109
|
+
"subtract": this_special_identifier + "CODE_SUBTRACT",
|
|
110
|
+
"multiply": this_special_identifier + "CODE_MULTIPLY",
|
|
111
|
+
"divide": this_special_identifier + "CODE_DIVIDE",
|
|
112
|
+
|
|
113
|
+
"equal_to": this_special_identifier + "CODE_IS_EQUAL",
|
|
114
|
+
"more_than": this_special_identifier + "CODE_MORE_THAN",
|
|
115
|
+
"less_than": this_special_identifier + "CODE_LESS_THAN",
|
|
116
|
+
"more_or_equal_to": this_special_identifier + "CODE_MORE_OR_EQUAL",
|
|
117
|
+
"less_or_equal_to": this_special_identifier + "CODE_LESS_OR_EQUAL",
|
|
118
|
+
|
|
119
|
+
"print": this_special_identifier + "CODE_PRINT",
|
|
120
|
+
"input": this_special_identifier + "CODE_INPUT",
|
|
121
|
+
|
|
122
|
+
"if": this_special_identifier + "CODE_IF_STATEMENT",
|
|
123
|
+
"while": this_special_identifier + "CODE_WHILE_STATEMENT",
|
|
124
|
+
"loop": this_special_identifier + "CODE_LOOP_STATEMENT",
|
|
125
|
+
|
|
126
|
+
"end": this_special_identifier + "CODE_END",
|
|
127
|
+
"next": this_special_identifier + "CODE_LOOP_NEXT",
|
|
128
|
+
|
|
129
|
+
"new_line": this_special_identifier + "CODE_NEW_LINE",
|
|
130
|
+
"else": this_special_identifier + "CODE_ELSE"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
lib_syntax = {
|
|
134
|
+
"mrrauu": lib_reverse_search["set_var"],
|
|
135
|
+
"murrp": lib_reverse_search["new_line"],
|
|
136
|
+
|
|
137
|
+
"mryau meow": lib_reverse_search["input"],
|
|
138
|
+
"mryau mrrp": lib_reverse_search["print"],
|
|
139
|
+
"mryau miau": lib_reverse_search["end"],
|
|
140
|
+
"mryau meww": lib_reverse_search["else"],
|
|
141
|
+
|
|
142
|
+
"mryau mrow": lib_reverse_search["if"],
|
|
143
|
+
|
|
144
|
+
"mryau merow mew": lib_reverse_search["while"],
|
|
145
|
+
"mryau merow maow": lib_reverse_search["loop"],
|
|
146
|
+
"mryau merow meew": lib_reverse_search["next"]
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
lib_nest_up = [
|
|
150
|
+
lib_reverse_search["if"],
|
|
151
|
+
lib_reverse_search["while"],
|
|
152
|
+
lib_reverse_search["loop"]
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
lib_nest_ambiguous = [
|
|
156
|
+
lib_reverse_search["else"],
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
lib_nest_down = [
|
|
160
|
+
lib_reverse_search["end"],
|
|
161
|
+
lib_reverse_search["next"]
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
lib_operators = {
|
|
165
|
+
":3c": lib_reverse_search["equal"],
|
|
166
|
+
":3": lib_reverse_search["add"],
|
|
167
|
+
"3:": lib_reverse_search["subtract"],
|
|
168
|
+
">:3": lib_reverse_search["multiply"],
|
|
169
|
+
"3:<": lib_reverse_search["divide"],
|
|
170
|
+
|
|
171
|
+
":3c?": lib_reverse_search["equal_to"],
|
|
172
|
+
":3?": lib_reverse_search["more_than"],
|
|
173
|
+
"3:?": lib_reverse_search["less_than"],
|
|
174
|
+
">:3?": lib_reverse_search["more_or_equal_to"],
|
|
175
|
+
"3:<?": lib_reverse_search["less_or_equal_to"],
|
|
176
|
+
}
|