├── README.md ├── bebra.py ├── examples ├── bif.bbr ├── example.bbr ├── example2.bbr └── loop.bbr ├── shell.py └── strings_with_arrows.py /README.md: -------------------------------------------------------------------------------- 1 | # PyBebra 2 | Беброчный язык программирования 3 | 4 | Создан по рофлу, не воспринимайте его всерьёз! 5 | 6 | # Использование 7 | **Создай файл - `test.bbr`** 8 | ```py 9 | bebra("Привет Бебромир!") 10 | ``` 11 | **Запуск** 12 | 13 | ```py 14 | python shell.py 15 | > lopata("test.bbr") 16 | ``` 17 | 18 | # Беброчная документация 19 | 20 | **Главное** 21 | 22 | `python shell.py` открывает консоль. Команда запуска `lopata("test.bbr")` 23 | 24 | **Переменные** 25 | 26 | Переменные создаются с помощью ключевого слова `beb` 27 | 28 | ```py 29 | beb a = 100 30 | beb b = 50 31 | beb v = a + b 32 | beb g = v * b 33 | 34 | bebra(v) 35 | bebra(g) 36 | ``` 37 | 38 | Вывод: 39 | ``` 40 | 150 41 | 7500 42 | ``` 43 | 44 | **Условия** 45 | 46 | Если - bif, или - belif, иначе - belse 47 | 48 | ```py 49 | beb a = 100 50 | 51 | bif a == 100 thenb bebra("a = 100") belse bebra("a не = 100") 52 | ``` 53 | 54 | Вывод: 55 | ``` 56 | а = 100 57 | ``` 58 | 59 | **Циклы** 60 | 61 | ```py 62 | lopt i = 0 to 5 thenb 63 | bebra("привет") 64 | bend 65 | ``` 66 | 67 | Вывод: 68 | ``` 69 | привет 70 | привет 71 | привет 72 | привет 73 | привет 74 | ``` 75 | 76 | **Функции** 77 | 78 | ```py 79 | bfunc pybebra(a) -> a + "Bebra" 80 | 81 | bebra(pybebra("Это Py")) 82 | ``` 83 | 84 | Вывод: 85 | ``` 86 | Это PyBebra 87 | ``` 88 | 89 | # Конец 90 | Это беброчный конец файла ридми! Удачного беброиспользования! 91 | -------------------------------------------------------------------------------- /bebra.py: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # IMPORTS 3 | ####################################### 4 | 5 | from strings_with_arrows import * 6 | 7 | import string 8 | import os 9 | import math 10 | 11 | ####################################### 12 | # CONSTANTS 13 | ####################################### 14 | 15 | DIGITS = '0123456789' 16 | LETTERS = string.ascii_letters 17 | LETTERS_DIGITS = LETTERS + DIGITS 18 | 19 | ####################################### 20 | # ERRORS 21 | ####################################### 22 | 23 | class Error: 24 | def __init__(self, pos_start, pos_end, error_name, details): 25 | self.pos_start = pos_start 26 | self.pos_end = pos_end 27 | self.error_name = error_name 28 | self.details = details 29 | 30 | def as_string(self): 31 | result = f'{self.error_name}: {self.details}\n' 32 | result += f'File {self.pos_start.fn}, line {self.pos_start.ln + 1}' 33 | result += '\n\n' + string_with_arrows(self.pos_start.ftxt, self.pos_start, self.pos_end) 34 | return result 35 | 36 | class IllegalCharError(Error): 37 | def __init__(self, pos_start, pos_end, details): 38 | super().__init__(pos_start, pos_end, 'Illegal Character', details) 39 | 40 | class ExpectedCharError(Error): 41 | def __init__(self, pos_start, pos_end, details): 42 | super().__init__(pos_start, pos_end, 'Expected Character', details) 43 | 44 | class InvalidSyntaxError(Error): 45 | def __init__(self, pos_start, pos_end, details=''): 46 | super().__init__(pos_start, pos_end, 'Invalid Syntax', details) 47 | 48 | class RTError(Error): 49 | def __init__(self, pos_start, pos_end, details, context): 50 | super().__init__(pos_start, pos_end, 'Runtime Error', details) 51 | self.context = context 52 | 53 | def as_string(self): 54 | result = self.generate_traceback() 55 | result += f'{self.error_name}: {self.details}' 56 | result += '\n\n' + string_with_arrows(self.pos_start.ftxt, self.pos_start, self.pos_end) 57 | return result 58 | 59 | def generate_traceback(self): 60 | result = '' 61 | pos = self.pos_start 62 | ctx = self.context 63 | 64 | while ctx: 65 | result = f' File {pos.fn}, line {str(pos.ln + 1)}, in {ctx.display_name}\n' + result 66 | pos = ctx.parent_entry_pos 67 | ctx = ctx.parent 68 | 69 | return 'Traceback (most recent call last):\n' + result 70 | 71 | ####################################### 72 | # POSITION 73 | ####################################### 74 | 75 | class Position: 76 | def __init__(self, idx, ln, col, fn, ftxt): 77 | self.idx = idx 78 | self.ln = ln 79 | self.col = col 80 | self.fn = fn 81 | self.ftxt = ftxt 82 | 83 | def advance(self, current_char=None): 84 | self.idx += 1 85 | self.col += 1 86 | 87 | if current_char == '\n': 88 | self.ln += 1 89 | self.col = 0 90 | 91 | return self 92 | 93 | def copy(self): 94 | return Position(self.idx, self.ln, self.col, self.fn, self.ftxt) 95 | 96 | ####################################### 97 | # TOKENS 98 | ####################################### 99 | 100 | TT_INT = 'INT' 101 | TT_FLOAT = 'FLOAT' 102 | TT_STRING = 'STRING' 103 | TT_IDENTIFIER = 'IDENTIFIER' 104 | TT_KEYWORD = 'KEYWORD' 105 | TT_PLUS = 'PLUS' 106 | TT_MINUS = 'MINUS' 107 | TT_MUL = 'MUL' 108 | TT_DIV = 'DIV' 109 | TT_POW = 'POW' 110 | TT_EQ = 'EQ' 111 | TT_LPAREN = 'LPAREN' 112 | TT_RPAREN = 'RPAREN' 113 | TT_LSQUARE = 'LSQUARE' 114 | TT_RSQUARE = 'RSQUARE' 115 | TT_EE = 'EE' 116 | TT_NE = 'NE' 117 | TT_LT = 'LT' 118 | TT_GT = 'GT' 119 | TT_LTE = 'LTE' 120 | TT_GTE = 'GTE' 121 | TT_COMMA = 'COMMA' 122 | TT_ARROW = 'ARROW' 123 | TT_NEWLINE = 'NEWLINE' 124 | TT_EOF = 'EOF' 125 | 126 | KEYWORDS = [ 127 | 'beb', 128 | 'and', 129 | 'or', 130 | 'not', 131 | 'bif', 132 | 'belif', 133 | 'belse', 134 | 'lopt', 135 | 'to', 136 | 'step', 137 | 'bebhile', 138 | 'bfunc', 139 | 'thenb', 140 | 'bend', 141 | 'breturn', 142 | 'contin', 143 | 'bbreak', 144 | ] 145 | 146 | class Token: 147 | def __init__(self, type_, value=None, pos_start=None, pos_end=None): 148 | self.type = type_ 149 | self.value = value 150 | 151 | if pos_start: 152 | self.pos_start = pos_start.copy() 153 | self.pos_end = pos_start.copy() 154 | self.pos_end.advance() 155 | 156 | if pos_end: 157 | self.pos_end = pos_end.copy() 158 | 159 | def matches(self, type_, value): 160 | return self.type == type_ and self.value == value 161 | 162 | def __repr__(self): 163 | if self.value: return f'{self.type}:{self.value}' 164 | return f'{self.type}' 165 | 166 | ####################################### 167 | # LEXER 168 | ####################################### 169 | 170 | class Lexer: 171 | def __init__(self, fn, text): 172 | self.fn = fn 173 | self.text = text 174 | self.pos = Position(-1, 0, -1, fn, text) 175 | self.current_char = None 176 | self.advance() 177 | 178 | def advance(self): 179 | self.pos.advance(self.current_char) 180 | self.current_char = self.text[self.pos.idx] if self.pos.idx < len(self.text) else None 181 | 182 | def make_tokens(self): 183 | tokens = [] 184 | 185 | while self.current_char != None: 186 | if self.current_char in ' \t': 187 | self.advance() 188 | elif self.current_char == '#': 189 | self.skip_comment() 190 | elif self.current_char in ';\n': 191 | tokens.append(Token(TT_NEWLINE, pos_start=self.pos)) 192 | self.advance() 193 | elif self.current_char in DIGITS: 194 | tokens.append(self.make_number()) 195 | elif self.current_char in LETTERS: 196 | tokens.append(self.make_identifier()) 197 | elif self.current_char == '"': 198 | tokens.append(self.make_string()) 199 | elif self.current_char == '+': 200 | tokens.append(Token(TT_PLUS, pos_start=self.pos)) 201 | self.advance() 202 | elif self.current_char == '-': 203 | tokens.append(self.make_minus_or_arrow()) 204 | elif self.current_char == '*': 205 | tokens.append(Token(TT_MUL, pos_start=self.pos)) 206 | self.advance() 207 | elif self.current_char == '/': 208 | tokens.append(Token(TT_DIV, pos_start=self.pos)) 209 | self.advance() 210 | elif self.current_char == '^': 211 | tokens.append(Token(TT_POW, pos_start=self.pos)) 212 | self.advance() 213 | elif self.current_char == '(': 214 | tokens.append(Token(TT_LPAREN, pos_start=self.pos)) 215 | self.advance() 216 | elif self.current_char == ')': 217 | tokens.append(Token(TT_RPAREN, pos_start=self.pos)) 218 | self.advance() 219 | elif self.current_char == '[': 220 | tokens.append(Token(TT_LSQUARE, pos_start=self.pos)) 221 | self.advance() 222 | elif self.current_char == ']': 223 | tokens.append(Token(TT_RSQUARE, pos_start=self.pos)) 224 | self.advance() 225 | elif self.current_char == '!': 226 | token, error = self.make_not_equals() 227 | if error: return [], error 228 | tokens.append(token) 229 | elif self.current_char == '=': 230 | tokens.append(self.make_equals()) 231 | elif self.current_char == '<': 232 | tokens.append(self.make_less_than()) 233 | elif self.current_char == '>': 234 | tokens.append(self.make_greater_than()) 235 | elif self.current_char == ',': 236 | tokens.append(Token(TT_COMMA, pos_start=self.pos)) 237 | self.advance() 238 | else: 239 | pos_start = self.pos.copy() 240 | char = self.current_char 241 | self.advance() 242 | return [], IllegalCharError(pos_start, self.pos, "'" + char + "'") 243 | 244 | tokens.append(Token(TT_EOF, pos_start=self.pos)) 245 | return tokens, None 246 | 247 | def make_number(self): 248 | num_str = '' 249 | dot_count = 0 250 | pos_start = self.pos.copy() 251 | 252 | while self.current_char != None and self.current_char in DIGITS + '.': 253 | if self.current_char == '.': 254 | if dot_count == 1: break 255 | dot_count += 1 256 | num_str += self.current_char 257 | self.advance() 258 | 259 | if dot_count == 0: 260 | return Token(TT_INT, int(num_str), pos_start, self.pos) 261 | else: 262 | return Token(TT_FLOAT, float(num_str), pos_start, self.pos) 263 | 264 | def make_string(self): 265 | string = '' 266 | pos_start = self.pos.copy() 267 | escape_character = False 268 | self.advance() 269 | 270 | escape_characters = { 271 | 'n': '\n', 272 | 't': '\t' 273 | } 274 | 275 | while self.current_char != None and (self.current_char != '"' or escape_character): 276 | if escape_character: 277 | string += escape_characters.get(self.current_char, self.current_char) 278 | else: 279 | if self.current_char == '\\': 280 | escape_character = True 281 | else: 282 | string += self.current_char 283 | self.advance() 284 | escape_character = False 285 | 286 | self.advance() 287 | return Token(TT_STRING, string, pos_start, self.pos) 288 | 289 | def make_identifier(self): 290 | id_str = '' 291 | pos_start = self.pos.copy() 292 | 293 | while self.current_char != None and self.current_char in LETTERS_DIGITS + '_': 294 | id_str += self.current_char 295 | self.advance() 296 | 297 | tok_type = TT_KEYWORD if id_str in KEYWORDS else TT_IDENTIFIER 298 | return Token(tok_type, id_str, pos_start, self.pos) 299 | 300 | def make_minus_or_arrow(self): 301 | tok_type = TT_MINUS 302 | pos_start = self.pos.copy() 303 | self.advance() 304 | 305 | if self.current_char == '>': 306 | self.advance() 307 | tok_type = TT_ARROW 308 | 309 | return Token(tok_type, pos_start=pos_start, pos_end=self.pos) 310 | 311 | def make_not_equals(self): 312 | pos_start = self.pos.copy() 313 | self.advance() 314 | 315 | if self.current_char == '=': 316 | self.advance() 317 | return Token(TT_NE, pos_start=pos_start, pos_end=self.pos), None 318 | 319 | self.advance() 320 | return None, ExpectedCharError(pos_start, self.pos, "'=' (after '!')") 321 | 322 | def make_equals(self): 323 | tok_type = TT_EQ 324 | pos_start = self.pos.copy() 325 | self.advance() 326 | 327 | if self.current_char == '=': 328 | self.advance() 329 | tok_type = TT_EE 330 | 331 | return Token(tok_type, pos_start=pos_start, pos_end=self.pos) 332 | 333 | def make_less_than(self): 334 | tok_type = TT_LT 335 | pos_start = self.pos.copy() 336 | self.advance() 337 | 338 | if self.current_char == '=': 339 | self.advance() 340 | tok_type = TT_LTE 341 | 342 | return Token(tok_type, pos_start=pos_start, pos_end=self.pos) 343 | 344 | def make_greater_than(self): 345 | tok_type = TT_GT 346 | pos_start = self.pos.copy() 347 | self.advance() 348 | 349 | if self.current_char == '=': 350 | self.advance() 351 | tok_type = TT_GTE 352 | 353 | return Token(tok_type, pos_start=pos_start, pos_end=self.pos) 354 | 355 | def skip_comment(self): 356 | self.advance() 357 | 358 | while self.current_char != '\n': 359 | self.advance() 360 | 361 | self.advance() 362 | 363 | ####################################### 364 | # NODES 365 | ####################################### 366 | 367 | class NumberNode: 368 | def __init__(self, tok): 369 | self.tok = tok 370 | 371 | self.pos_start = self.tok.pos_start 372 | self.pos_end = self.tok.pos_end 373 | 374 | def __repr__(self): 375 | return f'{self.tok}' 376 | 377 | class StringNode: 378 | def __init__(self, tok): 379 | self.tok = tok 380 | 381 | self.pos_start = self.tok.pos_start 382 | self.pos_end = self.tok.pos_end 383 | 384 | def __repr__(self): 385 | return f'{self.tok}' 386 | 387 | class ListNode: 388 | def __init__(self, element_nodes, pos_start, pos_end): 389 | self.element_nodes = element_nodes 390 | 391 | self.pos_start = pos_start 392 | self.pos_end = pos_end 393 | 394 | class VarAccessNode: 395 | def __init__(self, var_name_tok): 396 | self.var_name_tok = var_name_tok 397 | 398 | self.pos_start = self.var_name_tok.pos_start 399 | self.pos_end = self.var_name_tok.pos_end 400 | 401 | class VarAssignNode: 402 | def __init__(self, var_name_tok, value_node): 403 | self.var_name_tok = var_name_tok 404 | self.value_node = value_node 405 | 406 | self.pos_start = self.var_name_tok.pos_start 407 | self.pos_end = self.value_node.pos_end 408 | 409 | class BinOpNode: 410 | def __init__(self, left_node, op_tok, right_node): 411 | self.left_node = left_node 412 | self.op_tok = op_tok 413 | self.right_node = right_node 414 | 415 | self.pos_start = self.left_node.pos_start 416 | self.pos_end = self.right_node.pos_end 417 | 418 | def __repr__(self): 419 | return f'({self.left_node}, {self.op_tok}, {self.right_node})' 420 | 421 | class UnaryOpNode: 422 | def __init__(self, op_tok, node): 423 | self.op_tok = op_tok 424 | self.node = node 425 | 426 | self.pos_start = self.op_tok.pos_start 427 | self.pos_end = node.pos_end 428 | 429 | def __repr__(self): 430 | return f'({self.op_tok}, {self.node})' 431 | 432 | class IfNode: 433 | def __init__(self, cases, else_case): 434 | self.cases = cases 435 | self.else_case = else_case 436 | 437 | self.pos_start = self.cases[0][0].pos_start 438 | self.pos_end = (self.else_case or self.cases[len(self.cases) - 1])[0].pos_end 439 | 440 | class ForNode: 441 | def __init__(self, var_name_tok, start_value_node, end_value_node, step_value_node, body_node, should_return_null): 442 | self.var_name_tok = var_name_tok 443 | self.start_value_node = start_value_node 444 | self.end_value_node = end_value_node 445 | self.step_value_node = step_value_node 446 | self.body_node = body_node 447 | self.should_return_null = should_return_null 448 | 449 | self.pos_start = self.var_name_tok.pos_start 450 | self.pos_end = self.body_node.pos_end 451 | 452 | class WhileNode: 453 | def __init__(self, condition_node, body_node, should_return_null): 454 | self.condition_node = condition_node 455 | self.body_node = body_node 456 | self.should_return_null = should_return_null 457 | 458 | self.pos_start = self.condition_node.pos_start 459 | self.pos_end = self.body_node.pos_end 460 | 461 | class FuncDefNode: 462 | def __init__(self, var_name_tok, arg_name_toks, body_node, should_auto_return): 463 | self.var_name_tok = var_name_tok 464 | self.arg_name_toks = arg_name_toks 465 | self.body_node = body_node 466 | self.should_auto_return = should_auto_return 467 | 468 | if self.var_name_tok: 469 | self.pos_start = self.var_name_tok.pos_start 470 | elif len(self.arg_name_toks) > 0: 471 | self.pos_start = self.arg_name_toks[0].pos_start 472 | else: 473 | self.pos_start = self.body_node.pos_start 474 | 475 | self.pos_end = self.body_node.pos_end 476 | 477 | class CallNode: 478 | def __init__(self, node_to_call, arg_nodes): 479 | self.node_to_call = node_to_call 480 | self.arg_nodes = arg_nodes 481 | 482 | self.pos_start = self.node_to_call.pos_start 483 | 484 | if len(self.arg_nodes) > 0: 485 | self.pos_end = self.arg_nodes[len(self.arg_nodes) - 1].pos_end 486 | else: 487 | self.pos_end = self.node_to_call.pos_end 488 | 489 | class ReturnNode: 490 | def __init__(self, node_to_return, pos_start, pos_end): 491 | self.node_to_return = node_to_return 492 | 493 | self.pos_start = pos_start 494 | self.pos_end = pos_end 495 | 496 | class ContinueNode: 497 | def __init__(self, pos_start, pos_end): 498 | self.pos_start = pos_start 499 | self.pos_end = pos_end 500 | 501 | class BreakNode: 502 | def __init__(self, pos_start, pos_end): 503 | self.pos_start = pos_start 504 | self.pos_end = pos_end 505 | 506 | ####################################### 507 | # PARSE RESULT 508 | ####################################### 509 | 510 | class ParseResult: 511 | def __init__(self): 512 | self.error = None 513 | self.node = None 514 | self.last_registered_advance_count = 0 515 | self.advance_count = 0 516 | self.to_reverse_count = 0 517 | 518 | def register_advancement(self): 519 | self.last_registered_advance_count = 1 520 | self.advance_count += 1 521 | 522 | def register(self, res): 523 | self.last_registered_advance_count = res.advance_count 524 | self.advance_count += res.advance_count 525 | if res.error: self.error = res.error 526 | return res.node 527 | 528 | def try_register(self, res): 529 | if res.error: 530 | self.to_reverse_count = res.advance_count 531 | return None 532 | return self.register(res) 533 | 534 | def success(self, node): 535 | self.node = node 536 | return self 537 | 538 | def failure(self, error): 539 | if not self.error or self.last_registered_advance_count == 0: 540 | self.error = error 541 | return self 542 | 543 | ####################################### 544 | # PARSER 545 | ####################################### 546 | 547 | class Parser: 548 | def __init__(self, tokens): 549 | self.tokens = tokens 550 | self.tok_idx = -1 551 | self.advance() 552 | 553 | def advance(self): 554 | self.tok_idx += 1 555 | self.update_current_tok() 556 | return self.current_tok 557 | 558 | def reverse(self, amount=1): 559 | self.tok_idx -= amount 560 | self.update_current_tok() 561 | return self.current_tok 562 | 563 | def update_current_tok(self): 564 | if self.tok_idx >= 0 and self.tok_idx < len(self.tokens): 565 | self.current_tok = self.tokens[self.tok_idx] 566 | 567 | def parse(self): 568 | res = self.statements() 569 | if not res.error and self.current_tok.type != TT_EOF: 570 | return res.failure(InvalidSyntaxError( 571 | self.current_tok.pos_start, self.current_tok.pos_end, 572 | "Token cannot appear after previous tokens" 573 | )) 574 | return res 575 | 576 | ################################### 577 | 578 | def statements(self): 579 | res = ParseResult() 580 | statements = [] 581 | pos_start = self.current_tok.pos_start.copy() 582 | 583 | while self.current_tok.type == TT_NEWLINE: 584 | res.register_advancement() 585 | self.advance() 586 | 587 | statement = res.register(self.statement()) 588 | if res.error: return res 589 | statements.append(statement) 590 | 591 | more_statements = True 592 | 593 | while True: 594 | newline_count = 0 595 | while self.current_tok.type == TT_NEWLINE: 596 | res.register_advancement() 597 | self.advance() 598 | newline_count += 1 599 | if newline_count == 0: 600 | more_statements = False 601 | 602 | if not more_statements: break 603 | statement = res.try_register(self.statement()) 604 | if not statement: 605 | self.reverse(res.to_reverse_count) 606 | more_statements = False 607 | continue 608 | statements.append(statement) 609 | 610 | return res.success(ListNode( 611 | statements, 612 | pos_start, 613 | self.current_tok.pos_end.copy() 614 | )) 615 | 616 | def statement(self): 617 | res = ParseResult() 618 | pos_start = self.current_tok.pos_start.copy() 619 | 620 | if self.current_tok.matches(TT_KEYWORD, 'breturn'): 621 | res.register_advancement() 622 | self.advance() 623 | 624 | expr = res.try_register(self.expr()) 625 | if not expr: 626 | self.reverse(res.to_reverse_count) 627 | return res.success(ReturnNode(expr, pos_start, self.current_tok.pos_start.copy())) 628 | 629 | if self.current_tok.matches(TT_KEYWORD, 'contin'): 630 | res.register_advancement() 631 | self.advance() 632 | return res.success(ContinueNode(pos_start, self.current_tok.pos_start.copy())) 633 | 634 | if self.current_tok.matches(TT_KEYWORD, 'bbreak'): 635 | res.register_advancement() 636 | self.advance() 637 | return res.success(BreakNode(pos_start, self.current_tok.pos_start.copy())) 638 | 639 | expr = res.register(self.expr()) 640 | if res.error: 641 | return res.failure(InvalidSyntaxError( 642 | self.current_tok.pos_start, self.current_tok.pos_end, 643 | "Expected 'breturn', 'contin', 'bbreak', 'beb', 'bif', 'lopt', 'bebhile', 'bfunc', int, float, identifier, '+', '-', '(', '[' or 'not'" 644 | )) 645 | return res.success(expr) 646 | 647 | def expr(self): 648 | res = ParseResult() 649 | 650 | if self.current_tok.matches(TT_KEYWORD, 'beb'): 651 | res.register_advancement() 652 | self.advance() 653 | 654 | if self.current_tok.type != TT_IDENTIFIER: 655 | return res.failure(InvalidSyntaxError( 656 | self.current_tok.pos_start, self.current_tok.pos_end, 657 | "Expected identifier" 658 | )) 659 | 660 | var_name = self.current_tok 661 | res.register_advancement() 662 | self.advance() 663 | 664 | if self.current_tok.type != TT_EQ: 665 | return res.failure(InvalidSyntaxError( 666 | self.current_tok.pos_start, self.current_tok.pos_end, 667 | "Expected '='" 668 | )) 669 | 670 | res.register_advancement() 671 | self.advance() 672 | expr = res.register(self.expr()) 673 | if res.error: return res 674 | return res.success(VarAssignNode(var_name, expr)) 675 | 676 | node = res.register(self.bin_op(self.comp_expr, ((TT_KEYWORD, 'and'), (TT_KEYWORD, 'or')))) 677 | 678 | if res.error: 679 | return res.failure(InvalidSyntaxError( 680 | self.current_tok.pos_start, self.current_tok.pos_end, 681 | "Expected 'beb', 'bif', 'lopt', 'bebhile', 'bfunc', int, float, identifier, '+', '-', '(', '[' or 'not'" 682 | )) 683 | 684 | return res.success(node) 685 | 686 | def comp_expr(self): 687 | res = ParseResult() 688 | 689 | if self.current_tok.matches(TT_KEYWORD, 'not'): 690 | op_tok = self.current_tok 691 | res.register_advancement() 692 | self.advance() 693 | 694 | node = res.register(self.comp_expr()) 695 | if res.error: return res 696 | return res.success(UnaryOpNode(op_tok, node)) 697 | 698 | node = res.register(self.bin_op(self.arith_expr, (TT_EE, TT_NE, TT_LT, TT_GT, TT_LTE, TT_GTE))) 699 | 700 | if res.error: 701 | return res.failure(InvalidSyntaxError( 702 | self.current_tok.pos_start, self.current_tok.pos_end, 703 | "Expected int, float, identifier, '+', '-', '(', '[', 'bif', 'lopt', 'bebhile', 'bfunc' or 'not'" 704 | )) 705 | 706 | return res.success(node) 707 | 708 | def arith_expr(self): 709 | return self.bin_op(self.term, (TT_PLUS, TT_MINUS)) 710 | 711 | def term(self): 712 | return self.bin_op(self.factor, (TT_MUL, TT_DIV)) 713 | 714 | def factor(self): 715 | res = ParseResult() 716 | tok = self.current_tok 717 | 718 | if tok.type in (TT_PLUS, TT_MINUS): 719 | res.register_advancement() 720 | self.advance() 721 | factor = res.register(self.factor()) 722 | if res.error: return res 723 | return res.success(UnaryOpNode(tok, factor)) 724 | 725 | return self.power() 726 | 727 | def power(self): 728 | return self.bin_op(self.call, (TT_POW, ), self.factor) 729 | 730 | def call(self): 731 | res = ParseResult() 732 | atom = res.register(self.atom()) 733 | if res.error: return res 734 | 735 | if self.current_tok.type == TT_LPAREN: 736 | res.register_advancement() 737 | self.advance() 738 | arg_nodes = [] 739 | 740 | if self.current_tok.type == TT_RPAREN: 741 | res.register_advancement() 742 | self.advance() 743 | else: 744 | arg_nodes.append(res.register(self.expr())) 745 | if res.error: 746 | return res.failure(InvalidSyntaxError( 747 | self.current_tok.pos_start, self.current_tok.pos_end, 748 | "Expected ')', 'beb', 'bif', 'lopt', 'bebhile', 'bfunc', int, float, identifier, '+', '-', '(', '[' or 'not'" 749 | )) 750 | 751 | while self.current_tok.type == TT_COMMA: 752 | res.register_advancement() 753 | self.advance() 754 | 755 | arg_nodes.append(res.register(self.expr())) 756 | if res.error: return res 757 | 758 | if self.current_tok.type != TT_RPAREN: 759 | return res.failure(InvalidSyntaxError( 760 | self.current_tok.pos_start, self.current_tok.pos_end, 761 | f"Expected ',' or ')'" 762 | )) 763 | 764 | res.register_advancement() 765 | self.advance() 766 | return res.success(CallNode(atom, arg_nodes)) 767 | return res.success(atom) 768 | 769 | def atom(self): 770 | res = ParseResult() 771 | tok = self.current_tok 772 | 773 | if tok.type in (TT_INT, TT_FLOAT): 774 | res.register_advancement() 775 | self.advance() 776 | return res.success(NumberNode(tok)) 777 | 778 | elif tok.type == TT_STRING: 779 | res.register_advancement() 780 | self.advance() 781 | return res.success(StringNode(tok)) 782 | 783 | elif tok.type == TT_IDENTIFIER: 784 | res.register_advancement() 785 | self.advance() 786 | return res.success(VarAccessNode(tok)) 787 | 788 | elif tok.type == TT_LPAREN: 789 | res.register_advancement() 790 | self.advance() 791 | expr = res.register(self.expr()) 792 | if res.error: return res 793 | if self.current_tok.type == TT_RPAREN: 794 | res.register_advancement() 795 | self.advance() 796 | return res.success(expr) 797 | else: 798 | return res.failure(InvalidSyntaxError( 799 | self.current_tok.pos_start, self.current_tok.pos_end, 800 | "Expected ')'" 801 | )) 802 | 803 | elif tok.type == TT_LSQUARE: 804 | list_expr = res.register(self.list_expr()) 805 | if res.error: return res 806 | return res.success(list_expr) 807 | 808 | elif tok.matches(TT_KEYWORD, 'bif'): 809 | if_expr = res.register(self.if_expr()) 810 | if res.error: return res 811 | return res.success(if_expr) 812 | 813 | elif tok.matches(TT_KEYWORD, 'lopt'): 814 | for_expr = res.register(self.for_expr()) 815 | if res.error: return res 816 | return res.success(for_expr) 817 | 818 | elif tok.matches(TT_KEYWORD, 'bebhile'): 819 | while_expr = res.register(self.while_expr()) 820 | if res.error: return res 821 | return res.success(while_expr) 822 | 823 | elif tok.matches(TT_KEYWORD, 'bfunc'): 824 | func_def = res.register(self.func_def()) 825 | if res.error: return res 826 | return res.success(func_def) 827 | 828 | return res.failure(InvalidSyntaxError( 829 | tok.pos_start, tok.pos_end, 830 | "Expected int, float, identifier, '+', '-', '(', '[', bif', 'lopt', 'bebhile', 'bfunc'" 831 | )) 832 | 833 | def list_expr(self): 834 | res = ParseResult() 835 | element_nodes = [] 836 | pos_start = self.current_tok.pos_start.copy() 837 | 838 | if self.current_tok.type != TT_LSQUARE: 839 | return res.failure(InvalidSyntaxError( 840 | self.current_tok.pos_start, self.current_tok.pos_end, 841 | f"Expected '['" 842 | )) 843 | 844 | res.register_advancement() 845 | self.advance() 846 | 847 | if self.current_tok.type == TT_RSQUARE: 848 | res.register_advancement() 849 | self.advance() 850 | else: 851 | element_nodes.append(res.register(self.expr())) 852 | if res.error: 853 | return res.failure(InvalidSyntaxError( 854 | self.current_tok.pos_start, self.current_tok.pos_end, 855 | "Expected ']', 'beb', 'bif', 'lopt', 'bebhile', 'bfunc', int, float, identifier, '+', '-', '(', '[' or 'not'" 856 | )) 857 | 858 | while self.current_tok.type == TT_COMMA: 859 | res.register_advancement() 860 | self.advance() 861 | 862 | element_nodes.append(res.register(self.expr())) 863 | if res.error: return res 864 | 865 | if self.current_tok.type != TT_RSQUARE: 866 | return res.failure(InvalidSyntaxError( 867 | self.current_tok.pos_start, self.current_tok.pos_end, 868 | f"Expected ',' or ']'" 869 | )) 870 | 871 | res.register_advancement() 872 | self.advance() 873 | 874 | return res.success(ListNode( 875 | element_nodes, 876 | pos_start, 877 | self.current_tok.pos_end.copy() 878 | )) 879 | 880 | def if_expr(self): 881 | res = ParseResult() 882 | all_cases = res.register(self.if_expr_cases('bif')) 883 | if res.error: return res 884 | cases, else_case = all_cases 885 | return res.success(IfNode(cases, else_case)) 886 | 887 | def if_expr_b(self): 888 | return self.if_expr_cases('belif') 889 | 890 | def if_expr_c(self): 891 | res = ParseResult() 892 | else_case = None 893 | 894 | if self.current_tok.matches(TT_KEYWORD, 'belse'): 895 | res.register_advancement() 896 | self.advance() 897 | 898 | if self.current_tok.type == TT_NEWLINE: 899 | res.register_advancement() 900 | self.advance() 901 | 902 | statements = res.register(self.statements()) 903 | if res.error: return res 904 | else_case = (statements, True) 905 | 906 | if self.current_tok.matches(TT_KEYWORD, 'bend'): 907 | res.register_advancement() 908 | self.advance() 909 | else: 910 | return res.failure(InvalidSyntaxError( 911 | self.current_tok.pos_start, self.current_tok.pos_end, 912 | "Expected 'bend'" 913 | )) 914 | else: 915 | expr = res.register(self.statement()) 916 | if res.error: return res 917 | else_case = (expr, False) 918 | 919 | return res.success(else_case) 920 | 921 | def if_expr_b_or_c(self): 922 | res = ParseResult() 923 | cases, else_case = [], None 924 | 925 | if self.current_tok.matches(TT_KEYWORD, 'belif'): 926 | all_cases = res.register(self.if_expr_b()) 927 | if res.error: return res 928 | cases, else_case = all_cases 929 | else: 930 | else_case = res.register(self.if_expr_c()) 931 | if res.error: return res 932 | 933 | return res.success((cases, else_case)) 934 | 935 | def if_expr_cases(self, case_keyword): 936 | res = ParseResult() 937 | cases = [] 938 | else_case = None 939 | 940 | if not self.current_tok.matches(TT_KEYWORD, case_keyword): 941 | return res.failure(InvalidSyntaxError( 942 | self.current_tok.pos_start, self.current_tok.pos_end, 943 | f"Expected '{case_keyword}'" 944 | )) 945 | 946 | res.register_advancement() 947 | self.advance() 948 | 949 | condition = res.register(self.expr()) 950 | if res.error: return res 951 | 952 | if not self.current_tok.matches(TT_KEYWORD, 'thenb'): 953 | return res.failure(InvalidSyntaxError( 954 | self.current_tok.pos_start, self.current_tok.pos_end, 955 | f"Expected 'thenb'" 956 | )) 957 | 958 | res.register_advancement() 959 | self.advance() 960 | 961 | if self.current_tok.type == TT_NEWLINE: 962 | res.register_advancement() 963 | self.advance() 964 | 965 | statements = res.register(self.statements()) 966 | if res.error: return res 967 | cases.append((condition, statements, True)) 968 | 969 | if self.current_tok.matches(TT_KEYWORD, 'bend'): 970 | res.register_advancement() 971 | self.advance() 972 | else: 973 | all_cases = res.register(self.if_expr_b_or_c()) 974 | if res.error: return res 975 | new_cases, else_case = all_cases 976 | cases.extend(new_cases) 977 | else: 978 | expr = res.register(self.statement()) 979 | if res.error: return res 980 | cases.append((condition, expr, False)) 981 | 982 | all_cases = res.register(self.if_expr_b_or_c()) 983 | if res.error: return res 984 | new_cases, else_case = all_cases 985 | cases.extend(new_cases) 986 | 987 | return res.success((cases, else_case)) 988 | 989 | def for_expr(self): 990 | res = ParseResult() 991 | 992 | if not self.current_tok.matches(TT_KEYWORD, 'lopt'): 993 | return res.failure(InvalidSyntaxError( 994 | self.current_tok.pos_start, self.current_tok.pos_end, 995 | f"Expected 'lopt'" 996 | )) 997 | 998 | res.register_advancement() 999 | self.advance() 1000 | 1001 | if self.current_tok.type != TT_IDENTIFIER: 1002 | return res.failure(InvalidSyntaxError( 1003 | self.current_tok.pos_start, self.current_tok.pos_end, 1004 | f"Expected identifier" 1005 | )) 1006 | 1007 | var_name = self.current_tok 1008 | res.register_advancement() 1009 | self.advance() 1010 | 1011 | if self.current_tok.type != TT_EQ: 1012 | return res.failure(InvalidSyntaxError( 1013 | self.current_tok.pos_start, self.current_tok.pos_end, 1014 | f"Expected '='" 1015 | )) 1016 | 1017 | res.register_advancement() 1018 | self.advance() 1019 | 1020 | start_value = res.register(self.expr()) 1021 | if res.error: return res 1022 | 1023 | if not self.current_tok.matches(TT_KEYWORD, 'to'): 1024 | return res.failure(InvalidSyntaxError( 1025 | self.current_tok.pos_start, self.current_tok.pos_end, 1026 | f"Expected 'to'" 1027 | )) 1028 | 1029 | res.register_advancement() 1030 | self.advance() 1031 | 1032 | end_value = res.register(self.expr()) 1033 | if res.error: return res 1034 | 1035 | if self.current_tok.matches(TT_KEYWORD, 'step'): 1036 | res.register_advancement() 1037 | self.advance() 1038 | 1039 | step_value = res.register(self.expr()) 1040 | if res.error: return res 1041 | else: 1042 | step_value = None 1043 | 1044 | if not self.current_tok.matches(TT_KEYWORD, 'thenb'): 1045 | return res.failure(InvalidSyntaxError( 1046 | self.current_tok.pos_start, self.current_tok.pos_end, 1047 | f"Expected 'thenb'" 1048 | )) 1049 | 1050 | res.register_advancement() 1051 | self.advance() 1052 | 1053 | if self.current_tok.type == TT_NEWLINE: 1054 | res.register_advancement() 1055 | self.advance() 1056 | 1057 | body = res.register(self.statements()) 1058 | if res.error: return res 1059 | 1060 | if not self.current_tok.matches(TT_KEYWORD, 'bend'): 1061 | return res.failure(InvalidSyntaxError( 1062 | self.current_tok.pos_start, self.current_tok.pos_end, 1063 | f"Expected 'bend'" 1064 | )) 1065 | 1066 | res.register_advancement() 1067 | self.advance() 1068 | 1069 | return res.success(ForNode(var_name, start_value, end_value, step_value, body, True)) 1070 | 1071 | body = res.register(self.statement()) 1072 | if res.error: return res 1073 | 1074 | return res.success(ForNode(var_name, start_value, end_value, step_value, body, False)) 1075 | 1076 | def while_expr(self): 1077 | res = ParseResult() 1078 | 1079 | if not self.current_tok.matches(TT_KEYWORD, 'bebhile'): 1080 | return res.failure(InvalidSyntaxError( 1081 | self.current_tok.pos_start, self.current_tok.pos_end, 1082 | f"Expected 'bebhile'" 1083 | )) 1084 | 1085 | res.register_advancement() 1086 | self.advance() 1087 | 1088 | condition = res.register(self.expr()) 1089 | if res.error: return res 1090 | 1091 | if not self.current_tok.matches(TT_KEYWORD, 'thenb'): 1092 | return res.failure(InvalidSyntaxError( 1093 | self.current_tok.pos_start, self.current_tok.pos_end, 1094 | f"Expected 'thenb'" 1095 | )) 1096 | 1097 | res.register_advancement() 1098 | self.advance() 1099 | 1100 | if self.current_tok.type == TT_NEWLINE: 1101 | res.register_advancement() 1102 | self.advance() 1103 | 1104 | body = res.register(self.statements()) 1105 | if res.error: return res 1106 | 1107 | if not self.current_tok.matches(TT_KEYWORD, 'bend'): 1108 | return res.failure(InvalidSyntaxError( 1109 | self.current_tok.pos_start, self.current_tok.pos_end, 1110 | f"Expected 'bend'" 1111 | )) 1112 | 1113 | res.register_advancement() 1114 | self.advance() 1115 | 1116 | return res.success(WhileNode(condition, body, True)) 1117 | 1118 | body = res.register(self.statement()) 1119 | if res.error: return res 1120 | 1121 | return res.success(WhileNode(condition, body, False)) 1122 | 1123 | def func_def(self): 1124 | res = ParseResult() 1125 | 1126 | if not self.current_tok.matches(TT_KEYWORD, 'bfunc'): 1127 | return res.failure(InvalidSyntaxError( 1128 | self.current_tok.pos_start, self.current_tok.pos_end, 1129 | f"Expected 'bfunc'" 1130 | )) 1131 | 1132 | res.register_advancement() 1133 | self.advance() 1134 | 1135 | if self.current_tok.type == TT_IDENTIFIER: 1136 | var_name_tok = self.current_tok 1137 | res.register_advancement() 1138 | self.advance() 1139 | if self.current_tok.type != TT_LPAREN: 1140 | return res.failure(InvalidSyntaxError( 1141 | self.current_tok.pos_start, self.current_tok.pos_end, 1142 | f"Expected '('" 1143 | )) 1144 | else: 1145 | var_name_tok = None 1146 | if self.current_tok.type != TT_LPAREN: 1147 | return res.failure(InvalidSyntaxError( 1148 | self.current_tok.pos_start, self.current_tok.pos_end, 1149 | f"Expected identifier or '('" 1150 | )) 1151 | 1152 | res.register_advancement() 1153 | self.advance() 1154 | arg_name_toks = [] 1155 | 1156 | if self.current_tok.type == TT_IDENTIFIER: 1157 | arg_name_toks.append(self.current_tok) 1158 | res.register_advancement() 1159 | self.advance() 1160 | 1161 | while self.current_tok.type == TT_COMMA: 1162 | res.register_advancement() 1163 | self.advance() 1164 | 1165 | if self.current_tok.type != TT_IDENTIFIER: 1166 | return res.failure(InvalidSyntaxError( 1167 | self.current_tok.pos_start, self.current_tok.pos_end, 1168 | f"Expected identifier" 1169 | )) 1170 | 1171 | arg_name_toks.append(self.current_tok) 1172 | res.register_advancement() 1173 | self.advance() 1174 | 1175 | if self.current_tok.type != TT_RPAREN: 1176 | return res.failure(InvalidSyntaxError( 1177 | self.current_tok.pos_start, self.current_tok.pos_end, 1178 | f"Expected ',' or ')'" 1179 | )) 1180 | else: 1181 | if self.current_tok.type != TT_RPAREN: 1182 | return res.failure(InvalidSyntaxError( 1183 | self.current_tok.pos_start, self.current_tok.pos_end, 1184 | f"Expected identifier or ')'" 1185 | )) 1186 | 1187 | res.register_advancement() 1188 | self.advance() 1189 | 1190 | if self.current_tok.type == TT_ARROW: 1191 | res.register_advancement() 1192 | self.advance() 1193 | 1194 | body = res.register(self.expr()) 1195 | if res.error: return res 1196 | 1197 | return res.success(FuncDefNode( 1198 | var_name_tok, 1199 | arg_name_toks, 1200 | body, 1201 | True 1202 | )) 1203 | 1204 | if self.current_tok.type != TT_NEWLINE: 1205 | return res.failure(InvalidSyntaxError( 1206 | self.current_tok.pos_start, self.current_tok.pos_end, 1207 | f"Expected '->' or NEWLINE" 1208 | )) 1209 | 1210 | res.register_advancement() 1211 | self.advance() 1212 | 1213 | body = res.register(self.statements()) 1214 | if res.error: return res 1215 | 1216 | if not self.current_tok.matches(TT_KEYWORD, 'bend'): 1217 | return res.failure(InvalidSyntaxError( 1218 | self.current_tok.pos_start, self.current_tok.pos_end, 1219 | f"Expected 'bend'" 1220 | )) 1221 | 1222 | res.register_advancement() 1223 | self.advance() 1224 | 1225 | return res.success(FuncDefNode( 1226 | var_name_tok, 1227 | arg_name_toks, 1228 | body, 1229 | False 1230 | )) 1231 | 1232 | ################################### 1233 | 1234 | def bin_op(self, func_a, ops, func_b=None): 1235 | if func_b == None: 1236 | func_b = func_a 1237 | 1238 | res = ParseResult() 1239 | left = res.register(func_a()) 1240 | if res.error: return res 1241 | 1242 | while self.current_tok.type in ops or (self.current_tok.type, self.current_tok.value) in ops: 1243 | op_tok = self.current_tok 1244 | res.register_advancement() 1245 | self.advance() 1246 | right = res.register(func_b()) 1247 | if res.error: return res 1248 | left = BinOpNode(left, op_tok, right) 1249 | 1250 | return res.success(left) 1251 | 1252 | ####################################### 1253 | # RUNTIME RESULT 1254 | ####################################### 1255 | 1256 | class RTResult: 1257 | def __init__(self): 1258 | self.reset() 1259 | 1260 | def reset(self): 1261 | self.value = None 1262 | self.error = None 1263 | self.func_return_value = None 1264 | self.loop_should_continue = False 1265 | self.loop_should_break = False 1266 | 1267 | def register(self, res): 1268 | self.error = res.error 1269 | self.func_return_value = res.func_return_value 1270 | self.loop_should_continue = res.loop_should_continue 1271 | self.loop_should_break = res.loop_should_break 1272 | return res.value 1273 | 1274 | def success(self, value): 1275 | self.reset() 1276 | self.value = value 1277 | return self 1278 | 1279 | def success_return(self, value): 1280 | self.reset() 1281 | self.func_return_value = value 1282 | return self 1283 | 1284 | def success_continue(self): 1285 | self.reset() 1286 | self.loop_should_continue = True 1287 | return self 1288 | 1289 | def success_break(self): 1290 | self.reset() 1291 | self.loop_should_break = True 1292 | return self 1293 | 1294 | def failure(self, error): 1295 | self.reset() 1296 | self.error = error 1297 | return self 1298 | 1299 | def should_return(self): 1300 | # Note: this will allow you to continue and break outside the current function 1301 | return ( 1302 | self.error or 1303 | self.func_return_value or 1304 | self.loop_should_continue or 1305 | self.loop_should_break 1306 | ) 1307 | 1308 | ####################################### 1309 | # VALUES 1310 | ####################################### 1311 | 1312 | class Value: 1313 | def __init__(self): 1314 | self.set_pos() 1315 | self.set_context() 1316 | 1317 | def set_pos(self, pos_start=None, pos_end=None): 1318 | self.pos_start = pos_start 1319 | self.pos_end = pos_end 1320 | return self 1321 | 1322 | def set_context(self, context=None): 1323 | self.context = context 1324 | return self 1325 | 1326 | def added_to(self, other): 1327 | return None, self.illegal_operation(other) 1328 | 1329 | def subbed_by(self, other): 1330 | return None, self.illegal_operation(other) 1331 | 1332 | def multed_by(self, other): 1333 | return None, self.illegal_operation(other) 1334 | 1335 | def dived_by(self, other): 1336 | return None, self.illegal_operation(other) 1337 | 1338 | def powed_by(self, other): 1339 | return None, self.illegal_operation(other) 1340 | 1341 | def get_comparison_eq(self, other): 1342 | return None, self.illegal_operation(other) 1343 | 1344 | def get_comparison_ne(self, other): 1345 | return None, self.illegal_operation(other) 1346 | 1347 | def get_comparison_lt(self, other): 1348 | return None, self.illegal_operation(other) 1349 | 1350 | def get_comparison_gt(self, other): 1351 | return None, self.illegal_operation(other) 1352 | 1353 | def get_comparison_lte(self, other): 1354 | return None, self.illegal_operation(other) 1355 | 1356 | def get_comparison_gte(self, other): 1357 | return None, self.illegal_operation(other) 1358 | 1359 | def anded_by(self, other): 1360 | return None, self.illegal_operation(other) 1361 | 1362 | def ored_by(self, other): 1363 | return None, self.illegal_operation(other) 1364 | 1365 | def notted(self, other): 1366 | return None, self.illegal_operation(other) 1367 | 1368 | def execute(self, args): 1369 | return RTResult().failure(self.illegal_operation()) 1370 | 1371 | def copy(self): 1372 | raise Exception('No copy method defined') 1373 | 1374 | def is_true(self): 1375 | return False 1376 | 1377 | def illegal_operation(self, other=None): 1378 | if not other: other = self 1379 | return RTError( 1380 | self.pos_start, other.pos_end, 1381 | 'Illegal operation', 1382 | self.context 1383 | ) 1384 | 1385 | class Number(Value): 1386 | def __init__(self, value): 1387 | super().__init__() 1388 | self.value = value 1389 | 1390 | def added_to(self, other): 1391 | if isinstance(other, Number): 1392 | return Number(self.value + other.value).set_context(self.context), None 1393 | else: 1394 | return None, Value.illegal_operation(self, other) 1395 | 1396 | def subbed_by(self, other): 1397 | if isinstance(other, Number): 1398 | return Number(self.value - other.value).set_context(self.context), None 1399 | else: 1400 | return None, Value.illegal_operation(self, other) 1401 | 1402 | def multed_by(self, other): 1403 | if isinstance(other, Number): 1404 | return Number(self.value * other.value).set_context(self.context), None 1405 | else: 1406 | return None, Value.illegal_operation(self, other) 1407 | 1408 | def dived_by(self, other): 1409 | if isinstance(other, Number): 1410 | if other.value == 0: 1411 | return None, RTError( 1412 | other.pos_start, other.pos_end, 1413 | 'Division by zero', 1414 | self.context 1415 | ) 1416 | 1417 | return Number(self.value / other.value).set_context(self.context), None 1418 | else: 1419 | return None, Value.illegal_operation(self, other) 1420 | 1421 | def powed_by(self, other): 1422 | if isinstance(other, Number): 1423 | return Number(self.value ** other.value).set_context(self.context), None 1424 | else: 1425 | return None, Value.illegal_operation(self, other) 1426 | 1427 | def get_comparison_eq(self, other): 1428 | if isinstance(other, Number): 1429 | return Number(int(self.value == other.value)).set_context(self.context), None 1430 | else: 1431 | return None, Value.illegal_operation(self, other) 1432 | 1433 | def get_comparison_ne(self, other): 1434 | if isinstance(other, Number): 1435 | return Number(int(self.value != other.value)).set_context(self.context), None 1436 | else: 1437 | return None, Value.illegal_operation(self, other) 1438 | 1439 | def get_comparison_lt(self, other): 1440 | if isinstance(other, Number): 1441 | return Number(int(self.value < other.value)).set_context(self.context), None 1442 | else: 1443 | return None, Value.illegal_operation(self, other) 1444 | 1445 | def get_comparison_gt(self, other): 1446 | if isinstance(other, Number): 1447 | return Number(int(self.value > other.value)).set_context(self.context), None 1448 | else: 1449 | return None, Value.illegal_operation(self, other) 1450 | 1451 | def get_comparison_lte(self, other): 1452 | if isinstance(other, Number): 1453 | return Number(int(self.value <= other.value)).set_context(self.context), None 1454 | else: 1455 | return None, Value.illegal_operation(self, other) 1456 | 1457 | def get_comparison_gte(self, other): 1458 | if isinstance(other, Number): 1459 | return Number(int(self.value >= other.value)).set_context(self.context), None 1460 | else: 1461 | return None, Value.illegal_operation(self, other) 1462 | 1463 | def anded_by(self, other): 1464 | if isinstance(other, Number): 1465 | return Number(int(self.value and other.value)).set_context(self.context), None 1466 | else: 1467 | return None, Value.illegal_operation(self, other) 1468 | 1469 | def ored_by(self, other): 1470 | if isinstance(other, Number): 1471 | return Number(int(self.value or other.value)).set_context(self.context), None 1472 | else: 1473 | return None, Value.illegal_operation(self, other) 1474 | 1475 | def notted(self): 1476 | return Number(1 if self.value == 0 else 0).set_context(self.context), None 1477 | 1478 | def copy(self): 1479 | copy = Number(self.value) 1480 | copy.set_pos(self.pos_start, self.pos_end) 1481 | copy.set_context(self.context) 1482 | return copy 1483 | 1484 | def is_true(self): 1485 | return self.value != 0 1486 | 1487 | def __str__(self): 1488 | return str(self.value) 1489 | 1490 | def __repr__(self): 1491 | return str(self.value) 1492 | 1493 | Number.null = Number(0) 1494 | Number.false = Number(0) 1495 | Number.true = Number(1) 1496 | Number.math_PI = Number(math.pi) 1497 | 1498 | class String(Value): 1499 | def __init__(self, value): 1500 | super().__init__() 1501 | self.value = value 1502 | 1503 | def added_to(self, other): 1504 | if isinstance(other, String): 1505 | return String(self.value + other.value).set_context(self.context), None 1506 | else: 1507 | return None, Value.illegal_operation(self, other) 1508 | 1509 | def multed_by(self, other): 1510 | if isinstance(other, Number): 1511 | return String(self.value * other.value).set_context(self.context), None 1512 | else: 1513 | return None, Value.illegal_operation(self, other) 1514 | 1515 | def is_true(self): 1516 | return len(self.value) > 0 1517 | 1518 | def copy(self): 1519 | copy = String(self.value) 1520 | copy.set_pos(self.pos_start, self.pos_end) 1521 | copy.set_context(self.context) 1522 | return copy 1523 | 1524 | def __str__(self): 1525 | return self.value 1526 | 1527 | def __repr__(self): 1528 | return f'"{self.value}"' 1529 | 1530 | class List(Value): 1531 | def __init__(self, elements): 1532 | super().__init__() 1533 | self.elements = elements 1534 | 1535 | def added_to(self, other): 1536 | new_list = self.copy() 1537 | new_list.elements.append(other) 1538 | return new_list, None 1539 | 1540 | def subbed_by(self, other): 1541 | if isinstance(other, Number): 1542 | new_list = self.copy() 1543 | try: 1544 | new_list.elements.pop(other.value) 1545 | return new_list, None 1546 | except: 1547 | return None, RTError( 1548 | other.pos_start, other.pos_end, 1549 | 'Element at this index could not be removed from list because index is out of bounds', 1550 | self.context 1551 | ) 1552 | else: 1553 | return None, Value.illegal_operation(self, other) 1554 | 1555 | def multed_by(self, other): 1556 | if isinstance(other, List): 1557 | new_list = self.copy() 1558 | new_list.elements.extend(other.elements) 1559 | return new_list, None 1560 | else: 1561 | return None, Value.illegal_operation(self, other) 1562 | 1563 | def dived_by(self, other): 1564 | if isinstance(other, Number): 1565 | try: 1566 | return self.elements[other.value], None 1567 | except: 1568 | return None, RTError( 1569 | other.pos_start, other.pos_end, 1570 | 'Element at this index could not be retrieved from list because index is out of bounds', 1571 | self.context 1572 | ) 1573 | else: 1574 | return None, Value.illegal_operation(self, other) 1575 | 1576 | def copy(self): 1577 | copy = List(self.elements) 1578 | copy.set_pos(self.pos_start, self.pos_end) 1579 | copy.set_context(self.context) 1580 | return copy 1581 | 1582 | def __str__(self): 1583 | return ", ".join([str(x) for x in self.elements]) 1584 | 1585 | def __repr__(self): 1586 | return f'[{", ".join([repr(x) for x in self.elements])}]' 1587 | 1588 | class BaseFunction(Value): 1589 | def __init__(self, name): 1590 | super().__init__() 1591 | self.name = name or "" 1592 | 1593 | def generate_new_context(self): 1594 | new_context = Context(self.name, self.context, self.pos_start) 1595 | new_context.symbol_table = SymbolTable(new_context.parent.symbol_table) 1596 | return new_context 1597 | 1598 | def check_args(self, arg_names, args): 1599 | res = RTResult() 1600 | 1601 | if len(args) > len(arg_names): 1602 | return res.failure(RTError( 1603 | self.pos_start, self.pos_end, 1604 | f"{len(args) - len(arg_names)} too many args passed into {self}", 1605 | self.context 1606 | )) 1607 | 1608 | if len(args) < len(arg_names): 1609 | return res.failure(RTError( 1610 | self.pos_start, self.pos_end, 1611 | f"{len(arg_names) - len(args)} too few args passed into {self}", 1612 | self.context 1613 | )) 1614 | 1615 | return res.success(None) 1616 | 1617 | def populate_args(self, arg_names, args, exec_ctx): 1618 | for i in range(len(args)): 1619 | arg_name = arg_names[i] 1620 | arg_value = args[i] 1621 | arg_value.set_context(exec_ctx) 1622 | exec_ctx.symbol_table.set(arg_name, arg_value) 1623 | 1624 | def check_and_populate_args(self, arg_names, args, exec_ctx): 1625 | res = RTResult() 1626 | res.register(self.check_args(arg_names, args)) 1627 | if res.should_return(): return res 1628 | self.populate_args(arg_names, args, exec_ctx) 1629 | return res.success(None) 1630 | 1631 | class Function(BaseFunction): 1632 | def __init__(self, name, body_node, arg_names, should_auto_return): 1633 | super().__init__(name) 1634 | self.body_node = body_node 1635 | self.arg_names = arg_names 1636 | self.should_auto_return = should_auto_return 1637 | 1638 | def execute(self, args): 1639 | res = RTResult() 1640 | interpreter = Interpreter() 1641 | exec_ctx = self.generate_new_context() 1642 | 1643 | res.register(self.check_and_populate_args(self.arg_names, args, exec_ctx)) 1644 | if res.should_return(): return res 1645 | 1646 | value = res.register(interpreter.visit(self.body_node, exec_ctx)) 1647 | if res.should_return() and res.func_return_value == None: return res 1648 | 1649 | ret_value = (value if self.should_auto_return else None) or res.func_return_value or Number.null 1650 | return res.success(ret_value) 1651 | 1652 | def copy(self): 1653 | copy = Function(self.name, self.body_node, self.arg_names, self.should_auto_return) 1654 | copy.set_context(self.context) 1655 | copy.set_pos(self.pos_start, self.pos_end) 1656 | return copy 1657 | 1658 | def __repr__(self): 1659 | return f"" 1660 | 1661 | class BuiltInFunction(BaseFunction): 1662 | def __init__(self, name): 1663 | super().__init__(name) 1664 | 1665 | def execute(self, args): 1666 | res = RTResult() 1667 | exec_ctx = self.generate_new_context() 1668 | 1669 | method_name = f'execute_{self.name}' 1670 | method = getattr(self, method_name, self.no_visit_method) 1671 | 1672 | res.register(self.check_and_populate_args(method.arg_names, args, exec_ctx)) 1673 | if res.should_return(): return res 1674 | 1675 | return_value = res.register(method(exec_ctx)) 1676 | if res.should_return(): return res 1677 | return res.success(return_value) 1678 | 1679 | def no_visit_method(self, node, context): 1680 | raise Exception(f'No execute_{self.name} method defined') 1681 | 1682 | def copy(self): 1683 | copy = BuiltInFunction(self.name) 1684 | copy.set_context(self.context) 1685 | copy.set_pos(self.pos_start, self.pos_end) 1686 | return copy 1687 | 1688 | def __repr__(self): 1689 | return f"" 1690 | 1691 | ##################################### 1692 | 1693 | def execute_print(self, exec_ctx): 1694 | print(str(exec_ctx.symbol_table.get('value'))) 1695 | return RTResult().success(Number.null) 1696 | execute_print.arg_names = ['value'] 1697 | 1698 | def execute_print_ret(self, exec_ctx): 1699 | return RTResult().success(String(str(exec_ctx.symbol_table.get('value')))) 1700 | execute_print_ret.arg_names = ['value'] 1701 | 1702 | def execute_input(self, exec_ctx): 1703 | text = input() 1704 | return RTResult().success(String(text)) 1705 | execute_input.arg_names = [] 1706 | 1707 | def execute_input_int(self, exec_ctx): 1708 | while True: 1709 | text = input() 1710 | try: 1711 | number = int(text) 1712 | break 1713 | except ValueError: 1714 | print(f"'{text}' must be an integer. Try again!") 1715 | return RTResult().success(Number(number)) 1716 | execute_input_int.arg_names = [] 1717 | 1718 | def execute_clear(self, exec_ctx): 1719 | os.system('cls' if os.name == 'nt' else 'cls') 1720 | return RTResult().success(Number.null) 1721 | execute_clear.arg_names = [] 1722 | 1723 | def execute_is_number(self, exec_ctx): 1724 | is_number = isinstance(exec_ctx.symbol_table.get("value"), Number) 1725 | return RTResult().success(Number.true if is_number else Number.false) 1726 | execute_is_number.arg_names = ["value"] 1727 | 1728 | def execute_is_string(self, exec_ctx): 1729 | is_number = isinstance(exec_ctx.symbol_table.get("value"), String) 1730 | return RTResult().success(Number.true if is_number else Number.false) 1731 | execute_is_string.arg_names = ["value"] 1732 | 1733 | def execute_is_list(self, exec_ctx): 1734 | is_number = isinstance(exec_ctx.symbol_table.get("value"), List) 1735 | return RTResult().success(Number.true if is_number else Number.false) 1736 | execute_is_list.arg_names = ["value"] 1737 | 1738 | def execute_is_function(self, exec_ctx): 1739 | is_number = isinstance(exec_ctx.symbol_table.get("value"), BaseFunction) 1740 | return RTResult().success(Number.true if is_number else Number.false) 1741 | execute_is_function.arg_names = ["value"] 1742 | 1743 | def execute_append(self, exec_ctx): 1744 | list_ = exec_ctx.symbol_table.get("list") 1745 | value = exec_ctx.symbol_table.get("value") 1746 | 1747 | if not isinstance(list_, List): 1748 | return RTResult().failure(RTError( 1749 | self.pos_start, self.pos_end, 1750 | "First argument must be list", 1751 | exec_ctx 1752 | )) 1753 | 1754 | list_.elements.append(value) 1755 | return RTResult().success(Number.null) 1756 | execute_append.arg_names = ["list", "value"] 1757 | 1758 | def execute_pop(self, exec_ctx): 1759 | list_ = exec_ctx.symbol_table.get("list") 1760 | index = exec_ctx.symbol_table.get("index") 1761 | 1762 | if not isinstance(list_, List): 1763 | return RTResult().failure(RTError( 1764 | self.pos_start, self.pos_end, 1765 | "First argument must be list", 1766 | exec_ctx 1767 | )) 1768 | 1769 | if not isinstance(index, Number): 1770 | return RTResult().failure(RTError( 1771 | self.pos_start, self.pos_end, 1772 | "Second argument must be number", 1773 | exec_ctx 1774 | )) 1775 | 1776 | try: 1777 | element = list_.elements.pop(index.value) 1778 | except: 1779 | return RTResult().failure(RTError( 1780 | self.pos_start, self.pos_end, 1781 | 'Element at this index could not be removed from list because index is out of bounds', 1782 | exec_ctx 1783 | )) 1784 | return RTResult().success(element) 1785 | execute_pop.arg_names = ["list", "index"] 1786 | 1787 | def execute_extend(self, exec_ctx): 1788 | listA = exec_ctx.symbol_table.get("listA") 1789 | listB = exec_ctx.symbol_table.get("listB") 1790 | 1791 | if not isinstance(listA, List): 1792 | return RTResult().failure(RTError( 1793 | self.pos_start, self.pos_end, 1794 | "First argument must be list", 1795 | exec_ctx 1796 | )) 1797 | 1798 | if not isinstance(listB, List): 1799 | return RTResult().failure(RTError( 1800 | self.pos_start, self.pos_end, 1801 | "Second argument must be list", 1802 | exec_ctx 1803 | )) 1804 | 1805 | listA.elements.extend(listB.elements) 1806 | return RTResult().success(Number.null) 1807 | execute_extend.arg_names = ["listA", "listB"] 1808 | 1809 | def execute_len(self, exec_ctx): 1810 | list_ = exec_ctx.symbol_table.get("list") 1811 | 1812 | if not isinstance(list_, List): 1813 | return RTResult().failure(RTError( 1814 | self.pos_start, self.pos_end, 1815 | "Argument must be list", 1816 | exec_ctx 1817 | )) 1818 | 1819 | return RTResult().success(Number(len(list_.elements))) 1820 | execute_len.arg_names = ["list"] 1821 | 1822 | def execute_run(self, exec_ctx): 1823 | fn = exec_ctx.symbol_table.get("fn") 1824 | 1825 | if not isinstance(fn, String): 1826 | return RTResult().failure(RTError( 1827 | self.pos_start, self.pos_end, 1828 | "Second argument must be string", 1829 | exec_ctx 1830 | )) 1831 | 1832 | fn = fn.value 1833 | 1834 | try: 1835 | with open(fn, "r") as f: 1836 | script = f.read() 1837 | except Exception as e: 1838 | return RTResult().failure(RTError( 1839 | self.pos_start, self.pos_end, 1840 | f"Failed to load script \"{fn}\"\n" + str(e), 1841 | exec_ctx 1842 | )) 1843 | 1844 | _, error = run(fn, script) 1845 | 1846 | if error: 1847 | return RTResult().failure(RTError( 1848 | self.pos_start, self.pos_end, 1849 | f"Failed to finish executing script \"{fn}\"\n" + 1850 | error.as_string(), 1851 | exec_ctx 1852 | )) 1853 | 1854 | return RTResult().success(Number.null) 1855 | execute_run.arg_names = ["fn"] 1856 | 1857 | BuiltInFunction.print = BuiltInFunction("print") 1858 | BuiltInFunction.print_ret = BuiltInFunction("print_ret") 1859 | BuiltInFunction.input = BuiltInFunction("input") 1860 | BuiltInFunction.input_int = BuiltInFunction("input_int") 1861 | BuiltInFunction.clear = BuiltInFunction("clear") 1862 | BuiltInFunction.is_number = BuiltInFunction("is_number") 1863 | BuiltInFunction.is_string = BuiltInFunction("is_string") 1864 | BuiltInFunction.is_list = BuiltInFunction("is_list") 1865 | BuiltInFunction.is_function = BuiltInFunction("is_function") 1866 | BuiltInFunction.append = BuiltInFunction("append") 1867 | BuiltInFunction.pop = BuiltInFunction("pop") 1868 | BuiltInFunction.extend = BuiltInFunction("extend") 1869 | BuiltInFunction.len = BuiltInFunction("len") 1870 | BuiltInFunction.run = BuiltInFunction("run") 1871 | 1872 | 1873 | ####################################### 1874 | # CONTEXT 1875 | ####################################### 1876 | 1877 | class Context: 1878 | def __init__(self, display_name, parent=None, parent_entry_pos=None): 1879 | self.display_name = display_name 1880 | self.parent = parent 1881 | self.parent_entry_pos = parent_entry_pos 1882 | self.symbol_table = None 1883 | 1884 | ####################################### 1885 | # SYMBOL TABLE 1886 | ####################################### 1887 | 1888 | class SymbolTable: 1889 | def __init__(self, parent=None): 1890 | self.symbols = {} 1891 | self.parent = parent 1892 | 1893 | def get(self, name): 1894 | value = self.symbols.get(name, None) 1895 | if value == None and self.parent: 1896 | return self.parent.get(name) 1897 | return value 1898 | 1899 | def set(self, name, value): 1900 | self.symbols[name] = value 1901 | 1902 | def remove(self, name): 1903 | del self.symbols[name] 1904 | 1905 | ####################################### 1906 | # INTERPRETER 1907 | ####################################### 1908 | 1909 | class Interpreter: 1910 | def visit(self, node, context): 1911 | method_name = f'visit_{type(node).__name__}' 1912 | method = getattr(self, method_name, self.no_visit_method) 1913 | return method(node, context) 1914 | 1915 | def no_visit_method(self, node, context): 1916 | raise Exception(f'No visit_{type(node).__name__} method defined') 1917 | 1918 | ################################### 1919 | 1920 | def visit_NumberNode(self, node, context): 1921 | return RTResult().success( 1922 | Number(node.tok.value).set_context(context).set_pos(node.pos_start, node.pos_end) 1923 | ) 1924 | 1925 | def visit_StringNode(self, node, context): 1926 | return RTResult().success( 1927 | String(node.tok.value).set_context(context).set_pos(node.pos_start, node.pos_end) 1928 | ) 1929 | 1930 | def visit_ListNode(self, node, context): 1931 | res = RTResult() 1932 | elements = [] 1933 | 1934 | for element_node in node.element_nodes: 1935 | elements.append(res.register(self.visit(element_node, context))) 1936 | if res.should_return(): return res 1937 | 1938 | return res.success( 1939 | List(elements).set_context(context).set_pos(node.pos_start, node.pos_end) 1940 | ) 1941 | 1942 | def visit_VarAccessNode(self, node, context): 1943 | res = RTResult() 1944 | var_name = node.var_name_tok.value 1945 | value = context.symbol_table.get(var_name) 1946 | 1947 | if not value: 1948 | return res.failure(RTError( 1949 | node.pos_start, node.pos_end, 1950 | f"'{var_name}' is not defined", 1951 | context 1952 | )) 1953 | 1954 | value = value.copy().set_pos(node.pos_start, node.pos_end).set_context(context) 1955 | return res.success(value) 1956 | 1957 | def visit_VarAssignNode(self, node, context): 1958 | res = RTResult() 1959 | var_name = node.var_name_tok.value 1960 | value = res.register(self.visit(node.value_node, context)) 1961 | if res.should_return(): return res 1962 | 1963 | context.symbol_table.set(var_name, value) 1964 | return res.success(value) 1965 | 1966 | def visit_BinOpNode(self, node, context): 1967 | res = RTResult() 1968 | left = res.register(self.visit(node.left_node, context)) 1969 | if res.should_return(): return res 1970 | right = res.register(self.visit(node.right_node, context)) 1971 | if res.should_return(): return res 1972 | 1973 | if node.op_tok.type == TT_PLUS: 1974 | result, error = left.added_to(right) 1975 | elif node.op_tok.type == TT_MINUS: 1976 | result, error = left.subbed_by(right) 1977 | elif node.op_tok.type == TT_MUL: 1978 | result, error = left.multed_by(right) 1979 | elif node.op_tok.type == TT_DIV: 1980 | result, error = left.dived_by(right) 1981 | elif node.op_tok.type == TT_POW: 1982 | result, error = left.powed_by(right) 1983 | elif node.op_tok.type == TT_EE: 1984 | result, error = left.get_comparison_eq(right) 1985 | elif node.op_tok.type == TT_NE: 1986 | result, error = left.get_comparison_ne(right) 1987 | elif node.op_tok.type == TT_LT: 1988 | result, error = left.get_comparison_lt(right) 1989 | elif node.op_tok.type == TT_GT: 1990 | result, error = left.get_comparison_gt(right) 1991 | elif node.op_tok.type == TT_LTE: 1992 | result, error = left.get_comparison_lte(right) 1993 | elif node.op_tok.type == TT_GTE: 1994 | result, error = left.get_comparison_gte(right) 1995 | elif node.op_tok.matches(TT_KEYWORD, 'and'): 1996 | result, error = left.anded_by(right) 1997 | elif node.op_tok.matches(TT_KEYWORD, 'or'): 1998 | result, error = left.ored_by(right) 1999 | 2000 | if error: 2001 | return res.failure(error) 2002 | else: 2003 | return res.success(result.set_pos(node.pos_start, node.pos_end)) 2004 | 2005 | def visit_UnaryOpNode(self, node, context): 2006 | res = RTResult() 2007 | number = res.register(self.visit(node.node, context)) 2008 | if res.should_return(): return res 2009 | 2010 | error = None 2011 | 2012 | if node.op_tok.type == TT_MINUS: 2013 | number, error = number.multed_by(Number(-1)) 2014 | elif node.op_tok.matches(TT_KEYWORD, 'not'): 2015 | number, error = number.notted() 2016 | 2017 | if error: 2018 | return res.failure(error) 2019 | else: 2020 | return res.success(number.set_pos(node.pos_start, node.pos_end)) 2021 | 2022 | def visit_IfNode(self, node, context): 2023 | res = RTResult() 2024 | 2025 | for condition, expr, should_return_null in node.cases: 2026 | condition_value = res.register(self.visit(condition, context)) 2027 | if res.should_return(): return res 2028 | 2029 | if condition_value.is_true(): 2030 | expr_value = res.register(self.visit(expr, context)) 2031 | if res.should_return(): return res 2032 | return res.success(Number.null if should_return_null else expr_value) 2033 | 2034 | if node.else_case: 2035 | expr, should_return_null = node.else_case 2036 | expr_value = res.register(self.visit(expr, context)) 2037 | if res.should_return(): return res 2038 | return res.success(Number.null if should_return_null else expr_value) 2039 | 2040 | return res.success(Number.null) 2041 | 2042 | def visit_ForNode(self, node, context): 2043 | res = RTResult() 2044 | elements = [] 2045 | 2046 | start_value = res.register(self.visit(node.start_value_node, context)) 2047 | if res.should_return(): return res 2048 | 2049 | end_value = res.register(self.visit(node.end_value_node, context)) 2050 | if res.should_return(): return res 2051 | 2052 | if node.step_value_node: 2053 | step_value = res.register(self.visit(node.step_value_node, context)) 2054 | if res.should_return(): return res 2055 | else: 2056 | step_value = Number(1) 2057 | 2058 | i = start_value.value 2059 | 2060 | if step_value.value >= 0: 2061 | condition = lambda: i < end_value.value 2062 | else: 2063 | condition = lambda: i > end_value.value 2064 | 2065 | while condition(): 2066 | context.symbol_table.set(node.var_name_tok.value, Number(i)) 2067 | i += step_value.value 2068 | 2069 | value = res.register(self.visit(node.body_node, context)) 2070 | if res.should_return() and res.loop_should_continue == False and res.loop_should_break == False: return res 2071 | 2072 | if res.loop_should_continue: 2073 | continue 2074 | 2075 | if res.loop_should_break: 2076 | break 2077 | 2078 | elements.append(value) 2079 | 2080 | return res.success( 2081 | Number.null if node.should_return_null else 2082 | List(elements).set_context(context).set_pos(node.pos_start, node.pos_end) 2083 | ) 2084 | 2085 | def visit_WhileNode(self, node, context): 2086 | res = RTResult() 2087 | elements = [] 2088 | 2089 | while True: 2090 | condition = res.register(self.visit(node.condition_node, context)) 2091 | if res.should_return(): return res 2092 | 2093 | if not condition.is_true(): 2094 | break 2095 | 2096 | value = res.register(self.visit(node.body_node, context)) 2097 | if res.should_return() and res.loop_should_continue == False and res.loop_should_break == False: return res 2098 | 2099 | if res.loop_should_continue: 2100 | continue 2101 | 2102 | if res.loop_should_break: 2103 | break 2104 | 2105 | elements.append(value) 2106 | 2107 | return res.success( 2108 | Number.null if node.should_return_null else 2109 | List(elements).set_context(context).set_pos(node.pos_start, node.pos_end) 2110 | ) 2111 | 2112 | def visit_FuncDefNode(self, node, context): 2113 | res = RTResult() 2114 | 2115 | func_name = node.var_name_tok.value if node.var_name_tok else None 2116 | body_node = node.body_node 2117 | arg_names = [arg_name.value for arg_name in node.arg_name_toks] 2118 | func_value = Function(func_name, body_node, arg_names, node.should_auto_return).set_context(context).set_pos(node.pos_start, node.pos_end) 2119 | 2120 | if node.var_name_tok: 2121 | context.symbol_table.set(func_name, func_value) 2122 | 2123 | return res.success(func_value) 2124 | 2125 | def visit_CallNode(self, node, context): 2126 | res = RTResult() 2127 | args = [] 2128 | 2129 | value_to_call = res.register(self.visit(node.node_to_call, context)) 2130 | if res.should_return(): return res 2131 | value_to_call = value_to_call.copy().set_pos(node.pos_start, node.pos_end) 2132 | 2133 | for arg_node in node.arg_nodes: 2134 | args.append(res.register(self.visit(arg_node, context))) 2135 | if res.should_return(): return res 2136 | 2137 | return_value = res.register(value_to_call.execute(args)) 2138 | if res.should_return(): return res 2139 | return_value = return_value.copy().set_pos(node.pos_start, node.pos_end).set_context(context) 2140 | return res.success(return_value) 2141 | 2142 | def visit_ReturnNode(self, node, context): 2143 | res = RTResult() 2144 | 2145 | if node.node_to_return: 2146 | value = res.register(self.visit(node.node_to_return, context)) 2147 | if res.should_return(): return res 2148 | else: 2149 | value = Number.null 2150 | 2151 | return res.success_return(value) 2152 | 2153 | def visit_ContinueNode(self, node, context): 2154 | return RTResult().success_continue() 2155 | 2156 | def visit_BreakNode(self, node, context): 2157 | return RTResult().success_break() 2158 | 2159 | ####################################### 2160 | # RUN 2161 | ####################################### 2162 | 2163 | global_symbol_table = SymbolTable() 2164 | global_symbol_table.set("bnull", Number.null) 2165 | global_symbol_table.set("bfalse", Number.false) 2166 | global_symbol_table.set("btrue", Number.true) 2167 | global_symbol_table.set("MATH_PI", Number.math_PI) 2168 | global_symbol_table.set("bebra", BuiltInFunction.print) 2169 | global_symbol_table.set("bebra_ret", BuiltInFunction.print_ret) 2170 | global_symbol_table.set("binp", BuiltInFunction.input) 2171 | global_symbol_table.set("binp_int", BuiltInFunction.input_int) 2172 | global_symbol_table.set("clear", BuiltInFunction.clear) 2173 | global_symbol_table.set("cls", BuiltInFunction.clear) 2174 | global_symbol_table.set("is_num", BuiltInFunction.is_number) 2175 | global_symbol_table.set("is_str", BuiltInFunction.is_string) 2176 | global_symbol_table.set("is_list", BuiltInFunction.is_list) 2177 | global_symbol_table.set("is_fun", BuiltInFunction.is_function) 2178 | global_symbol_table.set("append", BuiltInFunction.append) 2179 | global_symbol_table.set("pop", BuiltInFunction.pop) 2180 | global_symbol_table.set("extend", BuiltInFunction.extend) 2181 | global_symbol_table.set("len", BuiltInFunction.len) 2182 | global_symbol_table.set("lopata", BuiltInFunction.run) 2183 | 2184 | def run(fn, text): 2185 | # Generate tokens 2186 | lexer = Lexer(fn, text) 2187 | tokens, error = lexer.make_tokens() 2188 | if error: return None, error 2189 | 2190 | # Generate AST 2191 | parser = Parser(tokens) 2192 | ast = parser.parse() 2193 | if ast.error: return None, ast.error 2194 | 2195 | # Run program 2196 | interpreter = Interpreter() 2197 | context = Context('') 2198 | context.symbol_table = global_symbol_table 2199 | result = interpreter.visit(ast.node, context) 2200 | 2201 | return result.value, result.error 2202 | -------------------------------------------------------------------------------- /examples/bif.bbr: -------------------------------------------------------------------------------- 1 | beb hello = 100 2 | beb goodbye = 50 3 | 4 | bebra(hello) 5 | 6 | bif hello == 1 thenb bebra("hello = 1") belse bebra("hello > 1") 7 | bif hello == 100 thenb beb a = hello + 100 belse bebra("hello /= 100") 8 | bif goodbye == 50 thenb beb b = hello + goodbye belse bebra("goodbye /= 50") 9 | 10 | bebra(b) 11 | 12 | bif a >= 200 thenb bebra("Hello!") 13 | bif b >= 150 thenb bebra("Goodbye!") 14 | -------------------------------------------------------------------------------- /examples/example.bbr: -------------------------------------------------------------------------------- 1 | beb a = 100 2 | beb b = 50 3 | beb v = a + b 4 | beb g = v * b 5 | 6 | bebra(v) 7 | bebra(g) -------------------------------------------------------------------------------- /examples/example2.bbr: -------------------------------------------------------------------------------- 1 | bfunc bobr(a) -> a + "бебру!" 2 | lopt i = 0 to 5 thenb 3 | bebra(bobr("Нюхай ")) 4 | bend 5 | bebra("Сверху была беброфункция и лопатный цикл :)") 6 | -------------------------------------------------------------------------------- /examples/loop.bbr: -------------------------------------------------------------------------------- 1 | lopt i = 0 to 5 thenb 2 | bebra("Привет.") 3 | bend 4 | -------------------------------------------------------------------------------- /shell.py: -------------------------------------------------------------------------------- 1 | import bebra 2 | 3 | while True: 4 | text = input('> ') 5 | if text.strip() == "": continue 6 | result, error = bebra.run('', text) 7 | 8 | if error: 9 | print(error.as_string()) 10 | elif result: 11 | if len(result.elements) == 1: 12 | print(repr(result.elements[0])) 13 | else: 14 | print(repr(result)) 15 | -------------------------------------------------------------------------------- /strings_with_arrows.py: -------------------------------------------------------------------------------- 1 | def string_with_arrows(text, pos_start, pos_end): 2 | result = '' 3 | 4 | # Calculate indices 5 | idx_start = max(text.rfind('\n', 0, pos_start.idx), 0) 6 | idx_end = text.find('\n', idx_start + 1) 7 | if idx_end < 0: idx_end = len(text) 8 | 9 | # Generate each line 10 | line_count = pos_end.ln - pos_start.ln + 1 11 | for i in range(line_count): 12 | # Calculate line columns 13 | line = text[idx_start:idx_end] 14 | col_start = pos_start.col if i == 0 else 0 15 | col_end = pos_end.col if i == line_count - 1 else len(line) - 1 16 | 17 | # Append to result 18 | result += line + '\n' 19 | result += ' ' * col_start + '^' * (col_end - col_start) 20 | 21 | # Re-calculate indices 22 | idx_start = idx_end 23 | idx_end = text.find('\n', idx_start + 1) 24 | if idx_end < 0: idx_end = len(text) 25 | 26 | return result.replace('\t', '') 27 | --------------------------------------------------------------------------------