From bf40c5130cfd86bac2e669b3ac4d82d9eeaddcef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Sat, 6 Jul 2019 00:36:54 +0200 Subject: [PATCH] Enable extending existing types to add custom methods --- smnp/main.py | 2 +- smnp/newast/node/extend.py | 69 +++++++++++++++++++++++++++++++++ smnp/newast/node/function.py | 4 +- smnp/newast/node/program.py | 6 ++- smnp/newast/node/statement.py | 2 - smnp/token/tokenizer.py | 2 + smnp/token/tokenizers/extend.py | 6 +++ smnp/token/type.py | 1 + 8 files changed, 86 insertions(+), 6 deletions(-) create mode 100644 smnp/newast/node/extend.py create mode 100644 smnp/token/tokenizers/extend.py diff --git a/smnp/main.py b/smnp/main.py index d5af0f4..d77ea91 100644 --- a/smnp/main.py +++ b/smnp/main.py @@ -13,7 +13,7 @@ def main(): lines = [line.rstrip('\n') for line in source.readlines()] tokens = tokenize(lines) - print(tokens) + ast = Program.parse(tokens) ast.node.print() diff --git a/smnp/newast/node/extend.py b/smnp/newast/node/extend.py new file mode 100644 index 0000000..8aec58b --- /dev/null +++ b/smnp/newast/node/extend.py @@ -0,0 +1,69 @@ +from smnp.newast.node.block import BlockNode +from smnp.newast.node.function import FunctionDefinitionNode +from smnp.newast.node.identifier import IdentifierNode +from smnp.newast.node.none import NoneNode +from smnp.newast.node.statement import StatementNode +from smnp.newast.node.type import TypeNode +from smnp.newast.parser import Parser +from smnp.token.type import TokenType + + +class ExtendNode(StatementNode): + def __init__(self, pos): + super().__init__(pos) + self.children = [NoneNode(), NoneNode(), NoneNode()] + + @property + def type(self): + return self[0] + + @type.setter + def type(self, value): + self[0] = value + + @property + def variable(self): + return self[1] + + @variable.setter + def variable(self, value): + self[1] = value + + @property + def methods(self): + return self[2] + + @methods.setter + def methods(self, value): + self[2] = value + + @classmethod + def _parse(cls, input): + def createNode(extend, type, variable, methods): + node = ExtendNode(extend.pos) + node.type = type + node.variable = variable + node.methods = methods + return node + + return Parser.allOf( + Parser.terminalParser(TokenType.EXTEND), + TypeNode.parse, + IdentifierNode.identifierParser(), + cls._methodsDeclarationsParser(), + createNode=createNode + )(input) + + @classmethod + def _methodsDeclarationsParser(cls): + def createNode(openBracket, items, closeBracket): + node = BlockNode(openBracket.pos) + node.children = items + return node + + return Parser.loop( + Parser.terminalParser(TokenType.OPEN_BRACKET), + FunctionDefinitionNode.parse, + Parser.terminalParser(TokenType.CLOSE_BRACKET), + createNode=createNode + ) \ No newline at end of file diff --git a/smnp/newast/node/function.py b/smnp/newast/node/function.py index 2930931..8e9ca51 100644 --- a/smnp/newast/node/function.py +++ b/smnp/newast/node/function.py @@ -16,7 +16,7 @@ class ArgumentsDeclarationNode(Node): raise RuntimeError("This class is not supposed to be automatically called") -class FunctionDefinition(StatementNode): +class FunctionDefinitionNode(StatementNode): def __init__(self, pos): super().__init__(pos) self.children = [NoneNode(), NoneNode(), NoneNode()] @@ -48,7 +48,7 @@ class FunctionDefinition(StatementNode): @classmethod def _parse(cls, input): def createNode(function, name, arguments, body): - node = FunctionDefinition(function.pos) + node = FunctionDefinitionNode(function.pos) node.name = name node.arguments = arguments node.body = body diff --git a/smnp/newast/node/program.py b/smnp/newast/node/program.py index b72ce33..75c4a3c 100644 --- a/smnp/newast/node/program.py +++ b/smnp/newast/node/program.py @@ -1,5 +1,7 @@ from smnp.error.syntax import SyntaxException from smnp.newast.node.expression import ExpressionNode +from smnp.newast.node.extend import ExtendNode +from smnp.newast.node.function import FunctionDefinitionNode from smnp.newast.node.model import Node, ParseResult from smnp.newast.node.statement import StatementNode from smnp.newast.parser import Parser @@ -13,9 +15,11 @@ class Program(Node): def _parse(cls, input): def parseToken(input): return Parser.oneOf( + FunctionDefinitionNode.parse, + ExtendNode.parse, ExpressionNode.parse, StatementNode.parse, - exception = SyntaxException("Unknown statement") + exception = SyntaxException(f"Unknown statement: {input.current().pos}") )(input) root = Program() diff --git a/smnp/newast/node/statement.py b/smnp/newast/node/statement.py index 9c5d71b..7103880 100644 --- a/smnp/newast/node/statement.py +++ b/smnp/newast/node/statement.py @@ -7,13 +7,11 @@ class StatementNode(Node): @classmethod def _parse(cls, input): from smnp.newast.node.block import BlockNode - from smnp.newast.node.function import FunctionDefinition from smnp.newast.node.expression import ExpressionNode from smnp.newast.node.ret import ReturnNode return Parser.oneOf( BlockNode.parse, - FunctionDefinition.parse, ReturnNode.parse, ExpressionNode.parse )(input) \ No newline at end of file diff --git a/smnp/token/tokenizer.py b/smnp/token/tokenizer.py index cc96c14..23d264a 100644 --- a/smnp/token/tokenizer.py +++ b/smnp/token/tokenizer.py @@ -6,6 +6,7 @@ from smnp.token.tokenizers.bracket import tokenizeOpenBracket, tokenizeCloseBrac from smnp.token.tokenizers.comma import tokenizeComma from smnp.token.tokenizers.comment import tokenizeComment from smnp.token.tokenizers.dot import tokenizeDot +from smnp.token.tokenizers.extend import tokenizeExtend from smnp.token.tokenizers.function import tokenizeFunction from smnp.token.tokenizers.identifier import tokenizeIdentifier from smnp.token.tokenizers.integer import tokenizeInteger @@ -30,6 +31,7 @@ tokenizers = ( tokenizeString, tokenizeFunction, tokenizeReturn, + tokenizeExtend, tokenizeInteger, tokenizeNote, tokenizeIdentifier, diff --git a/smnp/token/tokenizers/extend.py b/smnp/token/tokenizers/extend.py new file mode 100644 index 0000000..1ae25fc --- /dev/null +++ b/smnp/token/tokenizers/extend.py @@ -0,0 +1,6 @@ +from smnp.token.tools import tokenizeKeyword +from smnp.token.type import TokenType + + +def tokenizeExtend(input, current, line): + return tokenizeKeyword(TokenType.EXTEND, "extend", input, current, line) \ No newline at end of file diff --git a/smnp/token/type.py b/smnp/token/type.py index cb691f5..110fc57 100644 --- a/smnp/token/type.py +++ b/smnp/token/type.py @@ -22,3 +22,4 @@ class TokenType(Enum): OPEN_SQUARE = auto() CLOSE_SQUARE = auto() TYPE = auto() + EXTEND = auto()