Adding error handling support
This commit is contained in:
parent
d73a5be3f5
commit
e2e058c8ac
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'
|
||||
|
||||
@ -14,11 +16,13 @@ class Variables:
|
||||
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]}"
|
||||
|
||||
|
40
spf.py
40
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()
|
||||
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:
|
||||
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);
|
||||
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
|
||||
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]
|
||||
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)
|
||||
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):
|
||||
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()
|
||||
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()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user