From f11b3b67f2bbeb1da349a98b61f291d3160f4113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Pluta?= Date: Sat, 6 Jul 2019 00:20:36 +0200 Subject: [PATCH] Add support for custom functions --- smnp/main.py | 2 +- smnp/newast/node/function.py | 67 +++++++++++++++++++++++++++++++ smnp/newast/node/identifier.py | 8 ++-- smnp/newast/node/ret.py | 32 +++++++++++++++ smnp/newast/node/statement.py | 4 ++ smnp/newast/node/type.py | 13 ++++++ smnp/newast/node/variable.py | 46 +++++++++++++++++++++ smnp/token/tokenizers/function.py | 2 +- 8 files changed, 168 insertions(+), 6 deletions(-) create mode 100644 smnp/newast/node/function.py create mode 100644 smnp/newast/node/ret.py create mode 100644 smnp/newast/node/type.py create mode 100644 smnp/newast/node/variable.py diff --git a/smnp/main.py b/smnp/main.py index d77ea91..d5af0f4 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/function.py b/smnp/newast/node/function.py new file mode 100644 index 0000000..2930931 --- /dev/null +++ b/smnp/newast/node/function.py @@ -0,0 +1,67 @@ +from smnp.newast.node.block import BlockNode +from smnp.newast.node.identifier import IdentifierNode +from smnp.newast.node.iterable import abstractIterableParser +from smnp.newast.node.model import Node +from smnp.newast.node.none import NoneNode +from smnp.newast.node.statement import StatementNode +from smnp.newast.node.variable import TypedVariableNode +from smnp.newast.parser import Parser +from smnp.token.type import TokenType + + +class ArgumentsDeclarationNode(Node): + + @classmethod + def _parse(cls, input): + raise RuntimeError("This class is not supposed to be automatically called") + + +class FunctionDefinition(StatementNode): + def __init__(self, pos): + super().__init__(pos) + self.children = [NoneNode(), NoneNode(), NoneNode()] + + @property + def name(self): + return self[0] + + @name.setter + def name(self, value): + self[0] = value + + @property + def arguments(self): + return self[1] + + @arguments.setter + def arguments(self, value): + self[1] = value + + @property + def body(self): + return self[2] + + @body.setter + def body(self, value): + self[2] = value + + @classmethod + def _parse(cls, input): + def createNode(function, name, arguments, body): + node = FunctionDefinition(function.pos) + node.name = name + node.arguments = arguments + node.body = body + return node + + return Parser.allOf( + Parser.terminalParser(TokenType.FUNCTION), + IdentifierNode.identifierParser(), + cls._argumentsDeclarationParser(), + BlockNode.parse, + createNode=createNode + )(input) + + @staticmethod + def _argumentsDeclarationParser(): + return abstractIterableParser(ArgumentsDeclarationNode, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, TypedVariableNode.parser()) \ No newline at end of file diff --git a/smnp/newast/node/identifier.py b/smnp/newast/node/identifier.py index 9b8bba2..ac8cdf6 100644 --- a/smnp/newast/node/identifier.py +++ b/smnp/newast/node/identifier.py @@ -17,7 +17,7 @@ class IdentifierNode(AccessNode): return Parser.oneOf( IdentifierNode._functionCallParser(), IdentifierNode._assignmentParser(), - IdentifierNode._identifierParser() + IdentifierNode.identifierParser() ) @staticmethod @@ -29,7 +29,7 @@ class IdentifierNode(AccessNode): return node return Parser.allOf( - IdentifierNode._identifierParser(), + IdentifierNode.identifierParser(), Parser.terminalParser(TokenType.ASSIGN), ExpressionNode.parse, createNode=createNode @@ -44,11 +44,11 @@ class IdentifierNode(AccessNode): return node return Parser.allOf( - IdentifierNode._identifierParser(), + IdentifierNode.identifierParser(), ArgumentsListNode.parse, createNode=createNode ) @staticmethod - def _identifierParser(): + def identifierParser(): return Parser.terminalParser(TokenType.IDENTIFIER, lambda val, pos: IdentifierNode.withValue(val, pos)) diff --git a/smnp/newast/node/ret.py b/smnp/newast/node/ret.py new file mode 100644 index 0000000..aa38fb6 --- /dev/null +++ b/smnp/newast/node/ret.py @@ -0,0 +1,32 @@ +from smnp.newast.node.expression import ExpressionNode +from smnp.newast.node.none import NoneNode +from smnp.newast.node.statement import StatementNode +from smnp.newast.parser import Parser +from smnp.token.type import TokenType + + +class ReturnNode(StatementNode): + def __init__(self, pos): + super().__init__(pos) + self.children.append(NoneNode()) + + @property + def value(self): + return self[0] + + @value.setter + def value(self, value): + self[0] = value + + @classmethod + def _parse(cls, input): + def createNode(ret, value): + node = ReturnNode(ret.pos) + node.value = value + return node + + return Parser.allOf( + Parser.terminalParser(TokenType.RETURN), + ExpressionNode.parse, + createNode=createNode + )(input) \ No newline at end of file diff --git a/smnp/newast/node/statement.py b/smnp/newast/node/statement.py index 9dbbc47..9c5d71b 100644 --- a/smnp/newast/node/statement.py +++ b/smnp/newast/node/statement.py @@ -7,9 +7,13 @@ 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/newast/node/type.py b/smnp/newast/node/type.py new file mode 100644 index 0000000..8553ba2 --- /dev/null +++ b/smnp/newast/node/type.py @@ -0,0 +1,13 @@ +from smnp.newast.node.access import AccessNode +from smnp.newast.node.literal import LiteralNode +from smnp.token.type import TokenType + + +class TypeNode(LiteralNode, AccessNode): + def __init__(self, pos): + super().__init__(pos) + del self.children[1] + + @classmethod + def _getTokenType(cls): + return TokenType.TYPE \ No newline at end of file diff --git a/smnp/newast/node/variable.py b/smnp/newast/node/variable.py new file mode 100644 index 0000000..4721132 --- /dev/null +++ b/smnp/newast/node/variable.py @@ -0,0 +1,46 @@ +from smnp.newast.node.expression import ExpressionNode +from smnp.newast.node.identifier import IdentifierNode +from smnp.newast.node.none import NoneNode +from smnp.newast.node.type import TypeNode +from smnp.newast.parser import Parser +from smnp.token.type import TokenType + +class TypedVariableNode(ExpressionNode): + def __init__(self, pos): + super().__init__(pos) + self.children.append(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 + + @classmethod + def parser(cls): + def createNode(type, variable): + node = TypedVariableNode(type.pos) + node.type = type + node.variable = variable + return node + + return Parser.allOf( + Parser.terminalParser(TokenType.TYPE, lambda val, pos: TypeNode.withValue(val, pos)), + IdentifierNode.identifierParser(), + createNode=createNode + ) + + @classmethod + def _parse(cls, input): + #TODO + raise RuntimeError("Not implemented yet. There is still required work to correctly build AST related to IdentifierNode") diff --git a/smnp/token/tokenizers/function.py b/smnp/token/tokenizers/function.py index de21ab0..2d12bab 100644 --- a/smnp/token/tokenizers/function.py +++ b/smnp/token/tokenizers/function.py @@ -2,4 +2,4 @@ from smnp.token.tools import tokenizeKeyword from smnp.token.type import TokenType def tokenizeFunction(input, current, line): - return tokenizeKeyword(TokenType.FUNCTION, 'library', input, current, line) + return tokenizeKeyword(TokenType.FUNCTION, 'function', input, current, line)