diff --git a/grammar.py b/grammar.py index 2444587..7a1235d 100644 --- a/grammar.py +++ b/grammar.py @@ -75,28 +75,38 @@ class Variable(IntEnum): ASTTerm: TypeAlias = 'ASTNegated | ASTProp' +@dataclass(frozen=True) +class ArgumentsForVariable: + term: Lexeme[Tok] + +@dataclass(frozen=True) +class UnidentifiedVariable: + term: Lexeme[Tok] + +GenIrError: TypeAlias = ArgumentsForVariable | UnidentifiedVariable + @dataclass(frozen=True) class ASTNegated: term: ASTTerm - def make_ir(self, props: Sequence[str], var: Sequence[str]) -> 'IRNeg': - return IRNeg(self.term.make_ir(props, var)) + def make_ir(self, props: Sequence[str], var: Sequence[str]) -> 'Result[IRTerm, GenIrError]': + return map_res(IRNeg, self.term.make_ir(props, var)) @dataclass(frozen=True) class ASTProp: ident: Lexeme[Tok] arguments: Sequence[ASTTerm] - def make_ir(self, props: Sequence[str], vars: Sequence[str]) -> 'IRVar | IRProp': + def make_ir(self, props: Sequence[str], vars: Sequence[str]) -> 'Result[IRTerm, GenIrError]': if self.ident.matched_string in props: - return IRProp(self.ident, [t.make_ir(props, vars) for t in self.arguments]) + return map_res(p(IRProp, self.ident), sequence([t.make_ir(props, vars) for t in self.arguments])) elif self.ident.matched_string in vars: if len(self.arguments): - raise Exception('Bad arg count!') #TODO + return Err(ArgumentsForVariable(self.ident)) else: - return IRVar(self.ident) + return Ok(IRVar(self.ident)) else: - raise Exception('Unidentified!') #TODO + return Err(UnidentifiedVariable(self.ident)) @dataclass(frozen=True) class IRProp: @@ -125,10 +135,10 @@ def make_ir( const_idents: Sequence[Lexeme[Tok]], func_idents: Sequence[Lexeme[Tok]], clauses: Sequence[Sequence[ASTTerm]], -) -> Sequence[Sequence[IRTerm]]: +) -> Result[Sequence[Sequence[IRTerm]], GenIrError]: prop_idents = [l.matched_string for l in (*const_idents, *func_idents, *predicate_idents)] var_idents = [l.matched_string for l in variable_idents] - return [[term.make_ir(prop_idents, var_idents) for term in clause] for clause in clauses] + return sequence([sequence([term.make_ir(prop_idents, var_idents) for term in clause]) for clause in clauses]) def cons(stack: Sequence[Any]) -> Sequence[Any]: match stack: @@ -256,8 +266,12 @@ if __name__ == '__main__': maybe_ast = parser_(lexemes) match maybe_ast: - case Ok([ast]): + case Ok([Ok(ast)]): print('\n'.join(' or '.join(str(t) for t in c) for c in ast)) + case Ok([Err(ArgumentsForVariable(v))]): + print(f'Semantic error: Arguments listed for variable {repr(v.matched_string)} on line {v.line}:{v.col_start}-{v.col_end}') + case Ok([Err(UnidentifiedVariable(v))]): + print(f'Semantic error: Unidentified identifier {repr(v.matched_string)} on line {v.line}:{v.col_start}-{v.col_end}') case Ok(huh): print('Unexpected end result: ', huh) case Err((Lexeme(token, text, line, col_start, col_end), expected)):