add concat and examples

This commit is contained in:
JOLIMAITRE Matthieu 2024-05-21 07:27:23 +02:00
parent 78ceb46b2e
commit d063ebbac6
5 changed files with 158 additions and 3 deletions

89
examples/evalexpr.py Executable file
View file

@ -0,0 +1,89 @@
#!/bin/env -S python
from dataclasses import dataclass
from typing import TypeVar, Union
from os.path import dirname
import sys
sys.path.append(f"{dirname(__file__)}/../src")
from pyalibert import regex, Parser, just, Declare
# ast modeling
@dataclass
class OpAdd:
def apply(self, left: float, right: float): return left + right
@dataclass
class OpSub:
def apply(self, left: float, right: float): return left - right
@dataclass
class OpMul:
def apply(self, left: float, right: float): return left * right
@dataclass
class OpDiv:
def apply(self, left: float, right: float): return left / right
@dataclass
class BinOp:
actual: Union[OpAdd, OpSub, OpMul, OpDiv]
def apply(self, left: float, right: float): return self.actual.apply(left, right)
@dataclass
class Value:
actual: float
@dataclass
class Math:
first: "Expr"
rest: list[tuple[BinOp, "Expr"]]
def eval(self) -> float:
value = self.first.eval()
for (op, oth) in self.rest: value = op.apply(value, oth.eval())
return value
@dataclass
class Expr:
actual: Union[Value, Math]
def eval(self) -> float:
if isinstance(self.actual, Value): return self.actual.actual
else: return self.actual.eval()
T = TypeVar("T")
def lexeme(p: Parser[T]): return p << just(" ").repeat()
none = just('')
oper = lexeme(just("+").set(OpAdd()) | just("-").set(OpSub()) | just("*").set(OpMul()) | just("/").set(OpDiv())).map(BinOp)
(lbrace, rbrace) = (lexeme(just('(')), lexeme(just(')')))
digit = regex("[0-9]")
integer = digit + digit.repeat().join()
signed = (just("-") | none) + integer
decimal = just(".") + integer
value = lexeme(signed + (decimal | none)).map(float).map(Value)
math = Declare[Math]()
expr = (value | math.parser()).map(Expr)
math_inner = (expr & (oper & expr).repeat()).map(lambda r: Math(*r))
math.define(lbrace >> math_inner << rbrace)
parser = math_inner
def repl():
print("[ New super EvalExpr. ]")
print("[ 100% composed and typed ]")
print("> ", end="")
sys.stdout.flush()
for line in sys.stdin:
result = parser.parse(line.strip())
print(result)
print(f"= {result.eval()}")
print("> ", end="")
sys.stdout.flush()
if __name__ == "__main__": repl()