add more evaluator
This commit is contained in:
parent
dd527edbc4
commit
15e6fb864d
89
evaluator.py
89
evaluator.py
@ -1,10 +1,15 @@
|
||||
from typing import List, Optional
|
||||
from typing import Dict, List, Optional, cast
|
||||
from position import Node
|
||||
from utils import Err, Ok, Result
|
||||
import parsed
|
||||
|
||||
class Value:
|
||||
pass
|
||||
|
||||
class Unit(Value):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
class Int(Value):
|
||||
def __init__(self, value: int) -> None:
|
||||
super().__init__()
|
||||
@ -48,6 +53,20 @@ class ContinueResult(EvalResult):
|
||||
super().__init__()
|
||||
self.value = value
|
||||
|
||||
class PanicResult(EvalResult):
|
||||
def __init__(self, message: str) -> None:
|
||||
super().__init__()
|
||||
self.message = message
|
||||
|
||||
class SymbolTable:
|
||||
def __init__(self) -> None:
|
||||
self.symbols: Dict[str, Value] = {}
|
||||
|
||||
def define(self, symbol_id: str, value: Value) -> Result[None, str]:
|
||||
if symbol_id in self.symbols:
|
||||
return Err("symbol already defined")
|
||||
return Ok(None)
|
||||
|
||||
class Evaluator:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
@ -57,60 +76,60 @@ class Evaluator:
|
||||
self.eval_expr(node)
|
||||
|
||||
def eval_expr(self, node: Node[parsed.Expr]) -> EvalResult:
|
||||
if node.value is parsed.ExprError:
|
||||
if isinstance(node.value, parsed.ExprError):
|
||||
return PanicResult(f"error: {cast(parsed.ExprError, node.value).message}, at {node.span}")
|
||||
elif isinstance(node.value, parsed.Id):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Id:
|
||||
elif isinstance(node.value, parsed.Int):
|
||||
return ValueResult(Int(cast(parsed.Int, node.value).value))
|
||||
elif isinstance(node.value, parsed.Char):
|
||||
return ValueResult(Char(cast(parsed.Char, node.value).value))
|
||||
elif isinstance(node.value, parsed.String):
|
||||
return ValueResult(String(cast(parsed.String, node.value).value))
|
||||
elif isinstance(node.value, parsed.Bool):
|
||||
return ValueResult(Bool(cast(parsed.Bool, node.value).value))
|
||||
elif isinstance(node.value, parsed.Unit):
|
||||
return ValueResult(Unit())
|
||||
elif isinstance(node.value, parsed.Tuple):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Int:
|
||||
elif isinstance(node.value, parsed.Block):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Char:
|
||||
elif isinstance(node.value, parsed.Lambda):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.String:
|
||||
elif isinstance(node.value, parsed.If):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Bool:
|
||||
elif isinstance(node.value, parsed.Match):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Unit:
|
||||
elif isinstance(node.value, parsed.Loop):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Tuple:
|
||||
elif isinstance(node.value, parsed.While):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Block:
|
||||
elif isinstance(node.value, parsed.For):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Lambda:
|
||||
elif isinstance(node.value, parsed.StructMember):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.If:
|
||||
elif isinstance(node.value, parsed.TupleMember):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Match:
|
||||
elif isinstance(node.value, parsed.Index):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Loop:
|
||||
elif isinstance(node.value, parsed.Call):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.While:
|
||||
elif isinstance(node.value, parsed.Unary):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.For:
|
||||
elif isinstance(node.value, parsed.Binary):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.StructMember:
|
||||
elif isinstance(node.value, parsed.Assign):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.TupleMember:
|
||||
elif isinstance(node.value, parsed.Let):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Index:
|
||||
elif isinstance(node.value, parsed.Function):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Call:
|
||||
elif isinstance(node.value, parsed.Return):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Unary:
|
||||
elif isinstance(node.value, parsed.Break):
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Binary:
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Assign:
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Let:
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Function:
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Return:
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Break:
|
||||
raise NotImplementedError()
|
||||
elif node.value is parsed.Continue:
|
||||
elif isinstance(node.value, parsed.Continue):
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError(str(node))
|
||||
|
||||
|
8
main.py
8
main.py
@ -1,14 +1,20 @@
|
||||
from lexer import Lexer
|
||||
from parser import Parser
|
||||
from evaluator import Evaluator
|
||||
|
||||
|
||||
def main() -> None:
|
||||
text = "\"\\\"hello\\\\\""
|
||||
text = "\"hello\""
|
||||
lexer = Lexer(text)
|
||||
parser = Parser(text, lexer)
|
||||
print("parsing...")
|
||||
parsed = parser.parse()
|
||||
print("ast = ")
|
||||
for node in parsed:
|
||||
print(node)
|
||||
evaluator = Evaluator()
|
||||
print("evaluating...")
|
||||
evaluator.evaluate(parsed)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
15
parsed.py
15
parsed.py
@ -1,6 +1,7 @@
|
||||
from enum import Enum, auto
|
||||
from position import Node
|
||||
from typing import Optional, List
|
||||
from utils import escape_string
|
||||
|
||||
class Type:
|
||||
def __str__(self) -> str:
|
||||
@ -64,7 +65,7 @@ class Char(Expr):
|
||||
self.value = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Char('{self.value}')"
|
||||
return f"Char('{escape_string(self.value)}')"
|
||||
|
||||
|
||||
class String(Expr):
|
||||
@ -73,7 +74,7 @@ class String(Expr):
|
||||
self.value = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"String(\"{self.value}\")"
|
||||
return f"String(\"{escape_string(self.value)}\")"
|
||||
|
||||
|
||||
class Bool(Expr):
|
||||
@ -99,7 +100,7 @@ class Tuple(Expr):
|
||||
self.values = values
|
||||
|
||||
def __str__(self) -> str:
|
||||
values = ", ".join(node.__str__() for node in self.values)
|
||||
values = ", ".join(str(node) for node in self.values)
|
||||
return f"Tuple {{ values: [{values}] }}"
|
||||
|
||||
class Block(Expr):
|
||||
@ -109,7 +110,7 @@ class Block(Expr):
|
||||
self.value = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
statements = ", ".join(node.__str__() for node in self.statements)
|
||||
statements = ", ".join(str(node) for node in self.statements)
|
||||
return f"Block {{ statements: [{statements}], value: {self.value} }}"
|
||||
|
||||
class Lambda(Expr):
|
||||
@ -119,7 +120,7 @@ class Lambda(Expr):
|
||||
self.body = body
|
||||
|
||||
def __str__(self) -> str:
|
||||
params = ", ".join(node.__str__() for node in self.params)
|
||||
params = ", ".join(str(node) for node in self.params)
|
||||
return f"Lambda {{ params: [{params}], body: {self.body} }}"
|
||||
|
||||
|
||||
@ -205,7 +206,7 @@ class Call(Expr):
|
||||
self.arguments = arguments
|
||||
|
||||
def __str__(self) -> str:
|
||||
arguments = ", ".join(node.__str__() for node in self.arguments)
|
||||
arguments = ", ".join(str(node) for node in self.arguments)
|
||||
return f"Index {{ subject: {self.subject}, arguments: {arguments} }}"
|
||||
|
||||
class UnaryType(Enum):
|
||||
@ -292,7 +293,7 @@ class Function(Expr):
|
||||
self.body = body
|
||||
|
||||
def __str__(self) -> str:
|
||||
params = ", ".join(node.__str__() for node in self.params)
|
||||
params = ", ".join(str(node) for node in self.params)
|
||||
return f"Function {{ subject_id: {self.subject_id}, params: [{params}], body: {self.body} }}"
|
||||
|
||||
class Return(Expr):
|
||||
|
18
parser.py
18
parser.py
@ -2,7 +2,7 @@ from tokens import Token, TokenType, TokenIterator
|
||||
from position import Position, Span, Node
|
||||
from parsed import Assign, AssignType, Binary, BinaryType, Block, Break, Call, Continue, Match, MatchArm, PatternError, Expr, For, Id, If, Index, Int, Char, Loop, Pattern, Return, String, ExprError, StructMember, Tuple, TupleMember, Unary, UnaryType, Unit, While
|
||||
from typing import List, Optional
|
||||
from utils import Result, Ok, Err
|
||||
from utils import Result, Ok, Err, unescape_string
|
||||
|
||||
|
||||
class Parser:
|
||||
@ -217,24 +217,28 @@ class Parser:
|
||||
def parse_operand(self) -> Node[Expr]:
|
||||
if self.current_is(TokenType.Id):
|
||||
token = self.current()
|
||||
value = token.text_slice(self.text)
|
||||
self.step()
|
||||
value = token.text_slice(self.text)
|
||||
return Node(Id(value), token.span)
|
||||
elif self.current_is(TokenType.Int):
|
||||
token = self.current()
|
||||
value = int(token.text_slice(self.text))
|
||||
self.step()
|
||||
value = int(token.text_slice(self.text))
|
||||
return Node(Int(value), token.span)
|
||||
elif self.current_is(TokenType.Char):
|
||||
token = self.current()
|
||||
value = token.text_slice(self.text)
|
||||
self.step()
|
||||
return Node(Char(value), token.span)
|
||||
value = unescape_string(token.text_slice(self.text)[1:-1])
|
||||
if not value.ok():
|
||||
return Node(ExprError(value.error()), token.span)
|
||||
return Node(Char(value.value()), token.span)
|
||||
elif self.current_is(TokenType.String):
|
||||
token = self.current()
|
||||
value = token.text_slice(self.text)
|
||||
self.step()
|
||||
return Node(String(value), token.span)
|
||||
value = unescape_string(token.text_slice(self.text)[1:-1])
|
||||
if not value.ok():
|
||||
return Node(ExprError(value.error()), token.span)
|
||||
return Node(String(value.value()), token.span)
|
||||
elif self.current_is(TokenType.LParen):
|
||||
return self.parse_unit_group_tuple()
|
||||
elif self.current_is(TokenType.LBrace):
|
||||
|
@ -1,12 +1,14 @@
|
||||
from __future__ import annotations
|
||||
from typing import NamedTuple, TypeVar, Generic
|
||||
|
||||
|
||||
class Position(NamedTuple):
|
||||
index: int
|
||||
line: int
|
||||
col: int
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.line}:{self.col}"
|
||||
|
||||
class Span(NamedTuple):
|
||||
begin: Position
|
||||
end: Position
|
||||
@ -14,6 +16,9 @@ class Span(NamedTuple):
|
||||
def to(self, end: Span) -> Span:
|
||||
return Span(self.begin, end.end)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.begin} to {self.end}"
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
@ -25,4 +30,4 @@ class Node(Generic[T]):
|
||||
self.span = span
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value.__str__()
|
||||
return str(self.value)
|
||||
|
44
utils.py
44
utils.py
@ -48,3 +48,47 @@ class Err(Result[T, E]):
|
||||
def error(self) -> E:
|
||||
return self.__error
|
||||
|
||||
def unescape_string(value: str) -> Result[str, str]:
|
||||
result = ""
|
||||
i = 0
|
||||
while i < len(value):
|
||||
if value[i] == "\\":
|
||||
i += 1
|
||||
if i >= len(value):
|
||||
return Err("unescaped '\\'")
|
||||
elif value[i] == "0":
|
||||
result += "\0"
|
||||
elif value[i] == "n":
|
||||
result += "\n"
|
||||
elif value[i] == "t":
|
||||
result += "\t"
|
||||
elif value[i] == "r":
|
||||
result += "\r"
|
||||
else:
|
||||
result += value[i]
|
||||
else:
|
||||
result += value[i]
|
||||
i += 1
|
||||
return Ok(result)
|
||||
|
||||
def escape_string(value: str) -> str:
|
||||
result = ""
|
||||
for char in value:
|
||||
if char == "\0":
|
||||
result += "\\0"
|
||||
elif char == "\n":
|
||||
result += "\\n"
|
||||
elif char == "\t":
|
||||
result += "\\t"
|
||||
elif char == "\r":
|
||||
result += "\\r"
|
||||
elif char == "\"":
|
||||
result += "\\\""
|
||||
elif char == "\'":
|
||||
result += "\\'"
|
||||
elif char == "\\":
|
||||
result += "\\\\"
|
||||
else:
|
||||
result += char
|
||||
return result
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user