fez-lisp 1.6.26 → 1.6.28

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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "fez-lisp",
3
3
  "description": "Lisp interpreted & compiled to JavaScript",
4
4
  "author": "AT290690",
5
- "version": "1.6.26",
5
+ "version": "1.6.28",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "keywords": [
@@ -0,0 +1,165 @@
1
+ import { serialise } from '../editor/utils.js'
2
+ import {
3
+ APPLY,
4
+ ATOM,
5
+ KEYWORDS,
6
+ TYPE,
7
+ VALUE,
8
+ WORD,
9
+ TRUE,
10
+ FALSE,
11
+ STATIC_TYPES
12
+ } from './keywords.js'
13
+ import { isLeaf, LISP } from './parser.js'
14
+ const keywords = {
15
+ [KEYWORDS.REMAINDER_OF_DIVISION]: (args, env) =>
16
+ evaluate(args[0], env) % evaluate(args[1], env),
17
+ [KEYWORDS.DIVISION]: (args, env) =>
18
+ evaluate(args[0], env) / evaluate(args[1], env),
19
+ [KEYWORDS.ARRAY_LENGTH]: (args, env) => evaluate(args[0], env).length,
20
+ [KEYWORDS.IS_ATOM]: (args, env) =>
21
+ +(typeof evaluate(args[0], env) === 'number'),
22
+ [KEYWORDS.IS_LAMBDA]: (args, env) =>
23
+ +(typeof evaluate(args[0], env) === 'function'),
24
+ [KEYWORDS.ADDITION]: (args, env) =>
25
+ evaluate(args[0], env) + evaluate(args[1], env),
26
+ [KEYWORDS.MULTIPLICATION]: (args, env) =>
27
+ evaluate(args[0], env) * evaluate(args[1], env),
28
+ [KEYWORDS.SUBTRACTION]: (args, env) =>
29
+ evaluate(args[0], env) - evaluate(args[1], env),
30
+ [KEYWORDS.CREATE_ARRAY]: (args, env) =>
31
+ args.length ? args.map((x) => evaluate(x, env)) : [],
32
+ [KEYWORDS.GET_ARRAY]: (args, env) =>
33
+ evaluate(args[0], env)[evaluate(args[1], env)],
34
+ [KEYWORDS.BLOCK]: (args, env) =>
35
+ args.reduce((_, x) => evaluate(x, env), FALSE),
36
+ [KEYWORDS.NOT]: (args, env) => +!evaluate(args[0], env),
37
+ [KEYWORDS.EQUAL]: (args, env) =>
38
+ +(evaluate(args[0], env) === evaluate(args[1], env)),
39
+ [KEYWORDS.LESS_THAN]: (args, env) =>
40
+ +(evaluate(args[0], env) < evaluate(args[1], env)),
41
+ [KEYWORDS.GREATHER_THAN]: (args, env) =>
42
+ +(evaluate(args[0], env) > evaluate(args[1], env)),
43
+ [KEYWORDS.GREATHER_THAN_OR_EQUAL]: (args, env) =>
44
+ +(evaluate(args[0], env) >= evaluate(args[1], env)),
45
+ [KEYWORDS.LESS_THAN_OR_EQUAL]: (args, env) =>
46
+ +(evaluate(args[0], env) <= evaluate(args[1], env)),
47
+ [KEYWORDS.AND]: (args, env) =>
48
+ !evaluate(args[0], env) ? FALSE : evaluate(args[1], env),
49
+ [KEYWORDS.OR]: (args, env) =>
50
+ evaluate(args[0], env) ? TRUE : evaluate(args[1], env),
51
+ [KEYWORDS.CALL_FUNCTION]: (args, env) => evaluate(args.pop(), env)(args, env),
52
+ [KEYWORDS.DEFINE_VARIABLE]: (args, env) =>
53
+ (env[args[0][VALUE]] = evaluate(args[1], env)),
54
+ [KEYWORDS.BITWISE_AND]: (args, env) =>
55
+ evaluate(args[0], env) & evaluate(args[1], env),
56
+ [KEYWORDS.BITWISE_NOT]: (args, env) => ~evaluate(args[0], env),
57
+ [KEYWORDS.BITWISE_OR]: (args, env) =>
58
+ evaluate(args[0], env) | evaluate(args[1], env),
59
+ [KEYWORDS.BITWISE_XOR]: (args, env) =>
60
+ evaluate(args[0], env) ^ evaluate(args[1], env),
61
+ [KEYWORDS.BITWISE_LEFT_SHIFT]: (args, env) =>
62
+ evaluate(args[0], env) << evaluate(args[1], env),
63
+ [KEYWORDS.BITWISE_RIGHT_SHIFT]: (args, env) =>
64
+ evaluate(args[0], env) >> evaluate(args[1], env),
65
+ [KEYWORDS.IF]: (args, env) =>
66
+ evaluate(args[0], env) ? evaluate(args[1], env) : evaluate(args[2], env),
67
+ [KEYWORDS.LOOP]: (args, env) => {
68
+ while (evaluate(args[0], env) === TRUE) evaluate(args[1], env)
69
+ return -1
70
+ },
71
+ [KEYWORDS.SET_ARRAY]: (args, env) => {
72
+ const array = evaluate(args[0], env)
73
+ array[evaluate(args[1], env)] = evaluate(args[2], env)
74
+ return array
75
+ },
76
+ [KEYWORDS.POP_ARRAY]: (args, env) => {
77
+ const array = evaluate(args[0], env)
78
+ array.pop()
79
+ return array
80
+ },
81
+ [KEYWORDS.ANONYMOUS_FUNCTION]: (args, env) => {
82
+ const params = args.slice(0, -1)
83
+ return (props = [], scope) => {
84
+ const localEnv = Object.create(env)
85
+ for (let i = 0; i < props.length; ++i)
86
+ localEnv[params[i][VALUE]] = evaluate(props[i], scope)
87
+ return evaluate(args.at(-1), localEnv)
88
+ }
89
+ },
90
+ // Only for type checking
91
+ [STATIC_TYPES.UNKNOWN]: (args, env) => evaluate(args[0], env),
92
+ [STATIC_TYPES.ANY]: (args, env) => evaluate(args[0], env),
93
+
94
+ [STATIC_TYPES.ATOM]: (args, env) => evaluate(args[0], env),
95
+ [STATIC_TYPES.ABSTRACTION]: (args, env) => evaluate(args[0], env),
96
+ [STATIC_TYPES.COLLECTION]: (args, env) => evaluate(args[0], env),
97
+
98
+ [STATIC_TYPES.BOOLEAN]: (args, env) => evaluate(args[0], env),
99
+ [STATIC_TYPES.NUMBER]: (args, env) => evaluate(args[0], env),
100
+ [STATIC_TYPES.NUMBERS]: (args, env) => evaluate(args[0], env),
101
+ [STATIC_TYPES.COLLECTIONS]: (args, env) => evaluate(args[0], env),
102
+ [STATIC_TYPES.ABSTRACTIONS]: (args, env) => evaluate(args[0], env),
103
+ [STATIC_TYPES.BOOLEANS]: (args, env) => evaluate(args[0], env)
104
+ }
105
+ const debugStack = []
106
+ const evaluate = (exp, env = keywords) => {
107
+ const [head, ...tail] = isLeaf(exp) ? [exp] : exp
108
+ if (head == undefined) return []
109
+ const type = head[TYPE]
110
+ const value = head[VALUE]
111
+ let res
112
+ switch (type) {
113
+ case WORD:
114
+ res = env[value]
115
+ return res
116
+ case APPLY:
117
+ res = env[value](tail, env)
118
+ if (
119
+ value !== KEYWORDS.BLOCK &&
120
+ value !== KEYWORDS.CALL_FUNCTION &&
121
+ value !== KEYWORDS.ANONYMOUS_FUNCTION &&
122
+ value !== KEYWORDS.DEFINE_VARIABLE
123
+ ) {
124
+ // debugStack.push(
125
+ // `\x1b[31m${LISP.source(exp)}\x1b[32m\n${
126
+ // typeof res === 'function' ? '(lambda)' : serialise(res)
127
+ // }\x1b[0m`
128
+ // )
129
+ const out = typeof res === 'function' ? '(lambda)' : serialise(res)
130
+ if (debugStack.at(-1)?.result !== out)
131
+ debugStack.push({
132
+ function: value,
133
+ source: LISP.source(exp),
134
+ result: out
135
+ })
136
+ // else debugStack[debugStack.length - 1].src += LISP.source(exp)
137
+ }
138
+ return res
139
+ case ATOM:
140
+ res = value
141
+ return res
142
+ }
143
+ }
144
+ export const debugStackToString = (stack) =>
145
+ stack.map(({ source, result }) => `${source}\n${result}`).join('\n')
146
+ export const startDebug = (ast, speed = 250, start, end) => {
147
+ debugStack.length = 0
148
+ evaluate(ast)
149
+ start = start ? debugStack.findIndex(start) : 0
150
+ end = end ? debugStack.findIndex(end) : debugStack.length
151
+ const stack = debugStack.slice(start, end).reverse()
152
+ if (speed !== 0) {
153
+ const rec = () => {
154
+ setTimeout(() => {
155
+ if (stack.length) {
156
+ const { source, result } = stack.pop()
157
+ console.log(`\x1b[31m${source}\x1b[32m\n${result}\x1b[0m`)
158
+ rec()
159
+ }
160
+ }, speed)
161
+ }
162
+ rec()
163
+ }
164
+ return stack
165
+ }
package/src/keywords.js CHANGED
@@ -3,6 +3,7 @@ export const VALUE = 1
3
3
  export const APPLY = 0
4
4
  export const WORD = 1
5
5
  export const ATOM = 2
6
+ export const FLAG = 3
6
7
  export const TRUE = 1
7
8
  export const FALSE = 0
8
9
  export const PLACEHOLDER = '.'
package/src/types.js CHANGED
@@ -5,11 +5,13 @@ import {
5
5
  APPLY,
6
6
  ATOM,
7
7
  DEBUG,
8
+ FLAG,
8
9
  KEYWORDS,
9
10
  PLACEHOLDER,
10
11
  STATIC_TYPES,
11
12
  TYPE,
12
- VALUE
13
+ VALUE,
14
+ WORD
13
15
  } from './keywords.js'
14
16
  import { isLeaf } from './parser.js'
15
17
  import { shakedList, stringifyArgs } from './utils.js'
@@ -1390,24 +1392,49 @@ export const formatInlineType = (name, env) => {
1390
1392
  : formatSubType(getTypes(stats))
1391
1393
  : name
1392
1394
  }
1395
+ export const formatAstSubType = (T) => {
1396
+ switch (T[0]) {
1397
+ case COLLECTION:
1398
+ return `${
1399
+ T[1] instanceof Set
1400
+ ? [...T[1]]
1401
+ .map((x) =>
1402
+ x === COLLECTION
1403
+ ? formatAstSubType([x])
1404
+ : toTypeNamesAnyToUknown(x)
1405
+ )
1406
+ .join(' ') || toTypeNames(UNKNOWN)
1407
+ : toTypeNames(UNKNOWN)
1408
+ }[]`
1409
+ case ATOM:
1410
+ return `${
1411
+ T[1] instanceof Set
1412
+ ? [...T[1]].map((x) => toTypeNamesAnyToUknown(x)).join(' ')
1413
+ : toTypeNamesAnyToUknown(NUMBER)
1414
+ }`
1415
+ default:
1416
+ return toTypeNamesAnyToUknown(T[0])
1417
+ }
1418
+ }
1393
1419
  export const formatAstTypes = (name, env) => {
1394
1420
  const stats = env[name][STATS]
1395
1421
  return stats
1396
1422
  ? getType(stats) === APPLY
1397
1423
  ? [
1398
- stats[ARG_COUNT] === VARIADIC
1399
- ? '...'
1424
+ FLAG,
1425
+ ...(stats[ARG_COUNT] === VARIADIC
1426
+ ? []
1400
1427
  : stats[ARGUMENTS]?.length
1401
1428
  ? stats[ARGUMENTS].map((x, i) =>
1402
1429
  getType(x[STATS]) === APPLY
1403
- ? formatType(i, stats[ARGUMENTS])
1404
- : formatSubType(getTypes(x[STATS]))
1430
+ ? formatAstTypes(i, stats[ARGUMENTS])
1431
+ : formatAstSubType(getTypes(x[STATS]))
1405
1432
  )
1406
- : '',
1407
- formatSubType(getReturns(stats))
1433
+ : []),
1434
+ formatAstSubType(getReturns(stats))
1408
1435
  ]
1409
- : formatSubType(getTypes(stats))
1410
- : name
1436
+ : [FLAG, formatAstSubType(getTypes(stats))]
1437
+ : [FLAG, name]
1411
1438
  }
1412
1439
  export const validateLambda = (exp, name) => {
1413
1440
  if (exp.length === 1)
package/src/utils.js CHANGED
@@ -2,6 +2,7 @@ import std from '../lib/baked/std.js'
2
2
  import {
3
3
  APPLY,
4
4
  ATOM,
5
+ FLAG,
5
6
  KEYWORDS,
6
7
  STATIC_TYPES,
7
8
  TYPE,
@@ -16,10 +17,16 @@ import {
16
17
  handleUnbalancedQuotes
17
18
  } from './macros.js'
18
19
  import { enhance, OPTIMIZATIONS } from './enhance.js'
19
- import { type } from './check.js'
20
+ import { type, typeCheck, withScope } from './check.js'
20
21
  import stdT from '../lib/baked/std-T.js'
21
- import { definedTypes, withCtxTypes } from './types.js'
22
+ import {
23
+ definedTypes,
24
+ filteredDefinedTypes,
25
+ formatAstTypes,
26
+ withCtxTypes
27
+ } from './types.js'
22
28
  import { compile } from './compiler.js'
29
+ import { startDebug } from './debugger.js'
23
30
  export const logError = (error) =>
24
31
  console.log('\x1b[31m', `\n${error}\n`, '\x1b[0m')
25
32
  export const logSuccess = (output) => console.log('\x1b[32m', output, '\x1b[0m')
@@ -359,6 +366,7 @@ export const isInputVariable = (x) =>
359
366
  x[1][VALUE] === 'INPUT'
360
367
 
361
368
  export const UTILS = {
369
+ startDebug,
362
370
  handleUnbalancedQuotes,
363
371
  handleUnbalancedParens,
364
372
  logError,
@@ -520,3 +528,34 @@ export const fez = (ast, c = false) => {
520
528
  return [null, err]
521
529
  }
522
530
  }
531
+
532
+ export const toTypedAst = (ast, userDefinedTypes) => {
533
+ try {
534
+ const typeSet = (Types, name, env, exp) => {
535
+ Types.set(withScope(name, env), () => {
536
+ if (exp.at(-1)[TYPE] !== FLAG) exp.push(formatAstTypes(name, env))
537
+ else exp[exp.length - 1] = formatAstTypes(name, env)
538
+ return ''
539
+ })
540
+ }
541
+ const types = typeCheck(
542
+ ast,
543
+ withCtxTypes(
544
+ userDefinedTypes
545
+ ? {
546
+ ...definedTypes(filteredDefinedTypes(ast, std, stdT)),
547
+ ...definedTypes(LISP.parse(removeNoCode(userDefinedTypes)))
548
+ }
549
+ : definedTypes(filteredDefinedTypes(ast, std, stdT))
550
+ ),
551
+ typeSet
552
+ )
553
+ for (const v of types[1].values()) v()
554
+ // types[0][1][1].slice(1)
555
+ return types
556
+ } catch (error) {
557
+ logError(error.message)
558
+ return []
559
+ }
560
+ }
561
+ export const atst = (ast, ctx) => toTypedAst(ast, ctx)[0]