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 | import sys | ||||||
|  |  | ||||||
|  | from modules.errors import SPFUnknownVariable, SPFUninitializedVariable, SPFAlreadyDefined, SPFIncompatibleType, SPFIndexError | ||||||
|  |  | ||||||
| trace_format = '\033[1m -> ' | trace_format = '\033[1m -> ' | ||||||
| reset_format = '\033[0m' | reset_format = '\033[0m' | ||||||
|  |  | ||||||
| @ -11,14 +13,16 @@ class Variables: | |||||||
|                   "booléen": bool, |                   "booléen": bool, | ||||||
|                   "liste": list } |                   "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" |             assert typ in self.types.keys(), "Ce type de variable est inconnu" | ||||||
|             self.type = typ |             self.type = typ | ||||||
|             assert self.checkType(value, typ), f"Le type n'est pas équivalent: { value } n'est pas {typ}" |             if not self.checkType(value, typ): | ||||||
|             self.value = value if (value is not None) else self.default(typ) |                 raise SPFIncompatibleType(value, self.type) | ||||||
|  |             self.value = value | ||||||
|  |  | ||||||
|         def set(self, 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 |             self.value = value | ||||||
|  |  | ||||||
|         def __str__(self): |         def __str__(self): | ||||||
| @ -49,19 +53,24 @@ class Variables: | |||||||
|         self.trace = trace |         self.trace = trace | ||||||
|  |  | ||||||
|     def get(self, name): |     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: |         if self.trace: | ||||||
|             print(f"{trace_format}accède {name}{reset_format}", file=sys.stderr) |             print(f"{trace_format}accède {name}{reset_format}", file=sys.stderr) | ||||||
|         return self.variables[name].value |         return self.variables[name].value | ||||||
|  |  | ||||||
|     def declare(self, typ, name, value=None): |     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) |         self.variables[name] = self.Variable(typ, value) | ||||||
|         if self.trace: |         if self.trace: | ||||||
|             print(f"{trace_format}déclare {name} = {value}{reset_format}", file=sys.stderr) |             print(f"{trace_format}déclare {name} = {value}{reset_format}", file=sys.stderr) | ||||||
|  |  | ||||||
|     def assign(self, name, value): |     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) |         self.variables[name].set(value) | ||||||
|         if self.trace: |         if self.trace: | ||||||
|             print(f"{trace_format}modifie {name} = {value}{reset_format}", file=sys.stderr) |             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]}" | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								spf.py
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								spf.py
									
									
									
									
									
								
							| @ -8,6 +8,7 @@ import lark | |||||||
| import sys | import sys | ||||||
| from enum import Enum | from enum import Enum | ||||||
| from modules.Variables import Variables | from modules.Variables import Variables | ||||||
|  | from modules.errors import * | ||||||
|  |  | ||||||
| class SPFInterpreter(lark.visitors.Interpreter): | class SPFInterpreter(lark.visitors.Interpreter): | ||||||
|     def __init__(self, trace=False): |     def __init__(self, trace=False): | ||||||
| @ -24,11 +25,19 @@ class SPFInterpreter(lark.visitors.Interpreter): | |||||||
|         type = el.children[0].value |         type = el.children[0].value | ||||||
|         name = el.children[1].value |         name = el.children[1].value | ||||||
|         old = self.variables.variables.copy() |         old = self.variables.variables.copy() | ||||||
|  |         try: | ||||||
|             self.variables.declare(type, name) |             self.variables.declare(type, name) | ||||||
|  |         except SPFException as e: | ||||||
|  |             e.errorline = el.meta.line | ||||||
|  |             raise e | ||||||
|  |  | ||||||
|         target = self.visit_children(el.children[2])[0] |         target = self.visit_children(el.children[2])[0] | ||||||
|         for i in target: |         for i in target: | ||||||
|  |             try: | ||||||
|                 self.variables.assign(name, i) |                 self.variables.assign(name, i) | ||||||
|  |             except SPFException as e: | ||||||
|  |                 e.errorline = el.meta.line | ||||||
|  |                 raise e | ||||||
|             self.visit_children(el.children[3]) |             self.visit_children(el.children[3]) | ||||||
|         self.variables.variables = old.copy() |         self.variables.variables = old.copy() | ||||||
|  |  | ||||||
| @ -40,20 +49,33 @@ class SPFInterpreter(lark.visitors.Interpreter): | |||||||
|  |  | ||||||
|     def append(self, el): |     def append(self, el): | ||||||
|         (_, toadd, var) = self.visit_children(el); |         (_, toadd, var) = self.visit_children(el); | ||||||
|  |         try: | ||||||
|             var_val = self.variables.get(var.value) |             var_val = self.variables.get(var.value) | ||||||
|  |         except SPFException as e: | ||||||
|  |             e.errorline = el.meta.line | ||||||
|  |             raise e | ||||||
|  |  | ||||||
|         var_val.append(toadd) |         var_val.append(toadd) | ||||||
|  |  | ||||||
|     def declaration(self, el): |     def declaration(self, el): | ||||||
|         type = el.children[0].value |         type = el.children[0].value | ||||||
|         name = el.children[1].value |         name = el.children[1].value | ||||||
|         value = self.visit_children(el.children[3])[0] if len(el.children) >= 3 else None |         value = self.visit_children(el.children[3])[0] if len(el.children) >= 3 else None | ||||||
|  |         try: | ||||||
|             self.variables.declare(type, name, value) |             self.variables.declare(type, name, value) | ||||||
|  |         except SPFException as e: | ||||||
|  |             e.errorline = el.meta.line | ||||||
|  |             raise e | ||||||
|  |  | ||||||
|     def assignation(self, el): |     def assignation(self, el): | ||||||
|         name = el.children[0].value |         name = el.children[0].value | ||||||
|         assert el.children[1].value == "=" and el.children[2].data == "expression", "Unexpected" |         assert el.children[1].value == "=" and el.children[2].data == "expression", "Unexpected" | ||||||
|         value = self.visit_children(el.children[2])[0] |         value = self.visit_children(el.children[2])[0] | ||||||
|  |         try: | ||||||
|             self.variables.assign(name, value) |             self.variables.assign(name, value) | ||||||
|  |         except SPFException as e: | ||||||
|  |             e.errorline = el.meta.line | ||||||
|  |             raise e | ||||||
|  |  | ||||||
|     def expression(self, el): |     def expression(self, el): | ||||||
|         return self.visit_children(el)[0] |         return self.visit_children(el)[0] | ||||||
| @ -108,7 +130,6 @@ class SPFInterpreter(lark.visitors.Interpreter): | |||||||
|  |  | ||||||
|     def priority(self, el): |     def priority(self, el): | ||||||
|         result = self.visit_children(el) |         result = self.visit_children(el) | ||||||
|         print(result) |  | ||||||
|         if len(result) < 2: |         if len(result) < 2: | ||||||
|             return result[0] |             return result[0] | ||||||
|         elif result[0].type == "SIZE_OP": |         elif result[0].type == "SIZE_OP": | ||||||
| @ -120,13 +141,22 @@ class SPFInterpreter(lark.visitors.Interpreter): | |||||||
|  |  | ||||||
|     def list_get(self, el): |     def list_get(self, el): | ||||||
|         result = self.visit_children(el) |         result = self.visit_children(el) | ||||||
|  |         try: | ||||||
|             return result[0][result[1] - 1] # Index start at 1 (like lua) |             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): |     def finalterm(self, el): | ||||||
|         return self.visit_children(el)[0] |         return self.visit_children(el)[0] | ||||||
|  |  | ||||||
|     def variable(self, el): |     def variable(self, el): | ||||||
|  |         try: | ||||||
|             return self.variables.get(el.children[0].value) |             return self.variables.get(el.children[0].value) | ||||||
|  |         except SPFException as e: | ||||||
|  |             e.errorline = el.meta.line | ||||||
|  |             raise e | ||||||
|  |  | ||||||
|     def test(self,el): |     def test(self,el): | ||||||
|         old = self.variables.variables.copy() |         old = self.variables.variables.copy() | ||||||
| @ -167,11 +197,16 @@ def main(): | |||||||
|     args = arg_parser.parse_args() |     args = arg_parser.parse_args() | ||||||
|  |  | ||||||
|     with open("spf.lark") as grammar: |     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: |     with open(args.spf_file) as spf_input: | ||||||
|         program = spf_input.read() |         program = spf_input.read() | ||||||
|  |         try: | ||||||
|             parsed = spf_parser.parse(program) |             parsed = spf_parser.parse(program) | ||||||
|  |         except lark.UnexpectedInput as u: | ||||||
|  |             e = SPFSyntaxError() | ||||||
|  |             e.errorline = u.line | ||||||
|  |             raise e | ||||||
|  |  | ||||||
|     if args.pretty: |     if args.pretty: | ||||||
|         print(parsed.pretty()) |         print(parsed.pretty()) | ||||||
| @ -183,7 +218,6 @@ def main(): | |||||||
|     if args.dump: |     if args.dump: | ||||||
|         interpreter.dump() |         interpreter.dump() | ||||||
|  |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     main() |     main() | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user