Add regex to reef #1

Merged
defunkt merged 11 commits from regex into main 2025-10-16 21:15:42 +00:00
Showing only changes of commit f3759c2259 - Show all commits

View File

@ -1,20 +1,21 @@
import { Scope } from "./scope"
import { Scope } from './scope'
export type Value =
| { type: 'null', value: null }
| { type: 'boolean', value: boolean }
| { type: 'number', value: number }
| { type: 'string', value: string }
| { type: 'array', value: Value[] }
| { type: 'dict', value: Dict }
| { type: 'null'; value: null }
| { type: 'boolean'; value: boolean }
| { type: 'number'; value: number }
| { type: 'string'; value: string }
| { type: 'array'; value: Value[] }
| { type: 'dict'; value: Dict }
| { type: 'regex'; value: RegExp }
| {
type: 'function',
params: string[],
defaults: Record<string, number>, // indices into constants
body: number,
parentScope: Scope,
variadic: boolean,
named: boolean,
type: 'function'
params: string[]
defaults: Record<string, number> // indices into constants
body: number
parentScope: Scope
variadic: boolean
named: boolean
value: '<function>'
}
@ -30,14 +31,13 @@ export type FunctionDef = {
}
export function toValue(v: any): Value /* throws */ {
if (v === null || v === undefined)
return { type: 'null', value: null }
if (v === null || v === undefined) return { type: 'null', value: null }
if (v && typeof v === 'object' && 'type' in v && 'value' in v)
return v as Value
if (v && typeof v === 'object' && 'type' in v && 'value' in v) return v as Value
if (Array.isArray(v))
return { type: 'array', value: v.map(toValue) }
if (Array.isArray(v)) return { type: 'array', value: v.map(toValue) }
if (v instanceof RegExp) return { type: 'regex', value: v }
switch (typeof v) {
case 'boolean':
@ -51,8 +51,7 @@ export function toValue(v: any): Value /* throws */ {
case 'object':
const dict: Dict = new Map()
for (const key of Object.keys(v))
dict.set(key, toValue(v[key]))
for (const key of Object.keys(v)) dict.set(key, toValue(v[key]))
return { type: 'dict', value: dict }
default:
@ -62,13 +61,16 @@ export function toValue(v: any): Value /* throws */ {
export function toNumber(v: Value): number {
switch (v.type) {
case 'number': return v.value
case 'boolean': return v.value ? 1 : 0
case 'number':
return v.value
case 'boolean':
return v.value ? 1 : 0
case 'string': {
const parsed = parseFloat(v.value)
return isNaN(parsed) ? 0 : parsed
}
default: return 0
default:
return 0
}
}
@ -85,17 +87,26 @@ export function isTrue(v: Value): boolean {
export function toString(v: Value): string {
switch (v.type) {
case 'string': return v.value
case 'number': return String(v.value)
case 'boolean': return String(v.value)
case 'null': return 'null'
case 'function': return '<function>'
case 'array': return `[${v.value.map(toString).join(', ')}]`
case 'string':
return v.value
case 'number':
return String(v.value)
case 'boolean':
return String(v.value)
case 'null':
return 'null'
case 'function':
return '<function>'
case 'array':
return `[${v.value.map(toString).join(', ')}]`
case 'dict': {
const pairs = Array.from(v.value.entries())
.map(([k, v]) => `${k}: ${toString(v)}`)
const pairs = Array.from(v.value.entries()).map(([k, v]) => `${k}: ${toString(v)}`)
return `{${pairs.join(', ')}}`
}
case 'regex':
return String(v.value)
default:
return String(v)
}
}
@ -103,10 +114,14 @@ export function isEqual(a: Value, b: Value): boolean {
if (a.type !== b.type) return false
switch (a.type) {
case 'null': return true
case 'boolean': return a.value === (b as typeof a).value
case 'number': return a.value === (b as typeof a).value
case 'string': return a.value === (b as typeof a).value
case 'null':
return true
case 'boolean':
return a.value === b.value
case 'number':
return a.value === b.value
case 'string':
return a.value === b.value
case 'array': {
const bArr = b as typeof a
if (a.value.length !== bArr.value.length) return false
@ -121,19 +136,35 @@ export function isEqual(a: Value, b: Value): boolean {
}
return true
}
case 'function': return false // functions never equal
case 'regex': {
if (!(b instanceof RegExp)) return false
return String(a.value) === String(b.value)
}
case 'function':
return false // functions never equal
default:
return false
}
}
export function fromValue(v: Value): any {
switch (v.type) {
case 'null': return null
case 'boolean': return v.value
case 'number': return v.value
case 'string': return v.value
case 'array': return v.value.map(fromValue)
case 'dict': return Object.fromEntries(v.value.entries().map(([k, v]) => [k, fromValue(v)]))
case 'function': return '<function>'
case 'null':
return null
case 'boolean':
return v.value
case 'number':
return v.value
case 'string':
return v.value
case 'array':
return v.value.map(fromValue)
case 'dict':
return Object.fromEntries(v.value.entries().map(([k, v]) => [k, fromValue(v)]))
case 'regex':
return v.value
case 'function':
return '<function>'
}
}