#!/usr/bin/env bun import { Compiler } from '../src/compiler/compiler' import { colors, globals } from '../src/prelude' import { VM, fromValue, bytecodeToString } from 'reefvm' import { readFileSync, writeFileSync, mkdirSync } from 'fs' import { randomUUID } from "crypto" import { spawn } from 'child_process' import { join } from 'path' async function runFile(filePath: string) { try { const code = readFileSync(filePath, 'utf-8') const compiler = new Compiler(code, Object.keys(globals)) const vm = new VM(compiler.bytecode, globals) await vm.run() return vm.stack.length ? fromValue(vm.stack[vm.stack.length - 1]) : null } catch (error: any) { console.error(`${colors.red}Error:${colors.reset} ${error.message}`) process.exit(1) } } async function compileFile(filePath: string) { try { const code = readFileSync(filePath, 'utf-8') const compiler = new Compiler(code) return bytecodeToString(compiler.bytecode) } catch (error: any) { console.error(`${colors.red}Error:${colors.reset} ${error.message}`) process.exit(1) } } function showHelp() { console.log(`${colors.bright}${colors.magenta}🦐 Shrimp${colors.reset} is a scripting language in a shell. ${colors.bright}Usage:${colors.reset} shrimp [...args] ${colors.bright}Commands:${colors.reset} ${colors.cyan}run ${colors.yellow}./my-file.sh${colors.reset} Execute a file with Shrimp ${colors.cyan}bytecode ${colors.yellow}./my-file.sh${colors.reset} Print bytecode for Shrimp file ${colors.cyan}eval ${colors.yellow}'some code'${colors.reset} Evaluate a line of Shrimp code ${colors.cyan}repl${colors.reset} Start REPL ${colors.cyan}help${colors.reset} Print this help message ${colors.cyan}version${colors.reset} Print version`) } function showVersion() { console.log('🦐 v0.0.1') } async function main() { const args = process.argv.slice(2) if (args.length === 0) { showHelp() return } const command = args[0] if (['help', '-help', '--help', '-h'].includes(command)) { showHelp() return } if (['version', '-version', '--version', '-v'].includes(command)) { showVersion() return } if (['repl', '-repl', '--repl'].includes(command)) { const replPath = join(import.meta.dir, 'repl') const replArgs = args.slice(1) const repl = spawn('bun', [replPath, ...replArgs], { stdio: 'inherit' }) repl.on('exit', code => process.exit(code || 0)) return } if (['eval', '-eval', '--eval', '-e'].includes(command)) { const code = args[1] if (!code) { console.log(`${colors.bright}usage: shrimp eval ${colors.reset}`) process.exit(1) } try { mkdirSync('/tmp/shrimp') } catch { } const path = `/tmp/shrimp/${randomUUID()}.sh` writeFileSync(path, code) console.log(await runFile(path)) return } if (['bytecode', '-bytecode', '--bytecode', '-b'].includes(command)) { const file = args[1] if (!file) { console.log(`${colors.bright}usage: shrimp bytecode ${colors.reset}`) process.exit(1) } console.log(await compileFile(file)) return } if (['run', '-run', '--run', '-r'].includes(command)) { const file = args[1] if (!file) { console.log(`${colors.bright}usage: shrimp run ${colors.reset}`) process.exit(1) } await runFile(file) return } await runFile(command) } await main()