@composita/compiler
Version:
Composita language compiler.
160 lines • 9.07 kB
JavaScript
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