add exceptions to prelude functions
This commit is contained in:
parent
4f961d3039
commit
f8d2236292
|
|
@ -39,7 +39,7 @@ export const globals = {
|
|||
switch (value.type) {
|
||||
case 'string': case 'array': return value.value.length
|
||||
case 'dict': return value.value.size
|
||||
default: return 0
|
||||
default: throw new Error(`length: expected string, array, or dict, got ${value.type}`)
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -65,7 +65,24 @@ export const globals = {
|
|||
identity: (v: any) => v,
|
||||
|
||||
// collections
|
||||
at: (collection: any, index: number | string) => collection[index],
|
||||
at: (collection: any, index: number | string) => {
|
||||
const value = toValue(collection)
|
||||
if (value.type === 'string' || value.type === 'array') {
|
||||
const idx = typeof index === 'number' ? index : parseInt(index as string)
|
||||
if (idx < 0 || idx >= value.value.length) {
|
||||
throw new Error(`at: index ${idx} out of bounds for ${value.type} of length ${value.value.length}`)
|
||||
}
|
||||
return value.value[idx]
|
||||
} else if (value.type === 'dict') {
|
||||
const key = String(index)
|
||||
if (!value.value.has(key)) {
|
||||
throw new Error(`at: key '${key}' not found in dict`)
|
||||
}
|
||||
return value.value.get(key)
|
||||
} else {
|
||||
throw new Error(`at: expected string, array, or dict, got ${value.type}`)
|
||||
}
|
||||
},
|
||||
range: (start: number, end: number | null) => {
|
||||
if (end === null) {
|
||||
end = start
|
||||
|
|
|
|||
|
|
@ -52,8 +52,14 @@ export const list = {
|
|||
first: (list: any[]) => list[0] ?? null,
|
||||
last: (list: any[]) => list[list.length - 1] ?? null,
|
||||
rest: (list: any[]) => list.slice(1),
|
||||
take: (list: any[], n: number) => list.slice(0, n),
|
||||
drop: (list: any[], n: number) => list.slice(n),
|
||||
take: (list: any[], n: number) => {
|
||||
if (n < 0) throw new Error(`take: count must be non-negative, got ${n}`)
|
||||
return list.slice(0, n)
|
||||
},
|
||||
drop: (list: any[], n: number) => {
|
||||
if (n < 0) throw new Error(`drop: count must be non-negative, got ${n}`)
|
||||
return list.slice(n)
|
||||
},
|
||||
append: (list: any[], item: any) => [...list, item],
|
||||
prepend: (list: any[], item: any) => [item, ...list],
|
||||
'index-of': (list: any[], item: any) => list.indexOf(item),
|
||||
|
|
|
|||
|
|
@ -3,12 +3,24 @@ export const math = {
|
|||
floor: (n: number) => Math.floor(n),
|
||||
ceil: (n: number) => Math.ceil(n),
|
||||
round: (n: number) => Math.round(n),
|
||||
min: (...nums: number[]) => Math.min(...nums),
|
||||
max: (...nums: number[]) => Math.max(...nums),
|
||||
min: (...nums: number[]) => {
|
||||
if (nums.length === 0) throw new Error('min: expected at least one argument')
|
||||
return Math.min(...nums)
|
||||
},
|
||||
max: (...nums: number[]) => {
|
||||
if (nums.length === 0) throw new Error('max: expected at least one argument')
|
||||
return Math.max(...nums)
|
||||
},
|
||||
pow: (base: number, exp: number) => Math.pow(base, exp),
|
||||
sqrt: (n: number) => Math.sqrt(n),
|
||||
sqrt: (n: number) => {
|
||||
if (n < 0) throw new Error(`sqrt: cannot take square root of negative number ${n}`)
|
||||
return Math.sqrt(n)
|
||||
},
|
||||
random: () => Math.random(),
|
||||
clamp: (n: number, min: number, max: number) => Math.min(Math.max(n, min), max),
|
||||
clamp: (n: number, min: number, max: number) => {
|
||||
if (min > max) throw new Error(`clamp: min (${min}) must be less than or equal to max (${max})`)
|
||||
return Math.min(Math.max(n, min), max)
|
||||
},
|
||||
sign: (n: number) => Math.sign(n),
|
||||
trunc: (n: number) => Math.trunc(n),
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ export const str = {
|
|||
'replace-all': (str: string, search: string, replacement: string) => str.replaceAll(search, replacement),
|
||||
slice: (str: string, start: number, end?: number | null) => str.slice(start, end ?? undefined),
|
||||
substring: (str: string, start: number, end?: number | null) => str.substring(start, end ?? undefined),
|
||||
repeat: (str: string, count: number) => str.repeat(count),
|
||||
repeat: (str: string, count: number) => {
|
||||
if (count < 0) throw new Error(`repeat: count must be non-negative, got ${count}`)
|
||||
if (!Number.isInteger(count)) throw new Error(`repeat: count must be an integer, got ${count}`)
|
||||
return str.repeat(count)
|
||||
},
|
||||
'pad-start': (str: string, length: number, pad: string = ' ') => str.padStart(length, pad),
|
||||
'pad-end': (str: string, length: number, pad: string = ' ') => str.padEnd(length, pad),
|
||||
lines: (str: string) => str.split('\n'),
|
||||
|
|
|
|||
|
|
@ -176,9 +176,12 @@ describe('introspection', () => {
|
|||
await expect(`length 'hello'`).toEvaluateTo(5, globals)
|
||||
await expect(`length [1 2 3]`).toEvaluateTo(3, globals)
|
||||
await expect(`length [a=1 b=2]`).toEvaluateTo(2, globals)
|
||||
await expect(`length 42`).toEvaluateTo(0, globals)
|
||||
await expect(`length true`).toEvaluateTo(0, globals)
|
||||
await expect(`length null`).toEvaluateTo(0, globals)
|
||||
})
|
||||
|
||||
test('length throws on invalid types', async () => {
|
||||
await expect(`try: length 42 catch e: 'error' end`).toEvaluateTo('error', globals)
|
||||
await expect(`try: length true catch e: 'error' end`).toEvaluateTo('error', globals)
|
||||
await expect(`try: length null catch e: 'error' end`).toEvaluateTo('error', globals)
|
||||
})
|
||||
|
||||
test('inspect formats values', async () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user