UNPKG

petcarescript

Version:

PetCareScript - A modern, expressive programming language designed for humans

199 lines (164 loc) 5.57 kB
/** * PetCareScript Runtime Classes * Runtime support classes for the interpreter */ class PCFunction { constructor(declaration, closure, isInitializer = false) { this.declaration = declaration; this.closure = closure; this.isInitializer = isInitializer; // Handle different function types if (declaration.name) { this.name = declaration.name.lexeme || declaration.name; } else { this.name = '<anonymous>'; } // Check if it's an arrow function this.isArrowFunction = declaration.constructor.name === 'ArrowFunctionNode'; } arity() { return this.declaration.params ? this.declaration.params.length : 0; } call(interpreter, args) { // Import Environment here to avoid circular dependencies const Environment = require('../interpreter/environment'); // Create new environment for function execution const environment = new Environment(this.closure); // Define parameters in the function environment const params = this.declaration.params || []; for (let i = 0; i < params.length; i++) { const paramName = params[i].lexeme || params[i].name?.lexeme || params[i]; const argValue = i < args.length ? args[i] : null; environment.define(paramName, argValue); } try { // Execute function body with parameter environment const body = this.declaration.body || []; // For arrow functions with expression body, the body is already wrapped in return interpreter.executeBlock(body, environment); } catch (returnValue) { if (returnValue instanceof ReturnException) { if (this.isInitializer) { return this.closure.getAt(0, 'self'); } return returnValue.value; } throw returnValue; } // If it's an initializer, return the instance if (this.isInitializer) { return this.closure.getAt(0, 'self'); } // Default return null return null; } bind(instance) { const Environment = require('../interpreter/environment'); const environment = new Environment(this.closure); environment.define('self', instance); // If this is a method in a blueprint with inheritance, also define parent if (instance && instance.blueprint && instance.blueprint.parentBlueprint !== null) { const parentProxy = new ParentProxy(instance.blueprint.parentBlueprint, instance); environment.define('parent', parentProxy); } return new PCFunction(this.declaration, environment, this.isInitializer); } toString() { if (this.isArrowFunction) { return `<arrow function ${this.name}>`; } return `<build ${this.name}>`; } } class PCBlueprint { constructor(name, parentBlueprint, methods) { this.name = name; this.parentBlueprint = parentBlueprint; this.methods = methods || new Map(); } arity() { const initializer = this.findMethod('init'); if (initializer === null) return 0; return initializer.arity(); } call(interpreter, args) { const instance = new PCInstance(this); const initializer = this.findMethod('init'); if (initializer !== null) { initializer.bind(instance).call(interpreter, args); } return instance; } findMethod(name) { if (this.methods.has(name)) { return this.methods.get(name); } if (this.parentBlueprint !== null) { return this.parentBlueprint.findMethod(name); } return null; } toString() { return this.name; } } class PCInstance { constructor(blueprint) { this.blueprint = blueprint; this.fields = new Map(); } get(name) { const propName = typeof name === 'string' ? name : (name.lexeme || name.name?.lexeme || name); if (this.fields.has(propName)) { return this.fields.get(propName); } const method = this.blueprint.findMethod(propName); if (method !== null) return method.bind(this); throw new Error(`Undefined property '${propName}'.`); } set(name, value) { const propName = typeof name === 'string' ? name : (name.lexeme || name.name?.lexeme || name); this.fields.set(propName, value); } toString() { return `${this.blueprint.name} instance`; } } // Parent proxy for blueprint inheritance class ParentProxy { constructor(blueprint, instance) { this.blueprint = blueprint; this.instance = instance; } findMethod(name) { return this.blueprint.findMethod(name); } } class ReturnException extends Error { constructor(value) { super(); this.value = value; this.name = 'ReturnException'; } } class BreakException extends Error { constructor() { super(); this.name = 'BreakException'; } } class ContinueException extends Error { constructor() { super(); this.name = 'ContinueException'; } } module.exports = { PCFunction, PCBlueprint, PCInstance, ParentProxy, ReturnException, BreakException, ContinueException };