functionalscript 0.0.525 → 0.0.526

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.
@@ -2,8 +2,8 @@ const operator = require('../../types/function/operator/module.f.cjs')
2
2
  const range_map = require('../../types/range_map/module.f.cjs')
3
3
  const { merge, fromRange, get } = range_map
4
4
  const list = require('../../types/list/module.f.cjs')
5
- const sorted_list = require('../../types/sorted_list/module.f.cjs')
6
- const { unsafeCmp } = require('../../types/function/compare/module.f.cjs')
5
+ const map = require('../../types/map/module.f.cjs')
6
+ const { at } = map
7
7
  const _range = require('../../types/range/module.f.cjs')
8
8
  const { one } = _range
9
9
  const { empty, stateScan, flat, toArray, reduce: listReduce, scan } = list
@@ -32,6 +32,8 @@ const {
32
32
  //
33
33
  space,
34
34
  quotationMark,
35
+ leftParenthesis,
36
+ rightParenthesis,
35
37
  plusSign,
36
38
  comma,
37
39
  hyphenMinus,
@@ -90,7 +92,24 @@ const {
90
92
 
91
93
  /** @typedef {{readonly kind: 'error', message: ErrorMessage}} ErrorToken */
92
94
 
93
- /** @typedef {{readonly kind: '{' | '}' | ':' | ',' | '[' | ']' | 'true' | 'false' | 'null'}} SimpleToken */
95
+ /** @typedef {{readonly kind: 'ws'}} WhitespaceToken */
96
+
97
+ /** @typedef {{readonly kind: 'true'}} TrueToken */
98
+
99
+ /** @typedef {{readonly kind: 'false'}} FalseToken */
100
+
101
+ /** @typedef {{readonly kind: 'null'}} NullToken */
102
+
103
+ /**
104
+ * @typedef {|
105
+ * {readonly kind: 'arguments' | 'await' | 'break' | 'case' | 'catch' | 'class' | 'const' | 'continue' } |
106
+ * {readonly kind: 'debugger' | 'default' | 'delete' | 'do' | 'else' | 'enum' | 'eval' | 'export' } |
107
+ * {readonly kind: 'extends' | 'finally' | 'for' | 'function' | 'if' | 'implements' | 'import' | 'in' } |
108
+ * {readonly kind: 'instanceof' | 'interface' | 'let' | 'new' | 'package' | 'private' | 'protected' | 'public' } |
109
+ * {readonly kind: 'return' | 'static' | 'super' | 'switch' | 'this' | 'throw' | 'try' | 'typeof' } |
110
+ * {readonly kind: 'var' | 'void' | 'while' | 'with' | 'yield' }
111
+ * } KeywordToken
112
+ */
94
113
 
95
114
  /**
96
115
  * @typedef {{
@@ -101,6 +120,8 @@ const {
101
120
 
102
121
  /**
103
122
  * @typedef {|
123
+ * {readonly kind: '{' | '}' | ':' | ',' | '[' | ']' } |
124
+ * {readonly kind: '(' | ')' } |
104
125
  * {readonly kind: '==' | '!=' | '===' | '!==' | '>' | '>=' | '<' | '<=' } |
105
126
  * {readonly kind: '+' | '-' | '*' | '/' | '%' | '++' | '--' | '**' } |
106
127
  * {readonly kind: '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '**='} |
@@ -114,7 +135,11 @@ const {
114
135
 
115
136
  /**
116
137
  * @typedef {|
117
- * SimpleToken |
138
+ * KeywordToken |
139
+ * TrueToken |
140
+ * FalseToken |
141
+ * NullToken |
142
+ * WhitespaceToken |
118
143
  * StringToken |
119
144
  * NumberToken |
120
145
  * ErrorToken |
@@ -134,17 +159,27 @@ const rangeSetWhiteSpace = [
134
159
  ]
135
160
 
136
161
  const rangeSetTerminalForNumber = [
137
- one(ht),
138
- one(lf),
139
- one(cr),
140
- one(space),
141
- one(quotationMark),
162
+ ...rangeSetWhiteSpace,
163
+ one(exclamationMark),
164
+ one(percentSign),
165
+ one(ampersand),
166
+ one(leftParenthesis),
167
+ one(rightParenthesis),
168
+ one(asterisk),
142
169
  one(comma),
143
- one(leftCurlyBracket),
144
- one(rightCurlyBracket),
170
+ one(solidus),
171
+ one(colon),
172
+ one(lessThanSign),
173
+ one(equalsSign),
174
+ one(greaterThanSign),
175
+ one(questionMark),
176
+ one(circumflexAccent),
145
177
  one(leftSquareBracket),
146
178
  one(rightSquareBracket),
147
- one(colon)
179
+ one(leftCurlyBracket),
180
+ one(verticalLine),
181
+ one(rightCurlyBracket),
182
+ one(tilde),
148
183
  ]
149
184
 
150
185
  const rangeSmallAF = range('af')
@@ -161,17 +196,26 @@ const rangeOpStart = [
161
196
  one(exclamationMark),
162
197
  one(percentSign),
163
198
  one(ampersand),
199
+ one(leftParenthesis),
200
+ one(rightParenthesis),
164
201
  one(asterisk),
202
+ one(plusSign),
203
+ one(comma),
204
+ one(hyphenMinus),
205
+ one(fullStop),
206
+ one(solidus),
207
+ one(colon),
165
208
  one(lessThanSign),
166
209
  one(equalsSign),
167
210
  one(greaterThanSign),
168
211
  one(questionMark),
169
212
  one(circumflexAccent),
213
+ one(leftSquareBracket),
214
+ one(rightSquareBracket),
215
+ one(leftCurlyBracket),
170
216
  one(verticalLine),
171
- one(tilde),
172
- one(plusSign),
173
- one(fullStop),
174
- one(solidus)
217
+ one(rightCurlyBracket),
218
+ one(tilde)
175
219
  ]
176
220
 
177
221
  const rangeId = [digitRange, ...rangeIdStart]
@@ -187,6 +231,7 @@ const rangeId = [digitRange, ...rangeIdStart]
187
231
  * InvalidNumberState |
188
232
  * ParseOperatorState |
189
233
  * ParseMinusState |
234
+ * ParseWhitespaceState |
190
235
  * EofState
191
236
  * } TokenizerState
192
237
  */
@@ -207,6 +252,8 @@ const rangeId = [digitRange, ...rangeIdStart]
207
252
 
208
253
  /** @typedef {{ readonly kind: 'id', readonly value: string}} ParseIdState */
209
254
 
255
+ /** @typedef {{ readonly kind: 'ws'}} ParseWhitespaceState */
256
+
210
257
  /** @typedef {{ readonly kind: 'string', readonly value: string}} ParseStringState */
211
258
 
212
259
  /** @typedef {{ readonly kind: 'escapeChar', readonly value: string}} ParseEscapeCharState */
@@ -341,88 +388,147 @@ const bufferToNumberToken = ({numberKind, value, b}) =>
341
388
  }
342
389
 
343
390
  /**
344
- * @typedef {{
345
- * readonly transitions: sorted_list.SortedArray<number>,
346
- * readonly token: JsToken
347
- * }} OperatorTransition
348
- */
391
+ * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords
392
+ * @type {list.List<map.Entry<JsToken>>}
393
+ */
394
+ const keywordEntries = [
395
+ ['arguments', { kind: 'arguments'}],
396
+ ['await', { kind: 'await'}],
397
+ ['break', { kind: 'break'}],
398
+ ['case', { kind: 'case'}],
399
+ ['catch', { kind: 'catch'}],
400
+ ['class', { kind: 'class'}],
401
+ ['const', { kind: 'const'}],
402
+ ['continue', { kind: 'continue'}],
403
+ ['debugger', { kind: 'debugger'}],
404
+ ['default', { kind: 'default'}],
405
+ ['delete', { kind: 'delete'}],
406
+ ['do', { kind: 'do'}],
407
+ ['else', { kind: 'else'}],
408
+ ['enum', { kind: 'enum'}],
409
+ ['eval', { kind: 'eval'}],
410
+ ['export', { kind: 'export'}],
411
+ ['extends', { kind: 'extends'}],
412
+ ['false', { kind: 'false'}],
413
+ ['finally', { kind: 'finally'}],
414
+ ['for', { kind: 'for'}],
415
+ ['function', { kind: 'function'}],
416
+ ['if', { kind: 'if'}],
417
+ ['implements', { kind: 'implements'}],
418
+ ['import', { kind: 'import'}],
419
+ ['in', { kind: 'in'}],
420
+ ['instanceof', { kind: 'instanceof'}],
421
+ ['interface', { kind: 'interface'}],
422
+ ['let', { kind: 'let'}],
423
+ ['new', { kind: 'new'}],
424
+ ['null', { kind: 'null'}],
425
+ ['package', { kind: 'package'}],
426
+ ['private', { kind: 'private'}],
427
+ ['protected', { kind: 'protected'}],
428
+ ['public', { kind: 'public'}],
429
+ ['return', { kind: 'return'}],
430
+ ['static', { kind: 'static'}],
431
+ ['super', { kind: 'super'}],
432
+ ['switch', { kind: 'switch'}],
433
+ ['this', { kind: 'this'}],
434
+ ['throw', { kind: 'throw'}],
435
+ ['true', { kind: 'true'}],
436
+ ['try', { kind: 'try'}],
437
+ ['typeof', { kind: 'typeof'}],
438
+ ['var', { kind: 'var'}],
439
+ ['void', { kind: 'void'}],
440
+ ['while', { kind: 'while'}],
441
+ ['with', { kind: 'with'}],
442
+ ['yield', { kind: 'yield'}],
443
+ ]
444
+
445
+ const keywordMap = map.fromEntries(keywordEntries)
446
+
447
+ /** @type {(token: JsToken) => Boolean} */
448
+ const isKeywordToken = token => at(token.kind)(keywordMap) !== null
349
449
 
350
450
  /**
351
- * @typedef {{
352
- * readonly[state in string]: OperatorTransition
353
- * }} OperatorDfa
354
- */
451
+ * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators
452
+ * @type {list.List<map.Entry<JsToken>>}
453
+ */
454
+ const operatorEntries = [
455
+ ['!', { kind: '!'}],
456
+ ['!=', { kind: '!='}],
457
+ ['!==', { kind: '!=='}],
458
+ ['%', { kind: '%'}],
459
+ ['%=', { kind: '%='}],
460
+ ['&', { kind: '&'}],
461
+ ['&&', { kind: '&&'}],
462
+ ['&&=', { kind: '&&='}],
463
+ ['&=', { kind: '&='}],
464
+ ['(', { kind: '('}],
465
+ [')', { kind: ')'}],
466
+ ['*', { kind: '*'}],
467
+ ['**', { kind: '**'}],
468
+ ['**=', { kind: '**='}],
469
+ ['*=', { kind: '*='}],
470
+ ['+', { kind: '+'}],
471
+ ['++', { kind: '++'}],
472
+ ['+=', { kind: '+='}],
473
+ [',', { kind: ','}],
474
+ ['-', { kind: '-'}],
475
+ ['--', { kind: '--'}],
476
+ ['-=', { kind: '-='}],
477
+ ['.', { kind: '.'}],
478
+ ['/', { kind: '/'}],
479
+ ['/=', { kind: '/='}],
480
+ [':', { kind: ':'}],
481
+ ['<', { kind: '<'}],
482
+ ['<<', { kind: '<<'}],
483
+ ['<<=', { kind: '<<='}],
484
+ ['<=', {kind: '<='}],
485
+ ['=', { kind: '='}],
486
+ ['==', { kind: '=='}],
487
+ ['===', { kind: '==='}],
488
+ ['=>', {kind: '=>'}],
489
+ ['>', { kind: '>'}],
490
+ ['>=', { kind: '>='}],
491
+ ['>>', { kind: '>>'}],
492
+ ['>>=', {kind: '>>='}],
493
+ ['>>>', {kind: '>>>'}],
494
+ ['>>>=', {kind: '>>>='}],
495
+ ['?', { kind: '?'}],
496
+ ['?.', { kind: '?.'}],
497
+ ['??', { kind: '??'}],
498
+ ['??=', { kind: '??='}],
499
+ ['^', { kind: '^'}],
500
+ ['^=', { kind: '^='}],
501
+ ['[', { kind: '['}],
502
+ [']', { kind: ']'}],
503
+ ['{', { kind: '{'}],
504
+ ['|', { kind: '|'}],
505
+ ['|=', { kind: '|='}],
506
+ ['||', { kind: '||'}],
507
+ ['||=', { kind: '||='}],
508
+ ['}', { kind: '}'}],
509
+ ['~', { kind: '~' }]
510
+ ]
355
511
 
356
- /** @type {OperatorDfa} */
357
- const operatorDfa = {
358
- '!' : { token: { kind: '!' }, transitions: [equalsSign]},
359
- '!=' : { token: { kind: '!=' }, transitions: [equalsSign]},
360
- '!==': { token: { kind: '!=='}, transitions: []},
361
- '%' : { token: { kind: '%' }, transitions: [equalsSign]},
362
- '%=' : { token: { kind: '%=' }, transitions: []},
363
- '&' : { token: { kind: '&' }, transitions: [ampersand, equalsSign]},
364
- '&&' : { token: { kind: '&&' }, transitions: [equalsSign]},
365
- '&&=' : { token: { kind: '&&=' }, transitions: []},
366
- '&=' : { token: { kind: '&=' }, transitions: []},
367
- '*' : { token: { kind: '*' }, transitions: [asterisk, equalsSign]},
368
- '**' : { token: { kind: '**' }, transitions: [equalsSign]},
369
- '**=' : { token: { kind: '**=' }, transitions: []},
370
- '*=' : { token: { kind: '*=' }, transitions: []},
371
- '+' : { token: { kind: '+' }, transitions: [plusSign, equalsSign]},
372
- '++' : { token: { kind: '++' }, transitions: []},
373
- '+=' : { token: { kind: '+=' }, transitions: []},
374
- '-' : { token: { kind: '-' }, transitions: [hyphenMinus, equalsSign]},
375
- '--' : { token: { kind: '--' }, transitions: []},
376
- '-=' : { token: { kind: '-=' }, transitions: []},
377
- '.' : { token: { kind: '.' }, transitions: []},
378
- '/' : { token: { kind: '/' }, transitions: [equalsSign]},
379
- '/=' : { token: { kind: '/=' }, transitions: []},
380
- '<' : { token: { kind: '<' }, transitions: [lessThanSign, equalsSign]},
381
- '<<' : { token: { kind: '<<' }, transitions: [equalsSign]},
382
- '<<=': { token: { kind: '<<='}, transitions: []},
383
- '<=': {token: {kind: '<='}, transitions: []},
384
- '=' : { token: { kind: '=' }, transitions: [equalsSign, greaterThanSign]},
385
- '==' : { token: { kind: '==' }, transitions: [equalsSign]},
386
- '===': { token: { kind: '==='}, transitions: []},
387
- '=>': {token: {kind: '=>'}, transitions: []},
388
- '>' : { token: { kind: '>' }, transitions: [equalsSign, greaterThanSign]},
389
- '>=' : { token: { kind: '>=' }, transitions: []},
390
- '>>': { token: { kind: '>>'}, transitions: [equalsSign, greaterThanSign]},
391
- '>>=': {token: {kind: '>>='}, transitions: []},
392
- '>>>': {token: {kind: '>>>'}, transitions: [equalsSign]},
393
- '>>>=': {token: {kind: '>>>='}, transitions: []},
394
- '?' : { token: { kind: '?' }, transitions: [fullStop, questionMark]},
395
- '?.' : { token: { kind: '?.' }, transitions: []},
396
- '??' : { token: { kind: '??' }, transitions: [equalsSign]},
397
- '??=' : { token: { kind: '??=' }, transitions: []},
398
- '^' : { token: { kind: '^' }, transitions: [equalsSign]},
399
- '^=' : { token: { kind: '^=' }, transitions: []},
400
- '|' : { token: { kind: '|' }, transitions: [equalsSign, verticalLine]},
401
- '|=' : { token: { kind: '|=' }, transitions: []},
402
- '||' : { token: { kind: '||' }, transitions: [equalsSign]},
403
- '||=' : { token: { kind: '||=' }, transitions: []},
404
- '~' : { token: { kind: '~' }, transitions: []}
405
- }
512
+ const operatorMap = map.fromEntries(operatorEntries)
513
+
514
+ /** @type {(op: string) => JsToken} */
515
+ const getOperatorToken = op => at(op)(operatorMap) ?? { kind: 'error', message: 'invalid token' }
516
+
517
+ /** @type {(op: string) => Boolean} */
518
+ const hasOperatorToken = op => at(op)(operatorMap) !== null
406
519
 
407
520
  /** @type {(state: InitialState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
408
521
  const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpected character' }], state])([
409
522
  rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: 'int' }]),
410
523
  rangeSetFunc(rangeIdStart)(() => input => [empty, { kind: 'id', value: fromCharCode(input) }]),
411
- rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state]),
412
- rangeFunc(one(leftCurlyBracket))(state => () => [[{ kind: '{' }], state]),
413
- rangeFunc(one(rightCurlyBracket))(state => () => [[{ kind: '}' }], state]),
414
- rangeFunc(one(colon))(state => () => [[{ kind: ':' }], state]),
415
- rangeFunc(one(comma))(state => () => [[{ kind: ',' }], state]),
416
- rangeFunc(one(leftSquareBracket))(state => () => [[{ kind: '[' }], state]),
417
- rangeFunc(one(rightSquareBracket))(state => () => [[{ kind: ']' }], state]),
524
+ rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, { kind: 'ws' }]),
418
525
  rangeFunc(one(quotationMark))(() => () => [empty, { kind: 'string', value: '' }]),
419
526
  rangeFunc(one(digit0))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: '0' }]),
420
- rangeFunc(one(hyphenMinus))(() => () => [empty, { kind: '-'}]),
421
527
  rangeSetFunc(rangeOpStart)(() => input => [empty, { kind: 'op', value: fromCharCode(input) }])
422
528
  ])
423
529
 
424
530
  /** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
425
- const invalidNumberToToken = state => input =>
531
+ const invalidNumberToToken = () => input =>
426
532
  {
427
533
  const next = tokenizeOp({ kind: 'initial' })(input)
428
534
  return [{ first: { kind: 'error', message: 'invalid number' }, tail: next[0] }, next[1]]
@@ -479,7 +585,7 @@ const expToToken = state => input => {
479
585
  const hyphenMinusToToken = state => input => {
480
586
  switch (state.numberKind) {
481
587
  case 'e': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: { ... state.b, es: -1}, numberKind: 'e-' }]
482
- default: return tokenizeOp({ kind: 'invalidNumber' })(input)
588
+ default: return terminalToToken(state)(input)
483
589
  }
484
590
  }
485
591
 
@@ -599,14 +705,7 @@ const parseUnicodeCharStateOp = create(parseUnicodeCharDefault)([
599
705
  ])
600
706
 
601
707
  /** @type {(s: string) => JsToken} */
602
- const idToToken = s => {
603
- switch (s) {
604
- case 'true': return { kind: 'true' }
605
- case 'false': return { kind: 'false' }
606
- case 'null': return { kind: 'null' }
607
- default: return { kind: 'id', value: s }
608
- }
609
- }
708
+ const idToToken = s => at(s)(keywordMap) ?? { kind: 'id', value: s }
610
709
 
611
710
  /** @type {(state: ParseIdState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
612
711
  const parseIdDefault = state => input => {
@@ -622,14 +721,24 @@ const parseIdStateOp = create(parseIdDefault)([
622
721
 
623
722
  /** @type {(state: ParseOperatorState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
624
723
  const parseOperatorStateOp = state => input => {
625
- const r = operatorDfa[state.value]
626
- const t = sorted_list.find(unsafeCmp)(input)(r.transitions)
627
- if (t !== null)
628
- return [empty, { kind: 'op', value: appendChar(state.value)(input) }]
724
+ const nextStateValue = appendChar(state.value)(input)
725
+ if (hasOperatorToken(nextStateValue))
726
+ return [empty, { kind: 'op', value: nextStateValue }]
727
+ const next = tokenizeOp({ kind: 'initial' })(input)
728
+ return [{ first: getOperatorToken(state.value), tail: next[0] }, next[1]]
729
+ }
730
+
731
+ /** @type {(state: ParseWhitespaceState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
732
+ const parseWhitespaceDefault = state => input => {
629
733
  const next = tokenizeOp({ kind: 'initial' })(input)
630
- return [{ first: r.token, tail: next[0] }, next[1]]
734
+ return [{ first: { kind: 'ws' }, tail: next[0] }, next[1]]
631
735
  }
632
736
 
737
+ /** @type {(state: ParseWhitespaceState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
738
+ const parseWhitespaceStateOp = create(parseWhitespaceDefault)([
739
+ rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state])
740
+ ])
741
+
633
742
  /** @type {(state: EofState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
634
743
  const eofStateOp = create(state => () => [[{ kind: 'error', message: 'eof' }], state])([])
635
744
 
@@ -645,6 +754,7 @@ const tokenizeCharCodeOp = state => {
645
754
  case 'number': return parseNumberStateOp(state)
646
755
  case 'op': return parseOperatorStateOp(state)
647
756
  case '-': return parseMinusStateOp(state)
757
+ case 'ws': return parseWhitespaceStateOp(state)
648
758
  case 'eof': return eofStateOp(state)
649
759
  }
650
760
  }
@@ -666,8 +776,9 @@ const tokenizeEofOp = state => {
666
776
  case 'e-': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'invalidNumber', }]
667
777
  default: return [[bufferToNumberToken(state)], { kind: 'eof' }]
668
778
  }
669
- case 'op': return [[operatorDfa[state.value].token], { kind: 'eof' }]
779
+ case 'op': return [[getOperatorToken(state.value)], { kind: 'eof' }]
670
780
  case '-': return [[{kind: '-'}], { kind: 'eof' }]
781
+ case 'ws': return [[{kind: 'ws'}], { kind: 'eof' }]
671
782
  case 'eof': return [[{ kind: 'error', message: 'eof' }], state]
672
783
  }
673
784
  }
@@ -684,5 +795,7 @@ const tokenize = input => flat(initial(flat([/** @type {list.List<CharCodeOrEof>
684
795
 
685
796
  module.exports = {
686
797
  /** @readonly */
687
- tokenize
798
+ tokenize,
799
+ /** @readonly */
800
+ isKeywordToken
688
801
  }