import { AssignmentStatement, Block, containsReturn, Expression, Function, FunctionArgument, FunctionCall, FunctionDeclaration, FunctionTypeUsage, Identifier, IfExpression, Impl, LetStatement, LiteralBool, LiteralFloat, LiteralInt, LiteralString, LiteralStruct, Module, ModuleItem, NamedTypeUsage, newNever, Operation, Path, ReturnStatement, Statement, StructField, StructGetter, StructTypeDeclaration, StructTypeField, TraitTypeDeclaration, TypeDeclaration, TypeUsage, } from "./ast"; import { boringGrammar } from "./grammar"; let unknownTypeCounter = 0; function nextUnknown() { let name = "S" + unknownTypeCounter.toString(); unknownTypeCounter += 1; return name; } export const semantics = boringGrammar.createSemantics(); semantics.addOperation("toAST", { LiteralInt(a): Expression { return { statementType: "Expression", subExpression: { expressionType: "LiteralInt", value: this.sourceString, type: { typeUsage: "NamedTypeUsage", name: { text: "i64", spanStart: 0, spanEnd: 0 }, }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, LiteralFloat(_1, _2, _3): Expression { return { statementType: "Expression", subExpression: { expressionType: "LiteralFloat", value: this.sourceString, type: { typeUsage: "NamedTypeUsage", name: { text: "f64", spanStart: 0, spanEnd: 0 }, }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, LiteralBool(_): Expression { return { statementType: "Expression", subExpression: { expressionType: "LiteralBool", value: this.sourceString, type: { typeUsage: "NamedTypeUsage", name: { text: "bool", spanStart: 0, spanEnd: 0 }, }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, LiteralString(_1, text, _3): Expression { return { statementType: "Expression", subExpression: { expressionType: "LiteralString", value: text.sourceString, type: { typeUsage: "NamedTypeUsage", name: { text: "String", spanStart: 0, spanEnd: 0 }, }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, LiteralStructField(identifier, _2, expression): StructField { return { name: identifier.toAST(), expression: expression.toAST(), }; }, LiteralStruct(identifier, _2, fields, _4): Expression { return { statementType: "Expression", subExpression: { expressionType: "LiteralStruct", name: identifier.toAST(), fields: fields.asIteration().children.map((c) => c.toAST()), type: { typeUsage: "NamedTypeUsage", name: identifier.toAST() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, identifier(_1, _2): Identifier { return { text: this.sourceString, spanStart: this.source.startIdx, spanEnd: this.source.endIdx, }; }, PrimaryExpression(literal): Expression { return literal.toAST(); }, PrimaryExpression_path(path): Expression { return { statementType: "Expression", subExpression: path.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, PrimaryExpression_parens(_1, term, _3): Expression { return term.toAST(); }, StructExpression(expression): Expression { return expression.toAST(); }, MemberExpression(expression): Expression { return expression.toAST(); }, MemberExpression_structGetter(expression, _2, identifier): Expression { return { statementType: "Expression", subExpression: { expressionType: "StructGetter", source: expression.toAST(), attribute: identifier.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, CallExpression(expression): Expression { return expression.toAST(); }, CallExpression_structGetter(expression, _2, identifier): Expression { return { statementType: "Expression", subExpression: { expressionType: "StructGetter", source: expression.toAST(), attribute: identifier.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, CallExpression_functionCall(expression, _2, args, _4): Expression { const resolvedArgs = args.asIteration().children.map((c) => c.toAST()); return { statementType: "Expression", subExpression: { expressionType: "FunctionCall", source: expression.toAST(), arguments: resolvedArgs, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown(), }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, CallExpression_memberFunctionCall(expression, _2, args, _4): Expression { const resolvedArgs = args.asIteration().children.map((c) => c.toAST()); return { statementType: "Expression", subExpression: { expressionType: "FunctionCall", source: expression.toAST(), arguments: resolvedArgs, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown(), }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, StructGetter(expression, _2, identifier): Expression { return { statementType: "Expression", subExpression: { expressionType: "StructGetter", source: expression.toAST(), attribute: identifier.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, IfExpression(_1, _2, expression, _4, block, _6, elseBlock): Expression { const eb = elseBlock.toAST(); return { statementType: "Expression", subExpression: { expressionType: "IfExpression", condition: expression.toAST(), block: block.toAST(), else: eb.length > 0 ? eb[0] : null, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, Path_base(identifier): Path { return { expressionType: "Path", value: { type: "Identifier", name: identifier.toAST() }, }; }, Path_nested(basePath, _2, attrIdent): Path { return { expressionType: "Path", value: { type: "Nested", parent: basePath.toAST(), name: attrIdent.toAST() }, }; }, MultExpression(expression): Expression { return expression.toAST(); }, MultExpression_mult(factor, _2, term): Expression { return { statementType: "Expression", subExpression: { expressionType: "Operation", left: factor.toAST(), op: "*", right: term.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, MultExpression_div(factor, _2, term): Expression { return { statementType: "Expression", subExpression: { expressionType: "Operation", left: factor.toAST(), op: "/", right: term.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, AddExpression(expression): Expression { return expression.toAST(); }, AddExpression_plus(expression, _2, factor): Expression { return { statementType: "Expression", subExpression: { expressionType: "Operation", left: expression.toAST(), op: "+", right: factor.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, AddExpression_minus(expression, _2, factor): Expression { return { statementType: "Expression", subExpression: { expressionType: "Operation", left: expression.toAST(), op: "-", right: factor.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, Expression(expression): Expression { return expression.toAST(); }, Statement(statement): Statement { return statement.toAST(); }, ReturnStatement(_1, expression, _3): ReturnStatement { return { statementType: "ReturnStatement", source: expression.toAST(), }; }, LetStatement(_1, ident, _3, typeUsage, _5, expression, _7): LetStatement { const tu = typeUsage.toAST(); return { statementType: "LetStatement", variableName: ident.toAST(), expression: expression.toAST(), type: tu.length > 0 ? tu[0] : { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, AssignmentStatement_identifier(variable, _2, expression, _4): AssignmentStatement { return { statementType: "AssignmentStatement", source: { type: "Identifier", name: variable.toAST() }, expression: expression.toAST(), }; }, AssignmentStatement_getter(variable, _2, expression, _4): AssignmentStatement { return { statementType: "AssignmentStatement", source: { type: "StructGetter", source: variable.toAST() }, expression: expression.toAST(), }; }, ExpressionStatement(expression, _2): Expression { return { statementType: "Expression", subExpression: expression.toAST(), type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, Block(_1, statements, expression, _4): Block { const lines = statements.asIteration().children.map((c) => c.toAST()); const finalExpression = expression.toAST(); if (finalExpression.length > 0) { lines.push(finalExpression[0]); } const block: Block = { expressionType: "Block", statements: lines, type: newNever(), }; if (!containsReturn(block)) { block.type = { typeUsage: "UnknownTypeUsage", name: nextUnknown() }; } return block; }, NamedTypeUsage(name): NamedTypeUsage { return { typeUsage: "NamedTypeUsage", name: name.toAST(), }; }, TypeUsage_function_tu(_1, _2, args, _4, _5, returnType): FunctionTypeUsage { return { typeUsage: "FunctionTypeUsage", arguments: args.asIteration().children.map((c) => c.toAST()), returnType: returnType.toAST(), }; }, TypeUsage(typeUsage): TypeUsage { return typeUsage.toAST(); }, FunctionArgument(identifier, _2, typeUsage): FunctionArgument { return { name: identifier.toAST(), type: typeUsage.toAST(), }; }, FunctionDeclaration(_1, identifier, _3, args, _4, _5, returnType): FunctionDeclaration { return { name: identifier.toAST(), arguments: args.asIteration().children.map((c) => c.toAST()), returnType: returnType.toAST(), }; }, Function(declaration, block): Function { return { moduleItem: "Function", declaration: declaration.toAST(), block: block.toAST(), }; }, StructTypeField(identifier, _2, typeUsage): StructTypeField { return { name: identifier.toAST(), type: typeUsage.toAST(), }; }, StructTypeDeclaration(_1, identifier, _3, _4, fields, _6): StructTypeDeclaration { return { moduleItem: "StructTypeDeclaration", typeDeclaration: "StructTypeDeclaration", name: identifier.toAST(), fields: fields.asIteration().children.map((c) => c.toAST()), }; }, TraitMethod(declaration, _2): FunctionDeclaration { return declaration.toAST(); }, TraitTypeDeclaration(_1, identifier, _3, _4, methods, _5): TraitTypeDeclaration { return { moduleItem: "TraitTypeDeclaration", typeDeclaration: "TraitTypeDeclaration", name: identifier.toAST(), functions: methods.asIteration().children.map((c) => c.toAST()), }; }, TypeDeclaration(declaration): TypeDeclaration { return declaration.toAST(); }, Impl(_1, trait, _3, struct, _4, methods, _5): Impl { const tr = trait.toAST(); return { moduleItem: "Impl", struct: struct.toAST(), trait: tr.length > 0 ? tr[0] : null, functions: methods.asIteration().children.map((c) => c.toAST()), }; }, ModuleItem(item): ModuleItem { return item.toAST(); }, Module(items): Module { return { items: items.asIteration().children.map((c) => c.toAST()), }; }, _iter(...children) { return children.map((c) => c.toAST()); }, });