Compare commits

..

No commits in common. "f9b0aa2db5f90c1f6399c0bdddff69925321fee2" and "e0e5e828692713fcaf5d62f88d3ad2c3a43802d4" have entirely different histories.

3 changed files with 70 additions and 94 deletions

View File

@ -1,7 +1,7 @@
// The prelude creates all the builtin Shrimp functions. // The prelude creates all the builtin Shrimp functions.
import { import {
type Value, type VM, toValue, type Value, toValue,
extractParamInfo, isWrapped, getOriginalFunction, extractParamInfo, isWrapped, getOriginalFunction,
} from 'reefvm' } from 'reefvm'
@ -34,11 +34,13 @@ export const globals = {
const val = toValue(v) const val = toValue(v)
return `#<${val.type}: ${formatValue(val)}>` return `#<${val.type}: ${formatValue(val)}>`
}, },
var: function (this: VM, v: any) { length: (v: any) => {
return typeof v === 'string' ? this.scope.get(v) : v const value = toValue(v)
}, switch (value.type) {
'var?': function (this: VM, v: string) { case 'string': case 'array': return value.value.length
return typeof v !== 'string' || this.scope.has(v) case 'dict': return value.value.size
default: throw new Error(`length: expected string, array, or dict, got ${value.type}`)
}
}, },
// type predicates // type predicates
@ -63,14 +65,6 @@ export const globals = {
identity: (v: any) => v, identity: (v: any) => v,
// collections // collections
length: (v: any) => {
const value = toValue(v)
switch (value.type) {
case 'string': case 'array': return value.value.length
case 'dict': return value.value.size
default: throw new Error(`length: expected string, array, or dict, got ${value.type}`)
}
},
at: (collection: any, index: number | string) => { at: (collection: any, index: number | string) => {
const value = toValue(collection) const value = toValue(collection)
if (value.type === 'string' || value.type === 'array') { if (value.type === 'string' || value.type === 'array') {

View File

@ -1,79 +0,0 @@
import { expect, describe, test } from 'bun:test'
import { globals } from '#prelude'
describe('var and var?', () => {
test('var? checks if a variable exists', async () => {
await expect(`var? 'nada'`).toEvaluateTo(false, globals)
await expect(`var? 'info'`).toEvaluateTo(false, globals)
await expect(`abc = abc; var? 'abc'`).toEvaluateTo(true, globals)
await expect(`var? 'var?'`).toEvaluateTo(true, globals)
await expect(`var? 'dict'`).toEvaluateTo(true, globals)
await expect(`var? dict`).toEvaluateTo(true, globals)
})
test('var returns a value or null', async () => {
await expect(`var 'nada'`).toEvaluateTo(null, globals)
await expect(`var nada`).toEvaluateTo(null, globals)
await expect(`var 'info'`).toEvaluateTo(null, globals)
await expect(`abc = my-string; var 'abc'`).toEvaluateTo('my-string', globals)
await expect(`abc = my-string; var abc`).toEvaluateTo(null, globals)
})
})
describe('type predicates', () => {
test('string? checks for string type', async () => {
await expect(`string? 'hello'`).toEvaluateTo(true, globals)
await expect(`string? 42`).toEvaluateTo(false, globals)
})
test('number? checks for number type', async () => {
await expect(`number? 42`).toEvaluateTo(true, globals)
await expect(`number? 'hello'`).toEvaluateTo(false, globals)
})
test('boolean? checks for boolean type', async () => {
await expect(`boolean? true`).toEvaluateTo(true, globals)
await expect(`boolean? 42`).toEvaluateTo(false, globals)
})
test('array? checks for array type', async () => {
await expect(`array? [1 2 3]`).toEvaluateTo(true, globals)
await expect(`array? 42`).toEvaluateTo(false, globals)
})
test('dict? checks for dict type', async () => {
await expect(`dict? [a=1]`).toEvaluateTo(true, globals)
await expect(`dict? []`).toEvaluateTo(false, globals)
})
test('null? checks for null type', async () => {
await expect(`null? null`).toEvaluateTo(true, globals)
await expect(`null? 42`).toEvaluateTo(false, globals)
})
test('some? checks for non-null', async () => {
await expect(`some? 42`).toEvaluateTo(true, globals)
await expect(`some? null`).toEvaluateTo(false, globals)
})
})
describe('introspection', () => {
test('type returns proper types', async () => {
await expect(`type 'hello'`).toEvaluateTo('string', globals)
await expect(`type 42`).toEvaluateTo('number', globals)
await expect(`type true`).toEvaluateTo('boolean', globals)
await expect(`type false`).toEvaluateTo('boolean', globals)
await expect(`type null`).toEvaluateTo('null', globals)
await expect(`type [1 2 3]`).toEvaluateTo('array', globals)
await expect(`type [a=1 b=2]`).toEvaluateTo('dict', globals)
})
test('inspect formats values', async () => {
await expect(`inspect 'hello'`).toEvaluateTo("\u001b[32m'hello\u001b[32m'\u001b[0m", globals)
})
test('describe describes values', async () => {
await expect(`describe 'hello'`).toEvaluateTo("#<string: \u001b[32m'hello\u001b[32m'\u001b[0m>", globals)
})
})

View File

@ -98,6 +98,43 @@ describe('string operations', () => {
}) })
}) })
describe('type predicates', () => {
test('string? checks for string type', async () => {
await expect(`string? 'hello'`).toEvaluateTo(true, globals)
await expect(`string? 42`).toEvaluateTo(false, globals)
})
test('number? checks for number type', async () => {
await expect(`number? 42`).toEvaluateTo(true, globals)
await expect(`number? 'hello'`).toEvaluateTo(false, globals)
})
test('boolean? checks for boolean type', async () => {
await expect(`boolean? true`).toEvaluateTo(true, globals)
await expect(`boolean? 42`).toEvaluateTo(false, globals)
})
test('array? checks for array type', async () => {
await expect(`array? [1 2 3]`).toEvaluateTo(true, globals)
await expect(`array? 42`).toEvaluateTo(false, globals)
})
test('dict? checks for dict type', async () => {
await expect(`dict? [a=1]`).toEvaluateTo(true, globals)
await expect(`dict? []`).toEvaluateTo(false, globals)
})
test('null? checks for null type', async () => {
await expect(`null? null`).toEvaluateTo(true, globals)
await expect(`null? 42`).toEvaluateTo(false, globals)
})
test('some? checks for non-null', async () => {
await expect(`some? 42`).toEvaluateTo(true, globals)
await expect(`some? null`).toEvaluateTo(false, globals)
})
})
describe('boolean logic', () => { describe('boolean logic', () => {
test('not negates value', async () => { test('not negates value', async () => {
await expect(`not true`).toEvaluateTo(false, globals) await expect(`not true`).toEvaluateTo(false, globals)
@ -124,7 +161,17 @@ describe('utilities', () => {
}) })
}) })
describe('collections', () => { describe('introspection', () => {
test('type returns proper types', async () => {
await expect(`type 'hello'`).toEvaluateTo('string', globals)
await expect(`type 42`).toEvaluateTo('number', globals)
await expect(`type true`).toEvaluateTo('boolean', globals)
await expect(`type false`).toEvaluateTo('boolean', globals)
await expect(`type null`).toEvaluateTo('null', globals)
await expect(`type [1 2 3]`).toEvaluateTo('array', globals)
await expect(`type [a=1 b=2]`).toEvaluateTo('dict', globals)
})
test('length', async () => { test('length', async () => {
await expect(`length 'hello'`).toEvaluateTo(5, globals) await expect(`length 'hello'`).toEvaluateTo(5, globals)
await expect(`length [1 2 3]`).toEvaluateTo(3, globals) await expect(`length [1 2 3]`).toEvaluateTo(3, globals)
@ -137,6 +184,20 @@ describe('collections', () => {
await expect(`try: length null catch e: 'error' end`).toEvaluateTo('error', globals) await expect(`try: length null catch e: 'error' end`).toEvaluateTo('error', globals)
}) })
test('inspect formats values', async () => {
// Just test that inspect returns something for now
// (we'd need more complex assertion to check the actual format)
await expect(`type (inspect 'hello')`).toEvaluateTo('string', globals)
})
test('describe describes values', async () => {
// Just test that inspect returns something for now
// (we'd need more complex assertion to check the actual format)
await expect(`describe 'hello'`).toEvaluateTo("#<string: \u001b[32m'hello\u001b[32m'\u001b[0m>", globals)
})
})
describe('collections', () => {
test('literal array creates array from arguments', async () => { test('literal array creates array from arguments', async () => {
await expect(`[ 1 2 3 ]`).toEvaluateTo([1, 2, 3], globals) await expect(`[ 1 2 3 ]`).toEvaluateTo([1, 2, 3], globals)
await expect(`['a' 'b']`).toEvaluateTo(['a', 'b'], globals) await expect(`['a' 'b']`).toEvaluateTo(['a', 'b'], globals)