shrimp/bin/shrimp

119 lines
3.4 KiB
Plaintext
Executable File

#!/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 <command> [...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 <code>${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 <file>${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 <file>${colors.reset}`)
process.exit(1)
}
await runFile(file)
return
}
await runFile(command)
}
await main()