import { AssignmentStatement, Block, containsReturn, Expression, Function, FunctionArgument, FunctionCall, FunctionDeclaration, FunctionTypeUsage, GenericDeclaration, GenericParameter, GenericUsage, 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", { GenericUsage(_1, typeUsage, _3): GenericUsage { return { genericUsage: "Known", parameters: typeUsage.asIteration().children.map((c) => c.toAST()), }; }, GenericParameter_conditions(identifier, _2, typeUsage): GenericParameter { return { name: identifier.toAST(), bounds: typeUsage.asIteration().children.map((c) => c.toAST()), }; }, GenericParameter(identifier): GenericParameter { return { name: identifier.toAST(), bounds: [], }; }, GenericDeclaration(_1, parameters, _2): GenericDeclaration { return { parameters: parameters.asIteration().children.map((c) => c.toAST()), }; }, LiteralInt(a): Expression { return { statementType: "Expression", subExpression: { expressionType: "LiteralInt", value: this.sourceString, type: { typeUsage: "NamedTypeUsage", typeParameters: { genericUsage: "Known", parameters: [] }, 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", typeParameters: { genericUsage: "Known", parameters: [] }, 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", typeParameters: { genericUsage: "Known", parameters: [] }, 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", typeParameters: { genericUsage: "Known", parameters: [] }, 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, genericUsage, _2, fields, _4): Expression { const gu = genericUsage.toAST(); return { statementType: "Expression", subExpression: { expressionType: "LiteralStruct", name: identifier.toAST(), typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" }, fields: fields.asIteration().children.map((c) => c.toAST()), type: { typeUsage: "NamedTypeUsage", typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" }, 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, genericUsage): Expression { const gu = genericUsage.toAST(); return { statementType: "Expression", subExpression: { expressionType: "StructGetter", source: expression.toAST(), attribute: identifier.toAST(), typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }, type: { typeUsage: "UnknownTypeUsage", name: nextUnknown() }, }; }, CallExpression(expression): Expression { return expression.toAST(); }, CallExpression_structGetter(expression, _2, identifier, genericUsage): Expression { const gu = genericUsage.toAST(); return { statementType: "Expression", subExpression: { expressionType: "StructGetter", source: expression.toAST(), attribute: identifier.toAST(), typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" }, 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(), typeParameters: { genericUsage: "Unknown" }, 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, genericUsage): Path { const gu = genericUsage.toAST(); return { expressionType: "Path", typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" }, value: { type: "Identifier", name: identifier.toAST() }, }; }, Path_nested(basePath, _2, attrIdent, genericUsage): Path { const gu = genericUsage.toAST(); return { expressionType: "Path", typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" }, 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, genericUsage): NamedTypeUsage { const gu = genericUsage.toAST(); return { typeUsage: "NamedTypeUsage", typeParameters: gu.length ? gu[0] : { genericUsage: "Unknown" }, 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, genericDeclaration, _4, args, _5, _6, returnType, ): FunctionDeclaration { const gd = genericDeclaration.toAST(); return { name: identifier.toAST(), generic: gd.length ? gd[0] : { parameters: [] }, 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, genericDeclaration, _4, _5, fields, _7, ): StructTypeDeclaration { const gd = genericDeclaration.toAST(); return { moduleItem: "StructTypeDeclaration", typeDeclaration: "StructTypeDeclaration", name: identifier.toAST(), generic: gd.length ? gd[0] : { parameters: [] }, fields: fields.asIteration().children.map((c) => c.toAST()), }; }, TraitMethod(declaration, _2): FunctionDeclaration { return declaration.toAST(); }, TraitTypeDeclaration( _1, identifier, genericDeclaration, _4, _5, methods, _7, ): TraitTypeDeclaration { const gd = genericDeclaration.toAST(); return { moduleItem: "TraitTypeDeclaration", typeDeclaration: "TraitTypeDeclaration", name: identifier.toAST(), generic: gd.length ? gd[0] : { parameters: [] }, functions: methods.asIteration().children.map((c) => c.toAST()), }; }, TypeDeclaration(declaration): TypeDeclaration { return declaration.toAST(); }, Impl(_1, genericDeclaration, trait, _4, struct, _6, methods, _8): Impl { const tr = trait.toAST(); const gd = genericDeclaration.toAST(); return { moduleItem: "Impl", generic: gd.length ? gd[0] : { parameters: [] }, 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()); }, });