├── .gitignore
├── Constants
├── __init__.py
├── constants.py
├── keywords.py
└── tokens.py
├── Context
├── __init__.py
└── context.py
├── DOCS.md
├── Errors
├── __init__.py
├── base_error.py
└── errors.py
├── Interpreter
├── __init__.py
└── interpreter.py
├── LICENSE
├── Parser
├── __init__.py
└── parser.py
├── README.md
├── SymbolTable
├── __init__.py
└── symbol_table.py
├── Tests
├── __init__.py
├── test_variables.py
└── tests_arithmetic.py
├── bugs.baji
├── example.baji
├── examples
├── HelloWorld.baji
├── fib.baji
├── fib2.baji
├── game_of_life.baji
└── if_else.baji
├── grammar.md
├── lexer
├── __init__.py
├── lexer.py
├── position.py
└── token.py
├── logo.gif
├── logo.svg
├── main.py
├── nodes
├── __init__.py
├── conditional.py
├── functions.py
├── loop.py
├── operation.py
├── value.py
└── variable.py
├── results
├── __init__.py
├── parse_result.py
└── runtime_result.py
├── shell.py
├── temp.baji
├── translate
└── __init__.py
└── values
├── __init__.py
├── function.py
├── list.py
├── number.py
├── string.py
└── value.py
/.gitignore:
--------------------------------------------------------------------------------
1 | temp.py
2 | __pycache__/
3 | .vscode/
4 | temp.txt
5 | dist/
6 | build/
7 | baji.spec
--------------------------------------------------------------------------------
/Constants/__init__.py:
--------------------------------------------------------------------------------
1 | from Constants.constants import *
2 | from Constants.tokens import *
3 | from Constants.keywords import *
--------------------------------------------------------------------------------
/Constants/constants.py:
--------------------------------------------------------------------------------
1 | # -----------CONSTANTS-----------
2 | DIGITS = "0123456789०१२३४५६७८९"
3 | MAR_DIGIRS="०१२३४५६७८९"
4 | MAR_LETTERS=("ऀँंःऄअआइईउऊऋऌऍऎएऐऑऒओऔकखगघङचछजझञटठडढणतथदधनऩपफबभमयरऱलळऴवशषस"
5 | +"हऺऻ़ऽािीुूृॄॅॆेैॉॊोौ्ॎॏॐ॒॑॓॔ॕॖॗक़ख़ग़ज़ड़ढ़फ़य़ॠॡॢॣ।॥"
6 | + "॰ॱॲॳॴॵॶॷॸॹॺॻॼॽॾॿ")
7 |
8 | LETTERS = (
9 | MAR_LETTERS+MAR_DIGIRS
10 | + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
11 | )
12 | LETTERS_DIGITS = LETTERS + DIGITS
--------------------------------------------------------------------------------
/Constants/keywords.py:
--------------------------------------------------------------------------------
1 | KEYWORDS = [
2 | "VAR",
3 | "चल",
4 |
5 | "AND",
6 | "आणि",
7 |
8 | "OR",
9 | "किंवा",
10 |
11 | "NOT",
12 | "नाही",
13 |
14 | "IF",
15 | 'जर',
16 |
17 | "ELIF",
18 | "किंवाजर",
19 |
20 | "ELSE",
21 | 'नाहीतर',
22 |
23 | "THEN",
24 | 'तर',
25 |
26 | "FOR",
27 | "वारंवार",
28 |
29 | 'TO',
30 | 'ते',
31 |
32 | 'STEP',
33 | 'पाऊल',
34 |
35 | 'WHILE',
36 | 'जोपर्यंत',
37 |
38 | "FUN",
39 | "कार्य",
40 |
41 | "END",
42 | "शेवट",
43 |
44 | "RETURN",
45 | "परत",
46 |
47 | "CONTINUE",
48 | "सुरू",
49 |
50 | "BREAK",
51 | "थांबवा",
52 |
53 | ]
54 |
55 |
--------------------------------------------------------------------------------
/Constants/tokens.py:
--------------------------------------------------------------------------------
1 | # -----------TOKEN---------------
2 | TT_INT = "INT"
3 | TT_FLOAT = "FLOAT"
4 | TT_STRING = "STRING"
5 | TT_IDENTIFIER = "IDENTIFIER"
6 | TT_KEYWORD = "KEYWORD"
7 | TT_PLUS = "PLUS"
8 | TT_MINUS = "MINUS"
9 | TT_MUL = "MUL"
10 | TT_DIV = "DIV"
11 | TT_POWER = "POWER"
12 | TT_MOD = "MOD"
13 | TT_EQ = "EQ"
14 | TT_LPAREN = "LPAREN"
15 | TT_RPAREN = "RPAREN"
16 | TT_LSQUARE = "LSQUARE"
17 | TT_RSQUARE = "RSQUARE"
18 | TT_EE = "EE"
19 | TT_NE = "NE"
20 | TT_LT = "LT"
21 | TT_GT = "GT"
22 | TT_LTE = "LTE"
23 | TT_GTE = "GTE"
24 | TT_COMMA = "COMMA"
25 | TT_ARROW = "ARROW"
26 | TT_NEWLINE = "NEWLINE"
27 | TT_EOF = "EOF"
28 |
--------------------------------------------------------------------------------
/Context/__init__.py:
--------------------------------------------------------------------------------
1 | from Context.context import *
--------------------------------------------------------------------------------
/Context/context.py:
--------------------------------------------------------------------------------
1 | # ------------Context-----------------
2 | class Context:
3 | def __init__(self, display_name, parent=None, parent_entry_pos=None):
4 | self.display_name = display_name
5 | self.parent = parent
6 | self.parent_entry_pos = parent_entry_pos
7 | self.symbol_table = None
8 |
--------------------------------------------------------------------------------
/DOCS.md:
--------------------------------------------------------------------------------
1 | ## Docs
2 | ### **Print**
3 | ```
4 | दाखवा("नमस्कार विश्व")
5 | ```
6 | ### Variable
7 |
8 | ```
9 | चल i = 10
10 | दाखवा(i)
11 | ```
12 |
13 | ### **Conditionals**
14 | * IF
15 | ```
16 | जर (१२== ३*४) तर
17 | दाखवा("जर(IF)")
18 | शेवट
19 |
20 | ```
21 | * ELSE
22 | ```
23 | जर (१२== ३*४) तर
24 | दाखवा("जर(IF)")
25 | नाहीतर
26 | दाखवा("नाहीतर(ELSE)")
27 | शेवट
28 |
29 | ```
30 | * ELSE-IF
31 | ```
32 | जर (१२!= ३*४) तर
33 | दाखवा("जर(IF)")
34 | किंवाजर १==१ तर
35 | दाखवा("नाहीतर(ELSE-IF)")
36 | शेवट
37 |
38 | ```
39 | ### **LOOPS**
40 | * FOR
41 | ```
42 | वारंवार i = 0 ते 10 तर
43 | दाखवा(i)
44 | दाखवा("\n")
45 | शेवट
46 | ```
47 |
48 | * WHILE
49 | ```
50 | जोपर्यंत i !=10 तर
51 | दाखवा(i)
52 | दाखवा("\n")
53 | i = i+1
54 |
55 | शेवट
56 | ```
57 |
58 |
59 | ### Functions
60 |
61 | ```
62 | कार्य नामस्कर(नाव)
63 | दाखवा("नामस्कर "+नाव)
64 | शेवट
65 |
66 |
67 | चल नाव = "Joey"
68 | नामस्कर(नाव)
69 |
70 | ```
--------------------------------------------------------------------------------
/Errors/__init__.py:
--------------------------------------------------------------------------------
1 | from Errors.errors import *
2 |
--------------------------------------------------------------------------------
/Errors/base_error.py:
--------------------------------------------------------------------------------
1 | # -----------ERROR--------------
2 | class Error:
3 | def __init__(self, error_name, pos_start, pos_end, details):
4 | self.pos_start = pos_start
5 | self.pos_end = pos_end
6 | self.error_name = error_name
7 | self.details = details
8 |
9 | def as_string(self):
10 | result = f"{self.error_name} : {self.details} \n"
11 | result += f"File {self.pos_start.fn}, line {self.pos_start.ln+1}"
12 | result += "\n\n" + self.string_with_arrows(
13 | self.pos_start.ftxt, self.pos_start, self.pos_end
14 | )
15 | return result
16 |
17 | def string_with_arrows(self, text, pos_start, pos_end):
18 | result = ""
19 |
20 | # Calculate indices
21 | idx_start = max(text.rfind("\n", 0, pos_start.idx), 0)
22 | idx_end = text.find("\n", idx_start + 1)
23 | if idx_end < 0:
24 | idx_end = len(text)
25 |
26 | # Generate each line
27 | line_count = pos_end.ln - pos_start.ln + 1
28 | for i in range(line_count):
29 | # Calculate line columns
30 | line = text[idx_start:idx_end]
31 | col_start = pos_start.col if i == 0 else 0
32 | col_end = pos_end.col if i == line_count - 1 else len(line) - 1
33 |
34 | # Append to result
35 | result += line + "\n"
36 | result += " " * col_start + "^" * (col_end - col_start)
37 |
38 | # Re-calculate indices
39 | idx_start = idx_end
40 | idx_end = text.find("\n", idx_start + 1)
41 | if idx_end < 0:
42 | idx_end = len(text)
43 |
44 | return result.replace("\t", "")
45 |
--------------------------------------------------------------------------------
/Errors/errors.py:
--------------------------------------------------------------------------------
1 | from Errors.base_error import Error
2 |
3 |
4 | class IllegalCharacterError(Error):
5 | def __init__(self, pos_start, pos_end, details):
6 | super().__init__(
7 | "चुकीचे अक्षर (Illegal Character)", pos_start, pos_end, details
8 | )
9 |
10 |
11 | class InvalidSyntaxError(Error):
12 | def __init__(self, pos_start, pos_end, details):
13 | super().__init__("अवैध वाक्यरचना (InvalidSyntax)", pos_start, pos_end, details)
14 |
15 |
16 | class ExpectedCharError(Error):
17 | def __init__(self, pos_start, pos_end, details):
18 | super().__init__("अपेक्षित अक्षर (Expected Character)", pos_start, pos_end, details)
19 |
20 |
21 | class RTError(Error):
22 | def __init__(self, pos_start, pos_end, details, context):
23 | super().__init__("प्रोग्राम चालू असताना त्रुटी आली (Runtime Error)", pos_start, pos_end, details)
24 | self.context = context
25 |
26 | def as_string(self):
27 | result = self.generate_traceback()
28 | result += f"{self.error_name}: {self.details}"
29 | result += "\n\n" + self.string_with_arrows(
30 | self.pos_start.ftxt, self.pos_start, self.pos_end
31 | )
32 | return result
33 |
34 | def generate_traceback(self):
35 | result = ""
36 | pos = self.pos_start
37 | ctx = self.context
38 |
39 | while ctx:
40 | result = (
41 | f" File {pos.fn}, line {str(pos.ln + 1)}, in {ctx.display_name}\n"
42 | + result
43 | )
44 | pos = ctx.parent_entry_pos
45 | ctx = ctx.parent
46 |
47 | return "त्रुटी मागोवा (Traceback (most recent call last)):\n" + result
48 |
--------------------------------------------------------------------------------
/Interpreter/__init__.py:
--------------------------------------------------------------------------------
1 | from Interpreter.interpreter import *
--------------------------------------------------------------------------------
/Interpreter/interpreter.py:
--------------------------------------------------------------------------------
1 | from Nodes.functions import FuncDefNode
2 | from Nodes import loop, value
3 | from Values import Number, Function, String, List
4 | from Errors import RTError
5 | from Constants import *
6 | from Results import ParseResult, RTResult
7 |
8 |
9 | # ------------Interpreter----------------
10 |
11 |
12 | class Interpreter:
13 | def __init__(self):
14 | pass
15 |
16 | def visit(self, node, context):
17 | method_name = f"visit_{type(node).__name__}"
18 | method = getattr(self, method_name, self.no_visit_method)
19 | return method(node, context)
20 |
21 | def no_visit_method(self, node, context):
22 | raise Exception(f"No visit_{type(node).__name__} method defined")
23 |
24 | ###################################
25 |
26 | def visit_NumberNode(self, node, context):
27 | return RTResult().success(
28 | Number(node.token.value)
29 | .set_context(context)
30 | .set_pos(node.pos_start, node.pos_end)
31 | )
32 |
33 | def visit_StringNode(self, node, context):
34 | return RTResult().success(
35 | String(node.token.value)
36 | .set_context(context)
37 | .set_pos(node.pos_start, node.pos_end)
38 | )
39 |
40 | def visit_ListNode(self, node, context):
41 | res = RTResult()
42 | elements = []
43 |
44 | for element_node in node.element_nodes:
45 | elements.append(res.register(self.visit(element_node, context)))
46 | if res.should_return():
47 | return res
48 |
49 | return res.success(
50 | List(elements).set_context(context).set_pos(node.pos_start, node.pos_end)
51 | )
52 |
53 | def visit_VarAccessNode(self, node, context):
54 | res = RTResult()
55 | var_name = node.var_name_token.value
56 | value = context.symbol_table.get(var_name)
57 |
58 | if value == None:
59 | return res.failure(
60 | RTError(
61 | node.pos_start, node.pos_end, f"{var_name} परिभाषित नाही (not defined)", context
62 | )
63 | )
64 | value = value.copy().set_pos(node.pos_start, node.pos_end).set_context(context)
65 | return res.success(value)
66 |
67 | def visit_VarAssignNode(self, node, context):
68 | res = RTResult()
69 | var_name = node.var_name_token.value
70 |
71 | if node.declare == False:
72 | value = context.symbol_table.get(var_name)
73 | if value == None:
74 | return res.failure(
75 | RTError(
76 | node.pos_start,
77 | node.pos_end,
78 | f"{var_name} नेमणूक करण्यापूर्वी संदर्भ(reference before assignment)",
79 | context,
80 | )
81 | )
82 | value = res.register(self.visit(node.value_node, context))
83 | if res.should_return():
84 | return res
85 | context.symbol_table.set(var_name, value)
86 | return res.success(value)
87 |
88 | def visit_BinOpNode(self, node, context):
89 | res = RTResult()
90 | left = res.register(self.visit(node.left_node, context))
91 | if res.should_return():
92 | return res
93 | right = res.register(self.visit(node.right_node, context))
94 | if res.should_return():
95 | return res
96 |
97 | if node.op_token.type == TT_PLUS:
98 | result, error = left.added_to(right)
99 | elif node.op_token.type == TT_MINUS:
100 | result, error = left.subbed_by(right)
101 | elif node.op_token.type == TT_MUL:
102 | result, error = left.multed_by(right)
103 | elif node.op_token.type == TT_DIV:
104 | result, error = left.dived_by(right)
105 | elif node.op_token.type == TT_MOD:
106 | result, error = left.moded_by(right)
107 | elif node.op_token.type == TT_POWER:
108 | result, error = left.power_by(right)
109 | elif node.op_token.type == TT_EE:
110 | result, error = left.get_comparison_eq(right)
111 | elif node.op_token.type == TT_NE:
112 | result, error = left.get_comparison_ne(right)
113 | elif node.op_token.type == TT_LT:
114 | result, error = left.get_comparison_lt(right)
115 | elif node.op_token.type == TT_GT:
116 | result, error = left.get_comparison_gt(right)
117 | elif node.op_token.type == TT_LTE:
118 | result, error = left.get_comparison_lte(right)
119 | elif node.op_token.type == TT_GTE:
120 | result, error = left.get_comparison_gte(right)
121 | elif node.op_token.matches(TT_KEYWORD, ("AND", "आणि")):
122 | result, error = left.anded_by(right)
123 | elif node.op_token.matches(TT_KEYWORD, ("OR", "किंवा")):
124 | result, error = left.ored_by(right)
125 |
126 | if error:
127 | return res.failure(error)
128 | else:
129 | return res.success(result.set_pos(node.pos_start, node.pos_end))
130 |
131 | def visit_UnaryOpNode(self, node, context):
132 | res = RTResult()
133 | number = res.register(self.visit(node.node, context))
134 | if res.should_return():
135 | return res
136 |
137 | error = None
138 |
139 | if node.op_token.type == TT_MINUS:
140 | number, error = number.multed_by(Number(-1))
141 | elif node.op_token.matches(TT_KEYWORD, ("NOT", "नाही")):
142 | number, error = number.notted()
143 |
144 | if error:
145 | return res.failure(error)
146 | else:
147 | return res.success(number.set_pos(node.pos_start, node.pos_end))
148 |
149 | def visit_IfNode(self, node, context):
150 | res = RTResult()
151 |
152 | for condition, expr, should_return_null in node.cases:
153 | condition_value = res.register(self.visit(condition, context))
154 | if res.should_return():
155 | return res
156 |
157 | if condition_value.is_true():
158 | expr_value = res.register(self.visit(expr, context))
159 | if res.should_return():
160 | return res
161 | return res.success(Number.null if should_return_null else expr_value)
162 |
163 | if node.else_case:
164 | expr, should_return_null = node.else_case
165 | else_value = res.register(self.visit(expr, context))
166 | if res.should_return():
167 | return res
168 | return res.success(Number.null if should_return_null else else_value)
169 |
170 | return res.success(Number.null)
171 |
172 | def visit_ForNode(self, node, context):
173 | res = RTResult()
174 | elements = []
175 |
176 | start_value = res.register(self.visit(node.start_value_node, context))
177 | if res.should_return():
178 | return res
179 |
180 | end_value = res.register(self.visit(node.end_value_node, context))
181 | if res.should_return():
182 | return res
183 |
184 | if node.step_value_node:
185 | step_value = res.register(self.visit(node.step_value_node, context))
186 | if res.should_return():
187 | return res
188 | else:
189 | step_value = Number(1)
190 |
191 | i = start_value.value
192 |
193 | if step_value.value >= 0:
194 | condition = lambda: i < end_value.value
195 | else:
196 | condition = lambda: i > end_value.value
197 |
198 | while condition():
199 | context.symbol_table.set(node.var_name_token.value, Number(i))
200 | i += step_value.value
201 |
202 | value_ = res.register(self.visit(node.body_node, context))
203 |
204 | if res.should_return() and res.loop_should_continue==False and res.loop_should_break==False:
205 | return res
206 |
207 | if res.loop_should_continue:
208 | continue
209 | if res.loop_should_break:
210 | break
211 |
212 | elements.append(value_)
213 |
214 |
215 |
216 | return res.success(
217 | Number.null
218 | if node.should_return_null
219 | else List(elements)
220 | .set_context(context)
221 | .set_pos(node.pos_start, node.pos_end)
222 | )
223 |
224 | def visit_WhileNode(self, node, context):
225 | res = RTResult()
226 |
227 | while True:
228 | condition = res.register(self.visit(node.condition_node, context))
229 | elements = []
230 | if res.should_return():
231 | return res
232 |
233 | if not condition.is_true():
234 | break
235 |
236 | value_ = res.register(self.visit(node.body_node, context))
237 |
238 | if res.should_return() and res.loop_should_continue==False and res.loop_should_break==False:
239 | return res
240 |
241 | if res.loop_should_continue:
242 | continue
243 | if res.loop_should_break:
244 | break
245 |
246 | elements.append(value_)
247 |
248 |
249 |
250 | return res.success(
251 | Number.null
252 | if node.should_return_null
253 | else List(elements)
254 | .set_context(context)
255 | .set_pos(node.pos_start, node.pos_end)
256 | )
257 |
258 | def visit_FuncDefNode(self, node, context):
259 | res = RTResult()
260 |
261 | func_name = node.var_name_token.value if node.var_name_token else None
262 | body_node = node.body_node
263 | arg_names = [arg_name.value for arg_name in node.arg_name_tokens]
264 | func_value = (
265 | Function(func_name, body_node, arg_names,node.should_auto_return)
266 | .set_context(context)
267 | .set_pos(node.pos_start, node.pos_end)
268 | )
269 |
270 | if node.var_name_token:
271 | context.symbol_table.set(func_name, func_value)
272 |
273 | return res.success(func_value)
274 |
275 | def visit_CallNode(self, node, context):
276 | res = RTResult()
277 | args = []
278 | func_name =node.node_to_call.var_name_token.value
279 | if not context.symbol_table.get(func_name):
280 | print("EERPR")
281 | return res.failure(
282 | RTError(
283 | node.pos_start, node.pos_end, f"अज्ञात कार्य बोलावले(call to unknown function)'{func_name}' ", context
284 | )
285 | )
286 |
287 |
288 | value_to_call = res.register(self.visit(node.node_to_call, context))
289 | if res.should_return():
290 | return res
291 | value_to_call = value_to_call.copy().set_pos(node.pos_start, node.pos_end)
292 |
293 | for arg_node in node.arg_nodes:
294 | args.append(res.register(self.visit(arg_node, context)))
295 | if res.should_return():
296 | return res
297 |
298 | return_value = res.register(value_to_call.execute(args))
299 | if res.should_return():
300 | return res
301 | return_value = (
302 | return_value.copy()
303 | .set_pos(node.pos_start, node.pos_end)
304 | .set_context(context)
305 | )
306 | return res.success(return_value)
307 | def visit_ReturnNode(self, node, context):
308 | res = RTResult()
309 |
310 | if node.node_to_return:
311 | value = res.register(self.visit(node.node_to_return, context))
312 | if res.should_return():
313 | return res
314 | else:
315 | value = Number.null
316 |
317 | return res.success_return(value)
318 |
319 | def visit_ContinueNode(self, node, context):
320 | return RTResult().success_continue()
321 |
322 | def visit_BreakNode(self, node, context):
323 | return RTResult().success_break()
324 |
325 | def visit_IndexNode(self,node:value.IndexNode,context):
326 | res = RTResult()
327 | args = []
328 |
329 | value_to_call = res.register(self.visit(node.index_node, context))
330 |
331 | value_=res.register(self.visit(node.expr, context))
332 |
333 | if res.should_return():
334 | return res
335 |
336 |
337 | try:
338 | return_value = value_to_call.elements[value_.value]
339 | except Exception as e:
340 | return res.failure(
341 | RTError(
342 | node.pos_start, node.pos_end, f"{value_to_call} अनुक्रमणिका मर्यादित नाही(Index out of bound) ", context
343 | )
344 | )
345 |
346 | return res.success(return_value)
347 |
348 | def visit_IndexAssignNode(self,node:value.IndexAssignNode,context):
349 | res = RTResult()
350 | args = []
351 |
352 | value_to_call = res.register(self.visit(node.index_node, context))
353 |
354 | value_=res.register(self.visit(node.expr, context))
355 |
356 | if res.should_return():
357 | return res
358 |
359 | assgin_expr=res.register(self.visit(node.assgin_expr, context))
360 | if res.should_return():
361 | return res
362 |
363 | try:
364 | value_to_call.elements[value_.value]=assgin_expr
365 | except Exception as e:
366 | return res.failure(
367 | RTError(
368 | node.pos_start, node.pos_end, f"{value_to_call} अनुक्रमणिका मर्यादित नाही(Index out of bound)", context
369 | )
370 | )
371 |
372 | return res.success(assgin_expr)
373 |
374 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 joey00072
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Parser/__init__.py:
--------------------------------------------------------------------------------
1 | from Parser.parser import Parser
--------------------------------------------------------------------------------
/Parser/parser.py:
--------------------------------------------------------------------------------
1 | from Errors import InvalidSyntaxError
2 | from Constants import *
3 | from Results import ParseResult
4 | from Nodes import *
5 |
6 |
7 | # ------------PARSER----------------
8 |
9 |
10 | class Parser:
11 | def __init__(self, tokens):
12 | self.tokens = tokens
13 | self.token_idx = -1
14 | self.advance()
15 |
16 | def advance(self):
17 | self.token_idx += 1
18 | self.update_current_token()
19 | return self.current_token
20 |
21 | def reverse(self, amount=1):
22 | self.token_idx -= amount
23 | self.update_current_token()
24 | return self.current_token
25 |
26 | def update_current_token(self):
27 | if self.token_idx >= 0 and self.token_idx < len(self.tokens):
28 | self.current_token = self.tokens[self.token_idx]
29 |
30 | def peak(self):
31 | idx = self.token_idx + 1
32 | if idx < len(self.tokens):
33 | return self.tokens[idx]
34 |
35 | # -------------------#
36 |
37 | def parse(self):
38 | res = self.statements()
39 | if not res.error and self.current_token.type != TT_EOF:
40 | return res.failure(
41 | InvalidSyntaxError(
42 | self.current_token.pos_start,
43 | self.current_token.pos_end,
44 | "अपेक्षित(Expected) '+','-', '*' or '/'",
45 | )
46 | )
47 | return res
48 |
49 | def statements(self):
50 | res = ParseResult()
51 | statements = []
52 | pos_start = self.current_token.pos_start.copy()
53 |
54 | while self.current_token.type == TT_NEWLINE:
55 | res.register_advancement()
56 | self.advance()
57 |
58 | statement = res.register(self.statement())
59 | if res.error:
60 | return res
61 | statements.append(statement)
62 |
63 | more_statements = True
64 |
65 | while True:
66 | newline_count = -1
67 | while self.current_token.type == TT_NEWLINE:
68 | res.register_advancement()
69 | self.advance()
70 | newline_count += 1
71 | if newline_count == -1:
72 | more_statements = False
73 |
74 | if not more_statements:
75 | break
76 | statement = res.try_register(self.statement())
77 | if not statement:
78 | self.reverse(res.to_reverse_count)
79 | more_statements = False
80 | continue
81 | statements.append(statement)
82 |
83 | return res.success(
84 | ListNode(statements, pos_start, self.current_token.pos_end.copy())
85 | )
86 |
87 | def statement(self):
88 | res = ParseResult()
89 | pos_start = self.current_token.pos_start.copy()
90 |
91 | if self.current_token.matches(TT_KEYWORD, ("RETURN", "परत")):
92 | res.register_advancement()
93 | self.advance()
94 |
95 | expr = res.try_register(self.expr())
96 | if not expr:
97 | self.reverse(res.to_reverse_count)
98 | return res.success(
99 | ReturnNode(expr, pos_start, self.current_token.pos_start.copy())
100 | )
101 |
102 | if self.current_token.matches(TT_KEYWORD, ("CONTINUE", "सुरू")):
103 | res.register_advancement()
104 | self.advance()
105 | return res.success(
106 | ContinueNode(pos_start, self.current_token.pos_start.copy())
107 | )
108 |
109 | if self.current_token.matches(TT_KEYWORD, ("BREAK", "थांबवा")):
110 | res.register_advancement()
111 | self.advance()
112 | return res.success(
113 | BreakNode(pos_start, self.current_token.pos_start.copy())
114 | )
115 |
116 | expr = res.register(self.expr())
117 | if res.error:
118 | return res.failure(
119 | InvalidSyntaxError(
120 | self.current_token.pos_start,
121 | self.current_token.pos_end,
122 | "अपेक्षित(Expected) 'परत', 'सुरू', 'थांबवा', 'चल', 'जर', 'वारंवार', 'जोपर्यंत', 'कार्य', 'संख्या', 'शब्द', '+', '-', '(', '['",
123 | )
124 | )
125 | return res.success(expr)
126 |
127 | def expr(self):
128 | res = ParseResult()
129 | if self.current_token.matches(TT_KEYWORD, ("VAR", "चल")):
130 | res.register_advancement()
131 | self.advance()
132 | if self.current_token.type != "IDENTIFIER":
133 | return res.failure(
134 | InvalidSyntaxError(
135 | self.current_token.pos_start,
136 | self.current_token.pos_end,
137 | "अपेक्षित चल शब्द (Expected Identifier)",
138 | )
139 | )
140 | var_name = self.current_token
141 | res.register_advancement()
142 | self.advance()
143 |
144 | if self.current_token.type != TT_EQ:
145 | return res.failure(
146 | InvalidSyntaxError(
147 | self.current_token.pos_start,
148 | self.current_token.pos_end,
149 | "अपेक्षित = (Expected =)",
150 | )
151 | )
152 | res.register_advancement()
153 | self.advance()
154 | expr = res.register(self.expr())
155 | if res.error:
156 | return res
157 | return res.success(VarAssignNode(var_name, expr, True))
158 |
159 | if self.current_token.type == "IDENTIFIER":
160 | var_name = self.current_token
161 | next_token = self.peak()
162 | if next_token != None and next_token.type == TT_EQ:
163 | res.register_advancement()
164 | self.advance()
165 | res.register_advancement()
166 | self.advance()
167 | expr = res.register(self.expr())
168 | if res.error:
169 | return res
170 | return res.success(VarAssignNode(var_name, expr, False))
171 |
172 | pass_keywords = (
173 | (TT_KEYWORD, "AND"),
174 | (TT_KEYWORD, "आणि"),
175 | (TT_KEYWORD, "OR"),
176 | (TT_KEYWORD, "किंवा"),
177 | )
178 | node = res.register(self.bin_op(self.comp_expr, pass_keywords))
179 |
180 | if res.error:
181 | return res.failure(
182 | InvalidSyntaxError(
183 | self.current_token.pos_start,
184 | self.current_token.pos_end,
185 | "अपेक्षित(Expected) 'चल', 'संख्या', 'शब्द','जर', 'वारंवार', 'जोपर्यंत', 'कार्य', '+', '-','(' or '[' ",
186 | )
187 | )
188 | return res.success(node)
189 |
190 | def comp_expr(self):
191 | res = ParseResult()
192 |
193 | if self.current_token.matches(TT_KEYWORD, ("NOT", "नाही")):
194 | op_token = self.current_token
195 | res.register_advancement()
196 | self.advance()
197 |
198 | node = res.register(self.comp_expr())
199 | if res.error:
200 | return res
201 | return res.success(UnaryOpNode(op_token, node))
202 |
203 | node = res.register(
204 | self.bin_op(self.arith_expr, (TT_EE, TT_NE, TT_LT, TT_GT, TT_LTE, TT_GTE))
205 | )
206 |
207 | if res.error:
208 | return res.failure(
209 | InvalidSyntaxError(
210 | self.current_token.pos_start,
211 | self.current_token.pos_end,
212 | "अपेक्षित(Expected), 'संख्या', 'शब्द', '+', '-', '(','['",
213 | )
214 | )
215 |
216 | return res.success(node)
217 |
218 | def arith_expr(self):
219 | return self.bin_op(self.term, (TT_PLUS, TT_MINUS))
220 |
221 | def term(self):
222 | return self.bin_op(self.factor, (TT_MUL, TT_DIV))
223 |
224 | def factor(self):
225 | res = ParseResult()
226 | token = self.current_token
227 | if token.type in (TT_PLUS, TT_MINUS):
228 | res.register_advancement()
229 | self.advance()
230 | factor = res.register(self.factor())
231 | if res.error:
232 | return res
233 | return res.success(UnaryOpNode(token, factor))
234 |
235 | return self.mod()
236 |
237 | def mod(self):
238 | return self.bin_op(self.power, (TT_MOD,), self.factor)
239 |
240 | def power(self):
241 | return self.bin_op(self.call, (TT_POWER,), self.mod)
242 |
243 |
244 | def call(self):
245 | res = ParseResult()
246 | atom = res.register(self.atom())
247 | if res.error:
248 | return res
249 |
250 | if self.current_token.type == TT_LPAREN:
251 | res.register_advancement()
252 | self.advance()
253 | arg_nodes = []
254 |
255 | if self.current_token.type == TT_RPAREN:
256 | res.register_advancement()
257 | self.advance()
258 | else:
259 | arg_nodes.append(res.register(self.expr()))
260 | if res.error:
261 | return res.failure(
262 | InvalidSyntaxError(
263 | self.current_token.pos_start,
264 | self.current_token.pos_end,
265 | "अपेक्षित(Expected) ')', 'चल', 'जर', 'वारंवार', 'जोपर्यंत', 'कार्य', 'संख्या', 'शब्द', '+', '-', '(','[' or 'NOT'",
266 | )
267 | )
268 |
269 | while self.current_token.type == TT_COMMA:
270 | res.register_advancement()
271 | self.advance()
272 |
273 | arg_nodes.append(res.register(self.expr()))
274 | if res.error:
275 | return res
276 |
277 | if self.current_token.type != TT_RPAREN:
278 | return res.failure(
279 | InvalidSyntaxError(
280 | self.current_token.pos_start,
281 | self.current_token.pos_end,
282 | f"अपेक्षित(Expected) ',' or ')'",
283 | )
284 | )
285 |
286 | res.register_advancement()
287 | self.advance()
288 | return res.success(CallNode(atom, arg_nodes))
289 |
290 | while self.current_token.type == TT_LSQUARE:
291 | res.register_advancement()
292 | self.advance()
293 | expr = res.register(self.expr())
294 | if self.current_token.type != TT_RSQUARE:
295 | return res.failure(
296 | InvalidSyntaxError(
297 | self.current_token.pos_start,
298 | self.current_token.pos_end,
299 | f"अपेक्षित(Expected) ']'",
300 | )
301 | )
302 | res.register_advancement()
303 | self.advance()
304 |
305 | if self.current_token.type == TT_EQ:
306 | res.register_advancement()
307 | self.advance()
308 | assgin_expr = res.register(self.expr())
309 | return res.success(IndexAssignNode(atom,expr,assgin_expr))
310 |
311 | atom= IndexNode(atom, expr)
312 |
313 |
314 |
315 |
316 |
317 | return res.success(atom)
318 |
319 | def atom(self):
320 | res = ParseResult()
321 | token = self.current_token
322 | if self.current_token.type in (TT_INT, TT_FLOAT):
323 | res.register_advancement()
324 | self.advance()
325 | return res.success(NumberNode(token))
326 |
327 | if self.current_token.type in (TT_STRING):
328 | res.register_advancement()
329 | self.advance()
330 | return res.success(StringNode(token))
331 |
332 | if self.current_token.type in (TT_IDENTIFIER):
333 | res.register_advancement()
334 | self.advance()
335 | return res.success(VarAccessNode(token))
336 |
337 | if token.type == TT_LSQUARE:
338 | list_expr = res.register(self.list_expr())
339 | if res.error:
340 | return res
341 | return res.success(list_expr)
342 |
343 | if token.type == TT_LPAREN:
344 | res.register_advancement()
345 | self.advance()
346 | expr = res.register(self.expr())
347 | if self.current_token.type == TT_RPAREN:
348 | res.register_advancement()
349 | self.advance()
350 | return res.success(expr)
351 | else:
352 | return res.failure(
353 | InvalidSyntaxError(
354 | self.current_token.pos_start,
355 | self.current_token.pos_end,
356 | "अपेक्षित(Expected) ')' ",
357 | )
358 | )
359 |
360 | if token.matches(TT_KEYWORD, ("IF", "जर")):
361 | if_expr = res.register(self.if_expr())
362 | if res.error:
363 | return res
364 | return res.success(if_expr)
365 | if token.matches(TT_KEYWORD, ("FOR", "वारंवार")):
366 | for_expr = res.register(self.for_expr())
367 | if res.error:
368 | return res
369 | return res.success(for_expr)
370 |
371 | if token.matches(TT_KEYWORD, ("WHILE", "जोपर्यंत")):
372 | while_expr = res.register(self.while_expr())
373 | if res.error:
374 | return res
375 | return res.success(while_expr)
376 |
377 | if token.matches(TT_KEYWORD, ("FUN", "कार्य")):
378 | func_def = res.register(self.func_def())
379 | if res.error:
380 | return res
381 | return res.success(func_def)
382 |
383 | return res.failure(
384 | InvalidSyntaxError(
385 | self.current_token.pos_start,
386 | self.current_token.pos_end,
387 | "अपेक्षित(Expected) int,float, identifier,'IF', 'FOR', 'WHILE', 'FUN', '+','-','[' or '('",
388 | )
389 | )
390 |
391 | def list_expr(self):
392 | res = ParseResult()
393 | element_nodes = []
394 | pos_start = self.current_token.pos_start.copy()
395 |
396 | if self.current_token.type != TT_LSQUARE:
397 | return res.failure(
398 | InvalidSyntaxError(
399 | self.current_token.pos_start,
400 | self.current_token.pos_end,
401 | f"अपेक्षित(Expected) '['",
402 | )
403 | )
404 |
405 | res.register_advancement()
406 | self.advance()
407 |
408 | if self.current_token.type == TT_RSQUARE:
409 | res.register_advancement()
410 | self.advance()
411 | else:
412 | element_nodes.append(res.register(self.expr()))
413 | if res.error:
414 | return res.failure(
415 | InvalidSyntaxError(
416 | self.current_token.pos_start,
417 | self.current_token.pos_end,
418 | "अपेक्षित(Expected) ']', 'चल', 'जर', 'वारंवार', 'जोपर्यंत', 'कार्य', 'संख्या', 'शब्द', '+', '-', '(', '[' or 'नाही'",
419 | )
420 | )
421 |
422 | while self.current_token.type == TT_COMMA:
423 | res.register_advancement()
424 | self.advance()
425 |
426 | element_nodes.append(res.register(self.expr()))
427 | if res.error:
428 | return res
429 |
430 | if self.current_token.type != TT_RSQUARE:
431 | return res.failure(
432 | InvalidSyntaxError(
433 | self.current_token.pos_start,
434 | self.current_token.pos_end,
435 | f"अपेक्षित(Expected) ',' or ']'",
436 | )
437 | )
438 |
439 | res.register_advancement()
440 | self.advance()
441 |
442 | return res.success(
443 | ListNode(element_nodes, pos_start, self.current_token.pos_end.copy())
444 | )
445 |
446 | def if_expr(self):
447 | res = ParseResult()
448 | all_cases = res.register(self.if_expr_cases(("IF", "जर")))
449 | if res.error:
450 | return res
451 | cases, else_case = all_cases
452 | return res.success(IfNode(cases, else_case))
453 |
454 | def if_expr_b(self):
455 | return self.if_expr_cases(("ELIF", "किंवाजर"))
456 |
457 | def if_expr_c(self):
458 | res = ParseResult()
459 | else_case = None
460 |
461 | if self.current_token.matches(TT_KEYWORD, ("ELSE", "नाहीतर")):
462 | res.register_advancement()
463 | self.advance()
464 |
465 | if self.current_token.type == TT_NEWLINE:
466 | res.register_advancement()
467 | self.advance()
468 |
469 | statements = res.register(self.statements())
470 | if res.error:
471 | return res
472 | else_case = (statements, True)
473 |
474 | if self.current_token.matches(TT_KEYWORD, ("END", "शेवट")):
475 | res.register_advancement()
476 | self.advance()
477 | else:
478 | return res.failure(
479 | InvalidSyntaxError(
480 | self.current_token.pos_start,
481 | self.current_token.pos_end,
482 | "अपेक्षित(Expected) 'शेवट'",
483 | )
484 | )
485 | else:
486 | expr = res.register(self.statement())
487 | if res.error:
488 | return res
489 | else_case = (expr, False)
490 |
491 | return res.success(else_case)
492 |
493 | def if_expr_b_or_c(self):
494 | res = ParseResult()
495 | cases, else_case = [], None
496 |
497 | if self.current_token.matches(TT_KEYWORD, ("ELIF", "किंवाजर")):
498 | all_cases = res.register(self.if_expr_b())
499 | if res.error:
500 | return res
501 | cases, else_case = all_cases
502 | else:
503 | else_case = res.register(self.if_expr_c())
504 | if res.error:
505 | return res
506 |
507 | return res.success((cases, else_case))
508 |
509 | def if_expr_cases(self, case_keyword):
510 | res = ParseResult()
511 | cases = []
512 | else_case = None
513 |
514 | if not self.current_token.matches(TT_KEYWORD, case_keyword):
515 | return res.failure(
516 | InvalidSyntaxError(
517 | self.current_token.pos_start,
518 | self.current_token.pos_end,
519 | f"अपेक्षित(Expected) '{case_keyword}'",
520 | )
521 | )
522 |
523 | res.register_advancement()
524 | self.advance()
525 |
526 | condition = res.register(self.expr())
527 | if res.error:
528 | return res
529 |
530 | if not self.current_token.matches(TT_KEYWORD, ("THEN", "तर")):
531 | return res.failure(
532 | InvalidSyntaxError(
533 | self.current_token.pos_start,
534 | self.current_token.pos_end,
535 | f"अपेक्षित(Expected) 'तर'",
536 | )
537 | )
538 |
539 | res.register_advancement()
540 | self.advance()
541 |
542 | if self.current_token.type == TT_NEWLINE:
543 | res.register_advancement()
544 | self.advance()
545 |
546 | statements = res.register(self.statements())
547 | if res.error:
548 | return res
549 | cases.append((condition, statements, True))
550 |
551 | if self.current_token.matches(TT_KEYWORD, ("END", "शेवट")):
552 | res.register_advancement()
553 | self.advance()
554 | else:
555 | all_cases = res.register(self.if_expr_b_or_c())
556 | if res.error:
557 | return res
558 | new_cases, else_case = all_cases
559 | cases.extend(new_cases)
560 | else:
561 | expr = res.register(self.statement())
562 | if res.error:
563 | return res
564 | cases.append((condition, expr, False))
565 |
566 | all_cases = res.register(self.if_expr_b_or_c())
567 | if res.error:
568 | return res
569 | new_cases, else_case = all_cases
570 | cases.extend(new_cases)
571 |
572 | return res.success((cases, else_case))
573 |
574 | def for_expr(self):
575 | res = ParseResult()
576 |
577 | if not self.current_token.matches(TT_KEYWORD, ("FOR", "वारंवार")):
578 | return res.failure(
579 | InvalidSyntaxError(
580 | self.current_token.pos_start,
581 | self.current_token.pos_end,
582 | f"अपेक्षित(Expected) 'वारंवार'",
583 | )
584 | )
585 |
586 | res.register_advancement()
587 | self.advance()
588 |
589 | if self.current_token.type != TT_IDENTIFIER:
590 | return res.failure(
591 | InvalidSyntaxError(
592 | self.current_token.pos_start,
593 | self.current_token.pos_end,
594 | f"अपेक्षित(Expected) शब्द",
595 | )
596 | )
597 |
598 | var_name = self.current_token
599 | res.register_advancement()
600 | self.advance()
601 |
602 | if self.current_token.type != TT_EQ:
603 | return res.failure(
604 | InvalidSyntaxError(
605 | self.current_token.pos_start,
606 | self.current_token.pos_end,
607 | f"अपेक्षित(Expected) '='",
608 | )
609 | )
610 |
611 | res.register_advancement()
612 | self.advance()
613 |
614 | start_value = res.register(self.expr())
615 | if res.error:
616 | return res
617 |
618 | if not self.current_token.matches(TT_KEYWORD, ("TO", "ते")):
619 | return res.failure(
620 | InvalidSyntaxError(
621 | self.current_token.pos_start,
622 | self.current_token.pos_end,
623 | f"अपेक्षित(Expected) 'ते'",
624 | )
625 | )
626 |
627 | res.register_advancement()
628 | self.advance()
629 |
630 | end_value = res.register(self.expr())
631 | if res.error:
632 | return res
633 |
634 | if self.current_token.matches(TT_KEYWORD, ("STEP", "पाऊल")):
635 | res.register_advancement()
636 | self.advance()
637 |
638 | step_value = res.register(self.expr())
639 | if res.error:
640 | return res
641 | else:
642 | step_value = None
643 |
644 | if not self.current_token.matches(TT_KEYWORD, ("THEN", "तर")):
645 | return res.failure(
646 | InvalidSyntaxError(
647 | self.current_token.pos_start,
648 | self.current_token.pos_end,
649 | f"अपेक्षित(Expected) 'तर'",
650 | )
651 | )
652 |
653 | res.register_advancement()
654 | self.advance()
655 |
656 | if self.current_token.type == TT_NEWLINE:
657 | res.register_advancement()
658 | self.advance()
659 |
660 | body = res.register(self.statements())
661 | if res.error:
662 | return res
663 |
664 | if not self.current_token.matches(TT_KEYWORD, ("END", "शेवट")):
665 | return res.failure(
666 | InvalidSyntaxError(
667 | self.current_token.pos_start,
668 | self.current_token.pos_end,
669 | f"अपेक्षित(Expected) 'शेवट'",
670 | )
671 | )
672 |
673 | res.register_advancement()
674 | self.advance()
675 |
676 | return res.success(
677 | ForNode(var_name, start_value, end_value, step_value, body, True)
678 | )
679 |
680 | body = res.register(self.statement())
681 | if res.error:
682 | return res
683 |
684 | return res.success(
685 | ForNode(var_name, start_value, end_value, step_value, body, False)
686 | )
687 |
688 | def while_expr(self):
689 | res = ParseResult()
690 |
691 | if not self.current_token.matches(TT_KEYWORD, ("WHILE", "जोपर्यंत")):
692 | return res.failure(
693 | InvalidSyntaxError(
694 | self.current_token.pos_start,
695 | self.current_token.pos_end,
696 | f"अपेक्षित(Expected) 'जोपर्यंत'",
697 | )
698 | )
699 |
700 | res.register_advancement()
701 | self.advance()
702 |
703 | condition = res.register(self.expr())
704 | if res.error:
705 | return res
706 |
707 | if not self.current_token.matches(TT_KEYWORD, ("THEN", "तर")):
708 | return res.failure(
709 | InvalidSyntaxError(
710 | self.current_token.pos_start,
711 | self.current_token.pos_end,
712 | f"अपेक्षित(Expected) 'तर'",
713 | )
714 | )
715 |
716 | res.register_advancement()
717 | self.advance()
718 |
719 | if self.current_token.type == TT_NEWLINE:
720 | res.register_advancement()
721 | self.advance()
722 |
723 | body = res.register(self.statements())
724 | if res.error:
725 | return res
726 |
727 | if not self.current_token.matches(TT_KEYWORD, ("END", "शेवट")):
728 | return res.failure(
729 | InvalidSyntaxError(
730 | self.current_token.pos_start,
731 | self.current_token.pos_end,
732 | f"अपेक्षित(Expected) 'शेवट'",
733 | )
734 | )
735 |
736 | res.register_advancement()
737 | self.advance()
738 |
739 | return res.success(WhileNode(condition, body, True))
740 |
741 | body = res.register(self.statement())
742 | if res.error:
743 | return res
744 |
745 | return res.success(WhileNode(condition, body, False))
746 |
747 | def func_def(self):
748 | res = ParseResult()
749 |
750 | if not self.current_token.matches(TT_KEYWORD, ("FUN", "कार्य")):
751 | return res.failure(
752 | InvalidSyntaxError(
753 | self.current_token.pos_start,
754 | self.current_token.pos_end,
755 | f"अपेक्षित(Expected) 'FUN'",
756 | )
757 | )
758 |
759 | res.register_advancement()
760 | self.advance()
761 |
762 | if self.current_token.type == TT_IDENTIFIER:
763 | var_name_tok = self.current_token
764 | res.register_advancement()
765 | self.advance()
766 | if self.current_token.type != TT_LPAREN:
767 | return res.failure(
768 | InvalidSyntaxError(
769 | self.current_token.pos_start,
770 | self.current_token.pos_end,
771 | f"अपेक्षित(Expected) '('",
772 | )
773 | )
774 | else:
775 | var_name_tok = None
776 | if self.current_token.type != TT_LPAREN:
777 | return res.failure(
778 | InvalidSyntaxError(
779 | self.current_token.pos_start,
780 | self.current_token.pos_end,
781 | f"अपेक्षित(Expected) शब्द or '('",
782 | )
783 | )
784 |
785 | res.register_advancement()
786 | self.advance()
787 | arg_name_toks = []
788 |
789 | if self.current_token.type == TT_IDENTIFIER:
790 | arg_name_toks.append(self.current_token)
791 | res.register_advancement()
792 | self.advance()
793 |
794 | while self.current_token.type == TT_COMMA:
795 | res.register_advancement()
796 | self.advance()
797 |
798 | if self.current_token.type != TT_IDENTIFIER:
799 | return res.failure(
800 | InvalidSyntaxError(
801 | self.current_token.pos_start,
802 | self.current_token.pos_end,
803 | f"अपेक्षित(Expected) शब्द",
804 | )
805 | )
806 |
807 | arg_name_toks.append(self.current_token)
808 | res.register_advancement()
809 | self.advance()
810 |
811 | if self.current_token.type != TT_RPAREN:
812 | return res.failure(
813 | InvalidSyntaxError(
814 | self.current_token.pos_start,
815 | self.current_token.pos_end,
816 | f"अपेक्षित(Expected) ',' or ')'",
817 | )
818 | )
819 | else:
820 | if self.current_token.type != TT_RPAREN:
821 | return res.failure(
822 | InvalidSyntaxError(
823 | self.current_token.pos_start,
824 | self.current_token.pos_end,
825 | f"अपेक्षित(Expected) शब्द or ')'",
826 | )
827 | )
828 |
829 | res.register_advancement()
830 | self.advance()
831 |
832 | if self.current_token.type == TT_ARROW:
833 | res.register_advancement()
834 | self.advance()
835 |
836 | body = res.register(self.expr())
837 | if res.error:
838 | return res
839 |
840 | return res.success(FuncDefNode(var_name_tok, arg_name_toks, body, True))
841 |
842 | if self.current_token.type != TT_NEWLINE:
843 | return res.failure(
844 | InvalidSyntaxError(
845 | self.current_token.pos_start,
846 | self.current_token.pos_end,
847 | f"अपेक्षित(Expected) '->' or '\\n'NEWLINE",
848 | )
849 | )
850 |
851 | res.register_advancement()
852 | self.advance()
853 |
854 | body = res.register(self.statements())
855 | if res.error:
856 | return res
857 |
858 | if not self.current_token.matches(TT_KEYWORD,("END", "शेवट")):
859 | return res.failure(
860 | InvalidSyntaxError(
861 | self.current_token.pos_start,
862 | self.current_token.pos_end,
863 | f"अपेक्षित(Expected) 'शेवट'",
864 | )
865 | )
866 |
867 | res.register_advancement()
868 | self.advance()
869 |
870 | return res.success(FuncDefNode(var_name_tok, arg_name_toks, body, False))
871 |
872 | ################
873 |
874 | def bin_op(self, func_a, ops, func_b=None):
875 | if func_b == None:
876 | func_b = func_a
877 | res = ParseResult()
878 | left = res.register(func_a())
879 | if res.error:
880 | return res
881 |
882 | while (
883 | self.current_token.type in ops
884 | or (self.current_token.type, self.current_token.value) in ops
885 | ):
886 | op_token = self.current_token
887 | res.register_advancement()
888 | self.advance()
889 | right = res.register(func_b())
890 | if res.error:
891 | return res
892 | left = BinOpNode(left, op_token, right)
893 | return res.success(left)
894 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **बाजी (Baji)- Marathi Programing Language**
2 |

3 |
4 | बाजी (baji) high-level,dynamically typed, interpreted first Marathi programing language.
5 |
6 | ## Quick Start
7 | ### Hello World
8 | ```
9 | दाखवा("नमस्कार विश्व")
10 | ```
11 | ### Fibonacci Series
12 | ```
13 | कार्य फिबोनॅकी(क)
14 | जर क<2 तर
15 | परत 1
16 | नाहीतर
17 | परत फिबोनॅकी(क-1) + फिबोनॅकी(क-2)
18 | शेवट
19 | शेवट
20 |
21 |
22 |
23 | वारंवार क=0 ते 24 तर
24 | दाखवा(क)
25 | दाखवा(" ")
26 | दाखवा(फिबोनॅकी(क))
27 | दाखवा("\n")
28 | शेवट
29 |
30 |
31 | दाखवा("\n")
32 | ```
33 | Save file with `.baji` extension.
34 |
35 | RUN
36 | ```
37 | baji example.baji
38 | ```
39 | ## Docs
40 | refer [DOCS.md](./DOCS.md)
41 |
42 | ## Installation
43 | 1. Download binary from Here
44 | * [RELEASE](https://github.com/joey00072/Marathi-Programing-Language/releases/tag/1.0.1)
45 |
46 | * Windows baji.zip
47 |
48 | * Linux baji.tar
49 |
50 | * Mac Comming Soon...
51 | 2.
52 | **Winodows**
53 | Unzip baji.zip move `baji.exe` to suitable folder path
54 | ```
55 | C:/baji/baji.exe -> recommanded
56 | ```
57 | Then set environment variables [guide](https://support.microsoft.com/en-us/topic/how-to-manage-environment-variables-in-windows-xp-5bf6725b-655e-151c-0b55-9a8c9c7f747d)
58 |
59 | 3. **Linux/Mac**
60 | Download baji.tar
61 | then run this command
62 | ```
63 | tar -xvf baji.tar && sudo mv .baji /bin/ && echo 'export PATH="$PATH:/bin/.baji/"' >> ~/.bashrc && source ~/.bashrc
64 | ```
65 | note : you need password to run this command also
66 | change bashrc to zshrc if you are using zsh shell
67 | 4. Run File
68 | ```
69 | baji example.baji
70 | ```
71 |
72 | ## Build
73 | **Run With Python**
74 | ```
75 | python3 shell.py example.baji
76 | ```
77 | Build executable
78 |
79 | Use [pyinstaller](https://github.com/pyinstaller/pyinstaller) to genrate executable
80 |
81 | ```
82 | python3 -m pyinstller shell.py -n baji
83 | ```
84 |
85 |
86 |
87 | ## Todo List
88 |
89 | - [x] Refactor
90 | - [ ] print function with multiple args
91 | - [ ] Class Object
92 | - [ ] Replace block Structure with {}
93 | - [ ] Web/Js Version
94 | - [ ] syntax highlighting
95 |
96 | ## Reporting Bugs
97 | Create issue on github or
98 | you can also content me on 00shxf@gmail.com
99 |
100 |
101 | ## Contributions
102 | Any contribution is welcome, drop me a line or file a pull request.
103 |
104 | ## Licenses
105 | Refer [LICENSE](./LICENSE)
106 |
107 | [](https://ko-fi.com/R6R8KQTZ5)
108 |
--------------------------------------------------------------------------------
/SymbolTable/__init__.py:
--------------------------------------------------------------------------------
1 | from Values import *
2 | from SymbolTable.symbol_table import SymbolTable
3 |
4 |
5 |
6 |
7 | #Global Symbols
8 | global_symbol_table = SymbolTable()
9 |
10 | # global_symbol_table.set('null',Number(0))
11 | # global_symbol_table.set('true',Number(1))
12 | # global_symbol_table.set('false',Number(0))
13 | global_symbol_table.set("NULL", Number.null)
14 | global_symbol_table.set("FALSE", Number.false)
15 | global_symbol_table.set("TRUE", Number.true)
16 | global_symbol_table.set("MATH_PI", Number(3.141592653589793))
17 |
--------------------------------------------------------------------------------
/SymbolTable/symbol_table.py:
--------------------------------------------------------------------------------
1 | class SymbolTable:
2 | def __init__(self, parent=None):
3 | self.symbols = {}
4 | self.parent = parent
5 |
6 | def get(self, name):
7 | value = self.symbols.get(name, None)
8 | if value == None and self.parent:
9 | return self.parent.get(name)
10 | return value
11 |
12 | def set(self, name, value):
13 | self.symbols[name] = value
14 |
15 | def remove(self, name):
16 | del self.symbols[name]
17 |
--------------------------------------------------------------------------------
/Tests/__init__.py:
--------------------------------------------------------------------------------
1 | from Tests.test_variables import *
2 | from Tests.tests_arithmetic import *
--------------------------------------------------------------------------------
/Tests/test_variables.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import main
3 |
4 |
5 | class TestVariable(unittest.TestCase):
6 | def test_sum_var(self):
7 | text = "2+(var a=2)"
8 | result, error = main.run("", text)
9 | self.assertEqual(str(result), "४")
10 |
11 | text = "var b=2"
12 | result, error = main.run("", text)
13 |
14 | text = "b+a"
15 | result, error = main.run("", text)
16 | self.assertEqual(str(result), "४")
17 |
18 | def test_sub_var(self):
19 | text = "8-(var a=4)"
20 | result, error = main.run("", text)
21 | self.assertEqual(str(result), "४")
22 |
23 | text = "var b=8"
24 | result, error = main.run("", text)
25 |
26 | text = "b-a"
27 | result, error = main.run("", text)
28 | self.assertEqual(str(result), "४")
29 |
30 | def test_mul_var(self):
31 | text = "2*(var a=2)"
32 | result, error = main.run("", text)
33 | self.assertEqual(str(result), "४")
34 |
35 | text = "var b=2"
36 | result, error = main.run("", text)
37 |
38 | text = "b*a"
39 | result, error = main.run("", text)
40 | self.assertEqual(str(result), "४")
41 |
42 | def test_div_var(self):
43 | text = "8/(var a=2)"
44 | result, error = main.run("", text)
45 | self.assertEqual(str(result), "४")
46 |
47 | text = "var b=8"
48 | result, error = main.run("", text)
49 |
50 | text = "b/a"
51 | result, error = main.run("", text)
52 | self.assertEqual(str(result), "४")
53 |
54 | def test_div_var_float(self):
55 | text = "22/(var a=7)"
56 | result, error = main.run("", text)
57 | self.assertEqual(str(result), "३.१४२८५७१४२८५७१४३")
58 |
59 | text = "var b=22"
60 | result, error = main.run("", text)
61 |
62 | text = "b/a"
63 | result, error = main.run("", text)
64 | self.assertEqual(str(result), "३.१४२८५७१४२८५७१४३")
65 |
66 |
67 | class TestVariableMAR(unittest.TestCase):
68 | def test_sum_var(self):
69 | text = "२+(चल क=२)"
70 | result, error = main.run("", text)
71 | self.assertEqual(str(result), "४")
72 |
73 | text = "चल जग=२"
74 | result, error = main.run("", text)
75 |
76 | text = "जग+क"
77 | result, error = main.run("", text)
78 | self.assertEqual(str(result), "४")
79 |
80 | def test_sub_var(self):
81 | text = "8-(चल क=4)"
82 | result, error = main.run("", text)
83 | self.assertEqual(str(result), "४")
84 |
85 | text = "चल जग=8"
86 | result, error = main.run("", text)
87 |
88 | text = "जग-क"
89 | result, error = main.run("", text)
90 | self.assertEqual(str(result), "४")
91 |
92 | def test_mul_var(self):
93 | text = "२*(चल क=२)"
94 | result, error = main.run("", text)
95 | self.assertEqual(str(result), "४")
96 |
97 | text = "चल जग=२"
98 | result, error = main.run("", text)
99 |
100 | text = "जग*क"
101 | result, error = main.run("", text)
102 | self.assertEqual(str(result), "४")
103 |
104 | def test_div_var(self):
105 | text = "८/(चल क=२)"
106 | result, error = main.run("", text)
107 | self.assertEqual(str(result), "४")
108 |
109 | text = "चल जग=८"
110 | result, error = main.run("", text)
111 |
112 | text = "जग/क"
113 | result, error = main.run("", text)
114 | self.assertEqual(str(result), "४")
115 |
116 | def test_div_var_float(self):
117 | text = "२२/(चल क=७)"
118 | result, error = main.run("", text)
119 | self.assertEqual(str(result), "३.१४२८५७१४२८५७१४३")
120 |
121 | text = "चल जग=२२"
122 | result, error = main.run("", text)
123 |
124 | text = "जग/क"
125 | result, error = main.run("", text)
126 | self.assertEqual(str(result), "३.१४२८५७१४२८५७१४३")
127 |
--------------------------------------------------------------------------------
/Tests/tests_arithmetic.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import main
3 |
4 | class TestArithmetic(unittest.TestCase):
5 |
6 | def test_sum(self):
7 | text = '2+2'
8 | result , error = main.run('',text)
9 | self.assertEqual(str(result), "४")
10 |
11 | def test_sub(self):
12 | text = '8-4'
13 | result , error = main.run('',text)
14 | self.assertEqual(str(result), "४")
15 |
16 | def test_mul(self):
17 | text = '2*2'
18 | result , error = main.run('',text)
19 | self.assertEqual(str(result), "४")
20 |
21 | def test_div(self):
22 | text = '8/2'
23 | result , error = main.run('',text)
24 | self.assertEqual(str(result), "४")
25 |
26 | def test_div_float(self):
27 | text = '22/7'
28 | result , error = main.run('',text)
29 | self.assertEqual(str(result), "३.१४२८५७१४२८५७१४३")
30 |
31 |
32 |
33 |
34 |
35 |
36 | if __name__ == '__main__':
37 | unittest.main()
--------------------------------------------------------------------------------
/bugs.baji:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joey00072/Baji-Marathi-Programing-Language/43db51c563e351388459044a28f09aec7a74cda3/bugs.baji
--------------------------------------------------------------------------------
/example.baji:
--------------------------------------------------------------------------------
1 | वारंवार i = 1 ते 101 तर
2 | IF (i%3==0 AND i%5==0 )THEN
3 | PRINT("FIZZBUZZ\n")
4 | ELIF i%3==0 THEN
5 | PRINT("FIZZ\n")
6 | ELIF i%5==0 THEN
7 | PRINT("BUZZ\n")
8 | ELSE
9 | PRINT(i)
10 | PRINT("\n")
11 | END
12 | शेवट
--------------------------------------------------------------------------------
/examples/HelloWorld.baji:
--------------------------------------------------------------------------------
1 | दाखवा("नमस्कार विश्व")
--------------------------------------------------------------------------------
/examples/fib.baji:
--------------------------------------------------------------------------------
1 | दाखवा("Recurrsive \n")
2 |
3 |
4 | कार्य फिबोनॅकी(क)
5 | जर क<2 तर
6 | परत 1
7 | नाहीतर
8 | परत फिबोनॅकी(क-1) + फिबोनॅकी(क-2)
9 | शेवट
10 | शेवट
11 |
12 |
13 |
14 | वारंवार क=0 ते 24 तर
15 | दाखवा(क)
16 | दाखवा(" ")
17 | दाखवा(फिबोनॅकी(क))
18 | दाखवा("\n")
19 | शेवट
20 |
21 |
22 | दाखवा("\n")
--------------------------------------------------------------------------------
/examples/fib2.baji:
--------------------------------------------------------------------------------
1 |
2 | दाखवा("Dynamic Programing \n")
3 |
4 | कार्य get_2d_array(length)
5 | चल यादी =[]
6 | वारंवार i = 0 ते length तर
7 | वाढवा(यादी,[RAND_INT(0,0)])
8 | शेवट
9 | परत यादी
10 | शेवट
11 |
12 |
13 | चल यादी = get_2d_array(100)
14 |
15 |
16 | कार्य फिबोनॅकी(n)
17 | जर n<2 तर
18 | परत 1
19 | किंवाजर यादी[n]!=0 तर
20 | परत यादी[n]
21 | नाहीतर
22 | यादी[n]=फिबोनॅकी(n-1) + फिबोनॅकी(n-2)
23 | परत यादी[n]
24 | शेवट
25 | शेवट
26 |
27 | वारंवार i=0 ते 100 तर
28 | दाखवा(i)
29 | दाखवा(" ")
30 | दाखवा(फिबोनॅकी(i))
31 | दाखवा("\n")
32 | शेवट
--------------------------------------------------------------------------------
/examples/game_of_life.baji:
--------------------------------------------------------------------------------
1 | # Game Of Lजरe
2 |
3 | कार्य बोर्ड_घ्या(तत,दद)
4 | चल बोर्ड =[]
5 | वारंवार i = 0 ते तत तर
6 | चल कतक = []
7 | वारंवार j=0 ते दद तर
8 | वाढवा(कतक,[०])
9 | शेवट
10 | बोर्ड = बोर्ड+कतक
11 | शेवट
12 | परत बोर्ड
13 | शेवट
14 |
15 | चल आकार = 10
16 | चल बोर्ड = बोर्ड_घ्या(आकार,2*आकार)
17 |
18 |
19 | बोर्ड[1+2][0+2]=1
20 | बोर्ड[0+2][2+2]=1
21 | बोर्ड[1+2][2+2]=1
22 | बोर्ड[2+2][2+2]=1
23 | बोर्ड[2+2][1+2]=1
24 |
25 | कार्य दाखवा_बोर्ड()
26 | वारंवार i=0 ते लांबी(बोर्ड) तर
27 | वारंवार j=0 ते लांबी(बोर्ड[0]) तर
28 | दाखवा(".")
29 | जर बोर्ड[i][j]==1 तर
30 | दाखवा("#")
31 | नाहीतर
32 | दाखवा(".")
33 | शेवट
34 | शेवट
35 | दाखवा("\n")
36 | शेवट
37 | शेवट
38 |
39 |
40 | कार्य ददद(पप,कर)
41 | चल करर =0
42 | करर = (पप+कर+आकार)%आकार
43 | परत करर
44 | शेवट
45 |
46 |
47 |
48 |
49 | कार्य is_alive(ox,oy)
50 | चल cnt =0
51 | चल x =0
52 | चल y =0
53 | वारंवार i=-1 ते 2 तर
54 | वारंवार j=-1 ते 2 तर
55 | जर (i==0 AND j==0) != 1 तर
56 | x = ददद(ox,i)
57 | y = ददद(oy,j)
58 | जर बोर्ड[y][x]==1 तर
59 | cnt= cnt+1
60 | शेवट
61 | शेवट
62 | शेवट
63 | शेवट
64 | चल RT = 0
65 | जर cnt<2 OR cnt>3 तर
66 | RT= 0
67 | किंवाजर बोर्ड[oy][ox]==1 AND cnt<4 तर
68 | RT= 1
69 | किंवाजर cnt==3 तर
70 | RT= 1
71 | शेवट
72 | परत RT
73 | शेवट
74 |
75 | कार्य next_gen()
76 | चल गद = बोर्ड_घ्या(आकार,2*आकार)
77 | वारंवार y=0 ते आकार तर
78 | वारंवार x=0 ते आकार तर
79 | गद[y][x]=is_alive(x,y)
80 | शेवट
81 | शेवट
82 | परत गद
83 | शेवट
84 |
85 |
86 |
87 | WHILE 5==5 तर
88 | पुसा()
89 | दाखवा_बोर्ड()
90 | बोर्ड = next_gen()
91 | शेवट
92 |
93 |
--------------------------------------------------------------------------------
/examples/if_else.baji:
--------------------------------------------------------------------------------
1 |
2 | IF 1==1 THEN
3 | PRINT("IF")
4 | END
5 |
6 | IF 1==1 THEN
7 | PRINT("IF")
8 | END
9 |
10 | IF 1==1 THEN
11 | PRINT("IF")
12 | END
13 |
14 | IF 1==1 THEN
15 | PRINT("IF")
16 | END
--------------------------------------------------------------------------------
/grammar.md:
--------------------------------------------------------------------------------
1 | ## GRAMMAR
2 | ---
3 | statements : NEWLINE* statement (NEWLINE+ statement)* NEWLINE*
4 | ---
5 | statement : KEYWORD:RETURN expr?
6 | : KEYWORD:CONTINUE
7 | : KEYWORD:BREAK
8 | : expr
9 | ---
10 |
11 | expr : KEYWORD var|चल IDENTIFIER EQ expr
12 | : comp-expr ((KEYWORD:AND|KEYWORD:OR) comp-expr)*
13 |
14 | ---
15 |
16 | comp-expr : NOT comp-expr
17 | : arith-expr ((EE|LT|GT|LTE|GTE) arith-expr)*
18 |
19 | ---
20 |
21 | arith-expr : term ((PLUS|MINUS) term)*
22 |
23 | ---
24 |
25 | term : factor((MUL|DIV) factor)*
26 |
27 | ---
28 |
29 | factor : (PLUS|MINUS) factor
30 | : mod
31 | ---
32 | mod : power((MUL|DIV) factor)*
33 | ---
34 |
35 | power : call(POWER mod)*
36 | ---
37 | call : atom (LPAREN (expr (COMMA expr)*)? RPAREN)?
38 | : atom (LSQUARE (expr) LSQUARE)? EQ expr
39 | : atom (LSQUARE (expr) LSQUARE)?
40 |
41 | ---
42 |
43 | atom : INT | FLOAT | STRING | IDENTIFIER
44 | : LPARAN expr RPARAN
45 | : list-expr
46 | : if-expr
47 | : for-expr
48 | : while-expr
49 | : func-def
50 | ---
51 | list-expr : LSQUARE (expr (COMMA expr)*)? RSQUARE
52 | ---
53 | if-expr : KEYWORD:IF expr KEYWORD:THEN
54 | (statement if-expr-b|if-expr-c?)
55 | | (NEWLINE statements KEYWORD:END|if-expr-b|if-expr-c)
56 | ---
57 | if-expr-b : KEYWORD:ELIF expr KEYWORD:THEN
58 | (statement if-expr-b|if-expr-c?)
59 | | (NEWLINE statements KEYWORD:END|if-expr-b|if-expr-c)
60 | ---
61 | if-expr-c : KEYWORD:ELSE
62 | statement
63 | | (NEWLINE statements KEYWORD:END)
64 |
65 | ---
66 | for-expr : KEYWORD:FOR IDENTIFIER EQ expr KEYWORD:TO
67 | statement
68 | | (NEWLINE statements KEYWORD:END)expr
69 |
70 | ---
71 | while-expr : KEYWORD:WHILE expr KEYWORD:THEN
72 | statement
73 | | (NEWLINE statements KEYWORD:END)
74 | ---
75 | func-def : KEYWORD:FUN IDENTIFIER?
76 | LPAREN (IDENTIFIER (COMMA IDENTIFIER)*)? RPAREN
77 | (ARROW expr)
78 | | (NEWLINE statements KEYWORD:END)
79 |
80 |
--------------------------------------------------------------------------------
/lexer/__init__.py:
--------------------------------------------------------------------------------
1 | from Lexer.lexer import *
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/lexer/lexer.py:
--------------------------------------------------------------------------------
1 | from typing import Counter
2 | from Translate import Translate
3 | from Errors import Error, IllegalCharacterError, ExpectedCharError
4 | from Lexer.position import Position
5 | from Lexer.token import Token
6 | from Constants import *
7 |
8 |
9 | # -----------LEXER---------------
10 |
11 |
12 | class Lexer:
13 | def __init__(self, fn, text):
14 | self.fn = fn
15 | self.text = text
16 | self.pos = Position(-1, 0, -1, fn, text)
17 | self.current_char = None
18 | self.advance()
19 | self.translate = Translate()
20 |
21 | def advance(self):
22 | self.pos.advance(self.current_char)
23 | self.current_char = (
24 | self.text[self.pos.idx] if self.pos.idx < len(self.text) else None
25 | )
26 |
27 | def peak(self, idx=1):
28 | if self.pos.idx + idx < len(self.text):
29 | return self.text[self.pos.idx + idx]
30 | return None
31 |
32 | def primitive_token(self):
33 | if self.current_char == "+":
34 | return TT_PLUS, None
35 |
36 | if self.current_char == "-":
37 | return self.make_minus_or_arrow()
38 |
39 | if self.current_char == "*":
40 | return self.make_mul_or_power()
41 |
42 | if self.current_char == "/":
43 | return TT_DIV, None
44 |
45 | if self.current_char == "%":
46 | return TT_MOD, None
47 |
48 | if self.current_char == ",":
49 | return TT_COMMA, None
50 |
51 | if self.current_char == "(":
52 | return TT_LPAREN, None
53 |
54 | if self.current_char == ")":
55 | return TT_RPAREN, None
56 |
57 | if self.current_char == "[":
58 | return TT_LSQUARE, None
59 |
60 | if self.current_char == "]":
61 | return TT_RSQUARE , None
62 |
63 | if self.current_char == "=":
64 | return self.make_equals()
65 | if self.current_char == "<":
66 | return self.make_less_than()
67 |
68 | if self.current_char == ">":
69 | return self.make_greater_than()
70 |
71 | if self.current_char == "!":
72 | token, error = self.make_not_equals()
73 | if error:
74 | return None, error
75 | return token, None
76 |
77 | if self.current_char in ";\n":
78 | return TT_NEWLINE,None
79 |
80 |
81 |
82 |
83 | return None, None
84 |
85 | def get_token(self):
86 | token, error = self.primitive_token()
87 |
88 | if error:
89 | return error
90 | if token:
91 | self.advance()
92 | return Token(token, pos_start=self.pos)
93 |
94 | if self.current_char == '"':
95 | return self.make_string()
96 |
97 | if self.current_char in DIGITS:
98 | return self.make_number()
99 |
100 | if self.current_char in LETTERS:
101 | return self.make_identifier()
102 |
103 |
104 |
105 |
106 | position_start = self.pos.copy()
107 |
108 | return IllegalCharacterError(
109 | position_start, self.pos, "'" + self.current_char + "'"
110 | )
111 |
112 | def make_tokens(self):
113 | tokens = []
114 | while self.current_char != None:
115 | if self.current_char in " \t":
116 | self.advance()
117 | continue
118 | if self.current_char == "#":
119 | self.skip_comment()
120 | current_token = self.get_token()
121 | if isinstance(current_token, Error):
122 | return [], current_token
123 | tokens.append(current_token)
124 |
125 | tokens.append(Token(TT_EOF, pos_start=self.pos))
126 | return tokens, None
127 |
128 | def make_number(self):
129 | num_str = ""
130 | dot = False
131 | pos_start = self.pos
132 |
133 | while self.current_char != None and self.current_char in DIGITS + ".":
134 | if self.current_char == ".":
135 | if dot == True:
136 | break
137 | dot = True
138 | num_str += "."
139 | else:
140 | num_str += self.translate.digit_to_eng(self.current_char)
141 | self.advance()
142 |
143 | if dot:
144 | return Token(
145 | TT_FLOAT, float(num_str), pos_start=pos_start, pos_end=self.pos
146 | )
147 | else:
148 | return Token(TT_INT, int(num_str), pos_start=pos_start, pos_end=self.pos)
149 |
150 | def make_string(self):
151 | string = ''
152 | pos_start = self.pos.copy()
153 | escape_character = False
154 | self.advance()
155 |
156 | escape_characters = {
157 | 'n': '\n',
158 | 't': '\t'
159 | }
160 |
161 | while self.current_char != None and (self.current_char != '"' or escape_character):
162 | if escape_character:
163 | string += escape_characters.get(self.current_char, self.current_char)
164 | else:
165 | if self.current_char == '\\':
166 | escape_character = True
167 | if self.peak()=="n":
168 | self.advance()
169 | string+="\n"
170 | else:
171 | string += self.current_char
172 | self.advance()
173 | escape_character = False
174 |
175 | self.advance()
176 | return Token(TT_STRING, string, pos_start, self.pos)
177 |
178 |
179 | def make_identifier(self):
180 | id_str = ""
181 | pos_start = self.pos
182 |
183 | while self.current_char != None and self.current_char in LETTERS_DIGITS + "_":
184 | id_str += self.translate.digit_to_eng(self.current_char)
185 | self.advance()
186 |
187 | token_type = TT_KEYWORD if id_str in KEYWORDS else TT_IDENTIFIER
188 | return Token(token_type, id_str, pos_start, self.pos)
189 |
190 | def make_not_equals(self):
191 | pos_start = self.pos.copy()
192 | self.advance()
193 |
194 | if self.current_char == "=":
195 | return TT_NE, None
196 |
197 | return None, ExpectedCharError(pos_start, self.pos, "'=' (after '!')")
198 |
199 | def make_equals(self):
200 | tok_type = TT_EQ
201 | nxt = self.peak()
202 | if nxt == "=":
203 | self.advance()
204 | tok_type = TT_EE
205 | return tok_type, None
206 |
207 | def make_less_than(self):
208 | tok_type = TT_LT
209 | nxt = self.peak()
210 |
211 | if nxt == "=":
212 | self.advance()
213 | tok_type = TT_LTE
214 |
215 | return tok_type, None
216 |
217 | def make_greater_than(self):
218 | tok_type = TT_GT
219 | nxt = self.peak()
220 |
221 | if nxt == "=":
222 | self.advance()
223 | tok_type = TT_GTE
224 |
225 | return tok_type, None
226 |
227 | def make_mul_or_power(self):
228 | tok_type = TT_MUL
229 | nxt = self.peak()
230 |
231 | if nxt == "*":
232 | self.advance()
233 | tok_type = TT_POWER
234 |
235 | return tok_type, None
236 |
237 | def make_minus_or_arrow(self):
238 | tok_type = TT_MINUS
239 | nxt = self.peak()
240 |
241 | if nxt == ">":
242 | self.advance()
243 | tok_type = TT_ARROW
244 |
245 | return tok_type, None
246 |
247 | def skip_comment(self):
248 | while self.current_char != '\n':
249 | self.advance()
250 | self.advance()
251 |
--------------------------------------------------------------------------------
/lexer/position.py:
--------------------------------------------------------------------------------
1 | # ----------Position--------------
2 |
3 |
4 | class Position:
5 | def __init__(self, idx, ln, col, fn, ftxt):
6 | self.idx = idx
7 | self.ln = ln
8 | self.col = col
9 | self.fn = fn
10 | self.ftxt = ftxt
11 |
12 | def advance(self, current_char=None):
13 | self.idx += 1
14 | self.col += 1
15 |
16 | if current_char == "\n":
17 | self.ln += 1
18 | self.col = 0
19 | return self
20 |
21 | def copy(self):
22 | return Position(self.idx, self.ln, self.col, self.fn, self.ftxt)
--------------------------------------------------------------------------------
/lexer/token.py:
--------------------------------------------------------------------------------
1 | class Token:
2 | def __init__(self, type_, value=None, pos_start=None, pos_end=None):
3 | self.type = type_
4 | self.value = value
5 | if pos_start:
6 | self.pos_start = pos_start.copy()
7 | self.pos_end = pos_start.copy()
8 | self.pos_end.advance()
9 |
10 | if pos_end:
11 | self.pos_end = pos_end.copy()
12 |
13 | def matches(self, type_, value):
14 | if isinstance(value,tuple):
15 | match=False
16 | for val in value:
17 | match = match or (self.type == type_ and self.value == val)
18 | return match
19 | return self.type == type_ and self.value == value
20 |
21 | def __repr__(self):
22 | return f"{self.type}:{self.value}" if self.value else f"{self.type}"
23 |
--------------------------------------------------------------------------------
/logo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joey00072/Baji-Marathi-Programing-Language/43db51c563e351388459044a28f09aec7a74cda3/logo.gif
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
405 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from Lexer import Lexer
2 | from Parser import Parser
3 | from Interpreter import Interpreter
4 | from Context import Context
5 | from SymbolTable import global_symbol_table
6 |
7 | import sys
8 |
9 |
10 | #------------EXECUTE--------------
11 |
12 | # ------------RUN-----------------
13 |
14 | context =None
15 | def run(fn, text, debug=False):
16 | global context
17 | lexer = Lexer(fn, text)
18 | # Genarate Tokens
19 | tokens, error = lexer.make_tokens()
20 | if error:
21 | return None, error
22 |
23 | # Generate AST
24 | parser = Parser(tokens)
25 | ast = parser.parse()
26 |
27 | if debug:
28 | print("---symbols--\n")
29 | print(global_symbol_table.symbols, "\n")
30 | print("---tokens--\n")
31 | print(tokens, "\n")
32 | print("--AST--\n")
33 | print(ast.node, "\n")
34 | print("--output--\n")
35 |
36 | if ast.error:
37 | return None, ast.error
38 |
39 | # Run program
40 | interpreter = Interpreter()
41 | context = Context("")
42 | context.symbol_table = global_symbol_table
43 | result = interpreter.visit(ast.node, context)
44 |
45 | return result.value, result.error
46 |
47 |
48 | def run_from_file(file_name):
49 | splits = file_name.strip().split(".")
50 |
51 | if len(splits)<2:
52 | print("Invalid argument")
53 |
54 | name = "".join(splits[:-1])
55 |
56 | extension = splits[-1].lower()
57 |
58 | if extension!='baji':
59 | print("File extension should .baji")
60 | print(f"Found -> {extension}")
61 | exit()
62 |
63 | try:
64 | with open(file_name , 'r',encoding='utf-8') as f:
65 | script = f.read()
66 | except BaseException as e:
67 | print("Failed to load Script")
68 | print(str(e))
69 |
70 | _,error = run(f"<{name}>", script, debug=False)
71 |
72 | if error:
73 | print(error.as_string())
74 |
75 |
76 | if __name__=="__main__":
77 | args = sys.argv
78 |
79 | if len(args)>1:
80 | run_from_file(args[1])
81 | else:
82 | print("Provide file name")
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/nodes/__init__.py:
--------------------------------------------------------------------------------
1 | # ------------NODES----------------
2 |
3 | from Nodes.operation import *
4 | from Nodes.value import *
5 | from Nodes.variable import *
6 | from Nodes.conditional import *
7 | from Nodes.loop import *
8 | from Nodes.functions import *
--------------------------------------------------------------------------------
/nodes/conditional.py:
--------------------------------------------------------------------------------
1 | class IfNode:
2 | def __init__(self, cases, else_case):
3 | self.cases = cases
4 | self.else_case = else_case
5 |
6 | self.pos_start = self.cases[0][0].pos_start
7 | self.pos_end = (self.else_case or self.cases[len(self.cases) - 1])[0].pos_end
8 |
9 | def __repr__(self):
10 | return f"(IF {self.cases}, THEN )"
11 |
--------------------------------------------------------------------------------
/nodes/functions.py:
--------------------------------------------------------------------------------
1 | class FuncDefNode:
2 | def __init__(self, var_name_token, arg_name_tokens, body_node, should_auto_return):
3 | self.var_name_token = var_name_token
4 | self.arg_name_tokens = arg_name_tokens
5 | self.body_node = body_node
6 |
7 | if self.var_name_token:
8 | self.pos_start = self.var_name_token.pos_start
9 | elif len(self.arg_name_tokens) > 0:
10 | self.pos_start = self.arg_name_tokens[0].pos_start
11 | else:
12 | self.pos_start = self.body_node.pos_start
13 |
14 | self.pos_end = self.body_node.pos_end
15 |
16 | self.should_auto_return = should_auto_return
17 |
18 | def __repr__(self):
19 | return f"( function {self.var_name_token}->args({self.arg_name_tokens}) ({self.body_node}) ) "
20 |
21 |
22 | class CallNode:
23 | def __init__(self, node_to_call, arg_nodes):
24 | self.node_to_call = node_to_call
25 | self.arg_nodes = arg_nodes
26 |
27 | self.pos_start = self.node_to_call.pos_start
28 |
29 | if len(self.arg_nodes) > 0:
30 | self.pos_end = self.arg_nodes[len(self.arg_nodes) - 1].pos_end
31 | else:
32 | self.pos_end = self.node_to_call.pos_end
33 |
34 | def __repr__(self):
35 | return f"( function call {self.node_to_call}->args({self.arg_nodes}) ) "
36 |
37 |
38 | class ReturnNode:
39 | def __init__(self, node_to_return, pos_start, pos_end):
40 | self.node_to_return = node_to_return
41 |
42 | self.pos_start = pos_start
43 | self.pos_end = pos_end
44 |
45 | def __repr__(self) -> str:
46 | return f"( return ->({self.node_to_return}) ) "
47 |
--------------------------------------------------------------------------------
/nodes/loop.py:
--------------------------------------------------------------------------------
1 | class ForNode:
2 | def __init__(
3 | self,
4 | var_name_token,
5 | start_value_node,
6 | end_value_node,
7 | step_value_node,
8 | body_node,
9 | should_return_null,
10 | ):
11 | self.var_name_token = var_name_token
12 | self.start_value_node = start_value_node
13 | self.end_value_node = end_value_node
14 | self.step_value_node = step_value_node
15 | self.body_node = body_node
16 |
17 | self.pos_start = self.var_name_token.pos_start
18 | self.pos_end = self.body_node.pos_end
19 | self.should_return_null = should_return_null
20 |
21 | def __repr__(self):
22 | return f"(For Loop[{self.start_value_node},{self.end_value_node},{self.step_value_node}] :{self.body_node})"
23 |
24 |
25 | class WhileNode:
26 | def __init__(self, condition_node, body_node, should_return_null):
27 | self.condition_node = condition_node
28 | self.body_node = body_node
29 |
30 | self.pos_start = self.condition_node.pos_start
31 | self.pos_end = self.body_node.pos_end
32 | self.should_return_null = should_return_null
33 |
34 | def __repr__(self):
35 | return f"(WHILE {self.body_node})"
36 |
37 |
38 | class ContinueNode:
39 | def __init__(self, pos_start, pos_end):
40 | self.pos_start = pos_start
41 | self.pos_end = pos_end
42 | def __repr__(self) -> str:
43 | return f"(continue)"
44 |
45 |
46 | class BreakNode:
47 | def __init__(self, pos_start, pos_end):
48 | self.pos_start = pos_start
49 | self.pos_end = pos_end
50 | def __repr__(self) -> str:
51 | return f"(break)"
52 |
--------------------------------------------------------------------------------
/nodes/operation.py:
--------------------------------------------------------------------------------
1 |
2 | class BinOpNode:
3 | def __init__(self, left_node, op_token, right_node):
4 | self.left_node = left_node
5 | self.op_token = op_token
6 | self.right_node = right_node
7 |
8 | self.pos_start = self.left_node.pos_start
9 | self.pos_end = self.right_node.pos_end
10 |
11 | def __repr__(self):
12 | return f'( {self.left_node} {self.op_token} {self.right_node} )'
13 |
14 | class UnaryOpNode:
15 | def __init__(self, op_token, node):
16 | self.op_token = op_token
17 | self.node = node
18 |
19 | self.pos_start = self.op_token.pos_start
20 | self.pos_end = node.pos_end
21 |
22 | def __repr__(self):
23 | return f'({self.op_token}, {self.node})'
--------------------------------------------------------------------------------
/nodes/value.py:
--------------------------------------------------------------------------------
1 | class NumberNode:
2 | def __init__(self, token):
3 | self.token = token
4 | self.pos_start = self.token.pos_start
5 | self.pos_end = self.token.pos_end
6 |
7 | def __repr__(self):
8 | return f"{self.token}"
9 |
10 | class StringNode:
11 | def __init__(self, token):
12 | self.token = token
13 | self.pos_start = self.token.pos_start
14 | self.pos_end = self.token.pos_end
15 |
16 | def __repr__(self):
17 | return f"{self.token}"
18 |
19 |
20 | class ListNode:
21 | def __init__(self, element_nodes,pos_start,pos_end):
22 | self.element_nodes = element_nodes
23 | self.pos_start = pos_start
24 | self.pos_end = pos_end
25 |
26 | def __repr__(self):
27 | return f"{self.element_nodes}"
28 |
29 |
30 | class IndexNode:
31 | def __init__(self, index_node, expr):
32 | self.index_node = index_node
33 | self.expr = expr
34 |
35 | self.pos_start = self.index_node.pos_start
36 |
37 | self.pos_end = self.index_node.pos_end
38 |
39 | def __repr__(self):
40 | return f"( Index {self.index_node}->expr({self.expr}) ) "
41 |
42 |
43 | class IndexAssignNode:
44 | def __init__(self, index_node, expr,assgin_expr):
45 | self.index_node = index_node
46 | self.expr = expr
47 |
48 | self.pos_start = self.index_node.pos_start
49 |
50 | self.pos_end = self.index_node.pos_end
51 | self.assgin_expr = assgin_expr
52 |
53 | def __repr__(self):
54 | return f"( Index assign {self.index_node}->expr({self.expr}) := expr({self.assgin_expr}) ) "
--------------------------------------------------------------------------------
/nodes/variable.py:
--------------------------------------------------------------------------------
1 | class VarAccessNode:
2 | def __init__(self, var_name_token):
3 | self.var_name_token = var_name_token
4 | self.pos_start = self.var_name_token.pos_start
5 | self.pos_end = self.var_name_token.pos_end
6 |
7 |
8 | def __repr__(self):
9 | return f"(variable : ({self.var_name_token}))"
10 |
11 | class VarAssignNode:
12 | def __init__(self, var_name_token,value_node,declare=True):
13 | self.var_name_token = var_name_token
14 | self.value_node = value_node
15 | self.declare = declare
16 |
17 | self.pos_start = self.var_name_token.pos_start
18 | self.pos_end = self.var_name_token.pos_end
19 |
20 | def __repr__(self):
21 | return f"(var assign = ({self.var_name_token}))"
--------------------------------------------------------------------------------
/results/__init__.py:
--------------------------------------------------------------------------------
1 | from Results.parse_result import ParseResult
2 | from Results.runtime_result import RTResult
3 |
--------------------------------------------------------------------------------
/results/parse_result.py:
--------------------------------------------------------------------------------
1 | # ---------PARSE_RESULT------------
2 | class ParseResult:
3 | def __init__(self):
4 | self.error = None
5 | self.node = None
6 | self.advance_count = 0
7 | self.to_reverse_count = 0
8 |
9 | def register_advancement(self):
10 | self.advance_count += 1
11 |
12 | def register(self, res):
13 | self.advance_count += res.advance_count
14 | if res.error:
15 | self.error = res.error
16 | return res.node
17 |
18 | def try_register(self, res):
19 | if res.error:
20 | self.to_reverse_count = res.advance_count
21 | return None
22 | return self.register(res)
23 |
24 | def success(self, node):
25 | self.node = node
26 | return self
27 |
28 | def failure(self, error):
29 | if not self.error or self.advance_count == 0:
30 | self.error = error
31 | return self
32 |
--------------------------------------------------------------------------------
/results/runtime_result.py:
--------------------------------------------------------------------------------
1 | # ------------Runtime Result---------------
2 | class RTResult:
3 | def __init__(self):
4 | self.reset()
5 |
6 | def reset(self):
7 | self.value = None
8 | self.error = None
9 | self.func_return_value = None
10 | self.loop_should_continue = False
11 | self.loop_should_break = False
12 |
13 | def register(self, res):
14 | self.error = res.error
15 | self.func_return_value = res.func_return_value
16 | self.loop_should_continue = res.loop_should_continue
17 | self.loop_should_break = res.loop_should_break
18 | return res.value
19 |
20 | def success(self, value):
21 | self.reset()
22 | self.value = value
23 | return self
24 |
25 | def success_return(self, value):
26 | self.reset()
27 | self.func_return_value = value
28 | return self
29 |
30 | def success_continue(self):
31 | self.reset()
32 | self.loop_should_continue = True
33 | return self
34 |
35 | def success_break(self):
36 | self.reset()
37 | self.loop_should_break = True
38 | return self
39 |
40 | def failure(self, error):
41 | self.reset()
42 | self.error = error
43 | return self
44 |
45 | def should_return(self):
46 | return (
47 | self.error
48 | or self.func_return_value
49 | or self.loop_should_continue
50 | or self.loop_should_break
51 | )
52 |
--------------------------------------------------------------------------------
/shell.py:
--------------------------------------------------------------------------------
1 | import main
2 | import sys
3 |
4 | Debug=False
5 |
6 | try:
7 | if len(sys.argv)>1:
8 | main.run_from_file(sys.argv[1])
9 | else:
10 | while True:
11 | text = input("बाजी >")
12 | text = text.strip()
13 | if len(text)==0:
14 | continue
15 |
16 | result, error = main.run("<मुख्य>", text, debug=Debug)
17 | if error:
18 | print(error.as_string())
19 | elif result:
20 | if len(result)==1:
21 | print(result[0])
22 | else:
23 | print(result)
24 | except KeyboardInterrupt as e:
25 | print("\n--------------------")
26 | print("कीबोर्डद्वारे प्रोग्राम थांबविला")
27 | print("^^^^^^^^^^^^^^^^^^^^")
28 | except BaseException as e:
29 | print("\n--------------------")
30 | print("प्रोग्राम चालू असताना त्रुटी आली")
31 | print("^^^^^^^^^^^^^^^^^^^^")
32 |
--------------------------------------------------------------------------------
/temp.baji:
--------------------------------------------------------------------------------
1 | FUN get_2d_array(length)
2 | VAR arr =[]
3 | FOR i = 0 TO length THEN
4 | EXTEND(arr,[RAND_INT(0,0)])
5 | END
6 | RETURN arr
7 | END
8 |
9 | VAR arr = get_2d_array(100)
10 |
11 |
12 | FUN fib(n)
13 | IF n<2 THEN
14 | RETURN 1
15 | ELIF arr[n]!=0 THEN
16 | RETURN arr[n]
17 | ELSE
18 | arr[n]=fib(n-1) + fib(n-2)
19 | RETURN arr[n]
20 | END
21 | END
22 |
23 | FOR i=0 TO 10 THEN
24 | PRINT(fib(i))
25 | PRINT("\n")
26 | END
--------------------------------------------------------------------------------
/translate/__init__.py:
--------------------------------------------------------------------------------
1 | class Translate:
2 | def __init__(self):
3 | self.DIGITS_M_TO_E = {
4 | "०": "0",
5 | "१": "1",
6 | "२": "2",
7 | "३": "3",
8 | "४": "4",
9 | "५": "5",
10 | "६": "6",
11 | "७": "7",
12 | "८": "8",
13 | "९": "9",
14 | }
15 |
16 | self.DIGITS_E_TO_M = {
17 | "0": "०",
18 | "1": "१",
19 | "2": "२",
20 | "3": "३",
21 | "4": "४",
22 | "5": "५",
23 | "6": "६",
24 | "7": "७",
25 | "8": "८",
26 | "9": "९",
27 | }
28 |
29 | def digit_to_eng(self, num_char):
30 | if num_char in self.DIGITS_M_TO_E:
31 | return self.DIGITS_M_TO_E[num_char]
32 | return num_char
33 |
34 | def digit_to_mar(self, num_char):
35 | if num_char in self.DIGITS_E_TO_M:
36 | return self.DIGITS_E_TO_M[num_char]
37 | return num_char
38 |
39 | def number_to_mar(self, num):
40 | num = str(num)
41 | result = ""
42 | for char in num:
43 | if char == ".":
44 | result += "."
45 | else:
46 | result += self.digit_to_mar(char)
47 | return result
48 |
--------------------------------------------------------------------------------
/values/__init__.py:
--------------------------------------------------------------------------------
1 | from Values.number import *
2 | from Values.function import *
3 | from Values.string import *
4 | from Values.list import *
--------------------------------------------------------------------------------
/values/function.py:
--------------------------------------------------------------------------------
1 | from Nodes import value
2 | from Values.value import Value
3 | from Values.string import String
4 | from Values.number import Number
5 | from Values.list import List
6 | from Errors import RTError
7 | import Interpreter as IPTR
8 | from Context.context import Context
9 | import SymbolTable as S_Table
10 | from Results.runtime_result import RTResult
11 | from Values import *
12 | import os
13 | import time
14 | import random
15 |
16 |
17 | class BaseFunction(Value):
18 | def __init__(self, name):
19 | super().__init__()
20 | self.name = name or ""
21 |
22 | def generate_new_context(self):
23 | new_context = Context(self.name, self.context, self.pos_start)
24 | new_context.symbol_table = S_Table.symbol_table.SymbolTable(
25 | new_context.parent.symbol_table
26 | )
27 | return new_context
28 |
29 | def check_args(self, arg_names, args):
30 | res = RTResult()
31 |
32 | if len(args) > len(arg_names):
33 | return res.failure(
34 | RTError(
35 | self.pos_start,
36 | self.pos_end,
37 | f"{len(args) - len(arg_names)} too many args passed into {self}",
38 | self.context,
39 | )
40 | )
41 |
42 | if len(args) < len(arg_names):
43 | return res.failure(
44 | RTError(
45 | self.pos_start,
46 | self.pos_end,
47 | f"{len(arg_names) - len(args)} too few args passed into {self}",
48 | self.context,
49 | )
50 | )
51 |
52 | return res.success(None)
53 |
54 | def populate_args(self, arg_names, args, exec_ctx):
55 | for i in range(len(args)):
56 | arg_name = arg_names[i]
57 | arg_value = args[i]
58 | arg_value.set_context(exec_ctx)
59 | exec_ctx.symbol_table.set(arg_name, arg_value)
60 |
61 | def check_and_populate_args(self, arg_names, args, exec_ctx):
62 | res = RTResult()
63 | res.register(self.check_args(arg_names, args))
64 | if res.should_return():
65 | return res
66 | self.populate_args(arg_names, args, exec_ctx)
67 | return res.success(None)
68 |
69 |
70 | class Function(BaseFunction):
71 | def __init__(self, name, body_node, arg_names, should_auto_return):
72 | super().__init__(name)
73 | self.body_node = body_node
74 | self.arg_names = arg_names
75 | self.should_auto_return = should_auto_return
76 |
77 | def execute(self, args):
78 | res = RTResult()
79 | interpreter = IPTR.Interpreter()
80 | exec_ctx = self.generate_new_context()
81 |
82 | res.register(self.check_and_populate_args(self.arg_names, args, exec_ctx))
83 | if res.should_return():
84 | return res
85 |
86 | value = res.register(interpreter.visit(self.body_node, exec_ctx))
87 | if res.should_return() and res.func_return_value == None:
88 | return res
89 |
90 | ret_value = (value if self.should_auto_return else None) or res.func_return_value or Number.null
91 | return res.success(ret_value)
92 |
93 | def copy(self):
94 | copy = Function(
95 | self.name, self.body_node, self.arg_names, self.should_auto_return
96 | )
97 | copy.set_context(self.context)
98 | copy.set_pos(self.pos_start, self.pos_end)
99 | return copy
100 |
101 | def __repr__(self):
102 | return f""
103 |
104 |
105 | class BuiltInFunction(BaseFunction):
106 | def __init__(self, name):
107 | super().__init__(name)
108 |
109 | def execute(self, args):
110 | res = RTResult()
111 | exec_ctx = self.generate_new_context()
112 |
113 | method_name = f"execute_{self.name}"
114 | method = getattr(self, method_name, self.no_visit_method)
115 |
116 | res.register(self.check_and_populate_args(method.arg_names, args, exec_ctx))
117 | if res.should_return():
118 | return res
119 |
120 | return_value = res.register(method(exec_ctx))
121 | if res.should_return():
122 | return res
123 | return res.success(return_value)
124 |
125 | def no_visit_method(self, node, context):
126 | raise Exception(f"No execute_{self.name} method defined")
127 |
128 | def copy(self):
129 | copy = BuiltInFunction(self.name)
130 | copy.set_context(self.context)
131 | copy.set_pos(self.pos_start, self.pos_end)
132 | return copy
133 |
134 | def __repr__(self):
135 | return f""
136 |
137 | #####################################
138 |
139 | def execute_print(self, exec_ctx):
140 | print(str(exec_ctx.symbol_table.get("value")),end="")
141 | return RTResult().success(Number.null)
142 |
143 | execute_print.arg_names = ["value"]
144 |
145 |
146 | def execute_print_ret(self, exec_ctx):
147 | return RTResult().success(String(str(exec_ctx.symbol_table.get("value"))))
148 |
149 | execute_print_ret.arg_names = ["value"]
150 |
151 | def execute_input(self, exec_ctx):
152 | text = input()
153 | return RTResult().success(String(text))
154 |
155 | execute_input.arg_names = []
156 |
157 | def execute_input_int(self, exec_ctx):
158 | while True:
159 | text = input()
160 | try:
161 | number = int(text)
162 | break
163 | except ValueError:
164 | print(f"'{text}' must be an integer. Try again!")
165 | return RTResult().success(Number(number))
166 |
167 | execute_input_int.arg_names = []
168 |
169 | def execute_clear(self, exec_ctx):
170 | os.system("cls" if os.name == "nt" else "clear")
171 | return RTResult().success(Number.null)
172 |
173 | execute_clear.arg_names = []
174 |
175 | def execute_is_number(self, exec_ctx):
176 | is_number = isinstance(exec_ctx.symbol_table.get("value"), Number)
177 | return RTResult().success(Number.true if is_number else Number.false)
178 |
179 | execute_is_number.arg_names = ["value"]
180 |
181 | def execute_is_string(self, exec_ctx):
182 | is_number = isinstance(exec_ctx.symbol_table.get("value"), String)
183 | return RTResult().success(Number.true if is_number else Number.false)
184 |
185 | execute_is_string.arg_names = ["value"]
186 |
187 | def execute_is_list(self, exec_ctx):
188 | is_number = isinstance(exec_ctx.symbol_table.get("value"), List)
189 | return RTResult().success(Number.true if is_number else Number.false)
190 |
191 | execute_is_list.arg_names = ["value"]
192 |
193 | def execute_is_function(self, exec_ctx):
194 | is_number = isinstance(exec_ctx.symbol_table.get("value"), BaseFunction)
195 | return RTResult().success(Number.true if is_number else Number.false)
196 |
197 | execute_is_function.arg_names = ["value"]
198 |
199 | def execute_append(self, exec_ctx):
200 | list_ = exec_ctx.symbol_table.get("list")
201 | value = exec_ctx.symbol_table.get("value")
202 |
203 | if not isinstance(list_, List):
204 | return RTResult().failure(
205 | RTError(
206 | self.pos_start,
207 | self.pos_end,
208 | "First argument must be list",
209 | exec_ctx,
210 | )
211 | )
212 |
213 | list_.elements.append(value)
214 | return RTResult().success(Number.null)
215 |
216 | execute_append.arg_names = ["list", "value"]
217 |
218 | def execute_pop(self, exec_ctx):
219 | list_ = exec_ctx.symbol_table.get("list")
220 | index = exec_ctx.symbol_table.get("index")
221 |
222 | if not isinstance(list_, List):
223 | return RTResult().failure(
224 | RTError(
225 | self.pos_start,
226 | self.pos_end,
227 | "First argument must be list",
228 | exec_ctx,
229 | )
230 | )
231 |
232 | if not isinstance(index, Number):
233 | return RTResult().failure(
234 | RTError(
235 | self.pos_start,
236 | self.pos_end,
237 | "Second argument must be number",
238 | exec_ctx,
239 | )
240 | )
241 |
242 | try:
243 | element = list_.elements.pop(index.value)
244 | except:
245 | return RTResult().failure(
246 | RTError(
247 | self.pos_start,
248 | self.pos_end,
249 | "Element at this index could not be removed from list because index is out of bounds",
250 | exec_ctx,
251 | )
252 | )
253 | return RTResult().success(element)
254 |
255 | execute_pop.arg_names = ["list", "index"]
256 |
257 | def execute_extend(self, exec_ctx):
258 | listA = exec_ctx.symbol_table.get("listA")
259 | listB = exec_ctx.symbol_table.get("listB")
260 |
261 | if not isinstance(listA, List):
262 | return RTResult().failure(
263 | RTError(
264 | self.pos_start,
265 | self.pos_end,
266 | "First argument must be list",
267 | exec_ctx,
268 | )
269 | )
270 |
271 | if not isinstance(listB, List):
272 | return RTResult().failure(
273 | RTError(
274 | self.pos_start,
275 | self.pos_end,
276 | "Second argument must be list",
277 | exec_ctx,
278 | )
279 | )
280 |
281 | listA.elements.extend(listB.elements)
282 | return RTResult().success(Number.null)
283 |
284 | execute_extend.arg_names = ["listA", "listB"]
285 |
286 |
287 | def execute_len(self, exec_ctx):
288 | list_ = exec_ctx.symbol_table.get("list")
289 |
290 | if not isinstance(list_, List):
291 | return RTResult().failure(
292 | RTError(
293 | self.pos_start,
294 | self.pos_end,
295 | "Argument must be list",
296 | exec_ctx,
297 | )
298 | )
299 |
300 | return RTResult().success(Number(len(list_.elements)))
301 |
302 | execute_len.arg_names = ["list"]
303 |
304 | def execute_sleep(self, exec_ctx):
305 | value_ = exec_ctx.symbol_table.get("time")
306 |
307 | if not isinstance(value_, Number):
308 | return RTResult().failure(
309 | RTError(
310 | self.pos_start,
311 | self.pos_end,
312 | "Argument must be Number",
313 | exec_ctx,
314 | )
315 | )
316 |
317 | time.sleep(value_.value)
318 | return RTResult().success(Number.null)
319 |
320 | execute_sleep.arg_names = ["time"]
321 |
322 | def execute_rand(self, exec_ctx):
323 | MIN = exec_ctx.symbol_table.get("MIN")
324 | MAX = exec_ctx.symbol_table.get("MAX")
325 | RAND = random.randint(MIN.value,MAX.value)
326 |
327 | return RTResult().success(Number(RAND))
328 |
329 | execute_rand.arg_names = ["MIN", "MAX"]
330 |
331 |
332 | BuiltInFunction.print = BuiltInFunction("print")
333 | BuiltInFunction.print_ret = BuiltInFunction("print_ret")
334 | BuiltInFunction.input = BuiltInFunction("input")
335 | BuiltInFunction.input_int = BuiltInFunction("input_int")
336 | BuiltInFunction.clear = BuiltInFunction("clear")
337 | BuiltInFunction.is_number = BuiltInFunction("is_number")
338 | BuiltInFunction.is_string = BuiltInFunction("is_string")
339 | BuiltInFunction.is_list = BuiltInFunction("is_list")
340 | BuiltInFunction.is_function = BuiltInFunction("is_function")
341 | BuiltInFunction.append = BuiltInFunction("append")
342 | BuiltInFunction.pop = BuiltInFunction("pop")
343 | BuiltInFunction.extend = BuiltInFunction("extend")
344 | BuiltInFunction.len = BuiltInFunction("len")
345 | BuiltInFunction.sleep = BuiltInFunction("sleep")
346 | BuiltInFunction.rand = BuiltInFunction("rand")
347 |
348 |
349 | S_Table.global_symbol_table.set("PRINT", BuiltInFunction.print)
350 | S_Table.global_symbol_table.set("दाखवा", BuiltInFunction.print)
351 |
352 | S_Table.global_symbol_table.set("PRINT_RET", BuiltInFunction.print_ret)
353 | S_Table.global_symbol_table.set("दाखवा_आणि_परत", BuiltInFunction.print_ret)
354 |
355 | S_Table.global_symbol_table.set("INPUT", BuiltInFunction.input)
356 | S_Table.global_symbol_table.set("इनपुट", BuiltInFunction.input)
357 |
358 | S_Table.global_symbol_table.set("INPUT_INT", BuiltInFunction.input_int)
359 | S_Table.global_symbol_table.set("इनपुट_संख्या", BuiltInFunction.input_int)
360 |
361 | S_Table.global_symbol_table.set("CLEAR", BuiltInFunction.clear)
362 | S_Table.global_symbol_table.set("पुसा", BuiltInFunction.clear)
363 |
364 | S_Table.global_symbol_table.set("IS_NUM", BuiltInFunction.is_number)
365 | S_Table.global_symbol_table.set("संख्या_आहे", BuiltInFunction.is_number)
366 |
367 | S_Table.global_symbol_table.set("IS_STR", BuiltInFunction.is_string)
368 | S_Table.global_symbol_table.set("शब्दांचीदोरी_आहे", BuiltInFunction.is_string)
369 |
370 | S_Table.global_symbol_table.set("IS_LIST", BuiltInFunction.is_list)
371 | S_Table.global_symbol_table.set("यादी_आहे", BuiltInFunction.is_list)
372 |
373 | S_Table.global_symbol_table.set("IS_FUN", BuiltInFunction.is_function)
374 | S_Table.global_symbol_table.set("कार्य_आहे", BuiltInFunction.is_function)
375 |
376 | S_Table.global_symbol_table.set("APPEND", BuiltInFunction.append)
377 | S_Table.global_symbol_table.set("जोडा", BuiltInFunction.append)
378 |
379 | S_Table.global_symbol_table.set("POP", BuiltInFunction.pop)
380 | S_Table.global_symbol_table.set("काढा", BuiltInFunction.pop)
381 |
382 | S_Table.global_symbol_table.set("EXTEND", BuiltInFunction.extend)
383 | S_Table.global_symbol_table.set("वाढवा", BuiltInFunction.extend)
384 |
385 |
386 | S_Table.global_symbol_table.set("LEN", BuiltInFunction.len)
387 | S_Table.global_symbol_table.set("लांबी", BuiltInFunction.len)
388 |
389 |
390 | S_Table.global_symbol_table.set("SLEEP", BuiltInFunction.sleep)
391 | S_Table.global_symbol_table.set("झोप", BuiltInFunction.sleep)
392 |
393 |
394 | S_Table.global_symbol_table.set("RAND_INT", BuiltInFunction.rand)
395 |
396 |
--------------------------------------------------------------------------------
/values/list.py:
--------------------------------------------------------------------------------
1 | from typing import NewType
2 | from Values.value import Value
3 | from Errors import RTError, errors
4 | from Translate import Translate
5 | from Values.number import Number
6 |
7 | class List(Value):
8 | def __init__(self, elements):
9 | super().__init__()
10 | self.elements = elements
11 |
12 | def added_to(self, other):
13 | new_list = self.copy()
14 | new_list.elements.append(other)
15 | return new_list, None
16 |
17 | def subbed_by(self, other):
18 | if isinstance(other, Number):
19 | new_list = self.copy()
20 | try:
21 | new_list.elements.pop(other.value)
22 | return new_list, None
23 | except:
24 | return None, RTError(
25 | other.pos_start, other.pos_end,
26 | 'Element at this index could not be removed from list because index is out of bounds',
27 | self.context
28 | )
29 | else:
30 | return None, Value.illegal_operation(self, other)
31 |
32 | def multed_by(self, other):
33 | if isinstance(other, List):
34 | new_list = self.copy()
35 | new_list.elements.extend(other.elements)
36 | return new_list, None
37 | else:
38 | return None, Value.illegal_operation(self, other)
39 |
40 | def dived_by(self, other):
41 | if isinstance(other, Number):
42 | try:
43 | return self.elements[other.value], None
44 | except:
45 | return None, RTError(
46 | other.pos_start, other.pos_end,
47 | 'Element at this index could not be retrieved from list because index is out of bounds',
48 | self.context
49 | )
50 | else:
51 | return None, Value.illegal_operation(self, other)
52 | def copy(self):
53 | copy = List(self.elements)
54 | copy.set_pos(self.pos_start, self.pos_end)
55 | copy.set_context(self.context)
56 | return copy
57 |
58 |
59 | def __len__(self):
60 | return len(self.elements)
61 |
62 | def __getitem__(self,index):
63 | return self.elements[index]
64 |
65 | def __repr__(self):
66 | return f'[{", ".join([str(x) for x in self.elements])}]'
67 |
68 |
69 |
--------------------------------------------------------------------------------
/values/number.py:
--------------------------------------------------------------------------------
1 | from Values.value import Value
2 | from Errors import RTError
3 | from Translate import Translate
4 | #------------Values-----------------
5 | class Number(Value):
6 | def __init__(self, value):
7 | super().__init__()
8 | self.value = value
9 | self.translate = Translate()
10 |
11 | def set_pos(self, pos_start=None, pos_end=None):
12 | self.pos_start = pos_start
13 | self.pos_end = pos_end
14 | return self
15 |
16 | def set_context(self, context=None):
17 | self.context = context
18 | return self
19 |
20 | def added_to(self, other):
21 | if isinstance(other, Number):
22 | return Number(self.value + other.value).set_context(self.context), None
23 | else:
24 | return None, Value.illegal_operation(self, other)
25 |
26 | def subbed_by(self, other):
27 | if isinstance(other, Number):
28 | return Number(self.value - other.value).set_context(self.context), None
29 | else:
30 | return None, Value.illegal_operation(self, other)
31 |
32 | def multed_by(self, other):
33 | if isinstance(other, Number):
34 | return Number(self.value * other.value).set_context(self.context), None
35 | else:
36 | return None, Value.illegal_operation(self, other)
37 |
38 | def dived_by(self, other):
39 | if isinstance(other, Number):
40 | if other.value == 0:
41 | return None, RTError(
42 | other.pos_start, other.pos_end,
43 | 'Division by zero',
44 | self.context
45 | )
46 | div = self.value / other.value
47 | #👇convert float->int if if int==float
48 | div = int(div) if int(div)==div else div
49 | return Number(div).set_context(self.context), None
50 | else:
51 | return None, Value.illegal_operation(self, other)
52 | def moded_by(self, other):
53 | if isinstance(other, Number):
54 | if other.value == 0:
55 | return None, RTError(
56 | other.pos_start, other.pos_end,
57 | 'Mod by zero',
58 | self.context
59 | )
60 | div = self.value % other.value
61 | #👇convert float->int if if int==float
62 | div = int(div) if int(div)==div else div
63 | return Number(div).set_context(self.context), None
64 | else:
65 | return None, Value.illegal_operation(self, other)
66 |
67 | def power_by(self,other):
68 | if isinstance(other,Number):
69 | return Number(self.value ** other.value).set_context(self.context), None
70 | else:
71 | return None, Value.illegal_operation(self, other)
72 |
73 | def get_comparison_eq(self, other):
74 | if isinstance(other, Number):
75 | return Number(int(self.value == other.value)).set_context(self.context), None
76 | else:
77 | return None, Value.illegal_operation(self, other)
78 |
79 | def get_comparison_ne(self, other):
80 | if isinstance(other, Number):
81 | return Number(int(self.value != other.value)).set_context(self.context), None
82 | else:
83 | return None, Value.illegal_operation(self, other)
84 |
85 | def get_comparison_lt(self, other):
86 | if isinstance(other, Number):
87 | return Number(int(self.value < other.value)).set_context(self.context), None
88 | else:
89 | return None, Value.illegal_operation(self, other)
90 |
91 | def get_comparison_gt(self, other):
92 | if isinstance(other, Number):
93 | return Number(int(self.value > other.value)).set_context(self.context), None
94 | else:
95 | return None, Value.illegal_operation(self, other)
96 |
97 | def get_comparison_lte(self, other):
98 | if isinstance(other, Number):
99 | return Number(int(self.value <= other.value)).set_context(self.context), None
100 | else:
101 | return None, Value.illegal_operation(self, other)
102 |
103 | def get_comparison_gte(self, other):
104 | if isinstance(other, Number):
105 | return Number(int(self.value >= other.value)).set_context(self.context), None
106 | else:
107 | return None, Value.illegal_operation(self, other)
108 |
109 | def anded_by(self, other):
110 | if isinstance(other, Number):
111 | return Number(int(self.value and other.value)).set_context(self.context), None
112 | else:
113 | return None, Value.illegal_operation(self, other)
114 |
115 | def ored_by(self, other):
116 | if isinstance(other, Number):
117 | return Number(int(self.value or other.value)).set_context(self.context), None
118 | else:
119 | return None, Value.illegal_operation(self, other)
120 |
121 | def notted(self):
122 | return Number(1 if self.value == 0 else 0).set_context(self.context), None
123 |
124 | def copy(self):
125 | copy = Number(self.value)
126 | copy.set_pos(self.pos_start, self.pos_end)
127 | copy.set_context(self.context)
128 | return copy
129 | def is_true(self):
130 | return self.value != 0
131 |
132 | def __repr__(self):
133 | return str(self.translate.number_to_mar(self.value))
134 |
135 | Number.null = Number(0)
136 | Number.false = Number(0)
137 | Number.true = Number(1)
--------------------------------------------------------------------------------
/values/string.py:
--------------------------------------------------------------------------------
1 | from Values.value import Value
2 | from Errors import RTError
3 | from Translate import Translate
4 | from Values.number import Number
5 |
6 |
7 | class String(Value):
8 | def __init__(self, value):
9 | super().__init__()
10 | self.value = value
11 |
12 | def added_to(self, other):
13 | if isinstance(other, String):
14 | return String(self.value + other.value).set_context(self.context), None
15 | else:
16 | return None, Value.illegal_operation(self, other)
17 |
18 | def multed_by(self, other):
19 | if isinstance(other, Number):
20 | return String(self.value * other.value).set_context(self.context), None
21 | else:
22 | return None, Value.illegal_operation(self, other)
23 |
24 | def is_true(self):
25 | return len(self.value) > 0
26 |
27 | def copy(self):
28 | copy = String(self.value)
29 | copy.set_pos(self.pos_start, self.pos_end)
30 | copy.set_context(self.context)
31 | return copy
32 |
33 | def __str__(self):
34 | return self.value
35 |
36 | def __repr__(self):
37 | return f'"{self.value}"'
38 |
--------------------------------------------------------------------------------
/values/value.py:
--------------------------------------------------------------------------------
1 | from Errors import RTError
2 | class Value:
3 | def __init__(self):
4 | self.set_pos()
5 | self.set_context()
6 |
7 | def set_pos(self, pos_start=None, pos_end=None):
8 | self.pos_start = pos_start
9 | self.pos_end = pos_end
10 | return self
11 |
12 | def set_context(self, context=None):
13 | self.context = context
14 | return self
15 |
16 | def added_to(self, other):
17 | return None, self.illegal_operation(other)
18 |
19 | def subbed_by(self, other):
20 | return None, self.illegal_operation(other)
21 |
22 | def multed_by(self, other):
23 | return None, self.illegal_operation(other)
24 |
25 | def dived_by(self, other):
26 | return None, self.illegal_operation(other)
27 |
28 | def powed_by(self, other):
29 | return None, self.illegal_operation(other)
30 |
31 | def get_comparison_eq(self, other):
32 | return None, self.illegal_operation(other)
33 |
34 | def get_comparison_ne(self, other):
35 | return None, self.illegal_operation(other)
36 |
37 | def get_comparison_lt(self, other):
38 | return None, self.illegal_operation(other)
39 |
40 | def get_comparison_gt(self, other):
41 | return None, self.illegal_operation(other)
42 |
43 | def get_comparison_lte(self, other):
44 | return None, self.illegal_operation(other)
45 |
46 | def get_comparison_gte(self, other):
47 | return None, self.illegal_operation(other)
48 |
49 | def anded_by(self, other):
50 | return None, self.illegal_operation(other)
51 |
52 | def ored_by(self, other):
53 | return None, self.illegal_operation(other)
54 |
55 | def notted(self):
56 | return None, self.illegal_operation(other)
57 |
58 | def execute(self, args):
59 | return RTResult().failure(self.illegal_operation())
60 |
61 | def copy(self):
62 | raise Exception('No copy method defined')
63 |
64 | def is_true(self):
65 | return False
66 |
67 | def illegal_operation(self, other=None):
68 | if not other: other = self
69 | return RTError(
70 | self.pos_start, other.pos_end,
71 | 'Illegal operation',
72 | self.context
73 | )
--------------------------------------------------------------------------------