Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions src/conductor/stdlib/list/list.prelude.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
export const listPrelude = `
def equal(xs, ys):
"""
Pure Function: Returns true if both have the same structure (pairs)
and identical values at corresponding leaf positions.
"""
if is_pair(xs):
return is_pair(ys) and \
equal(head(xs), head(ys)) and \
equal(tail(xs), tail(ys))
elif is_null(xs):
return is_null(ys)
elif is_number(xs):
return is_number(ys) and xs == ys
elif is_boolean(xs):
return is_boolean(ys) and xs == ys
elif is_string(xs):
return is_string(ys) and xs == ys
elif is_undefined(xs): # Catches None in Python
return is_undefined(ys)
elif is_function(xs):
return is_function(ys) and xs == ys
else:
return xs == ys

def _length(xs, acc):
"""
Helper for length, designed for Tail Recursion.
"""
return acc if is_null(xs) else _length(tail(xs), acc + 1)

def length(xs):
"""
Returns the length of the list xs.
"""
return _length(xs, 0)

def _map(f, xs, acc):
return reverse(acc) if is_null(xs) else _map(f, tail(xs), pair(f(head(xs)), acc))

def map(f, xs):
"""
Returns a list that results from list xs by element-wise application of unary function f.
"""
return _map(f, xs, None)

def _build_list(i, fun, already_built):
return already_built if i < 0 else _build_list(i - 1, fun, pair(fun(i), already_built))

def build_list(fun, n):
"""
Makes a list with n elements by applying the unary function fun
to the numbers 0 to n - 1.
"""
return _build_list(n - 1, fun, None)

def for_each(fun, xs):
"""
Applies the unary function fun to every element of the list xs.
"""
if is_null(xs):
return True
else:
fun(head(xs)) # Side effect happens here if fun is not pure
return for_each(fun, tail(xs))

def list_to_string(xs):
"""
Returns a string that represents list xs using the text-based box-and-pointer notation.
"""
return _list_to_string(xs, lambda x: x)

def _list_to_string(xs, cont):
if is_null(xs):
return cont('null')
elif is_pair(xs):
return _list_to_string(head(xs), lambda x_str:
_list_to_string(tail(xs), lambda y_str:
cont(f'[{x_str},{y_str}]')
))
else:
return cont(stringify(xs))

def list_to_string(xs):
"""
Returns a string that represents list xs using the text-based box-and-pointer notation.
"""
return _list_to_string(xs, lambda x: x)

def _reverse(original, reversed_acc):
return reversed_acc if is_null(original) else _reverse_iter(tail(original), pair(head(original), reversed_acc))

def reverse(xs):
"""
Returns list xs in reverse order.
"""
return _reverse_iter(xs, None)

def _append(xs, ys, cont):
return cont(ys) if is_null(xs) else _append(tail(xs), ys, lambda zs: cont(pair(head(xs), zs)))

def append(xs, ys):
"""
Returns a list that results from appending the list ys to the list xs.
"""
return _append(xs, ys, lambda x: x)

def member(v, xs):
"""
Returns first postfix sublist whose head is identical to v (using ===).
Returns null if the element does not occur in the list.
"""
if is_null(xs):
return None
elif v == head(xs):
return xs
else:
return member(v, tail(xs))

def _remove(v, xs, acc):
if is_null(xs):
return append(reverse(acc), xs)
elif v == head(xs):
return append(reverse(acc), tail(xs))
else:
return _remove(v, tail(xs), pair(head(xs), acc))

def remove(v, xs):
"""
Returns a list that results from xs by removing the first item from xs that is identical (===) to v.
"""
return _remove(v, xs, None)

def _remove_all(v, xs, acc):
if is_null(xs):
return append(reverse(acc), xs)
elif v == head(xs):
return _remove_all(v, tail(xs), acc)
else:
return _remove_all(v, tail(xs), pair(head(xs), acc))

def remove_all(v, xs):
"""
Returns a list that results from xs by removing all items from xs that are identical (===) to v.
"""
return _remove_all(v, xs, None)

def _enum_list(start, end, acc):
return reverse(acc) if start > end else _enum_list(start + 1, end, pair(start, acc))

def enum_list(start, end):
"""
Makes a list with elements from start to end (inclusive).
"""
return _enum_list(start, end, None)

def list_ref(xs, n):
"""
Returns the element of list xs at position n (0-indexed).
"""
if n == 0:
if is_null(xs): raise IndexError("list_ref: index out of bounds on null list")
return head(xs)
else:
if is_null(xs): raise IndexError("list_ref: index out of bounds")
return list_ref(tail(xs), n - 1)

def _accumulate(f, initial, xs, cont):
if is_null(xs):
return cont(initial)
else:
# Recursive CPS call: Process tail, then apply f with head, then pass to continuation
return _accumulate(f, initial, tail(xs), lambda x_accumulated_from_tail:
cont(f(head(xs), x_accumulated_from_tail)))

def accumulate(f, initial, xs):
"""
Applies binary function f to the elements of xs from right-to-left order.
"""
return _accumulate(f, initial, xs, lambda x: x)

def _filter(pred, xs, acc):
if is_null(xs):
return reverse(acc)
else:
if pred(head(xs)):
return _filter(pred, tail(xs), pair(head(xs), acc))
else:
return _filter(pred, tail(xs), acc)

def filter(pred, xs):
"""
Returns a list that contains only those elements for which the one-argument
function pred returns true.
"""
return _filter(pred, xs, None)
`;
125 changes: 125 additions & 0 deletions src/createContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Context } from './cse-machine/context';
import { importBuiltins } from './stdlib/index';
import { importPrelude } from './stdlib/preludes';
import { Chapter } from './stdlib/index';

// Re-export Chapter type for external use
export { Chapter };

// External builtins that might be loaded from external sources
const externalBuiltIns: Record<string, any> = {
// Add external builtins here when needed
};

// External symbols that might be loaded from modules
const externalSymbols: Record<string, any> = {
// Add external symbols here when needed
};

/**
* Creates a context for a specific chapter and variant
* @param chapter The chapter number (1-4) or 'LIBRARY_PARSER'
* @param variant The variant (not used in current implementation)
* @returns A new Context with all necessary builtins and preludes loaded
*/
export function createContext(chapter: Chapter, variant: string = 'default'): Context {
const context = new Context();

// Import builtins for the specific chapter
importBuiltins(context, chapter);

// Import external builtins
importExternalBuiltIns(context, externalBuiltIns);

// Import preludes and load them into the environment
const preludeCode = importPrelude(context, typeof chapter === 'number' ? chapter : 4);
if (preludeCode) {
context.prelude = preludeCode;
// Load the prelude code into the environment
loadPreludeIntoEnvironment(context, preludeCode);
}

// Import external symbols
importExternalSymbols(context, externalSymbols);

return context;
}

/**
* Imports external builtins into the context
*/
function importExternalBuiltIns(context: Context, externalBuiltIns: Record<string, any>) {
for (const [name, func] of Object.entries(externalBuiltIns)) {
context.nativeStorage.builtins.set(name, func);
}
}

/**
* Imports external symbols into the context
*/
function importExternalSymbols(context: Context, externalSymbols: Record<string, any>) {
for (const [name, value] of Object.entries(externalSymbols)) {
context.nativeStorage.builtins.set(name, value);
}
}

/**
* Creates an empty context without any builtins or preludes
* Useful for testing or when you want to load everything manually
*/
export function createEmptyContext(chapter: Chapter, variant: string = 'default'): Context {
return new Context();
}

/**
* Loads modules from a server (similar to js-slang's module loading)
* @param context The context to load modules into
* @param serverUrl The URL of the module server
*/
export async function loadModulesFromServer(context: Context, serverUrl: string) {
try {
// This would implement the actual module loading logic
// For now, it's a placeholder
console.log(`Loading modules from ${serverUrl}`);
} catch (error) {
console.error('Failed to load modules from server:', error);
}
}

/**
* Loads a specific module by name
* @param context The context to load the module into
* @param moduleName The name of the module to load
*/
export async function loadModule(context: Context, moduleName: string) {
try {
// This would implement the actual module loading logic
// For now, it's a placeholder
console.log(`Loading module: ${moduleName}`);
} catch (error) {
console.error(`Failed to load module ${moduleName}:`, error);
}
}

/**
* Loads prelude code into the environment by parsing and evaluating it
* @param context The context to load the prelude into
* @param preludeCode The prelude code to load
*/
function loadPreludeIntoEnvironment(context: Context, preludeCode: string) {
try {
// Import the necessary modules for parsing and evaluation
const { parsePythonToEstreeAst } = require('./index');
const { runCSEMachine } = require('./runner/pyRunner');

// Parse the prelude code
const preludeAst = parsePythonToEstreeAst(preludeCode, 1, true);

// Run the prelude code in the context
const result = runCSEMachine(preludeCode, preludeAst, context, { isPrelude: true });

console.log('Prelude loaded successfully');
} catch (error) {
console.error('Failed to load prelude into environment:', error);
}
}
1 change: 1 addition & 0 deletions src/cse-machine/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class Context {
public stash: Stash;
//public environment: Environment;
public errors: CseError[] = [];
public prelude: string | null = null;

runtime: {
break: boolean
Expand Down
Loading
Loading