Compare commits
2
Commits
8bc0918517
...
74ac9c5381
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74ac9c5381
|
||
|
|
e10d71a66b
|
No files matched your search
+27
-1
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Generic, Optional, TypeVar
|
from typing import Any, Generic, Optional, TypeVar
|
||||||
|
|
||||||
from lexer.token import Token
|
from lexer.token import Token
|
||||||
|
|
||||||
@@ -79,6 +79,12 @@ class Expr(ABC):
|
|||||||
def accept(self, visitor: Visitor[T]) -> T: ...
|
def accept(self, visitor: Visitor[T]) -> T: ...
|
||||||
|
|
||||||
class Visitor(ABC, Generic[T]):
|
class Visitor(ABC, Generic[T]):
|
||||||
|
@abstractmethod
|
||||||
|
def visit_wildcard_expr(self, expr: WildcardExpr) -> T: ...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visit_literal_expr(self, expr: LiteralExpr) -> T: ...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_type_expr(self, expr: TypeExpr) -> T: ...
|
def visit_type_expr(self, expr: TypeExpr) -> T: ...
|
||||||
|
|
||||||
@@ -89,6 +95,22 @@ class Expr(ABC):
|
|||||||
def visit_type_body_expr(self, expr: TypeBodyExpr) -> T: ...
|
def visit_type_body_expr(self, expr: TypeBodyExpr) -> T: ...
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class WildcardExpr(Expr):
|
||||||
|
token: Token
|
||||||
|
|
||||||
|
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||||
|
return visitor.visit_wildcard_expr(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class LiteralExpr(Expr):
|
||||||
|
value: Any
|
||||||
|
|
||||||
|
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||||
|
return visitor.visit_literal_expr(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class TypeExpr(Expr):
|
class TypeExpr(Expr):
|
||||||
name: Token
|
name: Token
|
||||||
@@ -100,6 +122,10 @@ class TypeExpr(Expr):
|
|||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ConstraintExpr(Expr):
|
class ConstraintExpr(Expr):
|
||||||
|
left: Expr
|
||||||
|
op: Token
|
||||||
|
right: Expr
|
||||||
|
|
||||||
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||||
return visitor.visit_constraint_expr(self)
|
return visitor.visit_constraint_expr(self)
|
||||||
|
|
||||||
|
|||||||
+28
-8
@@ -102,7 +102,7 @@ class AnnotationAstPrinter(AstPrinter, a.Expr.Visitor[None], a.Stmt.Visitor[None
|
|||||||
if i == len(expr.constraints) - 1:
|
if i == len(expr.constraints) - 1:
|
||||||
self._mark_last()
|
self._mark_last()
|
||||||
constraint.accept(self)
|
constraint.accept(self)
|
||||||
|
|
||||||
def visit_constraint_expr(self, expr: a.ConstraintExpr) -> None:
|
def visit_constraint_expr(self, expr: a.ConstraintExpr) -> None:
|
||||||
self._write_line("ConstraintExpr")
|
self._write_line("ConstraintExpr")
|
||||||
with self._child_level():
|
with self._child_level():
|
||||||
@@ -110,9 +110,9 @@ class AnnotationAstPrinter(AstPrinter, a.Expr.Visitor[None], a.Stmt.Visitor[None
|
|||||||
with self._child_level():
|
with self._child_level():
|
||||||
self._mark_last()
|
self._mark_last()
|
||||||
expr.left.accept(self)
|
expr.left.accept(self)
|
||||||
|
|
||||||
self._write_line(f"operator: {expr.op.lexeme}")
|
self._write_line(f"operator: {expr.op.lexeme}")
|
||||||
|
|
||||||
self._write_line("right", last=True)
|
self._write_line("right", last=True)
|
||||||
with self._child_level():
|
with self._child_level():
|
||||||
self._mark_last()
|
self._mark_last()
|
||||||
@@ -133,14 +133,14 @@ class AnnotationAstPrinter(AstPrinter, a.Expr.Visitor[None], a.Stmt.Visitor[None
|
|||||||
name_text: str = "None" if expr.name is None else f'"{expr.name.lexeme}"'
|
name_text: str = "None" if expr.name is None else f'"{expr.name.lexeme}"'
|
||||||
self._write_line(f"name: {name_text}")
|
self._write_line(f"name: {name_text}")
|
||||||
self._write_optional_child("type", expr.type, last=True)
|
self._write_optional_child("type", expr.type, last=True)
|
||||||
|
|
||||||
def visit_wildcard_expr(self, expr: a.WildcardExpr) -> None:
|
def visit_wildcard_expr(self, expr: a.WildcardExpr) -> None:
|
||||||
self._write_line("WildcardExpr")
|
self._write_line("WildcardExpr")
|
||||||
|
|
||||||
def visit_literal_expr(self, expr: a.LiteralExpr) -> None:
|
def visit_literal_expr(self, expr: a.LiteralExpr) -> None:
|
||||||
self._write_line("LiteralExpr")
|
self._write_line("LiteralExpr")
|
||||||
with self._child_level():
|
with self._child_level():
|
||||||
self._write_line(f'value: {expr.value}', last=True)
|
self._write_line(f"value: {expr.value}", last=True)
|
||||||
|
|
||||||
|
|
||||||
class AnnotationPrinter(a.Expr.Visitor[str], a.Stmt.Visitor[str]):
|
class AnnotationPrinter(a.Expr.Visitor[str], a.Stmt.Visitor[str]):
|
||||||
@@ -158,12 +158,12 @@ class AnnotationPrinter(a.Expr.Visitor[str], a.Stmt.Visitor[str]):
|
|||||||
for constraint in expr.constraints:
|
for constraint in expr.constraints:
|
||||||
parts.append("(" + constraint.accept(self) + ")")
|
parts.append("(" + constraint.accept(self) + ")")
|
||||||
return " + ".join(parts)
|
return " + ".join(parts)
|
||||||
|
|
||||||
def visit_constraint_expr(self, expr: a.ConstraintExpr) -> str:
|
def visit_constraint_expr(self, expr: a.ConstraintExpr) -> str:
|
||||||
parts: list[str] = [
|
parts: list[str] = [
|
||||||
expr.left.accept(self),
|
expr.left.accept(self),
|
||||||
expr.op.lexeme,
|
expr.op.lexeme,
|
||||||
expr.right.accept(self)
|
expr.right.accept(self),
|
||||||
]
|
]
|
||||||
return " ".join(parts)
|
return " ".join(parts)
|
||||||
|
|
||||||
@@ -257,6 +257,18 @@ class MidasAstPrinter(AstPrinter, m.Expr.Visitor[None], m.Stmt.Visitor[None]):
|
|||||||
|
|
||||||
def visit_constraint_expr(self, expr: m.ConstraintExpr):
|
def visit_constraint_expr(self, expr: m.ConstraintExpr):
|
||||||
self._write_line("ConstraintExpr")
|
self._write_line("ConstraintExpr")
|
||||||
|
with self._child_level():
|
||||||
|
self._write_line("left")
|
||||||
|
with self._child_level():
|
||||||
|
self._mark_last()
|
||||||
|
expr.left.accept(self)
|
||||||
|
|
||||||
|
self._write_line(f"operator: {expr.op.lexeme}")
|
||||||
|
|
||||||
|
self._write_line("right", last=True)
|
||||||
|
with self._child_level():
|
||||||
|
self._mark_last()
|
||||||
|
expr.right.accept(self)
|
||||||
|
|
||||||
def visit_type_body_expr(self, expr: m.TypeBodyExpr):
|
def visit_type_body_expr(self, expr: m.TypeBodyExpr):
|
||||||
self._write_line("TypeBodyExpr")
|
self._write_line("TypeBodyExpr")
|
||||||
@@ -268,3 +280,11 @@ class MidasAstPrinter(AstPrinter, m.Expr.Visitor[None], m.Stmt.Visitor[None]):
|
|||||||
if i == len(expr.properties) - 1:
|
if i == len(expr.properties) - 1:
|
||||||
self._mark_last()
|
self._mark_last()
|
||||||
property.accept(self)
|
property.accept(self)
|
||||||
|
|
||||||
|
def visit_wildcard_expr(self, expr: m.WildcardExpr) -> None:
|
||||||
|
self._write_line("WildcardExpr")
|
||||||
|
|
||||||
|
def visit_literal_expr(self, expr: m.LiteralExpr) -> None:
|
||||||
|
self._write_line("LiteralExpr")
|
||||||
|
with self._child_level():
|
||||||
|
self._write_line(f"value: {expr.value}", last=True)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from lexer.base import Lexer
|
from lexer.base import Lexer
|
||||||
|
from lexer.keyword import ANNOTATION_KEYWORDS
|
||||||
from lexer.token import TokenType
|
from lexer.token import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -86,7 +87,10 @@ class AnnotationLexer(Lexer):
|
|||||||
"""
|
"""
|
||||||
while self.peek().isalnum() or self.peek() == "_":
|
while self.peek().isalnum() or self.peek() == "_":
|
||||||
self.advance()
|
self.advance()
|
||||||
self.add_token(TokenType.IDENTIFIER)
|
|
||||||
|
lexeme: str = self.source[self.start : self.idx]
|
||||||
|
token_type: TokenType = ANNOTATION_KEYWORDS.get(lexeme, TokenType.IDENTIFIER)
|
||||||
|
self.add_token(token_type)
|
||||||
|
|
||||||
def scan_comment(self):
|
def scan_comment(self):
|
||||||
"""Scan the rest of a comment and add it as a token
|
"""Scan the rest of a comment and add it as a token
|
||||||
|
|||||||
+8
-1
@@ -1,9 +1,16 @@
|
|||||||
from lexer.token import TokenType
|
from lexer.token import TokenType
|
||||||
|
|
||||||
KEYWORDS: dict[str, TokenType] = {
|
ANNOTATION_KEYWORDS: dict[str, TokenType] = {
|
||||||
|
"True": TokenType.TRUE,
|
||||||
|
"False": TokenType.FALSE,
|
||||||
|
"None": TokenType.NONE,
|
||||||
|
}
|
||||||
|
|
||||||
|
MIDAS_KEYWORDS: dict[str, TokenType] = {
|
||||||
"type": TokenType.TYPE,
|
"type": TokenType.TYPE,
|
||||||
"op": TokenType.OP,
|
"op": TokenType.OP,
|
||||||
"constraint": TokenType.CONSTRAINT,
|
"constraint": TokenType.CONSTRAINT,
|
||||||
"true": TokenType.TRUE,
|
"true": TokenType.TRUE,
|
||||||
"false": TokenType.FALSE,
|
"false": TokenType.FALSE,
|
||||||
|
"none": TokenType.NONE,
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
from lexer.base import Lexer
|
from lexer.base import Lexer
|
||||||
from lexer.keyword import KEYWORDS
|
from lexer.keyword import MIDAS_KEYWORDS
|
||||||
from lexer.token import TokenType
|
from lexer.token import TokenType
|
||||||
|
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ class MidasLexer(Lexer):
|
|||||||
self.advance()
|
self.advance()
|
||||||
|
|
||||||
lexeme: str = self.source[self.start : self.idx]
|
lexeme: str = self.source[self.start : self.idx]
|
||||||
token_type: TokenType = KEYWORDS.get(lexeme, TokenType.IDENTIFIER)
|
token_type: TokenType = MIDAS_KEYWORDS.get(lexeme, TokenType.IDENTIFIER)
|
||||||
self.add_token(token_type)
|
self.add_token(token_type)
|
||||||
|
|
||||||
def scan_comment(self):
|
def scan_comment(self):
|
||||||
|
|||||||
@@ -68,8 +68,6 @@ class AnnotationParser(Parser):
|
|||||||
constraints: list[ConstraintExpr] = []
|
constraints: list[ConstraintExpr] = []
|
||||||
|
|
||||||
while not self.is_at_end() and self.match(TokenType.PLUS):
|
while not self.is_at_end() and self.match(TokenType.PLUS):
|
||||||
print(self.peek())
|
|
||||||
print(self.tokens)
|
|
||||||
self.consume(TokenType.LEFT_PAREN, "Expected '(' before type constraint")
|
self.consume(TokenType.LEFT_PAREN, "Expected '(' before type constraint")
|
||||||
constraints.append(self.constraint_expr())
|
constraints.append(self.constraint_expr())
|
||||||
self.consume(TokenType.RIGHT_PAREN, "Expected ')' after type constraint")
|
self.consume(TokenType.RIGHT_PAREN, "Expected ')' after type constraint")
|
||||||
|
|||||||
+33
-2
@@ -3,12 +3,15 @@ from typing import Optional
|
|||||||
from core.ast.midas import (
|
from core.ast.midas import (
|
||||||
ConstraintExpr,
|
ConstraintExpr,
|
||||||
ConstraintStmt,
|
ConstraintStmt,
|
||||||
|
Expr,
|
||||||
|
LiteralExpr,
|
||||||
OpStmt,
|
OpStmt,
|
||||||
PropertyStmt,
|
PropertyStmt,
|
||||||
Stmt,
|
Stmt,
|
||||||
TypeBodyExpr,
|
TypeBodyExpr,
|
||||||
TypeExpr,
|
TypeExpr,
|
||||||
TypeStmt,
|
TypeStmt,
|
||||||
|
WildcardExpr,
|
||||||
)
|
)
|
||||||
from lexer.token import Token, TokenType
|
from lexer.token import Token, TokenType
|
||||||
from parser.base import Parser
|
from parser.base import Parser
|
||||||
@@ -96,7 +99,9 @@ class MidasParser(Parser):
|
|||||||
constraints: list[ConstraintExpr] = []
|
constraints: list[ConstraintExpr] = []
|
||||||
|
|
||||||
while not self.is_at_end() and self.match(TokenType.PLUS):
|
while not self.is_at_end() and self.match(TokenType.PLUS):
|
||||||
|
self.consume(TokenType.LEFT_PAREN, "Expected '(' before type constraint")
|
||||||
constraints.append(self.constraint_expr())
|
constraints.append(self.constraint_expr())
|
||||||
|
self.consume(TokenType.RIGHT_PAREN, "Expected ')' after type constraint")
|
||||||
|
|
||||||
return TypeExpr(name=name, constraints=constraints)
|
return TypeExpr(name=name, constraints=constraints)
|
||||||
|
|
||||||
@@ -106,8 +111,34 @@ class MidasParser(Parser):
|
|||||||
Returns:
|
Returns:
|
||||||
ConstraintExpr: the parsed type constraint expression
|
ConstraintExpr: the parsed type constraint expression
|
||||||
"""
|
"""
|
||||||
# TODO
|
|
||||||
return ConstraintExpr()
|
left: Expr = self.constraint_value()
|
||||||
|
op: Token = self.constraint_operator()
|
||||||
|
right: Expr = self.constraint_value()
|
||||||
|
return ConstraintExpr(left=left, op=op, right=right)
|
||||||
|
|
||||||
|
def constraint_value(self) -> Expr:
|
||||||
|
if self.match(TokenType.UNDERSCORE):
|
||||||
|
return WildcardExpr(self.previous())
|
||||||
|
return self.literal()
|
||||||
|
|
||||||
|
def literal(self) -> LiteralExpr:
|
||||||
|
if self.match(TokenType.FALSE):
|
||||||
|
return LiteralExpr(False)
|
||||||
|
if self.match(TokenType.TRUE):
|
||||||
|
return LiteralExpr(True)
|
||||||
|
if self.match(TokenType.NONE):
|
||||||
|
return LiteralExpr(None)
|
||||||
|
|
||||||
|
if self.match(TokenType.NUMBER):
|
||||||
|
return LiteralExpr(self.previous().value)
|
||||||
|
|
||||||
|
raise self.error(self.peek(), "Expected literal")
|
||||||
|
|
||||||
|
def constraint_operator(self) -> Token:
|
||||||
|
if self.match(TokenType.LESS, TokenType.LESS_EQUAL, TokenType.GREATER, TokenType.GREATER_EQUAL, TokenType.EQUAL_EQUAL, TokenType.BANG_EQUAL):
|
||||||
|
return self.previous()
|
||||||
|
raise self.error(self.peek(), "Expected constraint operator")
|
||||||
|
|
||||||
def type_body_expr(self) -> TypeBodyExpr:
|
def type_body_expr(self) -> TypeBodyExpr:
|
||||||
"""Parse a type definition body
|
"""Parse a type definition body
|
||||||
|
|||||||
Reference in new issue
Block a user