528 lines
15 KiB
TypeScript
528 lines
15 KiB
TypeScript
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<any>("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());
|
|
},
|
|
});
|