fez-lisp 1.0.0

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/src/enums.js ADDED
@@ -0,0 +1,79 @@
1
+ // AST enums
2
+ export const WORD = 'w'
3
+ export const APPLY = 'f'
4
+ export const VALUE = 'v'
5
+ export const TYPE = 't'
6
+ export const ATOM = 'a'
7
+ // tokeniser enums
8
+ export const PLACEHOLDER = '.'
9
+ // keywords aliases
10
+ export const KEYWORDS = {
11
+ BIT_TYPE: 'Bit',
12
+ STRING_TYPE: 'String',
13
+ NUMBER_TYPE: 'Number',
14
+ BOOLEAN_TYPE: 'Boolean',
15
+ FUNCTION_TYPE: 'Function',
16
+ ARRAY_TYPE: 'Array',
17
+ CHAR_CODE_TYPE: 'Char-Code',
18
+ CHAR_TYPE: 'Char',
19
+
20
+ CAST_TYPE: 'type',
21
+ CONCATENATION: 'concatenate',
22
+ ARRAY_OR_STRING_LENGTH: 'length',
23
+ IS_ARRAY: 'Array?',
24
+ IS_NUMBER: 'Number?',
25
+ IS_STRING: 'String?',
26
+ IS_FUNCTION: 'Function?',
27
+
28
+ ADDITION: '+',
29
+ SUBTRACTION: '-',
30
+ MULTIPLICATION: '*',
31
+ DIVISION: '/',
32
+ REMAINDER_OF_DIVISION: 'mod',
33
+
34
+ BITWISE_AND: '&',
35
+ BITWISE_OR: '|',
36
+ BITWISE_NOT: '~',
37
+ BITWISE_XOR: '^',
38
+ BITWISE_LEFT_SHIFT: '<<',
39
+ BITWISE_RIGHT_SHIFT: '>>',
40
+ BITWISE_UNSIGNED_RIGHT_SHIFT: '>>>',
41
+ ATOM: 'Atom',
42
+ IS_ATOM: 'Atom?',
43
+ FIRST_ARRAY: 'car',
44
+ REST_ARRAY: 'cdr',
45
+ GET_ARRAY: 'get',
46
+
47
+ BLOCK: 'do',
48
+
49
+ MERGE: 'merge',
50
+ ANONYMOUS_FUNCTION: 'lambda',
51
+
52
+ IF: 'if',
53
+ UNLESS: 'unless',
54
+ WHEN: 'when',
55
+ OTHERWISE: 'otherwise',
56
+ CONDITION: 'cond',
57
+
58
+ NOT: 'not',
59
+ EQUAL: '=',
60
+ LESS_THAN: '<',
61
+ GREATHER_THAN: '>',
62
+ GREATHER_THAN_OR_EQUAL: '>=',
63
+ LESS_THAN_OR_EQUAL: '<=',
64
+ AND: 'and',
65
+ OR: 'or',
66
+ CALL_FUNCTION: 'apply',
67
+ DEFINE_VARIABLE: 'let',
68
+
69
+ PIPE: 'go',
70
+ THROW_ERROR: 'throw',
71
+ TAIL_CALLS_OPTIMISED_RECURSIVE_FUNCTION: 'let*',
72
+ IMMUTABLE_FUNCTION: 'safety',
73
+ NOT_COMPILED_BLOCK: 'void',
74
+ LOG: 'log!',
75
+
76
+ TEST_CASE: 'case',
77
+ TEST_BED: 'assert',
78
+ SERIALISE: 'serialise',
79
+ }
@@ -0,0 +1,29 @@
1
+ import { APPLY, ATOM, KEYWORDS, TYPE, VALUE, WORD } from './enums.js'
2
+ import { keywords } from './tokeniser.js'
3
+ import { stringifyArgs } from './utils.js'
4
+
5
+ export const evaluate = (expression, env) => {
6
+ const [first, ...rest] = Array.isArray(expression) ? expression : [expression]
7
+ if (first == undefined) return []
8
+ switch (first[TYPE]) {
9
+ case WORD: {
10
+ const word = env[first[VALUE]]
11
+ if (word == undefined)
12
+ throw new ReferenceError(`Undefined variable ${first[VALUE]}.`)
13
+ return word
14
+ }
15
+ case APPLY:
16
+ const apply = env[first[VALUE]]
17
+ if (typeof apply !== 'function')
18
+ throw new TypeError(`${first[VALUE]} is not a (function).`)
19
+ return apply(rest, env)
20
+ case ATOM:
21
+ return first[VALUE]
22
+ default:
23
+ throw new ReferenceError(
24
+ `Attempting to acces Undefined near ${stringifyArgs(expression)}`
25
+ )
26
+ }
27
+ }
28
+ export const run = (tree, env = {}) =>
29
+ keywords[KEYWORDS.BLOCK](tree, { ...keywords, ...env })
package/src/parser.js ADDED
@@ -0,0 +1,45 @@
1
+ import { APPLY, ATOM, TYPE, VALUE, WORD } from './enums.js'
2
+ import { escape } from './utils.js'
3
+
4
+ export const parse = (source) => {
5
+ const tree = []
6
+ let head = tree,
7
+ stack = [tree],
8
+ acc = ''
9
+ for (let i = 0; i < source.length; ++i) {
10
+ const cursor = source[i]
11
+ if (cursor === '"') {
12
+ acc += '"'
13
+ ++i
14
+ while (source[i] !== '"') {
15
+ if (source[i] === '\\') acc += escape(source[++i])
16
+ else acc += source[i]
17
+ ++i
18
+ }
19
+ }
20
+ if (cursor === '(') {
21
+ head.push([])
22
+ stack.push(head)
23
+ head = head.at(-1)
24
+ } else if (cursor === ')' || cursor === ' ') {
25
+ let token = acc
26
+ acc = ''
27
+ if (token) {
28
+ if (!head.length) head.push({ [TYPE]: APPLY, [VALUE]: token })
29
+ else if (token.match(/^"([^"]*)"/))
30
+ head.push({
31
+ [TYPE]: ATOM,
32
+ [VALUE]: token.substring(1, token.length - 1),
33
+ })
34
+ else if (token.match(/^-?[0-9]\d*(\.\d+)?$/))
35
+ head.push({
36
+ [TYPE]: ATOM,
37
+ [VALUE]: Number(token),
38
+ })
39
+ else head.push({ [TYPE]: WORD, [VALUE]: token })
40
+ }
41
+ if (cursor === ')') head = stack.pop()
42
+ } else acc += cursor
43
+ }
44
+ return tree
45
+ }