conjure-js 0.0.13 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist-cli/conjure-js.mjs +2328 -2089
  2. package/dist-vite-plugin/index.mjs +2327 -2088
  3. package/package.json +1 -1
  4. package/src/bin/version.ts +1 -1
  5. package/src/core/assertions.ts +10 -3
  6. package/src/core/bootstrap.ts +7 -23
  7. package/src/core/compiler/binding.ts +164 -0
  8. package/src/core/compiler/callable.ts +41 -0
  9. package/src/core/compiler/compile-env.ts +40 -0
  10. package/src/core/compiler/control-flow.ts +79 -0
  11. package/src/core/compiler/index.ts +121 -0
  12. package/src/core/env.ts +4 -4
  13. package/src/core/errors.ts +1 -0
  14. package/src/core/evaluator/apply.ts +7 -3
  15. package/src/core/evaluator/arity.ts +16 -6
  16. package/src/core/evaluator/async-evaluator.ts +68 -89
  17. package/src/core/evaluator/collections.ts +9 -4
  18. package/src/core/evaluator/destructure.ts +45 -55
  19. package/src/core/evaluator/dispatch.ts +21 -24
  20. package/src/core/evaluator/evaluate.ts +14 -2
  21. package/src/core/evaluator/expand.ts +5 -7
  22. package/src/core/evaluator/js-interop.ts +46 -33
  23. package/src/core/evaluator/quasiquote.ts +7 -11
  24. package/src/core/evaluator/recur-check.ts +1 -1
  25. package/src/core/evaluator/special-forms.ts +18 -38
  26. package/src/core/index.ts +1 -1
  27. package/src/core/keywords.ts +105 -0
  28. package/src/core/modules/core/index.ts +131 -0
  29. package/src/core/{stdlib → modules/core/stdlib}/arithmetic.ts +6 -6
  30. package/src/core/{stdlib → modules/core/stdlib}/async-fns.ts +6 -6
  31. package/src/core/{stdlib → modules/core/stdlib}/atoms.ts +7 -7
  32. package/src/core/{stdlib → modules/core/stdlib}/errors.ts +4 -4
  33. package/src/core/{stdlib → modules/core/stdlib}/hof.ts +6 -6
  34. package/src/core/{stdlib → modules/core/stdlib}/lazy.ts +4 -4
  35. package/src/core/{stdlib → modules/core/stdlib}/maps-sets.ts +6 -6
  36. package/src/core/{stdlib → modules/core/stdlib}/meta.ts +5 -5
  37. package/src/core/{stdlib → modules/core/stdlib}/predicates.ts +7 -7
  38. package/src/core/modules/core/stdlib/print.ts +108 -0
  39. package/src/core/{stdlib → modules/core/stdlib}/regex.ts +5 -5
  40. package/src/core/{stdlib → modules/core/stdlib}/seq.ts +7 -7
  41. package/src/core/{stdlib → modules/core/stdlib}/strings.ts +6 -6
  42. package/src/core/{stdlib → modules/core/stdlib}/transducers.ts +6 -6
  43. package/src/core/{stdlib → modules/core/stdlib}/utils.ts +10 -10
  44. package/src/core/{stdlib → modules/core/stdlib}/vars.ts +4 -4
  45. package/src/core/{stdlib → modules/core/stdlib}/vectors.ts +6 -6
  46. package/src/core/modules/js/index.ts +402 -0
  47. package/src/core/ns-forms.ts +25 -17
  48. package/src/core/positions.ts +22 -2
  49. package/src/core/printer.ts +162 -53
  50. package/src/core/reader.ts +25 -22
  51. package/src/core/registry.ts +10 -10
  52. package/src/core/runtime.ts +23 -23
  53. package/src/core/session.ts +17 -7
  54. package/src/core/tokenizer.ts +14 -4
  55. package/src/core/transformations.ts +48 -29
  56. package/src/core/types.ts +57 -81
  57. package/src/core/core-module.ts +0 -303
  58. package/src/core/stdlib/js-namespace.ts +0 -344
@@ -1,7 +1,7 @@
1
1
  import { is } from '../assertions'
2
2
  import { EvaluationError } from '../errors'
3
3
  import { printString } from '../printer'
4
- import { getPos } from '../positions'
4
+ import { maybeHydrateErrorPos } from '../positions'
5
5
  import type {
6
6
  CljList,
7
7
  CljValue,
@@ -12,7 +12,10 @@ import type {
12
12
 
13
13
  import { evaluateSpecialForm } from './special-forms'
14
14
 
15
- function dispatchMultiMethod(
15
+ const LIST_HEAD_POS = 0
16
+ const LIST_BODY_POS = 1
17
+
18
+ export function dispatchMultiMethod(
16
19
  mm: CljMultiMethod,
17
20
  args: CljValue[],
18
21
  ctx: EvaluationContext,
@@ -45,39 +48,33 @@ export function evaluateList(
45
48
  if (list.value.length === 0) {
46
49
  return list
47
50
  }
48
- const first = list.value[0]
51
+ const head = list.value[LIST_HEAD_POS]
49
52
 
50
- if (is.specialForm(first)) {
51
- return evaluateSpecialForm(first.name, list, env, ctx)
53
+ if (is.specialForm(head)) {
54
+ return evaluateSpecialForm(head.name, list, env, ctx)
52
55
  }
53
56
 
54
- const evaledFirst = ctx.evaluate(first, env)
57
+ const evaledHead = ctx.evaluate(head, env)
55
58
 
56
- if (is.multiMethod(evaledFirst)) {
57
- const args = list.value.slice(1).map((v) => ctx.evaluate(v, env))
58
- return dispatchMultiMethod(evaledFirst, args, ctx, env)
59
+ if (is.multiMethod(evaledHead)) {
60
+ const args = list.value
61
+ .slice(LIST_BODY_POS)
62
+ .map((arg) => ctx.evaluate(arg, env))
63
+ return dispatchMultiMethod(evaledHead, args, ctx, env)
59
64
  }
60
65
 
61
- if (!is.callable(evaledFirst)) {
62
- const name = is.symbol(first) ? first.name : printString(first)
66
+ if (!is.callable(evaledHead)) {
67
+ const name = is.symbol(head) ? head.name : printString(head)
63
68
  throw new EvaluationError(`${name} is not callable`, { list, env })
64
69
  }
65
70
 
66
- const args = list.value.slice(1).map((v) => ctx.evaluate(v, env))
71
+ const args = list.value
72
+ .slice(LIST_BODY_POS)
73
+ .map((arg) => ctx.evaluate(arg, env))
67
74
  try {
68
- return ctx.applyCallable(evaledFirst, args, env)
75
+ return ctx.applyCallable(evaledHead, args, env)
69
76
  } catch (e) {
70
- if (
71
- e instanceof EvaluationError &&
72
- e.data?.argIndex !== undefined &&
73
- !e.pos
74
- ) {
75
- const argForm = list.value[(e.data.argIndex as number) + 1]
76
- if (argForm) {
77
- const pos = getPos(argForm)
78
- if (pos) e.pos = pos
79
- }
80
- }
77
+ maybeHydrateErrorPos(e, list)
81
78
  throw e
82
79
  }
83
80
  }
@@ -1,9 +1,17 @@
1
+ /**
2
+ * Evaluator - Core entrypoint
3
+ * Handles the evaluation of a single expression.
4
+ * Delegates most of the work to domain handlers.
5
+ * Uses the compiler to compile the expression to a closure when possible.
6
+ * The interpreter is the source of truth for the semantics of the language.
7
+ */
8
+
9
+ import { compile } from '../compiler'
1
10
  import { derefValue, getNamespaceEnv, lookup } from '../env'
2
11
  import { EvaluationError } from '../errors'
3
12
  import { v } from '../factories'
13
+ import { valueKeywords } from '../keywords.ts'
4
14
  import { getPos } from '../positions'
5
- import { valueKeywords } from '../types'
6
-
7
15
  import type { CljValue, Env, EvaluationContext } from '../types'
8
16
  import { evaluateMap, evaluateSet, evaluateVector } from './collections'
9
17
  import { evaluateList } from './dispatch'
@@ -24,6 +32,10 @@ export function evaluateWithContext(
24
32
  ctx: EvaluationContext
25
33
  ): CljValue {
26
34
  try {
35
+ const compiled = compile(expr)
36
+ if (compiled !== null) {
37
+ return compiled(env, ctx)
38
+ }
27
39
  switch (expr.kind) {
28
40
  // self-evaluating forms
29
41
  case valueKeywords.number:
@@ -1,6 +1,6 @@
1
1
  import { is } from '../assertions'
2
2
  import { derefValue, getNamespaceEnv, tryLookup } from '../env'
3
- import { cljList, cljMap, cljVector } from '../factories'
3
+ import { v } from '../factories'
4
4
  import type { CljValue, Env, EvaluationContext } from '../types'
5
5
 
6
6
  /**
@@ -31,7 +31,7 @@ export function macroExpandAllWithContext(
31
31
  )
32
32
  return expanded.every((e, i) => e === form.value[i])
33
33
  ? form
34
- : cljVector(expanded)
34
+ : v.vector(expanded)
35
35
  }
36
36
 
37
37
  // Maps: expand each key and value
@@ -47,7 +47,7 @@ export function macroExpandAllWithContext(
47
47
  ([k, v], i) => k === form.entries[i][0] && v === form.entries[i][1]
48
48
  )
49
49
  ? form
50
- : cljMap(expanded)
50
+ : v.map(expanded)
51
51
  }
52
52
 
53
53
  // Atoms (number, string, boolean, keyword, nil, symbol, regex, functions, etc.)
@@ -65,7 +65,7 @@ export function macroExpandAllWithContext(
65
65
  )
66
66
  return expanded.every((e, i) => e === form.value[i])
67
67
  ? form
68
- : cljList(expanded)
68
+ : v.list(expanded)
69
69
  }
70
70
 
71
71
  const name = first.name
@@ -103,7 +103,5 @@ export function macroExpandAllWithContext(
103
103
  const expanded = form.value.map((sub) =>
104
104
  macroExpandAllWithContext(sub, env, ctx)
105
105
  )
106
- return expanded.every((e, i) => e === form.value[i])
107
- ? form
108
- : cljList(expanded)
106
+ return expanded.every((e, i) => e === form.value[i]) ? form : v.list(expanded)
109
107
  }
@@ -1,6 +1,6 @@
1
1
  import { is } from '../assertions'
2
2
  import { EvaluationError } from '../errors'
3
- import { cljBoolean, cljJsValue, cljNil, cljNumber, cljString } from '../factories'
3
+ import { v } from '../factories'
4
4
  import type { CljList, CljValue, Env, EvaluationContext } from '../types'
5
5
 
6
6
  // ---------------------------------------------------------------------------
@@ -14,12 +14,12 @@ import type { CljList, CljValue, Env, EvaluationContext } from '../types'
14
14
  * - primitives convert; everything else boxes.
15
15
  */
16
16
  export function jsToClj(raw: unknown): CljValue {
17
- if (raw === null) return cljNil()
18
- if (raw === undefined) return cljJsValue(undefined)
19
- if (typeof raw === 'number') return cljNumber(raw)
20
- if (typeof raw === 'string') return cljString(raw)
21
- if (typeof raw === 'boolean') return cljBoolean(raw)
22
- return cljJsValue(raw)
17
+ if (raw === null) return v.nil()
18
+ if (raw === undefined) return v.jsValue(undefined)
19
+ if (typeof raw === 'number') return v.number(raw)
20
+ if (typeof raw === 'string') return v.string(raw)
21
+ if (typeof raw === 'boolean') return v.boolean(raw)
22
+ return v.jsValue(raw)
23
23
  }
24
24
 
25
25
  /**
@@ -28,13 +28,13 @@ export function jsToClj(raw: unknown): CljValue {
28
28
  * have no meaningful JS representation and must be reduced to a primitive first.
29
29
  */
30
30
  function mapKeyToString(key: CljValue): string {
31
- if (key.kind === 'string') return key.value
32
- if (key.kind === 'keyword') return key.name.slice(1) // strip leading ':'
33
- if (key.kind === 'number') return String(key.value)
34
- if (key.kind === 'boolean') return String(key.value)
31
+ if (is.string(key)) return key.value
32
+ if (is.keyword(key)) return key.name.slice(1) // strip leading ':'
33
+ if (is.number(key)) return String(key.value)
34
+ if (is.boolean(key)) return String(key.value)
35
35
  throw new EvaluationError(
36
36
  `cljToJs: map key must be a string, keyword, number, or boolean — ` +
37
- `got ${key.kind} (rich keys are not allowed as JS object keys; reduce to a primitive first)`,
37
+ `got ${key.kind} (rich keys are not allowed as JS object keys; reduce to a primitive first)`,
38
38
  { key }
39
39
  )
40
40
  }
@@ -43,14 +43,24 @@ function mapKeyToString(key: CljValue): string {
43
43
  * Convert a CljValue to a raw JS value for crossing the interop boundary.
44
44
  * Called on each argument passed to `.` and `js/new`.
45
45
  */
46
- export function cljToJs(val: CljValue, ctx: EvaluationContext, callEnv: Env): unknown {
46
+ export function cljToJs(
47
+ val: CljValue,
48
+ ctx: EvaluationContext,
49
+ callEnv: Env
50
+ ): unknown {
47
51
  switch (val.kind) {
48
- case 'js-value': return val.value
49
- case 'number': return val.value
50
- case 'string': return val.value
51
- case 'boolean': return val.value
52
- case 'nil': return null
53
- case 'keyword': return val.name.slice(1) // strip leading ':'
52
+ case 'js-value':
53
+ return val.value
54
+ case 'number':
55
+ return val.value
56
+ case 'string':
57
+ return val.value
58
+ case 'boolean':
59
+ return val.value
60
+ case 'nil':
61
+ return null
62
+ case 'keyword':
63
+ return val.name.slice(1) // strip leading ':'
54
64
  case 'function':
55
65
  case 'native-function': {
56
66
  const fn = val
@@ -90,15 +100,14 @@ export function cljToJs(val: CljValue, ctx: EvaluationContext, callEnv: Env): un
90
100
  */
91
101
  function extractRawTarget(target: CljValue): unknown {
92
102
  switch (target.kind) {
93
- case 'js-value': return target.value
103
+ case 'js-value':
104
+ return target.value
94
105
  case 'string':
95
106
  case 'number':
96
- case 'boolean': return target.value
107
+ case 'boolean':
108
+ return target.value
97
109
  default:
98
- throw new EvaluationError(
99
- `cannot use . on ${target.kind}`,
100
- { target }
101
- )
110
+ throw new EvaluationError(`cannot use . on ${target.kind}`, { target })
102
111
  }
103
112
  }
104
113
 
@@ -108,10 +117,9 @@ export function evaluateDot(
108
117
  ctx: EvaluationContext
109
118
  ): CljValue {
110
119
  if (list.value.length < 3) {
111
- throw new EvaluationError(
112
- '. requires at least 2 arguments: (. obj prop)',
113
- { list }
114
- )
120
+ throw new EvaluationError('. requires at least 2 arguments: (. obj prop)', {
121
+ list,
122
+ })
115
123
  }
116
124
 
117
125
  const target = ctx.evaluate(list.value[1], env)
@@ -141,7 +149,7 @@ export function evaluateDot(
141
149
  // Functions are bound to their object so that ((. obj method)) works correctly.
142
150
  const rawProp = rawObj[propName]
143
151
  if (typeof rawProp === 'function') {
144
- return cljJsValue((rawProp as (...a: unknown[]) => unknown).bind(rawObj))
152
+ return v.jsValue((rawProp as (...a: unknown[]) => unknown).bind(rawObj))
145
153
  }
146
154
  return jsToClj(rawProp)
147
155
  }
@@ -157,7 +165,10 @@ export function evaluateDot(
157
165
 
158
166
  const cljArgs = list.value.slice(3).map((a) => ctx.evaluate(a, env))
159
167
  const jsArgs = cljArgs.map((a) => cljToJs(a, ctx, env))
160
- const rawResult = (method as (...args: unknown[]) => unknown).apply(rawObj, jsArgs)
168
+ const rawResult = (method as (...args: unknown[]) => unknown).apply(
169
+ rawObj,
170
+ jsArgs
171
+ )
161
172
  return jsToClj(rawResult)
162
173
  }
163
174
 
@@ -171,7 +182,9 @@ export function evaluateNew(
171
182
  ctx: EvaluationContext
172
183
  ): CljValue {
173
184
  if (list.value.length < 2) {
174
- throw new EvaluationError('js/new requires a constructor argument', { list })
185
+ throw new EvaluationError('js/new requires a constructor argument', {
186
+ list,
187
+ })
175
188
  }
176
189
 
177
190
  const cls = ctx.evaluate(list.value[1], env)
@@ -185,5 +198,5 @@ export function evaluateNew(
185
198
  const cljArgs = list.value.slice(2).map((a) => ctx.evaluate(a, env))
186
199
  const jsArgs = cljArgs.map((a) => cljToJs(a, ctx, env))
187
200
  const ctor = cls.value as new (...args: unknown[]) => unknown
188
- return cljJsValue(new ctor(...jsArgs))
201
+ return v.jsValue(new ctor(...jsArgs))
189
202
  }
@@ -1,14 +1,10 @@
1
1
  import { is } from '../assertions'
2
2
  import { EvaluationError } from '../errors'
3
- import { cljList, cljMap, cljVector } from '../factories'
4
- import { toSeq } from '../transformations'
3
+ import { v } from '../factories'
5
4
  import { makeGensym } from '../gensym'
6
- import {
7
- type CljValue,
8
- type Env,
9
- type EvaluationContext,
10
- valueKeywords,
11
- } from '../types'
5
+ import { valueKeywords } from '../keywords'
6
+ import { toSeq } from '../transformations'
7
+ import { type CljValue, type Env, type EvaluationContext } from '../types'
12
8
 
13
9
  export function evaluateQuasiquote(
14
10
  form: CljValue,
@@ -58,7 +54,7 @@ export function evaluateQuasiquote(
58
54
  // Otherwise, recursively evaluate the quasiquote
59
55
  elements.push(evaluateQuasiquote(elem, env, autoGensyms, ctx))
60
56
  }
61
- return isAList ? cljList(elements) : cljVector(elements)
57
+ return isAList ? v.list(elements) : v.vector(elements)
62
58
  }
63
59
  case valueKeywords.map: {
64
60
  const entries: [CljValue, CljValue][] = []
@@ -67,7 +63,7 @@ export function evaluateQuasiquote(
67
63
  const evaluatedValue = evaluateQuasiquote(value, env, autoGensyms, ctx)
68
64
  entries.push([evaluatedKey, evaluatedValue])
69
65
  }
70
- return cljMap(entries)
66
+ return v.map(entries)
71
67
  }
72
68
  case valueKeywords.number:
73
69
  case valueKeywords.string:
@@ -83,7 +79,7 @@ export function evaluateQuasiquote(
83
79
  if (!autoGensyms.has(form.name)) {
84
80
  autoGensyms.set(form.name, makeGensym(form.name.slice(0, -1)))
85
81
  }
86
- return { kind: 'symbol', name: autoGensyms.get(form.name)! }
82
+ return v.symbol(autoGensyms.get(form.name)!)
87
83
  }
88
84
  return form
89
85
  }
@@ -1,7 +1,7 @@
1
1
  import { is } from '../assertions'
2
2
  import { EvaluationError } from '../errors'
3
+ import { specialFormKeywords } from '../keywords.ts'
3
4
  import type { CljValue } from '../types'
4
- import { specialFormKeywords } from './special-forms'
5
5
 
6
6
  /**
7
7
  * Asserts that every `recur` form in `body` appears strictly in tail position.
@@ -13,6 +13,7 @@ import { v } from '../factories'
13
13
  // --- ASYNC (experimental) ---
14
14
  import { createAsyncEvalCtx } from './async-evaluator'
15
15
  // --- END ASYNC ---
16
+ import { specialFormKeywords } from '../keywords.ts'
16
17
  import { getLineCol, getPos } from '../positions'
17
18
  import type {
18
19
  CljFunction,
@@ -27,14 +28,16 @@ import type {
27
28
  } from '../types'
28
29
  import { parseArities, RecurSignal } from './arity'
29
30
  import { destructureBindings } from './destructure'
30
- import { evaluateDot, evaluateNew } from './js-interop'
31
- import { evaluateQuasiquote } from './quasiquote'
32
- import { assertRecurInTailPosition } from './recur-check'
33
31
  import {
34
32
  matchesDiscriminator,
35
33
  parseTryStructure,
36
34
  validateBindingVector,
37
35
  } from './form-parsers'
36
+ import { evaluateDot, evaluateNew } from './js-interop'
37
+ import { evaluateQuasiquote } from './quasiquote'
38
+ import { assertRecurInTailPosition } from './recur-check'
39
+
40
+ import { compile } from '../compiler/index.ts'
38
41
 
39
42
  function hasDynamicMeta(meta: CljMap | undefined): boolean {
40
43
  if (!meta) return false
@@ -51,36 +54,6 @@ function hasDynamicMeta(meta: CljMap | undefined): boolean {
51
54
  return false
52
55
  }
53
56
 
54
- export const specialFormKeywords = {
55
- quote: 'quote',
56
- def: 'def',
57
- if: 'if',
58
- do: 'do',
59
- let: 'let',
60
- fn: 'fn',
61
- defmacro: 'defmacro',
62
- quasiquote: 'quasiquote',
63
- ns: 'ns',
64
- loop: 'loop',
65
- recur: 'recur',
66
- defmulti: 'defmulti',
67
- defmethod: 'defmethod',
68
- try: 'try',
69
- var: 'var',
70
- binding: 'binding',
71
- 'set!': 'set!',
72
- letfn: 'letfn',
73
- delay: 'delay',
74
- 'lazy-seq': 'lazy-seq',
75
- // --- ASYNC (experimental) ---
76
- async: 'async',
77
- // --- END ASYNC ---
78
- // --- JS INTEROP ---
79
- '.': '.',
80
- 'js/new': 'js/new',
81
- // --- END JS INTEROP ---
82
- } as const
83
-
84
57
  function keywordToDispatchFn(kw: CljKeyword): CljNativeFunction {
85
58
  return v.nativeFn(`kw:${kw.name}`, (...args: CljValue[]) => {
86
59
  const target = args[0]
@@ -95,10 +68,7 @@ function evaluateTry(
95
68
  env: Env,
96
69
  ctx: EvaluationContext
97
70
  ): CljValue {
98
- const { bodyForms, catchClauses, finallyForms } = parseTryStructure(
99
- list,
100
- env
101
- )
71
+ const { bodyForms, catchClauses, finallyForms } = parseTryStructure(list, env)
102
72
 
103
73
  let result: CljValue = v.nil()
104
74
  let pendingThrow: unknown = null
@@ -294,13 +264,23 @@ function evaluateFn(
294
264
  // (fn name [...] ...) — optional name symbol before the param vector/arities
295
265
  let fnName: string | undefined
296
266
  let arityForms = rest
297
- if (rest[0]?.kind === 'symbol') {
267
+ if (rest[0] && is.symbol(rest[0])) {
298
268
  fnName = rest[0].name
299
269
  arityForms = rest.slice(1)
300
270
  }
301
271
  const arities = parseArities(arityForms, env)
302
272
  for (const arity of arities) {
303
273
  assertRecurInTailPosition(arity.body)
274
+ // Try to compile this arity
275
+ // store the compiled body if successful
276
+ // wrap the body in a do form so the compiler can handle it
277
+ // at the top level dispatcher
278
+ const compiled = compile(
279
+ v.list([v.symbol(specialFormKeywords.do), ...arity.body])
280
+ )
281
+ if (compiled !== null) {
282
+ arity.compiledBody = compiled
283
+ }
304
284
  }
305
285
  const fn = v.multiArityFunction(arities, env)
306
286
  if (fnName) {
package/src/core/index.ts CHANGED
@@ -12,7 +12,7 @@ export type { Runtime, RuntimeSnapshot, RuntimeOptions } from './runtime'
12
12
 
13
13
  // Module system
14
14
  export { resolveModuleOrder } from './module'
15
- export { makeCoreModule } from './core-module'
15
+ export { makeCoreModule } from './modules/core'
16
16
  export type {
17
17
  RuntimeModule,
18
18
  NamespaceDeclaration,
@@ -0,0 +1,105 @@
1
+ export const specialFormKeywords = {
2
+ // Core forms
3
+ def: 'def',
4
+ do: 'do',
5
+ fn: 'fn',
6
+ if: 'if',
7
+ let: 'let',
8
+ loop: 'loop',
9
+ recur: 'recur',
10
+ quote: 'quote',
11
+ try: 'try',
12
+ var: 'var',
13
+ // Namespace form
14
+ ns: 'ns',
15
+ // Macro forms
16
+ defmacro: 'defmacro',
17
+ quasiquote: 'quasiquote',
18
+ // Multi methods
19
+ defmulti: 'defmulti',
20
+ defmethod: 'defmethod',
21
+ // Binding forms
22
+ binding: 'binding',
23
+ 'set!': 'set!',
24
+ letfn: 'letfn',
25
+ // Lazy forms
26
+ delay: 'delay',
27
+ 'lazy-seq': 'lazy-seq',
28
+ async: 'async',
29
+ // JS INTEROP
30
+ '.': '.',
31
+ 'js/new': 'js/new',
32
+ } as const
33
+
34
+ export const valueKeywords = {
35
+ // Core values
36
+ boolean: 'boolean',
37
+ function: 'function',
38
+ nativeFunction: 'native-function',
39
+ keyword: 'keyword',
40
+ list: 'list',
41
+ macro: 'macro',
42
+ map: 'map',
43
+ nil: 'nil',
44
+ number: 'number',
45
+ regex: 'regex',
46
+ set: 'set',
47
+ string: 'string',
48
+ symbol: 'symbol',
49
+ vector: 'vector',
50
+ // Stateful values
51
+ atom: 'atom',
52
+ delay: 'delay',
53
+ multiMethod: 'multi-method',
54
+ volatile: 'volatile',
55
+ var: 'var',
56
+ // Exotic values
57
+ cons: 'cons',
58
+ lazySeq: 'lazy-seq',
59
+ reduced: 'reduced',
60
+ // Async value
61
+ pending: 'pending',
62
+ // Namespace representation
63
+ namespace: 'namespace',
64
+ // Boxed JS values, Interop containers
65
+ jsValue: 'js-value',
66
+ } as const
67
+ /** Tokens */
68
+ export const tokenKeywords = {
69
+ LParen: 'LParen',
70
+ RParen: 'RParen',
71
+ LBracket: 'LBracket',
72
+ RBracket: 'RBracket',
73
+ LBrace: 'LBrace',
74
+ RBrace: 'RBrace',
75
+ String: 'String',
76
+ Number: 'Number',
77
+ Keyword: 'Keyword',
78
+ Quote: 'Quote',
79
+ Quasiquote: 'Quasiquote',
80
+ Unquote: 'Unquote',
81
+ UnquoteSplicing: 'UnquoteSplicing',
82
+ Comment: 'Comment',
83
+ Whitespace: 'Whitespace',
84
+ Symbol: 'Symbol',
85
+ AnonFnStart: 'AnonFnStart',
86
+ Deref: 'Deref',
87
+ Regex: 'Regex',
88
+ VarQuote: 'VarQuote',
89
+ Meta: 'Meta',
90
+ SetStart: 'SetStart',
91
+ } as const
92
+ export const tokenSymbols = {
93
+ Quote: 'quote',
94
+ Quasiquote: 'quasiquote',
95
+ Unquote: 'unquote',
96
+ UnquoteSplicing: 'unquote-splicing',
97
+ LParen: '(',
98
+ RParen: ')',
99
+ LBracket: '[',
100
+ RBracket: ']',
101
+ LBrace: '{',
102
+ RBrace: '}',
103
+ } as const
104
+ export type TokenSymbols = (typeof tokenSymbols)[keyof typeof tokenSymbols]
105
+ export type TokenKinds = keyof typeof tokenKeywords