From e31dab52f6e14f1c08c365541e0af1d2e811ce3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Wed, 10 Jul 2019 21:17:16 +0200 Subject: [PATCH] Create parsers for literals (atoms) --- smnp/ast/node/atom.py | 57 +++++++++++++++++++++++++++++++++++++++ smnp/ast/node/chain.py | 2 ++ smnp/ast/node/model.py | 2 +- smnp/ast/node/program.py | 58 ++++++++++++++++++++++++---------------- smnp/ast/parser.py | 6 ++--- smnp/calc.py | 5 ++-- smnp/main.py | 8 +++--- 7 files changed, 105 insertions(+), 33 deletions(-) create mode 100644 smnp/ast/node/atom.py create mode 100644 smnp/ast/node/chain.py diff --git a/smnp/ast/node/atom.py b/smnp/ast/node/atom.py new file mode 100644 index 0000000..af92a74 --- /dev/null +++ b/smnp/ast/node/atom.py @@ -0,0 +1,57 @@ +from smnp.ast.node.model import Node +from smnp.ast.parser import Parser +from smnp.token.type import TokenType + + +class Atom(Node): + def __init__(self, pos): + super().__init__(pos) + self.children = [None] + + @property + def value(self): + return self[0] + + @value.setter + def value(self, value): + self[0] = value + + @classmethod + def withValue(cls, value, pos): + node = cls(pos) + node.value = value + return node + + +class IntegerLiteral(Atom): + pass + + +class StringLiteral(Atom): + pass + + +class NoteLiteral(Atom): + pass + + +class BoolLiteral(Atom): + pass + +integerParser = Parser.oneOf( + Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)), + Parser.allOf( + Parser.terminalParser(TokenType.MINUS), + Parser.terminalParser(TokenType.INTEGER, lambda val, pos: IntegerLiteral.withValue(int(val), pos)), + createNode=lambda minus, integer: IntegerLiteral.withValue(-integer.value, minus.pos) + ) +) + +parser = Parser.oneOf( + integerParser, + Parser.terminalParser(TokenType.STRING, lambda val, pos: StringLiteral.withValue(val, pos)), + Parser.terminalParser(TokenType.NOTE, lambda val, pos: NoteLiteral.withValue(val, pos)), + Parser.terminalParser(TokenType.BOOL, lambda val, pos: BoolLiteral.withValue(val, pos)), +) + +AtomParser = Parser(parser, "atom", parser) diff --git a/smnp/ast/node/chain.py b/smnp/ast/node/chain.py new file mode 100644 index 0000000..139597f --- /dev/null +++ b/smnp/ast/node/chain.py @@ -0,0 +1,2 @@ + + diff --git a/smnp/ast/node/model.py b/smnp/ast/node/model.py index 0aa143a..49a75d9 100644 --- a/smnp/ast/node/model.py +++ b/smnp/ast/node/model.py @@ -47,7 +47,7 @@ class Node: self._print(first=True) def _print(self, prefix="", last=True, first=False): - print(prefix, '' if first else '└─' if last else '├─', self.__class__.__name__, sep="") + print(prefix, '' if first else '└─' if last else '├─', self.__class__.__name__, f" (line {self.pos[0]+1}, col {self.pos[1]+1})", sep="") prefix += ' ' if last else '│ ' for i, child in enumerate(self.children): last = i == len(self.children) - 1 diff --git a/smnp/ast/node/program.py b/smnp/ast/node/program.py index a6991ac..3d77704 100644 --- a/smnp/ast/node/program.py +++ b/smnp/ast/node/program.py @@ -1,32 +1,44 @@ -from smnp.ast.node.expression import ExpressionNode -from smnp.ast.node.extend import ExtendNode -from smnp.ast.node.function import FunctionDefinitionNode -from smnp.ast.node.imports import ImportNode +from smnp.ast.node.atom import AtomParser from smnp.ast.node.model import Node, ParseResult -from smnp.ast.node.statement import StatementNode from smnp.ast.parser import Parser -from smnp.error.syntax import SyntaxException class Program(Node): def __init__(self): super().__init__((-1, -1)) - @classmethod - def _parse(cls, input): - def parseToken(input): - return Parser.oneOf( - FunctionDefinitionNode.parse, - ExtendNode.parse, - ExpressionNode.parse, - ImportNode.parse, - StatementNode.parse, - exception = SyntaxException(f"Invalid statement: {input.currentToEndOfLine()}", input.current().pos) - )(input) +def parse(input): + root = Program() + while input.hasCurrent(): + result = Parser.oneOf( + # Start Symbol - root = Program() - while input.hasCurrent(): - result = parseToken(input) - if result.result: - root.append(result.node) - return ParseResult.OK(root) \ No newline at end of file + + #TODO -> temporary (to remove): + AtomParser + )(input) + + if result.result: + root.append(result.node) + + return ParseResult.OK(root) + +ProgramParser = Parser(parse, name="program") + # @classmethod + # def _parse(cls, input): + # def parseToken(input): + # return Parser.oneOf( + # FunctionDefinitionNode.parse, + # ExtendNode.parse, + # ExpressionNode.parse, + # ImportNode.parse, + # StatementNode.parse, + # exception = SyntaxException(f"Invalid statement: {input.currentToEndOfLine()}", input.current().pos) + # )(input) + # + # root = Program() + # while input.hasCurrent(): + # result = parseToken(input) + # if result.result: + # root.append(result.node) + # return ParseResult.OK(root) \ No newline at end of file diff --git a/smnp/ast/parser.py b/smnp/ast/parser.py index cbec991..474d39c 100644 --- a/smnp/ast/parser.py +++ b/smnp/ast/parser.py @@ -5,8 +5,8 @@ from smnp.error.syntax import SyntaxException def parse(input): - from smnp.ast.node.program import Program - return Program.parse(input).node + from smnp.ast.node.program import ProgramParser + return ProgramParser(input).node class Parser: @@ -58,7 +58,7 @@ class Parser: return ParseResult.FAIL() - return Parser(parse, expectedType.name.lower()) + return Parser(parse, name=expectedType.name.lower()) # oneOf -> a | b | c | ... @staticmethod diff --git a/smnp/calc.py b/smnp/calc.py index b387b2a..e5f8115 100644 --- a/smnp/calc.py +++ b/smnp/calc.py @@ -31,7 +31,7 @@ class Operation(Node): return self[2] def atom(): - return Parser.terminalParser(TokenType.INTEGER, lambda val, pos: Atom(val, pos)) + return Parser.oneOfTerminals(TokenType.INTEGER, TokenType.NOTE, TokenType.STRING, createNode=lambda val, pos: Atom(val, pos)) def chain(): return Parser.leftAssociativeOperatorParser(atom(), [TokenType.DOT], atom(), lambda left, op, right: Operation(left, op, right, op.pos), name="chain") @@ -60,8 +60,7 @@ def evaluate(node): def draft(): - tokens = tokenize(['2**3/2 + 10 - 2']) + tokens = tokenize(['"fesf fe" + "fsefsef" + "fsefs"']) e = expr() node = e(tokens).node node.print() - print(evaluate(node)) diff --git a/smnp/main.py b/smnp/main.py index da14e33..d1ed282 100644 --- a/smnp/main.py +++ b/smnp/main.py @@ -1,12 +1,14 @@ -from smnp.calc import draft +import sys + from smnp.error.base import SmnpException +from smnp.program.interpreter import Interpreter def main(): try: #stdLibraryEnv = loadStandardLibrary() - #Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, execute=False, baseEnvironment=stdLibraryEnv) - draft() + Interpreter.interpretFile(sys.argv[1], printTokens=False, printAst=True, execute=False, baseEnvironment=None) + #draft() except SmnpException as e: print(e.message())