conjure-js 0.0.1

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 (80) hide show
  1. package/conjure +0 -0
  2. package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  3. package/dist/assets/editor.worker-CdQrwHl8.js +26 -0
  4. package/dist/assets/main-A7ZMId9A.css +1 -0
  5. package/dist/assets/main-CmI-7epE.js +3137 -0
  6. package/dist/index.html +195 -0
  7. package/dist/vite.svg +1 -0
  8. package/package.json +68 -0
  9. package/src/bin/__fixtures__/smoke/app/lib.clj +4 -0
  10. package/src/bin/__fixtures__/smoke/app/main.clj +4 -0
  11. package/src/bin/__fixtures__/smoke/repl-smoke.ts +12 -0
  12. package/src/bin/bencode.ts +205 -0
  13. package/src/bin/cli.ts +250 -0
  14. package/src/bin/nrepl-utils.ts +59 -0
  15. package/src/bin/nrepl.ts +393 -0
  16. package/src/bin/version.ts +4 -0
  17. package/src/clojure/core.clj +620 -0
  18. package/src/clojure/core.clj.d.ts +189 -0
  19. package/src/clojure/demo/math.clj +16 -0
  20. package/src/clojure/demo/math.clj.d.ts +4 -0
  21. package/src/clojure/demo.clj +42 -0
  22. package/src/clojure/demo.clj.d.ts +0 -0
  23. package/src/clojure/generated/builtin-namespace-registry.ts +14 -0
  24. package/src/clojure/generated/clojure-core-source.ts +623 -0
  25. package/src/clojure/generated/clojure-string-source.ts +196 -0
  26. package/src/clojure/string.clj +192 -0
  27. package/src/clojure/string.clj.d.ts +25 -0
  28. package/src/core/assertions.ts +134 -0
  29. package/src/core/conversions.ts +108 -0
  30. package/src/core/core-env.ts +58 -0
  31. package/src/core/env.ts +78 -0
  32. package/src/core/errors.ts +39 -0
  33. package/src/core/evaluator/apply.ts +114 -0
  34. package/src/core/evaluator/arity.ts +174 -0
  35. package/src/core/evaluator/collections.ts +25 -0
  36. package/src/core/evaluator/destructure.ts +247 -0
  37. package/src/core/evaluator/dispatch.ts +73 -0
  38. package/src/core/evaluator/evaluate.ts +100 -0
  39. package/src/core/evaluator/expand.ts +79 -0
  40. package/src/core/evaluator/index.ts +72 -0
  41. package/src/core/evaluator/quasiquote.ts +87 -0
  42. package/src/core/evaluator/recur-check.ts +109 -0
  43. package/src/core/evaluator/special-forms.ts +517 -0
  44. package/src/core/factories.ts +155 -0
  45. package/src/core/gensym.ts +9 -0
  46. package/src/core/index.ts +76 -0
  47. package/src/core/positions.ts +38 -0
  48. package/src/core/printer.ts +86 -0
  49. package/src/core/reader.ts +559 -0
  50. package/src/core/scanners.ts +93 -0
  51. package/src/core/session.ts +610 -0
  52. package/src/core/stdlib/arithmetic.ts +361 -0
  53. package/src/core/stdlib/atoms.ts +88 -0
  54. package/src/core/stdlib/collections.ts +784 -0
  55. package/src/core/stdlib/errors.ts +81 -0
  56. package/src/core/stdlib/hof.ts +307 -0
  57. package/src/core/stdlib/meta.ts +48 -0
  58. package/src/core/stdlib/predicates.ts +240 -0
  59. package/src/core/stdlib/regex.ts +238 -0
  60. package/src/core/stdlib/strings.ts +311 -0
  61. package/src/core/stdlib/transducers.ts +256 -0
  62. package/src/core/stdlib/utils.ts +287 -0
  63. package/src/core/tokenizer.ts +437 -0
  64. package/src/core/transformations.ts +75 -0
  65. package/src/core/types.ts +258 -0
  66. package/src/main.ts +1 -0
  67. package/src/monaco-esm.d.ts +7 -0
  68. package/src/playground/clojure-tokens.ts +67 -0
  69. package/src/playground/editor.worker.ts +5 -0
  70. package/src/playground/find-form.ts +138 -0
  71. package/src/playground/playground.ts +342 -0
  72. package/src/playground/samples/00-welcome.clj +385 -0
  73. package/src/playground/samples/01-collections.clj +191 -0
  74. package/src/playground/samples/02-higher-order-functions.clj +215 -0
  75. package/src/playground/samples/03-destructuring.clj +194 -0
  76. package/src/playground/samples/04-strings-and-regex.clj +202 -0
  77. package/src/playground/samples/05-error-handling.clj +212 -0
  78. package/src/repl/repl.ts +116 -0
  79. package/tsconfig.build.json +10 -0
  80. package/tsconfig.json +31 -0
@@ -0,0 +1,58 @@
1
+ import { define, makeEnv } from './env'
2
+ import { cljNativeFunction, cljNil } from './factories'
3
+ import { arithmeticFunctions } from './stdlib/arithmetic'
4
+ import { atomFunctions } from './stdlib/atoms'
5
+ import { collectionFunctions } from './stdlib/collections'
6
+ import { errorFunctions } from './stdlib/errors'
7
+ import { hofFunctions } from './stdlib/hof'
8
+ import { metaFunctions } from './stdlib/meta'
9
+ import { predicateFunctions } from './stdlib/predicates'
10
+ import { regexFunctions } from './stdlib/regex'
11
+ import { stringFunctions } from './stdlib/strings'
12
+ import { transducerFunctions } from './stdlib/transducers'
13
+ import { utilFunctions } from './stdlib/utils'
14
+ import { valueToString } from './transformations'
15
+ import { type CljValue, type Env } from './types'
16
+
17
+ const nativeFunctions = {
18
+ ...arithmeticFunctions,
19
+ ...atomFunctions,
20
+ ...collectionFunctions,
21
+ ...errorFunctions,
22
+ ...predicateFunctions,
23
+ ...hofFunctions,
24
+ ...metaFunctions,
25
+ ...transducerFunctions,
26
+ ...regexFunctions,
27
+ ...stringFunctions,
28
+ ...utilFunctions,
29
+ }
30
+
31
+ export function loadCoreFunctions(env: Env, output?: (text: string) => void) {
32
+ for (const [key, value] of Object.entries(nativeFunctions)) {
33
+ define(key, value, env)
34
+ }
35
+ const emit = output ?? ((text: string) => console.log(text))
36
+ define(
37
+ 'println',
38
+ cljNativeFunction('println', (...args: CljValue[]) => {
39
+ emit(args.map(valueToString).join(' '))
40
+ return cljNil()
41
+ }),
42
+ env
43
+ )
44
+ define(
45
+ 'print',
46
+ cljNativeFunction('print', (...args: CljValue[]) => {
47
+ emit(args.map(valueToString).join(' '))
48
+ return cljNil()
49
+ }),
50
+ env
51
+ )
52
+ }
53
+
54
+ export function makeCoreEnv(output?: (text: string) => void): Env {
55
+ const env = makeEnv()
56
+ loadCoreFunctions(env, output)
57
+ return env
58
+ }
@@ -0,0 +1,78 @@
1
+ import { EvaluationError } from './errors'
2
+ import type { CljValue, Env } from './types'
3
+
4
+ class EnvError extends Error {
5
+ context: any
6
+ constructor(message: string, context: any) {
7
+ super(message)
8
+ this.context = context
9
+ this.name = 'EnvError'
10
+ }
11
+ }
12
+
13
+ export function makeEnv(outer?: Env): Env {
14
+ return {
15
+ bindings: new Map(),
16
+ outer: outer ?? null,
17
+ }
18
+ }
19
+
20
+ export function lookup(name: string, env: Env): CljValue {
21
+ let current = env as Env | null
22
+ while (current) {
23
+ if (current.bindings.has(name)) {
24
+ return current.bindings.get(name)!
25
+ }
26
+ current = current.outer
27
+ }
28
+ throw new EvaluationError(`Symbol ${name} not found`, { name })
29
+ }
30
+
31
+ export function tryLookup(name: string, env: Env): CljValue | undefined {
32
+ let current = env as Env | null
33
+ while (current) {
34
+ if (current.bindings.has(name)) {
35
+ return current.bindings.get(name)!
36
+ }
37
+ current = current.outer
38
+ }
39
+ return undefined
40
+ }
41
+
42
+ export function define(name: string, value: CljValue, env: Env) {
43
+ env.bindings.set(name, value)
44
+ }
45
+
46
+ export function extend(params: string[], args: CljValue[], outer: Env): Env {
47
+ if (params.length !== args.length) {
48
+ throw new EnvError('Number of parameters and arguments must match', {
49
+ params,
50
+ args,
51
+ outer,
52
+ })
53
+ }
54
+ const env = makeEnv(outer)
55
+ for (let i = 0; i < params.length; i++) {
56
+ define(params[i], args[i], env)
57
+ }
58
+ return env
59
+ }
60
+
61
+ export function getRootEnv(env: Env): Env {
62
+ let current = env as Env | null
63
+ while (current?.outer) {
64
+ current = current.outer
65
+ }
66
+ return current!
67
+ }
68
+
69
+ export function getNamespaceEnv(env: Env): Env {
70
+ let current: Env | null = env
71
+ while (current) {
72
+ if (current.namespace) return current
73
+ current = current.outer
74
+ }
75
+ // fallback for un-namespaced envs for backwards compact
76
+ // eventually we'll remove this and require all envs to be namespaced
77
+ return getRootEnv(env)
78
+ }
@@ -0,0 +1,39 @@
1
+ import type { CljValue, Pos } from './types'
2
+
3
+ export class TokenizerError extends Error {
4
+ context: unknown
5
+ constructor(message: string, context: unknown) {
6
+ super(message)
7
+ this.name = 'TokenizerError'
8
+ this.context = context
9
+ }
10
+ }
11
+
12
+ export class ReaderError extends Error {
13
+ context: unknown
14
+ pos?: Pos
15
+ constructor(message: string, context: unknown, pos?: Pos) {
16
+ super(message)
17
+ this.name = 'ReaderError'
18
+ this.context = context
19
+ this.pos = pos
20
+ }
21
+ }
22
+
23
+ export class EvaluationError extends Error {
24
+ context: unknown
25
+ pos?: Pos
26
+ constructor(message: string, context: unknown, pos?: Pos) {
27
+ super(message)
28
+ this.name = 'EvaluationError'
29
+ this.context = context
30
+ this.pos = pos
31
+ }
32
+ }
33
+
34
+ export class CljThrownSignal {
35
+ value: CljValue
36
+ constructor(value: CljValue) {
37
+ this.value = value
38
+ }
39
+ }
@@ -0,0 +1,114 @@
1
+ import { isAFunction, isEqual, isKeyword, isMap } from '../assertions'
2
+ import { EvaluationError } from '../errors'
3
+ import { cljNil } from '../factories'
4
+ import { printString } from '../printer'
5
+ import type {
6
+ CljFunction,
7
+ CljMacro,
8
+ CljNativeFunction,
9
+ CljValue,
10
+ Env,
11
+ EvaluationContext,
12
+ } from '../types'
13
+ import { bindParams, RecurSignal, resolveArity } from './arity'
14
+
15
+ export function applyFunctionWithContext(
16
+ fn: CljFunction | CljNativeFunction,
17
+ args: CljValue[],
18
+ ctx: EvaluationContext,
19
+ callEnv: Env
20
+ ): CljValue {
21
+ if (fn.kind === 'native-function') {
22
+ // New path, native fns receive evaluation context as first argument
23
+ if (fn.fnWithContext) {
24
+ return fn.fnWithContext(ctx, callEnv, ...args)
25
+ }
26
+ return fn.fn(...args)
27
+ }
28
+ if (fn.kind === 'function') {
29
+ const arity = resolveArity(fn.arities, args.length)
30
+ let currentArgs = args
31
+ while (true) {
32
+ const localEnv = bindParams(
33
+ arity.params,
34
+ arity.restParam,
35
+ currentArgs,
36
+ fn.env,
37
+ ctx,
38
+ callEnv
39
+ )
40
+ try {
41
+ return ctx.evaluateForms(arity.body, localEnv)
42
+ } catch (e) {
43
+ if (e instanceof RecurSignal) {
44
+ currentArgs = e.args
45
+ continue
46
+ }
47
+ throw e
48
+ }
49
+ }
50
+ }
51
+
52
+ throw new EvaluationError(
53
+ `${(fn as CljValue).kind} is not a callable function`,
54
+ {
55
+ fn,
56
+ args,
57
+ }
58
+ )
59
+ }
60
+
61
+ /**
62
+ * Invokes any IFn value — functions, native functions, keywords, and maps.
63
+ * Used by comp, partial, and any other HOF that needs to call an arbitrary
64
+ * callable without going through the full list-evaluation dispatch.
65
+ */
66
+ export function applyCallableWithContext(
67
+ fn: CljValue,
68
+ args: CljValue[],
69
+ ctx: EvaluationContext,
70
+ callEnv: Env
71
+ ): CljValue {
72
+ if (isAFunction(fn)) {
73
+ return applyFunctionWithContext(fn, args, ctx, callEnv)
74
+ }
75
+ if (isKeyword(fn)) {
76
+ const target = args[0]
77
+ const defaultVal = args.length > 1 ? args[1] : cljNil()
78
+ if (isMap(target)) {
79
+ const entry = target.entries.find(([k]) => isEqual(k, fn))
80
+ return entry ? entry[1] : defaultVal
81
+ }
82
+ return defaultVal
83
+ }
84
+ if (isMap(fn)) {
85
+ if (args.length === 0) {
86
+ throw new EvaluationError('Map used as function requires at least one argument', { fn, args })
87
+ }
88
+ const key = args[0]
89
+ const defaultVal = args.length > 1 ? args[1] : cljNil()
90
+ const entry = fn.entries.find(([k]) => isEqual(k, key))
91
+ return entry ? entry[1] : defaultVal
92
+ }
93
+ throw new EvaluationError(`${printString(fn)} is not a callable value`, {
94
+ fn,
95
+ args,
96
+ })
97
+ }
98
+
99
+ export function applyMacroWithContext(
100
+ macro: CljMacro,
101
+ rawArgs: CljValue[],
102
+ ctx: EvaluationContext
103
+ ): CljValue {
104
+ const arity = resolveArity(macro.arities, rawArgs.length)
105
+ const localEnv = bindParams(
106
+ arity.params,
107
+ arity.restParam,
108
+ rawArgs,
109
+ macro.env,
110
+ ctx,
111
+ macro.env
112
+ )
113
+ return ctx.evaluateForms(arity.body, localEnv)
114
+ }
@@ -0,0 +1,174 @@
1
+ import { isList, isMap, isSymbol, isVector } from '../assertions'
2
+ import { extend } from '../env'
3
+ import { EvaluationError } from '../errors'
4
+ import { cljList, cljNil } from '../factories'
5
+ import type {
6
+ Arity,
7
+ CljValue,
8
+ CljVector,
9
+ DestructurePattern,
10
+ Env,
11
+ EvaluationContext,
12
+ } from '../types'
13
+ import { destructureBindings } from './destructure'
14
+
15
+ export class RecurSignal {
16
+ args: CljValue[]
17
+ constructor(args: CljValue[]) {
18
+ this.args = args
19
+ }
20
+ }
21
+
22
+ export function parseParamVector(
23
+ args: CljVector,
24
+ env: Env
25
+ ): { params: DestructurePattern[]; restParam: DestructurePattern | null } {
26
+ const ampIdx = args.value.findIndex((a) => isSymbol(a) && a.name === '&')
27
+ let params: DestructurePattern[] = []
28
+ let restParam: DestructurePattern | null = null
29
+ if (ampIdx === -1) {
30
+ params = args.value as DestructurePattern[]
31
+ } else {
32
+ const ampsCount = args.value.filter(
33
+ (a) => isSymbol(a) && a.name === '&'
34
+ ).length
35
+ if (ampsCount > 1) {
36
+ throw new EvaluationError('& can only appear once', { args, env })
37
+ }
38
+ if (ampIdx !== args.value.length - 2) {
39
+ throw new EvaluationError('& must be second-to-last argument', {
40
+ args,
41
+ env,
42
+ })
43
+ }
44
+ params = args.value.slice(0, ampIdx) as DestructurePattern[]
45
+ restParam = args.value[ampIdx + 1] as DestructurePattern
46
+ }
47
+ return { params, restParam }
48
+ }
49
+
50
+ export function parseArities(forms: CljValue[], env: Env): Arity[] {
51
+ if (forms.length === 0) {
52
+ throw new EvaluationError(
53
+ 'fn/defmacro requires at least a parameter vector',
54
+ {
55
+ forms,
56
+ env,
57
+ }
58
+ )
59
+ }
60
+
61
+ if (isVector(forms[0])) {
62
+ const paramVec = forms[0]
63
+ const { params, restParam } = parseParamVector(paramVec, env)
64
+ return [{ params, restParam, body: forms.slice(1) }]
65
+ }
66
+
67
+ if (isList(forms[0])) {
68
+ const arities: Arity[] = []
69
+ for (const form of forms) {
70
+ if (!isList(form) || form.value.length === 0) {
71
+ throw new EvaluationError(
72
+ 'Multi-arity clause must be a list starting with a parameter vector',
73
+ { form, env }
74
+ )
75
+ }
76
+ const paramVec = form.value[0]
77
+ if (!isVector(paramVec)) {
78
+ throw new EvaluationError(
79
+ 'First element of arity clause must be a parameter vector',
80
+ { paramVec, env }
81
+ )
82
+ }
83
+ const { params, restParam } = parseParamVector(paramVec, env)
84
+ arities.push({ params, restParam, body: form.value.slice(1) })
85
+ }
86
+
87
+ const variadicCount = arities.filter((a) => a.restParam !== null).length
88
+ if (variadicCount > 1) {
89
+ throw new EvaluationError(
90
+ 'At most one variadic arity is allowed per function',
91
+ { forms, env }
92
+ )
93
+ }
94
+
95
+ return arities
96
+ }
97
+
98
+ throw new EvaluationError(
99
+ 'fn/defmacro expects a parameter vector or arity clauses',
100
+ { forms, env }
101
+ )
102
+ }
103
+
104
+ export function bindParams(
105
+ params: DestructurePattern[],
106
+ restParam: DestructurePattern | null,
107
+ args: CljValue[],
108
+ outerEnv: Env,
109
+ ctx: EvaluationContext,
110
+ bindEnv: Env
111
+ ): Env {
112
+ if (restParam === null) {
113
+ if (args.length !== params.length) {
114
+ throw new EvaluationError(
115
+ `Arguments length mismatch: fn accepts ${params.length} arguments, but ${args.length} were provided`,
116
+ { params, args, outerEnv }
117
+ )
118
+ }
119
+ } else {
120
+ if (args.length < params.length) {
121
+ throw new EvaluationError(
122
+ `Arguments length mismatch: fn expects at least ${params.length} arguments, but ${args.length} were provided`,
123
+ { params, args, outerEnv }
124
+ )
125
+ }
126
+ }
127
+
128
+ const allPairs: [string, CljValue][] = []
129
+
130
+ for (let i = 0; i < params.length; i++) {
131
+ allPairs.push(...destructureBindings(params[i], args[i], ctx, bindEnv))
132
+ }
133
+
134
+ if (restParam !== null) {
135
+ const restArgs = args.slice(params.length)
136
+ let restValue: CljValue
137
+ if (isMap(restParam) && restArgs.length > 0) {
138
+ const entries: [CljValue, CljValue][] = []
139
+ for (let i = 0; i < restArgs.length; i += 2) {
140
+ entries.push([restArgs[i], restArgs[i + 1] ?? cljNil()])
141
+ }
142
+ restValue = { kind: 'map', entries }
143
+ } else {
144
+ restValue = restArgs.length > 0 ? cljList(restArgs) : cljNil()
145
+ }
146
+ allPairs.push(...destructureBindings(restParam, restValue, ctx, bindEnv))
147
+ }
148
+
149
+ return extend(
150
+ allPairs.map(([n]) => n),
151
+ allPairs.map(([, v]) => v),
152
+ outerEnv
153
+ )
154
+ }
155
+
156
+ export function resolveArity(arities: Arity[], argCount: number): Arity {
157
+ const exactMatch = arities.find(
158
+ (a) => a.restParam === null && a.params.length === argCount
159
+ )
160
+ if (exactMatch) return exactMatch
161
+
162
+ const variadicMatch = arities.find(
163
+ (a) => a.restParam !== null && argCount >= a.params.length
164
+ )
165
+ if (variadicMatch) return variadicMatch
166
+
167
+ const counts = arities.map((a) =>
168
+ a.restParam ? `${a.params.length}+` : `${a.params.length}`
169
+ )
170
+ throw new EvaluationError(
171
+ `No matching arity for ${argCount} arguments. Available arities: ${counts.join(', ')}`,
172
+ { arities, argCount }
173
+ )
174
+ }
@@ -0,0 +1,25 @@
1
+ import { cljMap, cljVector } from '../factories'
2
+ import type { CljMap, CljValue, CljVector, EvaluationContext } from '../types'
3
+ import type { Env } from '../types'
4
+
5
+ export function evaluateVector(
6
+ vector: CljVector,
7
+ env: Env,
8
+ ctx: EvaluationContext
9
+ ): CljValue {
10
+ return cljVector(vector.value.map((v) => ctx.evaluate(v, env)))
11
+ }
12
+
13
+ export function evaluateMap(
14
+ map: CljMap,
15
+ env: Env,
16
+ ctx: EvaluationContext
17
+ ): CljValue {
18
+ let entries: [CljValue, CljValue][] = []
19
+ for (const [key, value] of map.entries) {
20
+ const evaluatedKey = ctx.evaluate(key, env)
21
+ const evaluatedValue = ctx.evaluate(value, env)
22
+ entries.push([evaluatedKey, evaluatedValue])
23
+ }
24
+ return cljMap(entries)
25
+ }