├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── arguments.py ├── examples ├── HelloWorld.vo └── main.vo ├── favicon.png ├── main.py ├── repl.py ├── run.py ├── tokens.py └── vython ├── __init__.py ├── debug.py ├── errors.py ├── lang ├── affection_operators.py ├── binary_operators.py ├── comparators.py ├── conditions.py ├── expressions.py ├── functions.py ├── logic_operators.py ├── loops.py ├── statements.py ├── types.py ├── unique_operators.py └── variables.py ├── lexer.py └── parser.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: dopevog 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/python 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=python 4 | 5 | ### Python ### 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | pip-wheel-metadata/ 27 | share/python-wheels/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | MANIFEST 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .nox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | *.py,cover 54 | .hypothesis/ 55 | .pytest_cache/ 56 | pytestdebug.log 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | doc/_build/ 78 | 79 | # PyBuilder 80 | target/ 81 | 82 | # Jupyter Notebook 83 | .ipynb_checkpoints 84 | 85 | # IPython 86 | profile_default/ 87 | ipython_config.py 88 | 89 | # pyenv 90 | .python-version 91 | 92 | __pypackages__/ 93 | 94 | celerybeat-schedule 95 | celerybeat.pid 96 | 97 | 98 | *.sage.py 99 | 100 | .env/ 101 | .venv/ 102 | env/ 103 | venv/ 104 | ENV/ 105 | env.bak/ 106 | venv.bak/ 107 | pythonenv* 108 | 109 | .spyderproject 110 | .spyproject 111 | 112 | .ropeproject 113 | 114 | # mkdocs documentation 115 | /site 116 | 117 | .mypy_cache/ 118 | .dmypy.json 119 | dmypy.json 120 | 121 | .pyre/ 122 | # pytype static type analyzer 123 | .pytype/ 124 | *.DS_Store 125 | Thumbs.db 126 | .prof 127 | 128 | 129 | run.bat 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-Present Vedant Kothari 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **Vython** 2 | 3 | ## Download & Setup 4 | * Clone the repo from Github: 5 | ``` 6 | git clone https://github.com/cvython/Vython.git 7 | ``` 8 | * Enter Into Its Derectory 9 | ``` 10 | cd Vython 11 | ``` 12 | * You're All Set! 13 | 14 | 15 | ## Running A Script 16 | ``` 17 | $ python3 vython.py main.vo 18 | ``` 19 | * ~~The scripts' file extension must be~~```.vo``` 20 | * The scripts' file extension can be anything from ```.txt``` to ```.vo```! Though it is recommended to use the file extension ```.vo```. 21 | 22 | ## Usage 23 | * Print: 24 | ``` 25 | show("Hello World") 26 | ``` 27 | * Take Input: 28 | ``` 29 | age = enter("Age: ") 30 | ``` 31 | * Print Text And Variable: 32 | ``` 33 | show("Age = "+age) 34 | ``` 35 | * If Statements: 36 | ``` 37 | if a > 18 38 | { 39 | show("Adult") 40 | }else 41 | { 42 | show("Child") 43 | } 44 | ``` 45 | * If Statement With 'and': 46 | ``` 47 | if a > 18 and a < 50 48 | { 49 | show("Adult, But Not Old") 50 | } 51 | ``` 52 | * If Statement With 'or': 53 | ``` 54 | if a > 18 || a > 16 55 | { 56 | show("Can Drive") 57 | } 58 | ``` 59 | * Check If Variable A Particular *Type*: 60 | ``` 61 | if canbe(a, "int") 62 | { 63 | show("Variable is an integer") 64 | } 65 | ``` 66 | * Supported Variable Forms: 67 | * Integer ➡ int() 68 | * Float ➡ float() 69 | * String ➡ str() 70 | * List ➡ list[] 71 | * Select Cell From List: 72 | ``` 73 | a = [0, 1, 2, 3, 4, 5] 74 | ## Show The First Cell 75 | show(a[0]) 76 | ``` 77 | * Supported Arethmetic Opperations: 78 | * Addition ➡ '+' 79 | * Subtraction ➡ '-' 80 | * Division ➡ '/' 81 | * Multiplication ➡ '*' 82 | * Remainder ➡ '%' 83 | 84 | ## Credits 85 | * [Vedant K](https://github.com/dopevog) 86 | * [Pranav Baburaj](https://github.com/pranavbaburaj) 87 | * [Harry](https://github.com/fineans) 88 | 89 | ## License 90 | This Project is [MIT Licensed](https://github.com/cvython/Vython/blob/vython/LICENSE) 91 | 92 | -------------------------------------------------------------------------------- /arguments.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from repl import Repl 3 | from run import ExecuteScript 4 | 5 | 6 | class ArgumentParserException(object): 7 | def __init__(self, message, suggestion=None, fatal=True): 8 | self.message = message 9 | self.suggestion = suggestion 10 | self.is_fatal = fatal 11 | 12 | self.raise_exception() 13 | 14 | def raise_exception(self): 15 | print(f'[ERROR] {self.message}') 16 | if self.suggestion: 17 | print(self.suggestion) 18 | 19 | if self.is_fatal: 20 | sys.exit(1) 21 | 22 | 23 | class ArgumentParser(object): 24 | commands = None 25 | flags = [] 26 | 27 | def __init__(self, arguments=sys.argv[1:]): 28 | self.arguments = arguments 29 | self.length = len(self.arguments) 30 | 31 | def create_argument_parser(self): 32 | for argument in self.arguments: 33 | if not argument.startswith('-'): 34 | if not self.commands: 35 | self.commands = argument 36 | else: 37 | exception = ArgumentParserException( 38 | f'Invalid flag: {argument}', 39 | 'Flags should start with a comment') 40 | continue 41 | 42 | if argument[2:] not in self.flags: 43 | self.flags.append(argument[2:]) 44 | return self.commands, self.flags 45 | 46 | 47 | def create_argument_parser(lexer, parser): 48 | argument_parser = ArgumentParser() 49 | command, flags = argument_parser.create_argument_parser() 50 | if not command or command == 'repl': 51 | Repl('>>> ', lexer, parser) 52 | elif command == 'help': 53 | print("Showing help") 54 | else: 55 | ExecuteScript(command, 56 | error=ArgumentParserException, 57 | lexer=lexer, 58 | parser=parser) 59 | -------------------------------------------------------------------------------- /examples/HelloWorld.vo: -------------------------------------------------------------------------------- 1 | message = "Hello World" 2 | show(message) 3 | -------------------------------------------------------------------------------- /examples/main.vo: -------------------------------------------------------------------------------- 1 | a = 6 2 | 3 | 4 | # enter("LOL >> ") 5 | if a > 6 { 6 | show("lol") 7 | } else { 8 | show("NOLOL") 9 | } 10 | -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cvython/Vython/094808e9476a2841b7c6be0cd4528bf61996b739/favicon.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from vython.lexer import Lexer 2 | from vython.parser import Parser 3 | 4 | 5 | from arguments import create_argument_parser 6 | from tokens import tokens 7 | 8 | lexer = Lexer(list(tokens.keys()), list(tokens.values())).get_lexer() 9 | parser_object = Parser(list(tokens.keys())) 10 | parser_object.parse() 11 | parser = parser_object.get_parser() 12 | 13 | create_argument_parser(lexer, parser) 14 | -------------------------------------------------------------------------------- /repl.py: -------------------------------------------------------------------------------- 1 | class Repl(object): 2 | def __init__(self, prompt_message, lexer, parser): 3 | self.lexer = lexer 4 | self.parser = parser 5 | self.message = prompt_message 6 | self.create_repl() 7 | 8 | def create_repl(self): 9 | is_repl_launched = True 10 | while is_repl_launched: 11 | try: 12 | repl_input = input(self.message) 13 | tokens = self.lexer.lex(repl_input) 14 | parser = self.parser.parse(tokens) 15 | except KeyboardInterrupt: 16 | print("Your keyboard interrupted") 17 | is_repl_launched = False 18 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | class ExecuteScript(object): 4 | def __init__(self, 5 | filename=None, 6 | from_file=True, 7 | content=None, 8 | error=None, 9 | lexer=None, 10 | parser=None): 11 | self.filename = filename 12 | self.from_file = from_file 13 | self.content = content 14 | self.error = error 15 | self.lexer = lexer 16 | self.parser = parser 17 | 18 | if self.from_file: 19 | if not os.path.isfile(self.filename): 20 | if self.error: 21 | self.error(f'{self.filename} is not a file') 22 | with open(self.filename, 'r') as file_content_reader: 23 | self.content = file_content_reader.read() 24 | 25 | self.execute_script() 26 | 27 | def execute_script(self): 28 | tokens = self.lexer.lex(self.content) 29 | parser = self.parser.parse(tokens) 30 | -------------------------------------------------------------------------------- /tokens.py: -------------------------------------------------------------------------------- 1 | ## Tokens 2 | tokens = { 3 | 'COMMENT': r'#.*', 4 | 'NEWLINE': r'\n+', 5 | 'STRING': r'(\"([^\\\n]|(\\.))*?\")|(\'([^\\\n]|(\\.))*?\')', 6 | 'BOOLEAN': r'(true)|(false)', 7 | 'FLOAT': r'-?\d+\.\d+', 8 | 'INTEGER': r'-?\d+', 9 | 'ELSEIF': r'(else if)|(elseif)', 10 | 'IF': r'if', 11 | 'OPEN_CRO': r'\{', 12 | 'CLOSE_CRO': r'\}', 13 | 'ELSE': r'else', 14 | 'LOOP': r'loop', 15 | 'WHILE': r'while', 16 | 'AND': r'(and)|(&&)', 17 | 'OR': r'(or)|(\|\|)', 18 | 'NOT': r'(not)|(!)', 19 | 'PRINT': r'show', 20 | 'EXIT': r'exit', 21 | 'ENTER': r'enter', 22 | 'INT': r'int', 23 | 'FLOATF': r'float', 24 | 'STR': r'str', 25 | 'TYPE': r'type', 26 | 'BOOL': r'boolean', 27 | 'CANBE': r'canbe', 28 | 'VIRGULE': r',', 29 | 'IS': r'\=\=', 30 | 'LESSE': r'\<\=', 31 | 'MOREE': r'\>\=', 32 | 'LESS': r'\<', 33 | 'MORE': r'\>', 34 | 'INCREMENT': r'\+\+', 35 | 'DECREMENT': r'\-\-', 36 | 'SUMAFF': r'\+\=', 37 | 'SUBAFF': r'\-\=', 38 | 'MULAFF': r'\*\=', 39 | 'DIVAFF': r'\/\=', 40 | 'DIVEUAFF': r'\/\/\=', 41 | 'MODAFF': r'\%\=', 42 | 'POWAFF': r'\^\=', 43 | 'SUM': r'\+', 44 | 'SUB': r'\-', 45 | 'MUL': r'\*', 46 | 'DIV': r'\/', 47 | 'DIVEU': r'\/\/', 48 | 'MOD': r'\%', 49 | 'POW': r'\^', 50 | 'EGAL': r'\=', 51 | 'IDENTIFIER': r"[a-zA-Z][a-zA-Z0-9]*", 52 | 'OPEN_PAREN': r'\(', 53 | 'CLOSE_PAREN': r'\)', 54 | 'CRO_OPEN': r'\[', 55 | 'CRO_CLOSE': r'\]', 56 | 'POINT': r'\.' 57 | } 58 | -------------------------------------------------------------------------------- /vython/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vython/debug.py: -------------------------------------------------------------------------------- 1 | def debug(lexer, text_input): 2 | b = lexer.lex(text_input) 3 | for i in list(b): 4 | print(i) 5 | 6 | -------------------------------------------------------------------------------- /vython/errors.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | class Errors: 4 | NOTDECLARED = "NotDeclared" 5 | INVALIDTYPE = "InvalidType" 6 | UNEXPECTEDSYNTAX = "UnexceptedSyntax" 7 | EXPECTEDSYNTAX = "ExpectedSyntax" 8 | IMPOSSIBLEOPERATION = "ImpossibleOperation" 9 | NUMBERARG = "InvalidNumber" 10 | INDEXOUTOFRANGE = "IndexOutOfRange" 11 | 12 | 13 | class _ThrowException(object): 14 | def __init__(self, error_type, message, info): 15 | self.elements = info.get("type").split(", ") if info else [] 16 | self.message = message 17 | self.error = error_type 18 | self.info = info 19 | 20 | self.evoke_exception() 21 | 22 | def evoke_exception(self): 23 | print(f"{self.error} : {self.message}") 24 | 25 | if "token" in self.elements: 26 | print(" - Position : Lign", 27 | self.info["token"].getsourcepos().lineno, "| Column", 28 | self.info["token"].getsourcepos().colno) 29 | if self.error == Errors.NOTDECLARED: 30 | print(" - Name :", self.info["token"].getstr()) 31 | if "var" in self.elements: 32 | print(" - Variable : Name =", self.info["var"].name, "| Type =", 33 | self.info["var"].kind.tostr()) 34 | if "member" in self.elements: 35 | print(" - Member :", self.info["member"]) 36 | if "value" in self.elements: 37 | print(" - Value :", self.info["value"]) 38 | if "nbgived" in self.elements: 39 | print(" - Number Gived :", self.info["nbgived"]) 40 | if "nbwanted" in self.elements: 41 | print(" - Number Expected :", self.info["nbwanted"]) 42 | if "typegived" in self.elements: 43 | print(" - Type Gived :", self.info["typegived"]) 44 | if "typewanted" in self.elements: 45 | print(" - Type Expected :", self.info["typewanted"]) 46 | if "operationtype" in self.elements: 47 | print(" - Operation :", self.info["operationtype"]) 48 | if "index" in self.elements: 49 | print(" - Index :", self.info["index"]) 50 | if "max" in self.elements: 51 | print(" - Maximum :", self.info["max"]) 52 | if "values" in self.elements: 53 | print(" - Values :", self.info["values"][0], "|", 54 | self.info["values"][1]) 55 | if "types" in self.elements: 56 | print(" - Types :", self.info["types"][0], "|", 57 | self.info["types"][1]) 58 | 59 | 60 | def error(error_type, message, info): 61 | _ThrowException(error_type, message, info) 62 | sys.exit() 63 | return None 64 | -------------------------------------------------------------------------------- /vython/lang/affection_operators.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | import sys 3 | from vython.errors import error, Errors as errors 4 | 5 | class AffectionOperator(BaseBox): 6 | def __init__(self, var, right): 7 | self.right = right 8 | self.var = var 9 | self.kind = var.kind 10 | 11 | class SumAffector(AffectionOperator): 12 | def eval(self): 13 | if self.right.kind == "string": 14 | self.kind = "string" 15 | 16 | try: 17 | self.var.value = self.var.value + self.right.eval() 18 | return self.var.value 19 | except: 20 | try: 21 | self.var.value = self.var.expression().sum(self.right.eval()) 22 | return self.var.value 23 | except: 24 | error( 25 | errors.IMPOSSIBLEOPERATION, "", { 26 | "type": "values, types, operationtype", 27 | "operationtype": "Addition Affection", 28 | "values": [self.var.eval().eval(), 29 | self.right.eval()], 30 | "types": 31 | [self.var.kind.tostr(), 32 | self.right.kind.tostr()] 33 | }) 34 | sys.exit(1) 35 | 36 | 37 | class SubAffector(AffectionOperator): 38 | def eval(self): 39 | try: 40 | self.var.value = self.var.value - self.right.eval() 41 | return self.var.value 42 | except: 43 | try: 44 | self.var.value = self.var.expression().sub(self.right.eval()) 45 | return self.var.value 46 | except: 47 | error( 48 | errors.IMPOSSIBLEOPERATION, "", { 49 | "type": "values, types, operationtype", 50 | "operationtype": "Subtraction Affection", 51 | "values": [self.var.eval().eval(), 52 | self.right.eval()], 53 | "types": 54 | [self.var.kind.tostr(), 55 | self.right.kind.tostr()] 56 | }) 57 | sys.exit(1) 58 | 59 | 60 | class MulAffector(AffectionOperator): 61 | def eval(self): 62 | try: 63 | self.var.value = self.var.value * self.right.eval() 64 | return self.var.value 65 | except: 66 | try: 67 | self.var.value = self.var.expression().mul(self.right.eval()) 68 | return self.var.value 69 | except: 70 | error( 71 | errors.IMPOSSIBLEOPERATION, "", { 72 | "type": "values, types, operationtype", 73 | "operationtype": "Multiplication Affection", 74 | "values": [self.var.eval().eval(), 75 | self.right.eval()], 76 | "types": 77 | [self.var.kind.tostr(), 78 | self.right.kind.tostr()] 79 | }) 80 | sys.exit(1) 81 | 82 | 83 | class DivAffector(AffectionOperator): 84 | def eval(self): 85 | try: 86 | self.var.value = self.var.value / self.right.eval() 87 | return self.var.value 88 | except: 89 | try: 90 | self.var.value = self.var.expression().div(self.right.eval()) 91 | return self.var.value 92 | except: 93 | error( 94 | errors.IMPOSSIBLEOPERATION, "", { 95 | "type": "values, types, operationtype", 96 | "operationtype": "Division Affection", 97 | "values": [self.var.eval().eval(), 98 | self.right.eval()], 99 | "types": 100 | [self.var.kind.tostr(), 101 | self.right.kind.tostr()] 102 | }) 103 | sys.exit(1) 104 | 105 | 106 | class DivEuAffector(AffectionOperator): 107 | def eval(self): 108 | try: 109 | self.var.value = self.var.value // self.right.eval() 110 | return self.var.value 111 | except: 112 | try: 113 | self.var.value = self.var.expression().diveu(self.right.eval()) 114 | return self.var.value 115 | except: 116 | error( 117 | errors.IMPOSSIBLEOPERATION, "", { 118 | "type": "values, types, operationtype", 119 | "operationtype": "Euclidean Division Affection", 120 | "values": [self.var.eval().eval(), 121 | self.right.eval()], 122 | "types": 123 | [self.var.kind.tostr(), 124 | self.right.kind.tostr()] 125 | }) 126 | sys.exit(1) 127 | 128 | 129 | class ModAffector(AffectionOperator): 130 | def eval(self): 131 | try: 132 | self.var.value = self.var.value % self.right.eval() 133 | return self.var.value 134 | except: 135 | try: 136 | self.var.value = self.var.expression().mod(self.right.eval()) 137 | return self.var.value 138 | except: 139 | error( 140 | errors.IMPOSSIBLEOPERATION, "", { 141 | "type": "values, types, operationtype", 142 | "operationtype": "Modulo Affection", 143 | "values": [self.var.eval().eval(), 144 | self.right.eval()], 145 | "types": 146 | [self.var.kind.tostr(), 147 | self.right.kind.tostr()] 148 | }) 149 | sys.exit(1) 150 | 151 | 152 | class PowAffector(AffectionOperator): 153 | def eval(self): 154 | try: 155 | self.var.value = self.var.value**self.right.eval() 156 | return self.var.value 157 | except: 158 | try: 159 | self.var.value = self.var.expression().pow(self.right.eval()) 160 | return self.var.value 161 | except: 162 | error( 163 | errors.IMPOSSIBLEOPERATION, "", { 164 | "type": "values, types, operationtype", 165 | "operationtype": "Power Affection", 166 | "values": [self.var.eval().eval(), 167 | self.right.eval()], 168 | "types": 169 | [self.var.kind.tostr(), 170 | self.right.kind.tostr()] 171 | }) 172 | sys.exit(1) 173 | -------------------------------------------------------------------------------- /vython/lang/binary_operators.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | from vython.errors import error, Errors as errors 3 | import sys 4 | 5 | class BinaryOp(BaseBox): 6 | def __init__(self, left, right): 7 | self.left = left 8 | self.right = right 9 | if self.right.kind == "string" or self.left.kind == "string": 10 | self.kind = "string" 11 | else: 12 | self.kind = self.left.kind 13 | 14 | class Sum(BinaryOp): 15 | def eval(self): 16 | try: 17 | return self.left.eval() + self.right.eval() 18 | except: 19 | try: 20 | return self.left.sum(self.right) 21 | except: 22 | error( 23 | errors.IMPOSSIBLEOPERATION, "", { 24 | "type": "values, types, operationtype", 25 | "operationtype": "Addition", 26 | "values": [self.left.eval(), 27 | self.right.eval()], 28 | "types": 29 | [self.left.kind.tostr(), 30 | self.right.kind.tostr()] 31 | }) 32 | sys.exit(1) 33 | 34 | 35 | class Sub(BinaryOp): 36 | def eval(self): 37 | try: 38 | return self.left.eval() - self.right.eval() 39 | except: 40 | try: 41 | return self.left.sub(self.right) 42 | except: 43 | error( 44 | errors.IMPOSSIBLEOPERATION, "", { 45 | "type": "values, types, operationtype", 46 | "operationtype": "Substraction", 47 | "values": [self.left.eval(), 48 | self.right.eval()], 49 | "types": 50 | [self.left.kind.tostr(), 51 | self.right.kind.tostr()] 52 | }) 53 | sys.exit(1) 54 | 55 | 56 | class Mul(BinaryOp): 57 | def eval(self): 58 | try: 59 | return self.left.eval() * self.right.eval() 60 | except: 61 | try: 62 | return self.left.mul(self.right) 63 | except: 64 | error( 65 | errors.IMPOSSIBLEOPERATION, "", { 66 | "type": "values, types, operationtype", 67 | "operationtype": "Multiplication", 68 | "values": [self.left.eval(), 69 | self.right.eval()], 70 | "types": 71 | [self.left.kind.tostr(), 72 | self.right.kind.tostr()] 73 | }) 74 | sys.exit(1) 75 | 76 | 77 | class Div(BinaryOp): 78 | def eval(self): 79 | try: 80 | return self.left.eval() / self.right.eval() 81 | except: 82 | try: 83 | return self.left.div(self.right) 84 | except: 85 | error( 86 | errors.IMPOSSIBLEOPERATION, "", { 87 | "type": "values, types, operationtype", 88 | "operationtype": "Division", 89 | "values": [self.left.eval(), 90 | self.right.eval()], 91 | "types": 92 | [self.left.kind.tostr(), 93 | self.right.kind.tostr()] 94 | }) 95 | sys.exit(1) 96 | 97 | 98 | class DivEu(BinaryOp): 99 | def eval(self): 100 | try: 101 | return self.left.eval() // self.right.eval() 102 | except: 103 | try: 104 | return self.left.diveu(self.right) 105 | except: 106 | error( 107 | errors.IMPOSSIBLEOPERATION, "", { 108 | "type": "values, types, operationtype", 109 | "operationtype": "Euclidean Division", 110 | "values": [self.left.eval(), 111 | self.right.eval()], 112 | "types": 113 | [self.left.kind.tostr(), 114 | self.right.kind.tostr()] 115 | }) 116 | sys.exit(1) 117 | 118 | 119 | class Pow(BinaryOp): 120 | def eval(self): 121 | try: 122 | return self.left.eval()**self.right.eval() 123 | except: 124 | try: 125 | return self.left.pow(self.right) 126 | except: 127 | error( 128 | errors.IMPOSSIBLEOPERATION, "", { 129 | "type": "values, types, operationtype", 130 | "operationtype": "Power", 131 | "values": [self.left.eval(), 132 | self.right.eval()], 133 | "types": 134 | [self.left.kind.tostr(), 135 | self.right.kind.tostr()] 136 | }) 137 | sys.exit(1) 138 | 139 | 140 | class Mod(BinaryOp): 141 | def eval(self): 142 | try: 143 | return self.left.eval() % self.right.eval() 144 | except: 145 | try: 146 | return self.left.mod(self.right) 147 | except: 148 | error( 149 | errors.IMPOSSIBLEOPERATION, "", { 150 | "type": "values, types, operationtype", 151 | "operationtype": "Modulo", 152 | "values": [self.left.eval(), 153 | self.right.eval()], 154 | "types": 155 | [self.left.kind.tostr(), 156 | self.right.kind.tostr()] 157 | }) 158 | sys.exit(1) 159 | -------------------------------------------------------------------------------- /vython/lang/comparators.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | 3 | class Comparators(BaseBox): 4 | def __init__(self, left, right): 5 | self.left = left 6 | self.right = right 7 | self.value = False 8 | 9 | 10 | class Egal(Comparators): 11 | def eval(self): 12 | if self.left.eval() == self.right.eval(): 13 | return True 14 | else: 15 | return False 16 | 17 | 18 | class Less(Comparators): 19 | def eval(self): 20 | if self.left.eval() < self.right.eval(): 21 | return True 22 | else: 23 | return False 24 | 25 | 26 | class More(Comparators): 27 | def eval(self): 28 | if self.left.eval() > self.right.eval(): 29 | return True 30 | else: 31 | return False 32 | 33 | 34 | class LessOrEgal(Comparators): 35 | def eval(self): 36 | if self.left.eval() <= self.right.eval(): 37 | return True 38 | else: 39 | return False 40 | 41 | 42 | class MoreOrEgal(Comparators): 43 | def eval(self): 44 | if self.left.eval() >= self.right.eval(): 45 | return True 46 | else: 47 | return False 48 | -------------------------------------------------------------------------------- /vython/lang/conditions.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | 3 | class If(BaseBox): 4 | def __init__(self, condition, statementlist): 5 | self.condition = condition 6 | self.statementlist = statementlist 7 | 8 | def eval(self): 9 | if bool(self.condition.eval()): 10 | self.statementlist.eval() 11 | 12 | @staticmethod 13 | def gettokentype(): 14 | return 'statement' 15 | 16 | 17 | class Else(BaseBox): 18 | def __init__(self, statementlist): 19 | self.statementlist = statementlist 20 | 21 | 22 | class ElseIf(BaseBox): 23 | def __init__(self, condition, statementlist): 24 | self.condition = condition 25 | self.statementlist = statementlist 26 | 27 | def eval(self): 28 | if bool(self.condition.eval()): 29 | self.statementlist.eval() 30 | return True 31 | return False 32 | 33 | 34 | class ElseIfs(BaseBox): 35 | def __init__(self, elseif): 36 | self.elseifs = [] 37 | self.elseifs.append(elseif) 38 | 39 | def add(self, elseif): 40 | for i in elseif.elseifs: 41 | self.elseifs.append(i) 42 | return self 43 | 44 | def eval(self): 45 | find = False 46 | for i in range(len(self.elseifs)): 47 | if self.elseifs[i].eval(): 48 | find = True 49 | break 50 | return find 51 | 52 | 53 | class IfElseIf(BaseBox): 54 | def __init__(self, ifexp, elseifs): 55 | self.ifcondition = ifexp.condition 56 | self.ifstatementlist = ifexp.statementlist 57 | self.elseifs = elseifs 58 | 59 | def eval(self): 60 | if bool(self.ifcondition.eval()): 61 | self.ifstatementlist.eval() 62 | else: 63 | self.elseifs.eval() 64 | 65 | 66 | class IfElseIfElse(BaseBox): 67 | def __init__(self, ifexp, elseifs, elseexp): 68 | self.ifcondition = ifexp.condition 69 | self.ifstatementlist = ifexp.statementlist 70 | self.elseifs = elseifs 71 | self.elsestatementlist = elseexp.statementlist 72 | 73 | def eval(self): 74 | if bool(self.ifcondition.eval()): 75 | self.ifstatementlist.eval() 76 | else: 77 | if not self.elseifs.eval(): 78 | self.elsestatementlist.eval() 79 | 80 | 81 | class IfElse(BaseBox): 82 | def __init__(self, ifexp, elseexp): 83 | self.condition = ifexp.condition 84 | self.statementlistif = ifexp.statementlist 85 | self.statementlistelse = elseexp.statementlist 86 | 87 | def eval(self): 88 | if bool(self.condition.eval()): 89 | self.statementlistif.eval() 90 | else: 91 | self.statementlistelse.eval() 92 | 93 | @staticmethod 94 | def gettokentype(): 95 | return 'statement' 96 | -------------------------------------------------------------------------------- /vython/lang/expressions.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | from vython.lang.types import IntType, StrType, BoolType, FloatType, List, NoneType 3 | import sys 4 | from vython.errors import error, Errors as errors 5 | 6 | types = { 7 | "integer": IntType, 8 | "string": StrType, 9 | "boolean": BoolType, 10 | "float": FloatType, 11 | "list": List, 12 | "none": NoneType 13 | } 14 | 15 | class ExpressionBase(BaseBox): 16 | def __init__(self, value, kind, var=None): 17 | self.value = value 18 | if type(kind) == str: 19 | self.kind = types[kind](self) 20 | else: 21 | self.kind = kind 22 | self.var = var 23 | 24 | def eval(self): 25 | if self.var is not None: 26 | from vython.lang.variables import ListVar 27 | if type(self.var) == ListVar: 28 | self.var.eval() 29 | self.value, self.kind = self.var.value, self.var.kind 30 | return self.value 31 | 32 | def gettype(self): 33 | return self.kind 34 | 35 | def sum(self, exp): 36 | try: 37 | self.value = self.kind.sum(self.eval(), exp.eval()) 38 | except: 39 | self.value = exp.kind.sum(exp.eval(), self.eval()) 40 | return self.value 41 | 42 | def sub(self, exp): 43 | self.value = self.kind.sub(self.eval(), exp.eval()) 44 | return self.value 45 | 46 | def increment(self): 47 | self.value = self.kind.increment(self.eval()) 48 | return self.value 49 | 50 | 51 | class ExpressionFromList(ExpressionBase): 52 | def __init__(self, var, indice): 53 | self.value = "" 54 | self.kind = types["list"](self) 55 | self.var = var 56 | self.indice = indice 57 | 58 | def eval(self): 59 | var = self.var.exp.var 60 | if len(var) <= self.indice: 61 | values = self.var.exp.getexpression() 62 | value = [] 63 | for i in values: 64 | value.append(i.eval()) 65 | error(errors.INDEXOUTOFRANGE, "", { 66 | "type": "max, index", 67 | "index": self.indice, 68 | "max": len(var) - 1 69 | }) 70 | sys.exit(1) 71 | self.value, self.kind = var[self.indice].value, var[self.indice].kind 72 | return self.value 73 | 74 | 75 | class Nothing(BaseBox): 76 | @staticmethod 77 | def eval(): 78 | return None 79 | 80 | @staticmethod 81 | def gettokentype(): 82 | return "statement" 83 | -------------------------------------------------------------------------------- /vython/lang/functions.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | from vython.lang.expressions import ExpressionBase 3 | import sys 4 | from vython.lang.types import BoolType, StrType, IntType, FloatType 5 | from vython.errors import error, Errors as errors 6 | 7 | class CanBe(BaseBox): 8 | def __init__(self, exp, value): 9 | self.value = value 10 | self.exp = exp 11 | self.kind = BoolType(ExpressionBase(True, "boolean")) 12 | 13 | def eval(self): 14 | if self.value == "int": 15 | try: 16 | int(self.exp.eval()) 17 | return True 18 | except: 19 | return False 20 | elif self.value == "float": 21 | try: 22 | float(self.exp.eval()) 23 | return True 24 | except: 25 | return False 26 | elif self.value == "str": 27 | try: 28 | str(self.exp.eval()) 29 | return True 30 | except: 31 | return False 32 | elif self.value == "bool": 33 | try: 34 | bool(self.exp.eval()) 35 | return True 36 | except: 37 | return False 38 | else: 39 | error( 40 | errors.INVALIDTYPE, "", { 41 | "type": "operationtype, typegived, typewanted", 42 | "typewanted": "integer, string, float, boolean", 43 | "typegived": self.value, 44 | "operationtype": "CanBe Function" 45 | }) 46 | sys.exit(1) 47 | 48 | 49 | class Print(BaseBox): 50 | def __init__(self, value=ExpressionBase("", "string")): 51 | self.value = value 52 | self.kind = StrType(ExpressionBase("", "string")) 53 | 54 | def eval(self): 55 | self.value = self.value.eval() 56 | print(self.value) 57 | return self.value 58 | 59 | 60 | class Input(BaseBox): 61 | def __init__(self, text=""): 62 | self.text = text[1:-1] 63 | self.kind = StrType(ExpressionBase("", "string")) 64 | 65 | def eval(self): 66 | try: 67 | data = input(self.text) 68 | return data 69 | except KeyboardInterrupt: 70 | return '' 71 | 72 | 73 | class Int(BaseBox): 74 | def __init__(self, exp): 75 | self.exp = exp 76 | self.kind = IntType(ExpressionBase(0, "integer")) 77 | 78 | def eval(self): 79 | try: 80 | return int(self.exp.eval()) 81 | except: 82 | error( 83 | errors.IMPOSSIBLEOPERATION, "", { 84 | "type": "operationtype, value", 85 | "operationtype": "Become Integer", 86 | "value": self.exp.eval() 87 | }) 88 | sys.exit(1) 89 | 90 | 91 | class Float(BaseBox): 92 | def __init__(self, exp): 93 | self.exp = exp 94 | self.kind = FloatType(ExpressionBase(0.0, "float")) 95 | 96 | def eval(self): 97 | try: 98 | return float(self.exp.eval()) 99 | except: 100 | error( 101 | errors.IMPOSSIBLEOPERATION, "", { 102 | "type": "operationtype, value", 103 | "operationtype": "Become Float", 104 | "value": self.exp.eval() 105 | }) 106 | sys.exit(1) 107 | 108 | 109 | class Str(BaseBox): 110 | def __init__(self, exp): 111 | self.exp = exp 112 | self.kind = StrType(ExpressionBase("", "string")) 113 | 114 | def eval(self): 115 | try: 116 | return str(self.exp.eval()) 117 | except: 118 | error( 119 | errors.IMPOSSIBLEOPERATION, "", { 120 | "type": "operationtype, value", 121 | "operationtype": "Become String", 122 | "value": self.exp.eval() 123 | }) 124 | sys.exit(1) 125 | 126 | 127 | class Boolean(BaseBox): 128 | def __init__(self, exp): 129 | self.exp = exp 130 | self.kind = BoolType(ExpressionBase(True, "boolean")) 131 | 132 | def eval(self): 133 | try: 134 | return bool(self.exp.eval()) 135 | except: 136 | error( 137 | errors.IMPOSSIBLEOPERATION, "", { 138 | "type": "operationtype, value", 139 | "operationtype": "Become Boolean", 140 | "value": self.exp.eval() 141 | }) 142 | sys.exit(1) 143 | 144 | class Type(BaseBox): 145 | def __init__(self, exp): 146 | self.exp = exp 147 | self.kind = StrType(ExpressionBase("", "string")) 148 | 149 | def eval(self): 150 | self.exp.eval() 151 | return self.exp.gettype().tostr() 152 | -------------------------------------------------------------------------------- /vython/lang/logic_operators.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | 3 | class LogicOperators(BaseBox): 4 | def __init__(self, left, right=None): 5 | self.left = left 6 | self.right = right 7 | 8 | 9 | class And(LogicOperators): 10 | def eval(self): 11 | if self.left.eval() and self.right.eval(): 12 | return True 13 | else: 14 | return False 15 | 16 | 17 | class Or(LogicOperators): 18 | def eval(self): 19 | if self.left.eval() or self.right.eval(): 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | class Not(LogicOperators): 26 | def eval(self): 27 | if not self.left.eval(): 28 | return True 29 | else: 30 | return False 31 | -------------------------------------------------------------------------------- /vython/lang/loops.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | 3 | class Loop(BaseBox): 4 | def __init__(self, number, statementlist): 5 | self.number = number 6 | self.statementlist = statementlist 7 | 8 | def eval(self): 9 | for i in range(self.number): 10 | self.statementlist.eval() 11 | 12 | @staticmethod 13 | def gettokentype(): 14 | return 'statement' 15 | 16 | 17 | class While(BaseBox): 18 | def __init__(self, condition, statementlist): 19 | self.condition = condition 20 | self.statementlist = statementlist 21 | 22 | def eval(self): 23 | while bool(self.condition.eval()): 24 | self.statementlist.eval() 25 | 26 | @staticmethod 27 | def gettokentype(): 28 | return 'statement' 29 | -------------------------------------------------------------------------------- /vython/lang/statements.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | 3 | class Statement(BaseBox): 4 | def __init__(self, exp): 5 | self.exp = exp 6 | 7 | def eval(self): 8 | self.exp.eval() 9 | 10 | @staticmethod 11 | def gettokentype(): 12 | return "statement" 13 | 14 | 15 | class StatementList(BaseBox): 16 | def __init__(self, statement, sl=None): 17 | if sl is not None: 18 | self.statements = sl.statements 19 | else: 20 | self.statements = [] 21 | if statement is not None: 22 | self.statements.append(statement) 23 | 24 | def eval(self): 25 | for i in self.statements: 26 | i.eval() 27 | 28 | @staticmethod 29 | def gettokentype(): 30 | return "statementlist" 31 | -------------------------------------------------------------------------------- /vython/lang/types.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from vython.errors import error, Errors as errors 3 | 4 | 5 | class Type: 6 | def __init__(self, exp): 7 | self.name = "" 8 | self.exp = exp 9 | self.paramMember = [] 10 | 11 | def callmember(self, membre, param): 12 | self.paramMember = param 13 | try: 14 | return eval("self." + membre + "()") 15 | except AttributeError: 16 | error( 17 | errors.NOTDECLARED, "Unknown Member", { 18 | "type": "typeerror, member", 19 | "member": membre, 20 | "typeerror": self.name 21 | }) 22 | sys.exit(1) 23 | 24 | def tostr(self): 25 | return self.name 26 | 27 | 28 | class NoneType(Type): 29 | def __init__(self, exp): 30 | super(NoneType, self).__init__(exp) 31 | self.name = "none" 32 | 33 | 34 | class IntType(Type): 35 | def __init__(self, exp): 36 | super(IntType, self).__init__(exp) 37 | self.name = "integer" 38 | 39 | 40 | class StrType(Type): 41 | def __init__(self, exp): 42 | super(StrType, self).__init__(exp) 43 | self.name = "string" 44 | 45 | def sum(self, value1, value2): 46 | return str(value1) + str(value2) 47 | 48 | def sub(self, value1, value2): 49 | return str(value1)[:len(value1) - value2] 50 | 51 | def increment(self, value1): 52 | return value1 + value1 53 | 54 | def length(self): 55 | nbarg = 0 56 | if len(self.paramMember) != nbarg: 57 | error( 58 | errors.NUMBERARG, "", { 59 | "type": "nbwanted, nbgived, member", 60 | "member": "length", 61 | "nbgived": len(self.paramMember), 62 | "nbwanted": nbarg 63 | }) 64 | sys.exit(1) 65 | return len(self.exp.eval()) 66 | 67 | 68 | class FloatType(Type): 69 | def __init__(self, exp): 70 | super(FloatType, self).__init__(exp) 71 | self.name = "float" 72 | 73 | 74 | class BoolType(Type): 75 | def __init__(self, exp): 76 | super(BoolType, self).__init__(exp) 77 | self.name = "bool" 78 | 79 | 80 | class List(Type): 81 | def __init__(self, exp=None, exp2=None): 82 | super(List, self).__init__(exp) 83 | self.name = "list" 84 | self.kind = self 85 | if exp is None and exp2 is None: 86 | self.var = [] 87 | elif exp is None: 88 | if type(exp2) == List: 89 | self.var = exp2.var 90 | else: 91 | self.var = [exp2] 92 | elif exp2 is None: 93 | if type(exp) == List: 94 | self.var = exp.var 95 | else: 96 | self.var = [exp] 97 | else: 98 | if type(exp) == List and type(exp2) == List: 99 | self.var = exp.var 100 | for i in exp2.var: 101 | self.var.append(i) 102 | elif type(exp) == List: 103 | self.var = exp.var 104 | self.var.append(exp2) 105 | elif type(exp2) == List: 106 | self.var = [exp] 107 | for i in exp2.var: 108 | self.var.append(i) 109 | else: 110 | self.var = [exp, exp2] 111 | 112 | def add(self, exp): 113 | self.var.append(exp) 114 | 115 | def getexpression(self): 116 | return self.var 117 | 118 | def eval(self): 119 | for i in range(len(self.var)): 120 | self.var[i].value = self.var[i].eval() 121 | 122 | def length(self): 123 | nbarg = 0 124 | if len(self.paramMember) != nbarg: 125 | error( 126 | errors.NUMBERARG, "", { 127 | "type": "nbwanted, nbgived, member", 128 | "member": "length", 129 | "nbgived": len(self.paramMember), 130 | "nbwanted": nbarg 131 | }) 132 | sys.exit(1) 133 | self.eval() 134 | return len(self.var) 135 | 136 | def remove(self): 137 | nbarg = 1 138 | if len(self.paramMember) != nbarg: 139 | error( 140 | errors.NUMBERARG, "", { 141 | "type": "nbwanted, nbgived, member", 142 | "member": "length", 143 | "nbgived": len(self.paramMember), 144 | "nbwanted": nbarg 145 | }) 146 | sys.exit(1) 147 | if type(self.paramMember[0].kind) != IntType: 148 | error( 149 | errors.INVALIDTYPE, "", { 150 | "type": "typewanted, typegived, member", 151 | "member": "remove", 152 | "typegived": self.paramMember[0].kind.tostr(), 153 | "typewanted": IntType(None).tostr() 154 | }) 155 | sys.exit(1) 156 | self.eval() 157 | value = self.var[self.paramMember[0].eval()] 158 | del self.var[self.paramMember[0].eval()] 159 | return value.eval() 160 | 161 | 162 | typesOfMembers = {"length": IntType, "remove": NoneType} 163 | 164 | 165 | class MemberType: 166 | def __init__(self, name, var, param=None): 167 | if param is None: 168 | param = [] 169 | self.name = name 170 | self.var = var 171 | try: 172 | self.kind = typesOfMembers[self.name](None) 173 | except KeyError: 174 | error( 175 | errors.NOTDECLARED, "Unknown Member", { 176 | "type": "typeerror, member", 177 | "member": self.name, 178 | "typeerror": self.var.gettype().tostr() 179 | }) 180 | sys.exit(1) 181 | self.param = param 182 | 183 | def eval(self): 184 | return self.var.gettype().callmember(self.name, self.param) 185 | -------------------------------------------------------------------------------- /vython/lang/unique_operators.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | import sys 3 | from vython.errors import error, Errors as errors 4 | 5 | class UniqueOp(BaseBox): 6 | def __init__(self, var): 7 | self.var = var 8 | 9 | class Increment(UniqueOp): 10 | def eval(self): 11 | try: 12 | self.var.value = self.var.value + 1 13 | return self.var.value 14 | except: 15 | try: 16 | self.var.value = self.var.expression().increment() 17 | return self.var.value 18 | except: 19 | error( 20 | errors.IMPOSSIBLEOPERATION, "", { 21 | "type": "operationtype, var", 22 | "operationtype": "Increase", 23 | "var": self.var 24 | }) 25 | sys.exit(1) 26 | 27 | 28 | class Decrement(UniqueOp): 29 | def eval(self): 30 | try: 31 | self.var.value = self.var.value - 1 32 | return self.var.value 33 | except: 34 | try: 35 | self.var.value = self.var.expression().decrement() 36 | return self.var.value 37 | except: 38 | error( 39 | errors.IMPOSSIBLEOPERATION, "", { 40 | "type": "operationtype, var", 41 | "operationtype": "Decrease", 42 | "var": self.var 43 | }) 44 | sys.exit(1) 45 | -------------------------------------------------------------------------------- /vython/lang/variables.py: -------------------------------------------------------------------------------- 1 | from rply.token import BaseBox 2 | from vython.lang.expressions import ExpressionBase, ExpressionFromList 3 | from vython.lang.types import List 4 | 5 | class Variables(BaseBox): 6 | def __init__(self): 7 | self.vars = [] 8 | 9 | def add(self, var): 10 | if self.get(var.name) is not None: 11 | self.set(var.name, var.value) 12 | else: 13 | self.vars.append(var) 14 | 15 | def get(self, nom): 16 | for i in self.vars: 17 | if i.name == nom: 18 | return i 19 | 20 | def set(self, nom, exp): 21 | var = self.get(nom) 22 | if var is not None: 23 | var.value = exp 24 | 25 | 26 | class Variable(BaseBox): 27 | def __init__(self, name, exp): 28 | self.name = name 29 | self.exp = exp 30 | self.kind = exp.kind 31 | self.value = None 32 | 33 | def expression(self): 34 | return ExpressionBase(self.value, self.kind) 35 | 36 | def get(self, indice): 37 | return ExpressionBase(None, "none") 38 | 39 | def gettype(self): 40 | return self.kind 41 | 42 | def eval(self): 43 | self.value = self.exp.eval() 44 | self.kind = self.exp.kind 45 | return ExpressionBase(self.value, self.kind) 46 | 47 | 48 | class ListVar(BaseBox): 49 | def __init__(self, name, exp): 50 | self.name = name 51 | self.exp = exp 52 | self.kind = exp 53 | self.value = [] 54 | self.values = [] 55 | 56 | def expression(self): 57 | return ExpressionBase(self.values, self.kind, self) 58 | 59 | def get(self, indice): 60 | return ExpressionFromList(self, indice) 61 | 62 | def gettype(self): 63 | return self.kind 64 | 65 | def eval(self): 66 | self.exp.eval() 67 | self.values = self.exp.getexpression() 68 | self.value = [] 69 | for i in self.values: 70 | self.value.append(i.eval()) 71 | return self.value 72 | 73 | 74 | class AffectionVar(BaseBox): 75 | def __init__(self, var, exp): 76 | self.var = var 77 | self.exp = exp 78 | 79 | def eval(self): 80 | if type(self.exp) == List and type(self.var.exp) == List: 81 | self.var.exp.var = self.exp.var 82 | else: 83 | self.var.exp = self.exp 84 | self.var.eval() 85 | return self.var 86 | -------------------------------------------------------------------------------- /vython/lexer.py: -------------------------------------------------------------------------------- 1 | from rply import LexerGenerator 2 | 3 | 4 | class Lexer: 5 | def __init__(self, tokens, values): 6 | self.lexer = LexerGenerator() 7 | self.tokens = tokens 8 | self.values = values 9 | 10 | def _add_tokens(self): 11 | for i in range(len(self.tokens)): 12 | self.lexer.add(self.tokens[i], self.values[i]) 13 | # Ignore spaces 14 | self.lexer.ignore('\t+') 15 | self.lexer.ignore(r' +') 16 | 17 | def get_lexer(self): 18 | self._add_tokens() 19 | return self.lexer.build() 20 | -------------------------------------------------------------------------------- /vython/parser.py: -------------------------------------------------------------------------------- 1 | from rply import ParserGenerator 2 | import sys 3 | 4 | 5 | from vython.errors import error, Errors as errors 6 | 7 | from vython.lang.binary_operators import (Sum, Sub, Mul, Div, Mod, Pow, DivEu) 8 | from vython.lang.affection_operators import (SumAffector, SubAffector, 9 | DivEuAffector, MulAffector, 10 | DivAffector, ModAffector, 11 | PowAffector) 12 | from vython.lang.expressions import ExpressionBase, Nothing 13 | from vython.lang.functions import Print, Input, Int, Str, Float, Type, Boolean, CanBe 14 | from vython.lang.variables import Variable, Variables, AffectionVar, ListVar 15 | from vython.lang.unique_operators import Increment, Decrement 16 | from vython.lang.comparators import Egal, Less, LessOrEgal, More, MoreOrEgal 17 | from vython.lang.conditions import (If, IfElse, Else, ElseIf, IfElseIf, 18 | IfElseIfElse, ElseIfs) 19 | from vython.lang.logic_operators import And, Or, Not 20 | from vython.lang.statements import Statement, StatementList 21 | from vython.lang.loops import Loop, While 22 | from vython.lang.types import List, MemberType 23 | 24 | 25 | class Parser: 26 | def __init__(self, tokens): 27 | self.pg = ParserGenerator( 28 | tokens, 29 | precedence=[('left', ['NEWLINE']), ('left', ['EGAL']), 30 | ('left', ['AND', 'OR', 'NOT']), 31 | ('left', ['IS', 'LESS', 'MORE', 'LESSE', 'MOREE']), 32 | ('left', ['SUMAFF', 'SUBAFF']), 33 | ('left', ['MULAFF', 'DIVAFF', 'DIVEUAFF', 'MODAFF']), 34 | ('left', ['POWAFF']), ('left', ['SUM', 'SUB']), 35 | ('left', ['MUL', 'DIV', 'DIVEU', 'MOD']), 36 | ('left', ['POW'])]) 37 | self.var = Variables() 38 | 39 | def parse(self): 40 | @self.pg.production('program : statementlist') 41 | def program(p): 42 | return p[0].eval() 43 | 44 | @self.pg.production('statementlist : statementlist NEWLINE statement') 45 | @self.pg.production( 46 | 'statementlist : statementlist NEWLINE loop_statement') 47 | @self.pg.production( 48 | 'statementlist : statementlist NEWLINE if_statement') 49 | def statementlistexp(p): 50 | return StatementList(p[2], p[0]) 51 | 52 | @self.pg.production('statementlist : statement') 53 | @self.pg.production('statementlist : loop_statement') 54 | @self.pg.production('statementlist : if_statement') 55 | @self.pg.production('statementlist : statementlist NEWLINE') 56 | def statementlist(p): 57 | if p[0].gettokentype() == 'statement': 58 | return StatementList(p[0]) 59 | else: 60 | return StatementList(None, p[0]) 61 | 62 | @self.pg.production( 63 | 'loop_statement : LOOP INTEGER OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' 64 | ) 65 | def loop(p): 66 | return Loop(int(p[1].value), p[4]) 67 | 68 | @self.pg.production( 69 | 'loop_statement : LOOP INTEGER NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' 70 | ) 71 | def loop2(p): 72 | return Loop(int(p[1].value), p[5]) 73 | 74 | @self.pg.production( 75 | 'loop_statement : WHILE expression OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' 76 | ) 77 | def whileexp(p): 78 | return While(p[1], p[4]) 79 | 80 | @self.pg.production( 81 | 'loop_statement : WHILE expression NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE ' 82 | 'CLOSE_CRO') 83 | def whileexp2(p): 84 | return While(p[1], p[5]) 85 | 86 | @self.pg.production( 87 | 'if_statement : IF expression OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' 88 | ) 89 | def ifexp(p): 90 | return If(p[1], p[4]) 91 | 92 | @self.pg.production( 93 | 'if_statement : IF expression NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' 94 | ) 95 | def ifexp2(p): 96 | return If(p[1], p[5]) 97 | 98 | @self.pg.production( 99 | 'else_statement : ELSE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' 100 | ) 101 | def elseexp(p): 102 | return Else(p[3]) 103 | 104 | @self.pg.production( 105 | 'else_statement : ELSE NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE CLOSE_CRO' 106 | ) 107 | def elseexp2(p): 108 | return Else(p[4]) 109 | 110 | @self.pg.production( 111 | 'elseif_statement : ELSEIF expression OPEN_CRO NEWLINE statementlist NEWLINE ' 112 | 'CLOSE_CRO') 113 | def elseif(p): 114 | return ElseIfs(ElseIf(p[1], p[4])) 115 | 116 | @self.pg.production( 117 | 'elseif_statement : ELSEIF expression NEWLINE OPEN_CRO NEWLINE statementlist NEWLINE ' 118 | 'CLOSE_CRO') 119 | def elseif2(p): 120 | return ElseIfs(ElseIf(p[1], p[5])) 121 | 122 | @self.pg.production( 123 | 'elseif_statement : elseif_statement elseif_statement') 124 | def elseif3(p): 125 | return p[0].add(p[1]) 126 | 127 | @self.pg.production('if_statement : if_statement else_statement') 128 | def ifelse(p): 129 | if type(p[0]) == IfElse: 130 | error(errors.UNEXPECTEDSYNTAX, "Alone Else", {"type": ""}) 131 | sys.exit(1) 132 | elif type(p[0]) == IfElseIf: 133 | return IfElseIfElse(If(p[0].ifcondition, p[0].ifstatementlist), 134 | p[0].elseifs, p[1]) 135 | else: 136 | return IfElse(p[0], p[1]) 137 | 138 | @self.pg.production('if_statement : if_statement elseif_statement') 139 | def ifelseif(p): 140 | if type(p[0]) == IfElse: 141 | error(errors.UNEXPECTEDSYNTAX, "Alone ElseIf", {"type": ""}) 142 | sys.exit(1) 143 | return IfElseIf(p[0], p[1]) 144 | 145 | @self.pg.production('statement : expression COMMENT') 146 | @self.pg.production('statement : expression') 147 | def statement(p): 148 | return Statement(p[0]) 149 | 150 | @self.pg.production('statement : COMMENT') 151 | def statement(p): 152 | return Nothing() 153 | 154 | @self.pg.production('expression : IDENTIFIER EGAL expression') 155 | def programvar(p): 156 | if type(p[2]) == List: 157 | error(errors.EXPECTEDSYNTAX, "Expected hook around List.", { 158 | "type": "token", 159 | "token": p[0] 160 | }) 161 | sys.exit(1) 162 | var = self.var.get(p[0].value) 163 | if var is not None: 164 | if type(var) == ListVar: 165 | error(errors.INVALIDTYPE, "Cannot have basic type.", { 166 | "type": "token", 167 | "token": p[0] 168 | }) 169 | sys.exit(1) 170 | return AffectionVar(var, p[2]) 171 | else: 172 | var = Variable(p[0].value, p[2]) 173 | self.var.add(var) 174 | return var 175 | 176 | @self.pg.production('expression : IDENTIFIER EGAL CRO_OPEN CRO_CLOSE') 177 | def programvar2(p): 178 | var = self.var.get(p[0].value) 179 | if var is not None: 180 | if type(var) == Variable: 181 | error(errors.INVALIDTYPE, "Cannot have complex type.", { 182 | "type": "token", 183 | "token": p[0] 184 | }) 185 | sys.exit(1) 186 | return AffectionVar(var, List()) 187 | else: 188 | var = ListVar(p[0].value, List()) 189 | self.var.add(var) 190 | return var 191 | 192 | @self.pg.production( 193 | 'expression : IDENTIFIER EGAL CRO_OPEN expression CRO_CLOSE') 194 | def programvar3(p): 195 | var = self.var.get(p[0].value) 196 | if var is not None: 197 | if type(var) == Variable: 198 | error(errors.INVALIDTYPE, "Cannot have complex type.", { 199 | "type": "token", 200 | "token": p[0] 201 | }) 202 | sys.exit(1) 203 | return AffectionVar(var, List(p[3])) 204 | else: 205 | var = ListVar(p[0].value, List(p[3])) 206 | self.var.add(var) 207 | return var 208 | 209 | @self.pg.production( 210 | 'expression : IDENTIFIER POINT IDENTIFIER OPEN_PAREN CLOSE_PAREN') 211 | def membervar(p): 212 | var = self.var.get(p[0].value) 213 | if var is not None: 214 | return MemberType(p[2].value, var) 215 | else: 216 | error(errors.NOTDECLARED, "Variable is not declared.", { 217 | "type": "token", 218 | "token": p[0] 219 | }) 220 | sys.exit(1) 221 | 222 | @self.pg.production( 223 | 'expression : IDENTIFIER POINT IDENTIFIER OPEN_PAREN expression CLOSE_PAREN' 224 | ) 225 | def membervar2(p): 226 | var = self.var.get(p[0].value) 227 | if var is not None: 228 | return MemberType(p[2].value, var, [p[4]]) 229 | else: 230 | error(errors.NOTDECLARED, "Variable is not declared.", { 231 | "type": "token", 232 | "token": p[0] 233 | }) 234 | sys.exit(1) 235 | 236 | @self.pg.production('expression : expression VIRGULE expression') 237 | def list(p): 238 | return List(p[0], p[2]) 239 | 240 | @self.pg.production( 241 | 'expression : CANBE OPEN_PAREN expression VIRGULE STRING CLOSE_PAREN' 242 | ) 243 | def programfunc2(p): 244 | func = p[0] 245 | exp = p[2] 246 | if func.gettokentype() == 'CANBE': 247 | return CanBe(exp, p[4].value[1:-1]) 248 | 249 | @self.pg.production( 250 | 'expression : INT OPEN_PAREN expression CLOSE_PAREN') 251 | @self.pg.production( 252 | 'expression : FLOATF OPEN_PAREN expression CLOSE_PAREN') 253 | @self.pg.production( 254 | 'expression : BOOL OPEN_PAREN expression CLOSE_PAREN') 255 | @self.pg.production( 256 | 'expression : STR OPEN_PAREN expression CLOSE_PAREN') 257 | @self.pg.production( 258 | 'expression : TYPE OPEN_PAREN expression CLOSE_PAREN') 259 | @self.pg.production( 260 | 'expression : PRINT OPEN_PAREN expression CLOSE_PAREN') 261 | @self.pg.production('expression : ENTER OPEN_PAREN STRING CLOSE_PAREN') 262 | def programfunc1(p): 263 | func = p[0] 264 | exp = p[2] 265 | if func.gettokentype() == "INT": 266 | return Int(exp) 267 | elif func.gettokentype() == "FLOATF": 268 | return Float(exp) 269 | elif func.gettokentype() == "BOOL": 270 | return Boolean(exp) 271 | elif func.gettokentype() == "STR": 272 | return Str(exp) 273 | elif func.gettokentype() == "TYPE": 274 | return Type(exp) 275 | elif func.gettokentype() == "PRINT": 276 | return Print(exp) 277 | else: 278 | return Input(exp.value) 279 | 280 | @self.pg.production('expression : EXIT OPEN_PAREN CLOSE_PAREN') 281 | @self.pg.production('expression : ENTER OPEN_PAREN CLOSE_PAREN') 282 | @self.pg.production('expression : PRINT OPEN_PAREN CLOSE_PAREN') 283 | def programfunc0(p): 284 | func = p[0] 285 | if func.gettokentype() == "EXIT": 286 | sys.exit(0) 287 | elif func.gettokentype() == "ENTER": 288 | return Input() 289 | else: 290 | return Print() 291 | 292 | @self.pg.production('expression : OPEN_PAREN expression CLOSE_PAREN') 293 | def expressionparen(p): 294 | return p[1] 295 | 296 | @self.pg.production('expression : IDENTIFIER INCREMENT') 297 | @self.pg.production('expression : IDENTIFIER DECREMENT') 298 | def uniqueop(p): 299 | var = self.var.get(p[0].value) 300 | if var is not None: 301 | if p[1].gettokentype() == "INCREMENT": 302 | return Increment(var) 303 | else: 304 | return Decrement(var) 305 | else: 306 | error(errors.NOTDECLARED, "Variable is not declared.", { 307 | "type": "token", 308 | "token": p[0] 309 | }) 310 | sys.exit(1) 311 | 312 | @self.pg.production('expression : IDENTIFIER SUMAFF expression') 313 | @self.pg.production('expression : IDENTIFIER SUBAFF expression') 314 | @self.pg.production('expression : IDENTIFIER MULAFF expression') 315 | @self.pg.production('expression : IDENTIFIER DIVAFF expression') 316 | @self.pg.production('expression : IDENTIFIER MODAFF expression') 317 | @self.pg.production('expression : IDENTIFIER POWAFF expression') 318 | @self.pg.production('expression : IDENTIFIER DIVEUAFF expression') 319 | def affectionop(p): 320 | var = self.var.get(p[0].value) 321 | op = p[1] 322 | if var is not None: 323 | if op.gettokentype() == 'SUMAFF': 324 | return SumAffector(var, p[2]) 325 | elif op.gettokentype() == 'SUBAFF': 326 | return SubAffector(var, p[2]) 327 | elif op.gettokentype() == 'MULAFF': 328 | return MulAffector(var, p[2]) 329 | elif op.gettokentype() == 'MODAFF': 330 | return ModAffector(var, p[2]) 331 | elif op.gettokentype() == 'POWAFF': 332 | return PowAffector(var, p[2]) 333 | elif op.gettokentype() == 'DIVEUAFF': 334 | return DivEuAffector(var, p[2]) 335 | else: 336 | return DivAffector(var, p[2]) 337 | else: 338 | error(errors.NOTDECLARED, "Variable is not declared.", { 339 | "type": "token", 340 | "token": p[0] 341 | }) 342 | sys.exit(1) 343 | 344 | @self.pg.production('expression : expression SUM expression') 345 | @self.pg.production('expression : expression SUB expression') 346 | @self.pg.production('expression : expression MUL expression') 347 | @self.pg.production('expression : expression DIV expression') 348 | @self.pg.production('expression : expression MOD expression') 349 | @self.pg.production('expression : expression POW expression') 350 | @self.pg.production('expression : expression DIVEU expression') 351 | def binaryop(p): 352 | left = p[0] 353 | right = p[2] 354 | operator = p[1] 355 | if operator.gettokentype() == 'SUM': 356 | return Sum(left, right) 357 | elif operator.gettokentype() == 'SUB': 358 | return Sub(left, right) 359 | elif operator.gettokentype() == 'MUL': 360 | return Mul(left, right) 361 | elif operator.gettokentype() == 'MOD': 362 | return Mod(left, right) 363 | elif operator.gettokentype() == 'POW': 364 | return Pow(left, right) 365 | elif operator.gettokentype() == 'DIVEU': 366 | return DivEu(left, right) 367 | else: 368 | return Div(left, right) 369 | 370 | @self.pg.production('expression : expression AND expression') 371 | @self.pg.production('expression : expression OR expression') 372 | def logicoperators2(p): 373 | op = p[1] 374 | e1 = p[0] 375 | e2 = p[2] 376 | if op.gettokentype() == "AND": 377 | return And(e1, e2) 378 | else: 379 | return Or(e1, e2) 380 | 381 | @self.pg.production('expression : NOT expression') 382 | def logicoperator1(p): 383 | return ExpressionBase(Not(p[1]).eval(), "boolean") 384 | 385 | @self.pg.production('expression : expression IS expression') 386 | @self.pg.production('expression : expression LESS expression') 387 | @self.pg.production('expression : expression LESSE expression') 388 | @self.pg.production('expression : expression MORE expression') 389 | @self.pg.production('expression : expression MOREE expression') 390 | def comparators(p): 391 | c = p[1] 392 | e1 = p[0] 393 | e2 = p[2] 394 | if c.gettokentype() == "IS": 395 | return Egal(e1, e2) 396 | elif c.gettokentype() == "LESS": 397 | return Less(e1, e2) 398 | elif c.gettokentype() == "MORE": 399 | return More(e1, e2) 400 | elif c.gettokentype() == "LESSE": 401 | return LessOrEgal(e1, e2) 402 | else: 403 | return MoreOrEgal(e1, e2) 404 | 405 | @self.pg.production('expression : SUB expression') 406 | @self.pg.production('expression : SUM expression') 407 | def uniqueop(p): 408 | ope = p[0] 409 | exp = p[1] 410 | if ope.gettokentype() == 'SUM': 411 | return Sum(ExpressionBase(0, "integer"), exp) 412 | else: 413 | return Sub(ExpressionBase(0, "integer"), exp) 414 | 415 | @self.pg.production( 416 | 'expression : IDENTIFIER CRO_OPEN INTEGER CRO_CLOSE') 417 | def expressionlist(p): 418 | var = self.var.get(p[0].value) 419 | if var is not None: 420 | return var.get(int(p[2].value)) 421 | else: 422 | error(errors.NOTDECLARED, "Variable is not declared.", { 423 | "type": "token", 424 | "token": p[0] 425 | }) 426 | sys.exit(1) 427 | 428 | @self.pg.production('expression : FLOAT') 429 | @self.pg.production('expression : INTEGER') 430 | @self.pg.production('expression : STRING') 431 | @self.pg.production('expression : BOOLEAN') 432 | @self.pg.production('expression : IDENTIFIER') 433 | def expression(p): 434 | if p[0].gettokentype() == 'FLOAT': 435 | return ExpressionBase(float(p[0].value), "float") 436 | elif p[0].gettokentype() == 'STRING': 437 | return ExpressionBase(str(p[0].value)[1:-1], "string") 438 | elif p[0].gettokentype() == 'BOOLEAN': 439 | if p[0].value == "false": 440 | return ExpressionBase(False, "boolean") 441 | return ExpressionBase(True, "boolean") 442 | elif p[0].gettokentype() == 'IDENTIFIER': 443 | var = self.var.get(p[0].value) 444 | if var is not None: 445 | return ExpressionBase(var.value, var.kind, var) 446 | else: 447 | error(errors.NOTDECLARED, "Variable is not declared.", { 448 | "type": "token", 449 | "token": p[0] 450 | }) 451 | sys.exit(1) 452 | else: 453 | return ExpressionBase(int(p[0].value), "integer") 454 | 455 | @self.pg.error 456 | def error_handle(token): 457 | print("Syntax unexcepted : \n - Position :", token.getsourcepos(), 458 | "\n - Token : Valeur =", token.getstr(), "| Type =", 459 | token.gettokentype()) 460 | sys.exit(1) 461 | 462 | def get_parser(self): 463 | parser = self.pg.build() 464 | return parser 465 | --------------------------------------------------------------------------------