@prism-lang/core
Version:
A programming language for uncertainty
293 lines • 8.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultContextManager = exports.ContextAwareBase = exports.ContextManager = exports.ContextValidator = exports.ContextTransition = exports.ContextStack = exports.ContextScope = exports.Context = exports.ContextError = void 0;
exports.createContext = createContext;
exports.withContext = withContext;
class ContextError extends Error {
code;
constructor(message, code) {
super(message);
this.code = code;
this.name = 'ContextError';
}
}
exports.ContextError = ContextError;
class Context {
name;
properties;
parent;
scopes = [];
constructor(name, properties = {}, parent) {
this.name = name;
this.properties = properties;
this.parent = parent;
}
// Property inheritance from parent contexts
getInheritedProperty(key) {
if (key in this.properties) {
return this.properties[key];
}
if (this.parent) {
return this.parent.getInheritedProperty(key);
}
return undefined;
}
// Context compatibility checking
isCompatibleWith(other) {
// Basic compatibility: same domain or related contexts
const thisDomain = this.getInheritedProperty('domain');
const otherDomain = other.getInheritedProperty('domain');
if (thisDomain && otherDomain) {
return thisDomain === otherDomain;
}
// If no domain specified, contexts are compatible
return true;
}
// Create a new scope within this context
createScope(variables = {}) {
const scope = new ContextScope(this, variables);
this.scopes.push(scope);
return scope;
}
// Get all scopes in this context
getScopes() {
return [...this.scopes];
}
// Remove a scope
removeScope(scope) {
const index = this.scopes.indexOf(scope);
if (index >= 0) {
this.scopes.splice(index, 1);
return true;
}
return false;
}
toString() {
const parentPath = this.parent ? `${this.parent.toString()}.` : '';
return `${parentPath}${this.name}`;
}
}
exports.Context = Context;
class ContextScope {
context;
variables;
constructor(context, variables = {}) {
this.context = context;
this.variables = variables;
}
getVariable(name) {
return this.variables[name];
}
setVariable(name, value) {
this.variables[name] = value;
}
hasVariable(name) {
return name in this.variables;
}
getAllVariables() {
return { ...this.variables };
}
}
exports.ContextScope = ContextScope;
class ContextStack {
stack = [];
push(context) {
this.stack.push(context);
}
pop() {
const context = this.stack.pop();
if (!context) {
throw new ContextError('Cannot pop from empty context stack', 'STACK_UNDERFLOW');
}
return context;
}
current() {
return this.stack[this.stack.length - 1];
}
depth() {
return this.stack.length;
}
isEmpty() {
return this.stack.length === 0;
}
findContext(name) {
return this.stack.find(ctx => ctx.name === name);
}
getContextPath() {
return this.stack.map(ctx => ctx.name);
}
clear() {
this.stack.length = 0;
}
}
exports.ContextStack = ContextStack;
class ContextTransition {
from;
to;
options;
constructor(from, to, options = {}) {
this.from = from;
this.to = to;
this.options = options;
}
isValid() {
// Basic validation: check context compatibility
return this.from.isCompatibleWith(this.to);
}
execute() {
if (!this.isValid()) {
return {
success: false,
error: `Invalid transition from ${this.from.name} to ${this.to.name}`,
};
}
const result = {
success: true,
newContext: this.to,
};
// Preserve state if requested
if (this.options.preserveState) {
const scopes = this.from.getScopes();
if (scopes.length > 0) {
const preservedState = {};
scopes.forEach(scope => {
Object.assign(preservedState, scope.getAllVariables());
});
result.preservedState = preservedState;
}
}
return result;
}
}
exports.ContextTransition = ContextTransition;
class ContextValidator {
rules;
constructor(rules = []) {
this.rules = rules;
}
addRule(rule) {
this.rules.push(rule);
}
validateTransition(from, to) {
for (const rule of this.rules) {
if (!rule(from, to)) {
throw new ContextError(`Context transition validation failed: ${from?.name} -> ${to?.name}`, 'VALIDATION_FAILED');
}
}
}
removeRule(rule) {
const index = this.rules.indexOf(rule);
if (index >= 0) {
this.rules.splice(index, 1);
return true;
}
return false;
}
}
exports.ContextValidator = ContextValidator;
class ContextManager {
contexts = new Map();
stack = new ContextStack();
validator;
registerContext(context) {
this.contexts.set(context.name, context);
}
getContext(name) {
return this.contexts.get(name);
}
getAllContexts() {
return Array.from(this.contexts.values());
}
getCurrentContext() {
return this.stack.current();
}
enterContext(name) {
const context = this.getContext(name);
if (!context) {
throw new ContextError(`Context '${name}' not found`, 'CONTEXT_NOT_FOUND');
}
const current = this.getCurrentContext();
if (this.validator) {
this.validator.validateTransition(current, context);
}
this.stack.push(context);
}
exitContext() {
if (this.stack.isEmpty()) {
return undefined;
}
return this.stack.pop();
}
switchContext(name) {
const context = this.getContext(name);
if (!context) {
throw new ContextError(`Context '${name}' not found`, 'CONTEXT_NOT_FOUND');
}
const current = this.getCurrentContext();
if (this.validator) {
this.validator.validateTransition(current, context);
}
if (!this.stack.isEmpty()) {
this.stack.pop();
}
this.stack.push(context);
}
executeInContext(contextName, operation) {
const context = this.getContext(contextName);
if (!context) {
throw new ContextError(`Context '${contextName}' not found`, 'CONTEXT_NOT_FOUND');
}
const wasInContext = !this.stack.isEmpty();
this.enterContext(contextName);
try {
return operation();
}
finally {
this.exitContext();
if (!wasInContext && !this.stack.isEmpty()) {
this.stack.clear();
}
}
}
setValidator(validator) {
this.validator = validator;
}
getValidator() {
return this.validator;
}
getContextStack() {
return this.stack;
}
}
exports.ContextManager = ContextManager;
// Utility functions
function createContext(name, properties = {}) {
return new Context(name, properties);
}
function withContext(context, operation) {
return operation(context);
}
// Context-aware base class
class ContextAwareBase {
currentContext;
getCurrentContext() {
return this.currentContext;
}
setContext(context) {
this.currentContext = context;
}
inContext(context, operation) {
const previous = this.currentContext;
this.currentContext = context;
try {
return operation();
}
finally {
this.currentContext = previous;
}
}
}
exports.ContextAwareBase = ContextAwareBase;
// Default context manager instance
exports.defaultContextManager = new ContextManager();
//# sourceMappingURL=context.js.map