From af7f389a0406ae24e2640cdc8e6f6d35e4e5e918 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sun, 26 Oct 2025 13:13:53 -0700 Subject: [PATCH] use module --- src/prelude/index.ts | 38 ++++++++++++++++++++++++++++------- src/prelude/tests/use.test.ts | 28 ++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 src/prelude/tests/use.test.ts diff --git a/src/prelude/index.ts b/src/prelude/index.ts index fb80502..1423ef6 100644 --- a/src/prelude/index.ts +++ b/src/prelude/index.ts @@ -1,7 +1,12 @@ // The prelude creates all the builtin Shrimp functions. +import { resolve, parse } from 'path' import { readFileSync } from 'fs' -import { VM, isValue, toValue, type Value, extractParamInfo, isWrapped, getOriginalFunction } from 'reefvm' +import { Compiler } from '#compiler/compiler' +import { + VM, Scope, toValue, type Value, + extractParamInfo, isWrapped, getOriginalFunction, +} from 'reefvm' export const colors = { reset: '\x1b[0m', @@ -16,7 +21,7 @@ export const colors = { pink: '\x1b[38;2;255;105;180m' } -export const nativeFunctions = { +export const globalFunctions = { // hello echo: (...args: any[]) => { console.log(...args.map(a => { @@ -73,14 +78,33 @@ export const nativeFunctions = { }, // modules - use: function (this: VM, path: string) { - const file = readFileSync(path + '.sh') + use: async function (this: VM, path: string) { + const scope = this.scope + const pc = this.pc + + const fullPath = resolve(path) + '.sh' + const code = readFileSync(fullPath, 'utf-8') + + this.pc = this.instructions.length + this.scope = new Scope(scope) + const compiled = new Compiler(code) + this.appendBytecode(compiled.bytecode) + + await this.continue() + + const module: Map = new Map + for (const [name, value] of this.scope.locals.entries()) + module.set(name, value) + + this.scope = scope + this.pc = pc + this.stopped = false + + this.scope.set(parse(fullPath).name, { type: 'dict', value: module }) } } -export function formatValue(value: Value | any, inner = false): string { - if (!isValue(value)) value = toValue(value) - +export function formatValue(value: Value, inner = false): string { switch (value.type) { case 'string': return `${colors.green}'${value.value.replaceAll("'", "\\'")}${colors.green}'${colors.reset}` diff --git a/src/prelude/tests/use.test.ts b/src/prelude/tests/use.test.ts new file mode 100644 index 0000000..971e1b5 --- /dev/null +++ b/src/prelude/tests/use.test.ts @@ -0,0 +1,28 @@ +import { expect, describe, test } from 'bun:test' +import { globalFunctions } from '#prelude' + +describe('use', () => { + test(`imports all a file's functions`, async () => { + expect(` + use ./src/prelude/tests/math + dbl = math | at double + dbl 4 + `).toEvaluateTo(8, globalFunctions) + + expect(` + use ./src/prelude/tests/math + math | at pi + `).toEvaluateTo(3.14, globalFunctions) + + expect(` + use ./src/prelude/tests/math + math | at 🥧 + `).toEvaluateTo(3.14159265359, globalFunctions) + + expect(` + use ./src/prelude/tests/math + call = do x y: x y end + call (math | at add1) 5 + `).toEvaluateTo(6, globalFunctions) + }) +}) \ No newline at end of file