import { ConditionDeclaration, MainAgent, Monitor, ProcedureDeclaration, ProcedureParameter, Struct, VariableDeclarator } from "@pseuco/lang"; export type ClassDeclarator = Monitor | Struct; export class TypeEnvironment { protected constructor(readonly parentEnvironment: TypeEnvironment | null) {} // Get declarations /** * Get the declaring AST nodes for variable identifiers. Does *not* work with condition variables. * @param id A variable identifier. * @returns The AST node that defines the variable or undefined if the identifier is unknown. */ getDeclarationForVariableIdentifier(id: string): VariableDeclarator | ProcedureParameter | undefined { return this.parentEnvironment?.getDeclarationForVariableIdentifier(id); } /** * Get the declaring AST nodes for condition variable identifiers. * @param id A variable identifier. * @returns The AST node that defines the variable or undefined if the identifier is unknown. */ getDeclarationForConditionIdentifier(id: string): ConditionDeclaration | undefined { return this.parentEnvironment?.getDeclarationForConditionIdentifier(id); } /** * Get the AST node of a procedure declaration for procedure with the provided name. * @param id A procedure name. * @returns The procedure declaration AST node that defines the procedure or undefined if the identifier is unknown. */ getDeclarationForProcedureIdentifier(id: string): ProcedureDeclaration | undefined { return this.parentEnvironment?.getDeclarationForProcedureIdentifier(id); } getDeclarationForClassIdentifier(id: string): ClassDeclarator | undefined { return this.parentEnvironment?.getDeclarationForClassIdentifier(id); } getDeclarationForMainAgent(): MainAgent | undefined { return this.parentEnvironment?.getDeclarationForMainAgent(); } addVariable(id: string, declaration: VariableDeclarator | ProcedureParameter): TypeEnvironment { return this._addVariable(id, declaration, this); } getAllClassDeclarators(): ClassDeclarator[] { return this.parentEnvironment?.getAllClassDeclarators() ?? []; } get enclosingClassDeclarator(): Monitor | Struct | undefined { return this.parentEnvironment?.enclosingClassDeclarator; } // Add declarations addCondition(id: string, declaration: ConditionDeclaration): TypeEnvironment { return this._addCondition(id, declaration, this); } addProcedure(id: string, declaration: ProcedureDeclaration): TypeEnvironment { return this._addProcedure(id, declaration, this); } addClass(id: string, declaration: ClassDeclarator): TypeEnvironment { return this._addClass(id, declaration, this); } setMainAgent(declaration: MainAgent): TypeEnvironment { return this._setMainAgent(declaration, this); } protected _addVariable(id: string, declaration: VariableDeclarator | ProcedureParameter, calledOn: TypeEnvironment): TypeEnvironment { const res = this.parentEnvironment?._addVariable(id, declaration, calledOn); if (res == undefined) { throw Error("Internal Error: Cannot add variable to this environment!"); } else { return res; } } protected _addCondition(id: string, declaration: ConditionDeclaration, calledOn: TypeEnvironment): TypeEnvironment { const res = this.parentEnvironment?._addCondition(id, declaration, calledOn); if (res == undefined) { throw Error("Internal Error: Cannot add condition to this environment!"); } else { return res; } } protected _addProcedure(id: string, declaration: ProcedureDeclaration, calledOn: TypeEnvironment): TypeEnvironment { const res = this.parentEnvironment?._addProcedure(id, declaration, calledOn); if (res == undefined) { throw Error("Internal Error: Cannot add procedure to this environment!"); } else { return res; } } protected _addClass(id: string, declaration: ClassDeclarator, calledOn: TypeEnvironment): TypeEnvironment { const res = this.parentEnvironment?._addClass(id, declaration, calledOn); if (res == undefined) { throw Error("Internal Error: Cannot add class to this environment!"); } else { return res; } } protected _setMainAgent(declaration: MainAgent, calledOn: TypeEnvironment): TypeEnvironment { const res = this.parentEnvironment?._setMainAgent(declaration, calledOn); if (res == undefined) { throw Error("Internal Error: Cannot add mainAgent to this environment!"); } else { return res; } } }