UNPKG

@composita/compiler

Version:

Composita language compiler.

160 lines 9.07 kB
import { getOrThrow } from '@composita/ts-utility-types'; import { Visitor, BasicDesignatorNode, BasicExpressionDesignatorNode, } from '../ast/ast'; import { BlockScopeSymbol, CollectionVariableSymbol, VariableSymbol, SearchOptions, } from '../symbols/symbols'; import { FixExpressionNodeVisitor } from './fix-expression-node'; import { CheckerHelper } from './static-helpers'; export class FixStatementNodeVisitor extends Visitor { constructor(symbolTable, scope) { super(); this.symbolTable = symbolTable; this.scope = scope; } findCollectionVariable(node) { if (node instanceof BasicExpressionDesignatorNode || node instanceof BasicDesignatorNode) { const name = node.getName().getName(); const symbol = this.symbolTable.findCollectionVariable(name, true, [], new SearchOptions(this.scope, false, false)); if (symbol.length > 1) { throw new Error(`Found ${name} multiple times.`); } if (symbol.length < 1) { throw new Error(`Failed to find ${name}.`); } return symbol[0]; } // TODO throw new Error('Not implemented yet.'); } visitProgram(node) { node.getComponents().forEach((component) => component.accept(this)); } visitComponent(node) { const component = CheckerHelper.getComponent(this.symbolTable, node.getName().getName(), new SearchOptions(this.scope, true, true)); node.getBody()?.accept(new FixStatementNodeVisitor(this.symbolTable, component)); } visitComponentBody(node) { node.getDeclarations().forEach((declaration) => declaration.accept(this)); node.getImplementations().forEach((implementation) => implementation.accept(this)); node.getBeginBlock()?.accept(new FixStatementNodeVisitor(this.symbolTable, this.scope)); node.getActivityBlock()?.accept(new FixStatementNodeVisitor(this.symbolTable, this.scope)); node.getFinallyBlock()?.accept(new FixStatementNodeVisitor(this.symbolTable, this.scope)); } visitImplementation(node) { const implementation = CheckerHelper.getImplementation(this.symbolTable, node.getName().getName(), new SearchOptions(this.scope, true, false)); node.getDeclarations().forEach((declaration) => declaration.accept(new FixStatementNodeVisitor(this.symbolTable, implementation))); node.getStatements()?.accept(new FixStatementNodeVisitor(this.symbolTable, implementation)); } visitProcedure(node) { const procedure = CheckerHelper.getProcedureFromNode(node, this.symbolTable, new SearchOptions(this.scope, true, false)); node.getDeclarations().forEach((declaration) => declaration.accept(new FixStatementNodeVisitor(this.symbolTable, procedure))); node.getStatements()?.accept(new FixStatementNodeVisitor(this.symbolTable, procedure)); } visitStatementSequence(node) { node.getStatements().forEach((statement) => statement.accept(new FixStatementNodeVisitor(this.symbolTable, new BlockScopeSymbol(this.scope)))); } visitProcedureCall(node) { const params = node.getParams().map((param) => { param.accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); return getOrThrow(this.symbolTable.expressionToSymbol.get(param)); }); const procedure = CheckerHelper.getProcedure(node.getName().getName(), this.symbolTable, params, undefined, new SearchOptions(this.scope, true, false)); this.symbolTable.callToSymbol.set(node, procedure); } visitAssignment(node) { node.getDesignator().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); const symbol = getOrThrow(this.symbolTable.designatorToSymbol.get(node.getDesignator())); if (!(symbol instanceof VariableSymbol && symbol.mutable) && !(symbol instanceof CollectionVariableSymbol)) { throw new Error('Cannot asign to to a constant variable.'); } node.getExpression().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); } visitNew(node) { // TODO check if valid node.getDesignator().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); node.getArgs().forEach((argument) => argument.accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope))); } visitConnect(node) { // TODO check if connection is even possible node.getTo().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); node.getWhat().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); } visitDisconnect(node) { // TODO validity check node.getWhat().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); } visitSend(node) { this.symbolTable.sendReceiveToSymbol.set(node, CheckerHelper.getMessage(this.symbolTable, this.scope, node.getFrom(), node.getTarget().getName(), false, node.getArgs())); } visitReceive(node) { this.symbolTable.sendReceiveToSymbol.set(node, CheckerHelper.getMessage(this.symbolTable, this.scope, node.getFrom(), node.getReceiver().getName(), false, node.getTargets())); } visitDelete(node) { node.getTarget().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); } visitMove(node) { node.getFrom().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); node.getTo().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); } visitAwait(node) { node.getExpression().accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); } visitReturn(node) { node.getExpression()?.accept(new FixExpressionNodeVisitor(this.symbolTable, this.scope)); } visitIf(node) { const newScope = new BlockScopeSymbol(this.scope); node.getExpression().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); node.getThen().accept(new FixStatementNodeVisitor(this.symbolTable, newScope)); node.getElseIfs().forEach((elseif) => elseif.accept(new FixStatementNodeVisitor(this.symbolTable, newScope))); node.getElse()?.accept(new FixStatementNodeVisitor(this.symbolTable, newScope)); } visitElseIf(node) { const newScope = new BlockScopeSymbol(this.scope); node.getExpression().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); node.getThen().accept(new FixStatementNodeVisitor(this.symbolTable, newScope)); } visitWhile(node) { const newScope = new BlockScopeSymbol(this.scope); node.getExpresssion().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); node.getBody().accept(new FixStatementNodeVisitor(this.symbolTable, newScope)); } visitRepeat(node) { const newScope = new BlockScopeSymbol(this.scope); node.getExpresssion().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); node.getBody().accept(new FixStatementNodeVisitor(this.symbolTable, newScope)); } visitFor(node) { const newScope = new BlockScopeSymbol(this.scope); node.getExpression().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); const designator = node.getDesignator(); if (!(designator instanceof BasicDesignatorNode)) { throw new Error('Only basic designators currently supported.'); } node.getDesignator().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); node.getTo().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); node.getBy()?.accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); node.getStatements().accept(new FixStatementNodeVisitor(this.symbolTable, newScope)); } visitForeach(node) { const newScope = new BlockScopeSymbol(this.scope); node.getOf().accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); const variable = this.findCollectionVariable(node.getOf()); if (variable.parameters.length < node.getDesignators().length) { throw new Error('Foreach designator match error.'); } node.getDesignators().forEach((designator) => { if (!(designator instanceof BasicDesignatorNode)) { throw new Error('Only basic designators supported.'); } // the following woud register a new variable, but the language does not allow for that. //this.symbolTable.registerVariable( // new VariableSymbol(this.scope, designator.getName().getName(), true, variable.parameters[index]), //); designator.accept(new FixExpressionNodeVisitor(this.symbolTable, newScope)); }); node.getBody().accept(new FixStatementNodeVisitor(this.symbolTable, newScope)); } visitStatementBlock(node) { node.getStatements().accept(this); } } //# sourceMappingURL=fix-statement-node.js.map