add exceptions to prelude functions
This commit is contained in:
parent
4f961d3039
commit
f8d2236292
|
|
@ -39,7 +39,7 @@ export const globals = {
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
case 'string': case 'array': return value.value.length
|
case 'string': case 'array': return value.value.length
|
||||||
case 'dict': return value.value.size
|
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,
|
identity: (v: any) => v,
|
||||||
|
|
||||||
// collections
|
// 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) => {
|
range: (start: number, end: number | null) => {
|
||||||
if (end === null) {
|
if (end === null) {
|
||||||
end = start
|
end = start
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,14 @@ export const list = {
|
||||||
first: (list: any[]) => list[0] ?? null,
|
first: (list: any[]) => list[0] ?? null,
|
||||||
last: (list: any[]) => list[list.length - 1] ?? null,
|
last: (list: any[]) => list[list.length - 1] ?? null,
|
||||||
rest: (list: any[]) => list.slice(1),
|
rest: (list: any[]) => list.slice(1),
|
||||||
take: (list: any[], n: number) => list.slice(0, n),
|
take: (list: any[], n: number) => {
|
||||||
drop: (list: any[], n: number) => list.slice(n),
|
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],
|
append: (list: any[], item: any) => [...list, item],
|
||||||
prepend: (list: any[], item: any) => [item, ...list],
|
prepend: (list: any[], item: any) => [item, ...list],
|
||||||
'index-of': (list: any[], item: any) => list.indexOf(item),
|
'index-of': (list: any[], item: any) => list.indexOf(item),
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,24 @@ export const math = {
|
||||||
floor: (n: number) => Math.floor(n),
|
floor: (n: number) => Math.floor(n),
|
||||||
ceil: (n: number) => Math.ceil(n),
|
ceil: (n: number) => Math.ceil(n),
|
||||||
round: (n: number) => Math.round(n),
|
round: (n: number) => Math.round(n),
|
||||||
min: (...nums: number[]) => Math.min(...nums),
|
min: (...nums: number[]) => {
|
||||||
max: (...nums: number[]) => Math.max(...nums),
|
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),
|
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(),
|
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),
|
sign: (n: number) => Math.sign(n),
|
||||||
trunc: (n: number) => Math.trunc(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),
|
'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),
|
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),
|
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-start': (str: string, length: number, pad: string = ' ') => str.padStart(length, pad),
|
||||||
'pad-end': (str: string, length: number, pad: string = ' ') => str.padEnd(length, pad),
|
'pad-end': (str: string, length: number, pad: string = ' ') => str.padEnd(length, pad),
|
||||||
lines: (str: string) => str.split('\n'),
|
lines: (str: string) => str.split('\n'),
|
||||||
|
|
|
||||||
|
|
@ -176,9 +176,12 @@ describe('introspection', () => {
|
||||||
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)
|
||||||
await expect(`length [a=1 b=2]`).toEvaluateTo(2, 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 () => {
|
test('inspect formats values', async () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user