import { ConditionDeclaration, ProcedureDeclaration, ProcedureParameter, VariableDeclarator } from "@pseuco/lang"; import { PseucoError } from "../../PseucoError"; import { ClassDeclarator, TypeEnvironment } from "./TypeEnvironment"; // Environments for scopes, in which the order of declaration matters (e.g., local variables inside procedures). // Essentially, instances are ready to capture a new variable. // With every new variable, a new block environment object relaces the old one (and the new one is again ready to capture a new variable) export class BlockEnvironment extends TypeEnvironment { private identifier: string | null = null; private declaration: VariableDeclarator | ProcedureParameter | null = null; constructor(parentEnvironment: TypeEnvironment, id?: string, declarationNode?: VariableDeclarator | ProcedureParameter) { super(parentEnvironment); if ((id == undefined) != (declarationNode == undefined)) { throw new Error("Internal Error: BlockEnvironment: `id` must be undefined iff `declarationNode` is undefined"); } if (id != undefined) { this.identifier = id; this.declaration = declarationNode!; } } override getDeclarationForVariableIdentifier(id: string): VariableDeclarator | ProcedureParameter | undefined { if (id == this.identifier) { return this.declaration!; } else { return super.getDeclarationForVariableIdentifier(id); } } override _addVariable(id: string, declaration: VariableDeclarator | ProcedureParameter, calledOn: TypeEnvironment): TypeEnvironment { if (calledOn != this) { throw Error("Internal inconsistency: 'calledOn' should be 'this'."); } return new BlockEnvironment(this, id, declaration); } override _addCondition(id: string, declaration: ConditionDeclaration, calledOn: TypeEnvironment): TypeEnvironment { return (new PseucoError(declaration, "Type", "Conditions can only be declared on the top level of monitors.")).throw(); } override _addProcedure(id: string, declaration: ProcedureDeclaration, calledOn: TypeEnvironment): TypeEnvironment { return (new PseucoError(declaration, "Type", "Procedures can only be declared at the top level of a pseuCo program, or at the top level of monitors and structs. They cannot be defined in other procedures.")).throw(); } override _addClass(id: string, declaration: ClassDeclarator, calledOn: TypeEnvironment): TypeEnvironment { return (new PseucoError(declaration, "Type", "Structs and monitors can only be declared at the top level of a pseuCo program.")).throw(); } }