Compare commits
5 Commits
9bc514a782
...
c883854187
| Author | SHA1 | Date | |
|---|---|---|---|
| c883854187 | |||
| a8fd79a990 | |||
| 2abf3558d5 | |||
| cc8d64b3ec | |||
| 83fad9a68f |
26
bin/repl
26
bin/repl
|
|
@ -144,19 +144,33 @@ async function repl() {
|
|||
return
|
||||
}
|
||||
|
||||
codeHistory.push(trimmed)
|
||||
|
||||
try {
|
||||
const compiler = new Compiler(trimmed, Object.keys(globals))
|
||||
|
||||
vm.appendBytecode(compiler.bytecode)
|
||||
// Save VM state before appending bytecode, in case execution fails
|
||||
const savedInstructions = [...vm.instructions]
|
||||
const savedConstants = [...vm.constants]
|
||||
const savedPc = vm.pc
|
||||
const savedScope = vm.scope
|
||||
const savedStopped = vm.stopped
|
||||
|
||||
const result = await vm.continue()
|
||||
try {
|
||||
vm.appendBytecode(compiler.bytecode)
|
||||
const result = await vm.continue()
|
||||
|
||||
console.log(`${colors.dim}=>${colors.reset} ${formatValue(result)}`)
|
||||
codeHistory.push(trimmed)
|
||||
console.log(`${colors.dim}=>${colors.reset} ${formatValue(result)}`)
|
||||
} catch (error: any) {
|
||||
vm.instructions = savedInstructions
|
||||
vm.constants = savedConstants
|
||||
vm.pc = savedPc
|
||||
vm.scope = savedScope
|
||||
vm.stopped = savedStopped
|
||||
|
||||
console.log(`\n${colors.red}Error:${colors.reset} ${error.message}`)
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log(`\n${colors.red}Error:${colors.reset} ${error.message}`)
|
||||
codeHistory.pop()
|
||||
}
|
||||
|
||||
rl.prompt()
|
||||
|
|
|
|||
2
bun.lock
2
bun.lock
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
"hono": ["hono@4.9.8", "", {}, "sha512-JW8Bb4RFWD9iOKxg5PbUarBYGM99IcxFl2FPBo2gSJO11jjUDqlP1Bmfyqt8Z/dGhIQ63PMA9LdcLefXyIasyg=="],
|
||||
|
||||
"reefvm": ["reefvm@git+https://git.nose.space/defunkt/reefvm#030eb7487165b3ba502965a8b7fa09c4b5fdb0da", { "peerDependencies": { "typescript": "^5" } }, "030eb7487165b3ba502965a8b7fa09c4b5fdb0da"],
|
||||
"reefvm": ["reefvm@git+https://git.nose.space/defunkt/reefvm#c69b172c78853756ec8acba5bc33d93eb6a571c6", { "peerDependencies": { "typescript": "^5" } }, "c69b172c78853756ec8acba5bc33d93eb6a571c6"],
|
||||
|
||||
"style-mod": ["style-mod@4.1.2", "", {}, "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw=="],
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"dev": "bun generate-parser && bun --hot src/server/server.tsx",
|
||||
"generate-parser": "lezer-generator src/parser/shrimp.grammar --typeScript -o src/parser/shrimp.ts",
|
||||
"repl": "bun generate-parser && bun bin/repl",
|
||||
"update-reef": "cd packages/ReefVM && git pull origin main"
|
||||
"update-reef": "rm -rf ~/.bun/install/cache/ && bun update reefvm"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/view": "^6.38.3",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { type Value, toValue, toNull } from 'reefvm'
|
||||
|
||||
export const list = {
|
||||
slice: (list: any[], start: number, end?: number) => list.slice(start, end),
|
||||
map: async (list: any[], cb: Function) => {
|
||||
|
|
@ -40,9 +42,41 @@ export const list = {
|
|||
return true
|
||||
},
|
||||
|
||||
// mutating
|
||||
push: (list: Value, item: Value) => {
|
||||
if (list.type !== 'array') return toNull()
|
||||
return toValue(list.value.push(item))
|
||||
},
|
||||
pop: (list: Value) => {
|
||||
if (list.type !== 'array') return toNull()
|
||||
return toValue(list.value.pop())
|
||||
},
|
||||
shift: (list: Value) => {
|
||||
if (list.type !== 'array') return toNull()
|
||||
return toValue(list.value.shift())
|
||||
},
|
||||
unshift: (list: Value, item: Value) => {
|
||||
if (list.type !== 'array') return toNull()
|
||||
return toValue(list.value.unshift(item))
|
||||
},
|
||||
splice: (list: Value, start: Value, deleteCount: Value, ...items: Value[]) => {
|
||||
const realList = list.value as any[]
|
||||
const realStart = start.value as number
|
||||
const realDeleteCount = deleteCount.value as number
|
||||
const realItems = items.map(item => item.value)
|
||||
return toValue(realList.splice(realStart, realDeleteCount, ...realItems))
|
||||
},
|
||||
|
||||
// sequence operations
|
||||
reverse: (list: any[]) => list.slice().reverse(),
|
||||
sort: (list: any[], cb?: (a: any, b: any) => number) => list.slice().sort(cb),
|
||||
sort: async (list: any[], cb?: (a: any, b: any) => number) => {
|
||||
const arr = [...list]
|
||||
if (!cb) return arr.sort()
|
||||
for (let i = 0; i < arr.length; i++)
|
||||
for (let j = i + 1; j < arr.length; j++)
|
||||
if ((await cb(arr[i], arr[j])) > 0) [arr[i], arr[j]] = [arr[j], arr[i]]
|
||||
return arr
|
||||
},
|
||||
concat: (...lists: any[][]) => lists.flat(1),
|
||||
flatten: (list: any[], depth: number = 1) => list.flat(depth),
|
||||
unique: (list: any[]) => Array.from(new Set(list)),
|
||||
|
|
@ -87,3 +121,12 @@ export const list = {
|
|||
return groups
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
// raw functions deal directly in Value types, meaning we can modify collection
|
||||
// careful - they MUST return a Value!
|
||||
; (list.splice as any).raw = true
|
||||
; (list.push as any).raw = true
|
||||
; (list.pop as any).raw = true
|
||||
; (list.shift as any).raw = true
|
||||
; (list.unshift as any).raw = true
|
||||
|
|
@ -341,6 +341,84 @@ describe('collections', () => {
|
|||
await expect(`list.index-of [1 2 3] 5`).toEvaluateTo(-1, globals)
|
||||
})
|
||||
|
||||
test('list.push adds to end and mutates array', async () => {
|
||||
await expect(`arr = [1 2]; list.push arr 3; arr`).toEvaluateTo([1, 2, 3], globals)
|
||||
})
|
||||
|
||||
test('list.push returns the size of the array', async () => {
|
||||
await expect(`arr = [1 2]; arr | list.push 3`).toEvaluateTo(3, globals)
|
||||
})
|
||||
|
||||
test('list.pop removes from end and mutates array', async () => {
|
||||
await expect(`arr = [1 2 3]; list.pop arr; arr`).toEvaluateTo([1, 2], globals)
|
||||
})
|
||||
|
||||
test('list.pop returns removed element', async () => {
|
||||
await expect(`list.pop [1 2 3]`).toEvaluateTo(3, globals)
|
||||
})
|
||||
|
||||
test('list.pop returns null for empty array', async () => {
|
||||
await expect(`list.pop []`).toEvaluateTo(null, globals)
|
||||
})
|
||||
|
||||
test('list.shift removes from start and mutates array', async () => {
|
||||
await expect(`arr = [1 2 3]; list.shift arr; arr`).toEvaluateTo([2, 3], globals)
|
||||
})
|
||||
|
||||
test('list.shift returns removed element', async () => {
|
||||
await expect(`list.shift [1 2 3]`).toEvaluateTo(1, globals)
|
||||
})
|
||||
|
||||
test('list.shift returns null for empty array', async () => {
|
||||
await expect(`list.shift []`).toEvaluateTo(null, globals)
|
||||
})
|
||||
|
||||
test('list.unshift adds to start and mutates array', async () => {
|
||||
await expect(`arr = [2 3]; list.unshift arr 1; arr`).toEvaluateTo([1, 2, 3], globals)
|
||||
})
|
||||
|
||||
test('list.unshift returns the length of the array', async () => {
|
||||
await expect(`arr = [2 3]; arr | list.unshift 1`).toEvaluateTo(3, globals)
|
||||
})
|
||||
|
||||
test('list.splice removes elements and mutates array', async () => {
|
||||
await expect(`arr = [1 2 3 4 5]; list.splice arr 1 2; arr`).toEvaluateTo([1, 4, 5], globals)
|
||||
})
|
||||
|
||||
test('list.splice returns removed elements', async () => {
|
||||
await expect(`list.splice [1 2 3 4 5] 1 2`).toEvaluateTo([2, 3], globals)
|
||||
})
|
||||
|
||||
test('list.splice from start', async () => {
|
||||
await expect(`list.splice [1 2 3 4 5] 0 2`).toEvaluateTo([1, 2], globals)
|
||||
})
|
||||
|
||||
test('list.splice to end', async () => {
|
||||
await expect(`arr = [1 2 3 4 5]; list.splice arr 3 2; arr`).toEvaluateTo([1, 2, 3], globals)
|
||||
})
|
||||
|
||||
test('list.sort with no callback sorts ascending', async () => {
|
||||
await expect(`list.sort [3 1 4 1 5] null`).toEvaluateTo([1, 1, 3, 4, 5], globals)
|
||||
})
|
||||
|
||||
test('list.sort with callback sorts using comparator', async () => {
|
||||
await expect(`
|
||||
desc = do a b:
|
||||
b - a
|
||||
end
|
||||
list.sort [3 1 4 1 5] desc
|
||||
`).toEvaluateTo([5, 4, 3, 1, 1], globals)
|
||||
})
|
||||
|
||||
test('list.sort with callback for strings by length', async () => {
|
||||
await expect(`
|
||||
by-length = do a b:
|
||||
(length a) - (length b)
|
||||
end
|
||||
list.sort ['cat' 'a' 'dog' 'elephant'] by-length
|
||||
`).toEvaluateTo(['a', 'cat', 'dog', 'elephant'], globals)
|
||||
})
|
||||
|
||||
test('list.any? checks if any element matches', async () => {
|
||||
await expect(`
|
||||
gt-three = do x: x > 3 end
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user