Adding error handling support
This commit is contained in:
		
							
								
								
									
										14
									
								
								examples/errors.spf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								examples/errors.spf
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| blop x = blop #SyntaxError | ||||
|  | ||||
| # afficher y; #UnknownVariable | ||||
|  | ||||
| # texte z; | ||||
| # afficher z; #UninitializedVariable | ||||
|   | ||||
| # texte a; | ||||
| # texte a; #AlreadyDefined | ||||
|  | ||||
| # entier b = "test"; #IncompatibleType | ||||
|   | ||||
| # liste c = [0, 1, 2]; | ||||
| # afficher c[10]; #IndexError | ||||
| @ -1,5 +1,7 @@ | ||||
| import sys | ||||
|  | ||||
| from modules.errors import SPFUnknownVariable, SPFUninitializedVariable, SPFAlreadyDefined, SPFIncompatibleType, SPFIndexError | ||||
|  | ||||
| trace_format = '\033[1m -> ' | ||||
| reset_format = '\033[0m' | ||||
|  | ||||
| @ -11,14 +13,16 @@ class Variables: | ||||
|                   "booléen": bool, | ||||
|                   "liste": list } | ||||
|  | ||||
|         def __init__(self, typ, value = None): | ||||
|         def __init__(self, typ, value=None): | ||||
|             assert typ in self.types.keys(), "Ce type de variable est inconnu" | ||||
|             self.type = typ | ||||
|             assert self.checkType(value, typ), f"Le type n'est pas équivalent: { value } n'est pas {typ}" | ||||
|             self.value = value if (value is not None) else self.default(typ) | ||||
|             if not self.checkType(value, typ): | ||||
|                 raise SPFIncompatibleType(value, self.type) | ||||
|             self.value = value | ||||
|  | ||||
|         def set(self, value): | ||||
|             assert self.checkType(value, self.type), f"Le type n'est pas équivalent: {value} n'est pas {self.type}" | ||||
|             if not self.checkType(value, self.type): | ||||
|                 raise SPFIncompatibleType(value, self.type) | ||||
|             self.value = value | ||||
|  | ||||
|         def __str__(self): | ||||
| @ -49,19 +53,24 @@ class Variables: | ||||
|         self.trace = trace | ||||
|  | ||||
|     def get(self, name): | ||||
|         assert name in self.variables, f"la variable {name} n'éxiste pas" | ||||
|         if name not in self.variables: | ||||
|             raise SPFUnknownVariable(name) | ||||
|         if self.variables[name].value == None: | ||||
|             raise SPFUninitializedVariable(name) | ||||
|         if self.trace: | ||||
|             print(f"{trace_format}accède {name}{reset_format}", file=sys.stderr) | ||||
|         return self.variables[name].value | ||||
|  | ||||
|     def declare(self, typ, name, value=None): | ||||
|         assert name not in self.variables, f"la variable {name} existe déjà" | ||||
|         if name in self.variables: | ||||
|             raise SPFAlreadyDefined(name) | ||||
|         self.variables[name] = self.Variable(typ, value) | ||||
|         if self.trace: | ||||
|             print(f"{trace_format}déclare {name} = {value}{reset_format}", file=sys.stderr) | ||||
|  | ||||
|     def assign(self, name, value): | ||||
|         assert name in self.variables, f"la variable {name} n'éxiste pas" | ||||
|         if name not in self.variables: | ||||
|             raise SPFUnknownVariable(name) | ||||
|         self.variables[name].set(value) | ||||
|         if self.trace: | ||||
|             print(f"{trace_format}modifie {name} = {value}{reset_format}", file=sys.stderr) | ||||
|  | ||||
							
								
								
									
										44
									
								
								modules/errors.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								modules/errors.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| # args | ||||
| # 0) variable name | ||||
| # 1) list of lines of the stack trace | ||||
|  | ||||
| class SPFException(Exception): | ||||
|     def __init__(self, *args): | ||||
|         super().__init__(*args) | ||||
|         self.msg = "Une erreur est survenue" | ||||
|         self.errorline = None | ||||
|  | ||||
|     def __str__(self): | ||||
|         return (f"[ligne {self.errorline}] " if self.errorline else "") + f"{self.msg}" | ||||
|  | ||||
| class SPFSyntaxError(SPFException): | ||||
|     def __init__(self, *args): | ||||
|         super().__init__(*args) | ||||
|         self.msg = "Une erreur de syntaxe est survenue" | ||||
|  | ||||
| class SPFUnknownVariable(SPFException): | ||||
|     def __init__(self, *args): | ||||
|         super().__init__(*args) | ||||
|         self.msg = f"la variable `{args[0]}` n'est pas déclarée" | ||||
|  | ||||
| class SPFUninitializedVariable(SPFException): | ||||
|     def __init__(self, *args): | ||||
|         super().__init__(*args) | ||||
|         self.msg = f"la variable `{args[0]}` n'est pas initialisée" | ||||
|  | ||||
| class SPFAlreadyDefined(SPFException): | ||||
|     def __init__(self, *args): | ||||
|         super().__init__(*args) | ||||
|         self.msg = f"la variable `{args[0]}` est déjà déclarée" | ||||
|  | ||||
| class SPFIncompatibleType(SPFException): | ||||
|     def __init__(self, *args): | ||||
|         super().__init__(*args) | ||||
|         self.msg = f"`{args[0]}` n'est pas de type `{args[1]}`" | ||||
|  | ||||
| class SPFIndexError(SPFException): | ||||
|     def __init__(self, *args): | ||||
|         super().__init__(*args) | ||||
|         self.msg = f"La liste `{args[0]}` ne posède pas d'élèment d'indexe {args[1]}" | ||||
|  | ||||
|  | ||||
							
								
								
									
										56
									
								
								spf.py
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								spf.py
									
									
									
									
									
								
							| @ -8,6 +8,7 @@ import lark | ||||
| import sys | ||||
| from enum import Enum | ||||
| from modules.Variables import Variables | ||||
| from modules.errors import * | ||||
|  | ||||
| class SPFInterpreter(lark.visitors.Interpreter): | ||||
|     def __init__(self, trace=False): | ||||
| @ -24,11 +25,19 @@ class SPFInterpreter(lark.visitors.Interpreter): | ||||
|         type = el.children[0].value | ||||
|         name = el.children[1].value | ||||
|         old = self.variables.variables.copy() | ||||
|         self.variables.declare(type, name) | ||||
|         try: | ||||
|             self.variables.declare(type, name) | ||||
|         except SPFException as e: | ||||
|             e.errorline = el.meta.line | ||||
|             raise e | ||||
|  | ||||
|         target = self.visit_children(el.children[2])[0] | ||||
|         for i in target: | ||||
|             self.variables.assign(name, i) | ||||
|             try: | ||||
|                 self.variables.assign(name, i) | ||||
|             except SPFException as e: | ||||
|                 e.errorline = el.meta.line | ||||
|                 raise e | ||||
|             self.visit_children(el.children[3]) | ||||
|         self.variables.variables = old.copy() | ||||
|  | ||||
| @ -40,20 +49,33 @@ class SPFInterpreter(lark.visitors.Interpreter): | ||||
|  | ||||
|     def append(self, el): | ||||
|         (_, toadd, var) = self.visit_children(el); | ||||
|         var_val = self.variables.get(var.value) | ||||
|         try: | ||||
|             var_val = self.variables.get(var.value) | ||||
|         except SPFException as e: | ||||
|             e.errorline = el.meta.line | ||||
|             raise e | ||||
|  | ||||
|         var_val.append(toadd) | ||||
|  | ||||
|     def declaration(self, el): | ||||
|         type = el.children[0].value | ||||
|         name = el.children[1].value | ||||
|         value = self.visit_children(el.children[3])[0] if len(el.children) >= 3 else None | ||||
|         self.variables.declare(type, name, value) | ||||
|         try: | ||||
|             self.variables.declare(type, name, value) | ||||
|         except SPFException as e: | ||||
|             e.errorline = el.meta.line | ||||
|             raise e | ||||
|  | ||||
|     def assignation(self, el): | ||||
|         name = el.children[0].value | ||||
|         assert el.children[1].value == "=" and el.children[2].data == "expression", "Unexpected" | ||||
|         value = self.visit_children(el.children[2])[0] | ||||
|         self.variables.assign(name, value) | ||||
|         try: | ||||
|             self.variables.assign(name, value) | ||||
|         except SPFException as e: | ||||
|             e.errorline = el.meta.line | ||||
|             raise e | ||||
|  | ||||
|     def expression(self, el): | ||||
|         return self.visit_children(el)[0] | ||||
| @ -108,7 +130,6 @@ class SPFInterpreter(lark.visitors.Interpreter): | ||||
|  | ||||
|     def priority(self, el): | ||||
|         result = self.visit_children(el) | ||||
|         print(result) | ||||
|         if len(result) < 2: | ||||
|             return result[0] | ||||
|         elif result[0].type == "SIZE_OP": | ||||
| @ -120,13 +141,22 @@ class SPFInterpreter(lark.visitors.Interpreter): | ||||
|  | ||||
|     def list_get(self, el): | ||||
|         result = self.visit_children(el) | ||||
|         return result[0][result[1] - 1] # Index start at 1 (like lua) | ||||
|         try: | ||||
|             return result[0][result[1] - 1] # Index start at 1 (like lua) | ||||
|         except IndexError: | ||||
|             e = SPFIndexError(result[0], result[1]) | ||||
|             e.errorline = el.meta.line | ||||
|             raise e | ||||
|  | ||||
|     def finalterm(self, el): | ||||
|         return self.visit_children(el)[0] | ||||
|  | ||||
|     def variable(self, el): | ||||
|         return self.variables.get(el.children[0].value) | ||||
|         try: | ||||
|             return self.variables.get(el.children[0].value) | ||||
|         except SPFException as e: | ||||
|             e.errorline = el.meta.line | ||||
|             raise e | ||||
|  | ||||
|     def test(self,el): | ||||
|         old = self.variables.variables.copy() | ||||
| @ -167,11 +197,16 @@ def main(): | ||||
|     args = arg_parser.parse_args() | ||||
|  | ||||
|     with open("spf.lark") as grammar: | ||||
|         spf_parser = lark.Lark(grammar, parser="lalr", strict=True, debug=True) | ||||
|         spf_parser = lark.Lark(grammar, parser="lalr", strict=True, debug=True, propagate_positions=True) | ||||
|  | ||||
|     with open(args.spf_file) as spf_input: | ||||
|         program = spf_input.read() | ||||
|         parsed = spf_parser.parse(program) | ||||
|         try: | ||||
|             parsed = spf_parser.parse(program) | ||||
|         except lark.UnexpectedInput as u: | ||||
|             e = SPFSyntaxError() | ||||
|             e.errorline = u.line | ||||
|             raise e | ||||
|  | ||||
|     if args.pretty: | ||||
|         print(parsed.pretty()) | ||||
| @ -183,7 +218,6 @@ def main(): | ||||
|     if args.dump: | ||||
|         interpreter.dump() | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user