def ImportParser(input): return Parser.allOf( Parser.terminal(TokenType.IMPORT), Parser.doAssert(StringParser, "import source as string"), createNode=lambda imp, source: Import.withValue(source), name="import" )(input)
def ReturnParser(input): return Parser.allOf( Parser.terminal(TokenType.RETURN), Parser.optional(ExpressionParser), createNode=lambda ret, val: Return.withValue(val, ret.pos), name="return" )(input)
def BlockParser(input): return Parser.loop( Parser.terminal(TokenType.OPEN_CURLY), Parser.doAssert(StatementParser, f"statement or '{TokenType.CLOSE_CURLY.key}'"), Parser.terminal(TokenType.CLOSE_CURLY), createNode=lambda open, statements, close: Block.withChildren( statements, open.pos))(input)
def MethodsDeclarationParser(input): return Parser.loop( Parser.terminal(TokenType.OPEN_CURLY), Parser.doAssert(FunctionDefinitionParser, f"method definition or '{TokenType.CLOSE_CURLY.key}'"), Parser.terminal(TokenType.CLOSE_CURLY), createNode=lambda open, methods, close: Block.withChildren( methods, open.pos), name="methods block")(input)
def emptyIterable(input): def createNode(open, close): node = AbstractIterable(open.pos) node.value = open node.next = close return node return Parser.allOf(Parser.terminal(openTokenType), Parser.terminal(closeTokenType), createNode=createNode)(input)
def withSemicolon(parser, optional=False, doAssert=False): semicolonParser = Parser.optional(Parser.terminal(TokenType.SEMICOLON)) if optional else Parser.terminal( TokenType.SEMICOLON, doAssert=doAssert) return Parser.allOf( parser, semicolonParser, createNode=lambda stmt, semicolon: stmt, name="semicolon" + "?" if optional else "" )
def FunctionDefinitionParser(input): return Parser.allOf(Parser.terminal(TokenType.FUNCTION), Parser.doAssert(IdentifierLiteralParser, "function/method name"), Parser.doAssert(ArgumentsDeclarationParser, "function/method arguments"), Parser.doAssert(BlockParser, "function/method body"), createNode=lambda _, name, args, body: FunctionDefinition.withValues(name, args, body), name="function definition")(input)
def openIterable(input): def createNode(open, item, tail): node = AbstractIterable(open.pos) node.value = item node.next = tail return node return Parser.allOf(Parser.terminal(openTokenType), itemParser, abstractIterableTailParser, createNode=createNode)(input)
def TypeParser(input): typeWithSpecifier = Parser.allOf( TypeLiteralParser, Parser.many(TypesListParser, createNode=TypeSpecifiers.withChildren), createNode=lambda type, specifiers: Type.withValues( type.pos, type, specifiers), name="type with specifiers?") return Parser.oneOf(typeWithSpecifier, TypesListParser, name="mult. types or type with specifier")(input)
def nextItem(input): def createNode(comma, item, tail): node = AbstractIterableTail(item.pos) node.value = item node.next = tail return node return Parser.allOf(Parser.doAssert( Parser.terminal(TokenType.COMMA), f"'{TokenType.COMMA.key}' or '{closeTokenType.key}'"), itemParser, abstractIterableTailParser, createNode=createNode)(input)
def MapParser(input): from smnp.ast.node.expression import ExpressionParser keyParser = Parser.oneOf(LiteralParser, IdentifierLiteralParser) valueParser = ExpressionParser mapEntryParser = Parser.allOf(keyParser, Parser.terminal( TokenType.ARROW, createNode=Operator.withValue), Parser.doAssert(valueParser, "expression"), createNode=MapEntry.withValues) return abstractIterableParser(Map, TokenType.OPEN_CURLY, TokenType.CLOSE_CURLY, mapEntryParser)(input)
def OptionalArgumentParser(input): def createNode(type, variable, _, optional): pos = type.pos if isinstance(type, Type) else variable.pos node = Argument(pos) node.type = type node.variable = variable node.optionalValue = optional return node return Parser.allOf(Parser.optional(TypeParser), Parser.doAssert(IdentifierLiteralParser, "argument name"), Parser.terminal(TokenType.ASSIGN), Parser.doAssert(ExpressionParser, "expression"), createNode=createNode, name="optional function argument")(input)
def LiteralParser(input): return Parser.oneOf(IntegerParser, FloatParser, StringParser, NoteParser, BoolParser, TypeLiteralParser, name="literal")(input)
def ExpressionWithoutLoopParser(input): expr1 = Parser.leftAssociativeOperatorParser( TermParser, [TokenType.PLUS, TokenType.MINUS], TermParser, lambda left, op, right: Sum.withValues(left, op, right)) expr2 = Parser.leftAssociativeOperatorParser( expr1, [TokenType.RELATION, TokenType.OPEN_ANGLE, TokenType.CLOSE_ANGLE], expr1, lambda left, op, right: Relation.withValues(left, op, right)) expr3 = Parser.leftAssociativeOperatorParser( expr2, [TokenType.AND], expr2, lambda left, op, right: And.withValues(left, op, right)) return Parser.leftAssociativeOperatorParser( expr3, [TokenType.OR], expr3, lambda left, op, right: Or.withValues(left, op, right))(input)
def RegularArgumentParser(input): def createNode(type, variable, vararg): pos = type.pos if isinstance(type, Type) else variable.pos node = Argument(pos) node.type = type node.variable = variable node.vararg = vararg is True return node return Parser.allOf(Parser.optional(TypeParser), Parser.doAssert(IdentifierLiteralParser, "argument name"), Parser.optional( Parser.terminal(TokenType.DOTS, lambda val, pos: True)), createNode=createNode, name="regular function argument")(input)
def AtomParser(input): from smnp.ast.node.identifier import IdentifierParser from smnp.ast.node.list import ListParser from smnp.ast.node.map import MapParser from smnp.ast.node.expression import ExpressionParser parentheses = Parser.allOf(Parser.terminal(TokenType.OPEN_PAREN), Parser.doAssert(ExpressionParser, "expression"), Parser.terminal(TokenType.CLOSE_PAREN), createNode=lambda open, expr, close: expr, name="grouping parentheses") return Parser.oneOf(parentheses, LiteralParser, IdentifierParser, ListParser, MapParser, name="atom")(input)
def ListParser(input): from smnp.ast.node.expression import ExpressionParser return abstractIterableParser( List, TokenType.OPEN_SQUARE, TokenType.CLOSE_SQUARE, Parser.doAssert(ExpressionParser, "expression") )(input)
def IdentifierParser(input): functionCallParser = Parser.allOf( IdentifierLiteralParser, abstractIterableParser(ArgumentsList, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, Parser.doAssert(ExpressionParser, "expression")), createNode=lambda name, arguments: FunctionCall.withChildren(name, arguments) ) assignmentParser = Parser.allOf( IdentifierLiteralParser, Parser.terminal(TokenType.ASSIGN, createNode=Operator.withValue), Parser.doAssert(ExpressionParser, "expression"), createNode=lambda identifier, assign, expr: Assignment.withValues(identifier, assign, expr) ) return Parser.oneOf( assignmentParser, functionCallParser, IdentifierLiteralParser )(input)
def FactorParser(input): powerFactor = Parser.leftAssociativeOperatorParser( UnitParser, [TokenType.DOUBLE_ASTERISK], UnitParser, lambda left, op, right: Power.withValues(left, op, right), name="power operator" ) notOperator = Parser.allOf( Parser.terminal(TokenType.NOT, Operator.withValue), powerFactor, createNode=NotOperator.withValues, name="not" ) return Parser.oneOf( notOperator, powerFactor, name="factor" )(input)
def toFlatDesiredNode(iterableNodeType, parser): def parse(input): result = parser(input) if result.result: value = flattenList(result.node) node = iterableNodeType(result.node.pos) node.children.clear() for v in value: node.append(v) return ParseResult.OK(node) return ParseResult.FAIL() return Parser(parse, "flat", [parser])
def StatementParser(input): from smnp.ast.node.block import BlockParser from smnp.ast.node.condition import IfElseStatementParser from smnp.ast.node.expression import ExpressionParser from smnp.ast.node.ret import ReturnParser from smnp.ast.node.throw import ThrowParser return withSemicolon( Parser.oneOf( IfElseStatementParser, ExpressionParser, # Must be above BlockParser because of Map's syntax with curly braces BlockParser, ReturnParser, ThrowParser, name="statement" ), optional=True)(input)
def UnitParser(input): minusOperator = Parser.allOf(Parser.terminal( TokenType.MINUS, createNode=Operator.withValue), Parser.doAssert(AtomParser, "atom"), createNode=MinusOperator.withValues, name="minus") atom2 = Parser.oneOf(minusOperator, AtomParser, name="atom2") return Parser.leftAssociativeOperatorParser( atom2, [TokenType.DOT], Parser.doAssert(atom2, "atom"), createNode=lambda left, op, right: Access.withValues(left, op, right), name="unit")(input)
def parse(input): root = Program() # Start Symbol startSymbolParser = Parser.oneOf( ImportParser, FunctionDefinitionParser, ExtendParser, StatementParser, exception=lambda inp: SyntaxException( f"Invalid statement: {inp.currentToEndOfLine()}", inp.current().pos), name="start symbol") while input.hasCurrent(): result = startSymbolParser(input) if result.result: root.append(result.node) return ParseResult.OK(root)
def TypeLiteralParser(input): return Parser.terminal(TokenType.TYPE, createNode=TypeLiteral.withValue)(input)
def ArgumentsDeclarationParser(input): return abstractIterableParser( ArgumentsDeclaration, TokenType.OPEN_PAREN, TokenType.CLOSE_PAREN, Parser.doAssert(ArgumentParser, "function/method argument"))(input)
def ArgumentParser(input): return Parser.oneOf(OptionalArgumentParser, RegularArgumentParser, name="function argument")(input)
def NoteParser(input): return Parser.terminal(TokenType.NOTE, createNode=NoteLiteral.withValue)(input)
def ExtendParser(input): simpleExtend = Parser.allOf( Parser.terminal(TokenType.EXTEND), TypeParser, Parser.terminal(TokenType.AS), IdentifierLiteralParser, Parser.terminal(TokenType.WITH), Parser.doAssert( Parser.wrap( FunctionDefinitionParser, lambda method: Block.withChildren([method], method.pos)), "method definition"), createNode=lambda extend, type, _, variable, __, methods: Extend. withValues(extend.pos, type, variable, methods), name="simple extend") multiExtend = Parser.allOf( Parser.terminal(TokenType.EXTEND), Parser.doAssert(TypeParser, "type being extended"), Parser.terminal(TokenType.AS, doAssert=True), Parser.doAssert(IdentifierLiteralParser, "variable name"), Parser.doAssert( MethodsDeclarationParser, f"block with methods definitions or '{TokenType.WITH.key}' keyword" ), createNode=lambda extend, type, _, variable, methods: Extend. withValues(extend.pos, type, variable, methods), name="multiple extend") return Parser.oneOf(simpleExtend, multiExtend, name="extend")(input)
def BoolParser(input): return Parser.terminal(TokenType.BOOL, createNode=BoolLiteral.withValue)(input)
def IdentifierLiteralParser(input): return Parser.terminal(TokenType.IDENTIFIER, createNode=Identifier.withValue)(input)