functionalscript 0.0.327 → 0.0.331

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/README.md CHANGED
@@ -11,6 +11,8 @@ FunctionalScript is a purely functional programming language and a strict subset
11
11
 
12
12
  Create a new FunctionalScript repository on GitHub [here](https://github.com/functionalscript/template/generate).
13
13
 
14
+ Learn more about [FunctionalScript](https://medium.com/@sergeyshandar/purely-functional-programming-in-javascript-91114b1b2dff).
15
+
14
16
  ## Design Principles
15
17
 
16
18
  In FunctionalScript:
@@ -3,18 +3,6 @@ const operator = require('../../types/function/operator')
3
3
  const { concat } = require('../../types/list')
4
4
  const list = require('../../types/list')
5
5
 
6
- /** @typedef {{readonly kind: '{'}} LeftBraceToken */
7
-
8
- /** @typedef {{readonly kind: '}'}} RightBraceToken */
9
-
10
- /** @typedef {{readonly kind: ':'}} ColonToken */
11
-
12
- /** @typedef {{readonly kind: ','}} CommaToken */
13
-
14
- /** @typedef {{readonly kind: '['}} LeftBracketToken */
15
-
16
- /** @typedef {{readonly kind: ']'}} RightBracketToken */
17
-
18
6
  /**
19
7
  * @typedef {{
20
8
  * readonly kind: 'string'
@@ -29,27 +17,15 @@ const list = require('../../types/list')
29
17
  * }} NumberToken
30
18
  * */
31
19
 
32
- /** @typedef {{readonly kind: 'true'}} TrueToken */
33
-
34
- /** @typedef {{readonly kind: 'false'}} FalseToken */
35
-
36
- /** @typedef {{readonly kind: 'null'}} NullToken */
37
-
38
20
  /** @typedef {{readonly kind: 'error', message: ErrorMessage}} ErrorToken */
39
21
 
22
+ /** @typedef {{readonly kind: '{' | '}' | ':' | ',' | '[' | ']' | 'true' | 'false' | 'null'}} SimpleToken */
23
+
40
24
  /**
41
25
  * @typedef {|
42
- * LeftBraceToken |
43
- * RightBraceToken |
44
- * ColonToken |
45
- * CommaToken |
46
- * LeftBracketToken |
47
- * RightBracketToken |
26
+ * SimpleToken |
48
27
  * StringToken |
49
28
  * NumberToken |
50
- * TrueToken |
51
- * FalseToken |
52
- * NullToken |
53
29
  * ErrorToken
54
30
  * } JsonToken
55
31
  */
@@ -74,7 +50,7 @@ const newLine = 0x0a
74
50
  const carriageReturn = 0x0d
75
51
  const space = 0x20
76
52
 
77
- const backslach = 0x5c
53
+ const backslash = 0x5c
78
54
  const slash = 0x2f
79
55
  const backspace = 0x08
80
56
  const formfeed = 0x0c
@@ -140,21 +116,17 @@ const letterZ = 0x7a
140
116
 
141
117
  /** @typedef {{ readonly kind: 'eof'}} EofState */
142
118
 
143
- /** @typedef {number|undefined} JsonCharacter */
119
+ /** @typedef {number|undefined} CharCodeOrEof */
144
120
 
145
- /** @type {(old: string) => (input: JsonCharacter) => string} */
121
+ /** @type {(old: string) => (input: CharCodeOrEof) => string} */
146
122
  const appendChar = old => input => input === undefined ? old : operator.concat(charToString(input))(old)
147
123
 
148
- /** @type {(input: JsonCharacter) => string} */
124
+ /** @type {(input: CharCodeOrEof) => string} */
149
125
  const charToString = input => input === undefined ? '' : String.fromCharCode(input)
150
126
 
151
- /** @type {(state: InitialState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
127
+ /** @type {(state: InitialState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
152
128
  const initialStateOp = initialState => input =>
153
129
  {
154
- if (input === undefined)
155
- {
156
- return[undefined, {kind: 'eof'}]
157
- }
158
130
  if (input >= digit1 && input <= digit9)
159
131
  {
160
132
  return [undefined, { kind: 'number', value: charToString(input), numberKind: 'int'}]
@@ -182,21 +154,9 @@ const initialStateOp = initialState => input =>
182
154
  }
183
155
  }
184
156
 
185
- /** @type {(state: ParseNumberState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
157
+ /** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
186
158
  const parseNumberStateOp = state => input =>
187
159
  {
188
- if (input === undefined)
189
- {
190
- switch (state.numberKind)
191
- {
192
- case '-':
193
- case '.':
194
- case 'e':
195
- case 'e+':
196
- case 'e-': return [[{kind: 'error', message: 'invalid number'}], {kind: 'invalidNumber', }]
197
- default: return [[{kind: 'number', value: state.value}], {kind: 'eof'}]
198
- }
199
- }
200
160
  if (input === decimalPoint)
201
161
  {
202
162
  switch (state.numberKind)
@@ -297,13 +257,9 @@ const isTerminalForNumber = char =>
297
257
  }
298
258
  }
299
259
 
300
- /** @type {(state: InvalidNumberState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
260
+ /** @type {(state: InvalidNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
301
261
  const invalidNumberStateOp = state => input =>
302
262
  {
303
- if (input === undefined)
304
- {
305
- return [[{kind: 'error', message: 'invalid number'}], {kind: 'eof'}]
306
- }
307
263
  if (isTerminalForNumber(input))
308
264
  {
309
265
  const next = tokenizeOp({kind: 'initial'})(input)
@@ -312,25 +268,24 @@ const invalidNumberStateOp = state => input =>
312
268
  return [undefined, {kind: 'invalidNumber'}]
313
269
  }
314
270
 
315
- /** @type {(state: ParseStringState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
271
+ /** @type {(state: ParseStringState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
316
272
  const parseStringStateOp = state => input =>
317
273
  {
318
274
  switch(input)
319
275
  {
320
276
  case quotationMark: return[[{kind: 'string', value: state.value}], {kind: 'initial'}]
321
- case backslach: return [undefined, {kind:'escapeChar', value: state.value}]
322
- case undefined: return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
277
+ case backslash: return [undefined, {kind:'escapeChar', value: state.value}]
323
278
  default: return [undefined, {kind:'string', value: appendChar(state.value)(input)}]
324
279
  }
325
280
  }
326
281
 
327
- /** @type {(state: ParseEscapeCharState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
282
+ /** @type {(state: ParseEscapeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
328
283
  const parseEscapeCharStateOp = state => input =>
329
284
  {
330
285
  switch(input)
331
286
  {
332
287
  case quotationMark:
333
- case backslach:
288
+ case backslash:
334
289
  case slash: return [undefined, {kind: 'string', value: appendChar(state.value)(input)}]
335
290
  case letterB: return [undefined, {kind: 'string', value: appendChar(state.value)(backspace)}]
336
291
  case letterF: return [undefined, {kind: 'string', value: appendChar(state.value)(formfeed)}]
@@ -338,7 +293,6 @@ const parseEscapeCharStateOp = state => input =>
338
293
  case letterR: return [undefined, {kind: 'string', value: appendChar(state.value)(carriageReturn)}]
339
294
  case letterT: return [undefined, {kind: 'string', value: appendChar(state.value)(horizontalTab)}]
340
295
  case letterU: return [undefined, {kind: 'unicodeChar', value: state.value, unicode: 0, hexIndex: 0}]
341
- case undefined: return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
342
296
  default: {
343
297
  const next = tokenizeOp({kind: 'string', value: state.value})(input)
344
298
  return [{first: {kind: 'error', message: 'unescaped character'}, tail: next[0]}, next[1]]
@@ -354,13 +308,9 @@ const hexDigitToNumber = hex =>
354
308
  if (hex >= letterA && hex <= letterF) { return hex - letterA + 10 }
355
309
  }
356
310
 
357
- /** @type {(state: ParseUnicodeCharState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
311
+ /** @type {(state: ParseUnicodeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
358
312
  const parseUnicodeCharStateOp = state => input =>
359
313
  {
360
- if (input === undefined)
361
- {
362
- return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
363
- }
364
314
  const hexValue = hexDigitToNumber(input)
365
315
  if (hexValue === undefined)
366
316
  {
@@ -385,14 +335,9 @@ const stringToKeywordToken = s =>
385
335
  }
386
336
  }
387
337
 
388
- /** @type {(state: ParseKeywordState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
338
+ /** @type {(state: ParseKeywordState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
389
339
  const parseKeyWordStateOp = state => input =>
390
340
  {
391
- if (input === undefined)
392
- {
393
- const keyWordToken = stringToKeywordToken(state.value)
394
- return [[keyWordToken], {kind: 'eof'}]
395
- }
396
341
  if (input >= letterA && input <= letterZ)
397
342
  {
398
343
  return [undefined, {kind: 'keyword', value: appendChar(state.value)(input)}]
@@ -402,29 +347,52 @@ const parseKeyWordStateOp = state => input =>
402
347
  return [{first: keyWordToken, tail: next[0]}, next[1]]
403
348
  }
404
349
 
405
- /** @type {(state: EofState) => (input: JsonCharacter) => readonly[list.List<JsonToken>, TokenizerState]} */
350
+ /** @type {(state: EofState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
406
351
  const eofStateOp = state => input => [[{kind: 'error', message: 'eof'}], state]
407
352
 
408
- /** @type {operator.StateScan<JsonCharacter, TokenizerState, list.List<JsonToken>>} */
409
- const tokenizeOp = state => input =>
410
- {
411
- const f = () => {
412
- switch(state.kind)
413
- {
414
- case 'initial': return initialStateOp(state)
415
- case 'keyword': return parseKeyWordStateOp(state)
416
- case 'string': return parseStringStateOp(state)
417
- case 'escapeChar': return parseEscapeCharStateOp(state)
418
- case 'unicodeChar': return parseUnicodeCharStateOp(state)
419
- case 'invalidNumber': return invalidNumberStateOp(state)
420
- case 'number': return parseNumberStateOp(state)
421
- case 'eof': return eofStateOp(state)
422
- }
353
+ /** @type {operator.StateScan<number, TokenizerState, list.List<JsonToken>>} */
354
+ const tokenizeCharCodeOp = state => {
355
+ switch(state.kind)
356
+ {
357
+ case 'initial': return initialStateOp(state)
358
+ case 'keyword': return parseKeyWordStateOp(state)
359
+ case 'string': return parseStringStateOp(state)
360
+ case 'escapeChar': return parseEscapeCharStateOp(state)
361
+ case 'unicodeChar': return parseUnicodeCharStateOp(state)
362
+ case 'invalidNumber': return invalidNumberStateOp(state)
363
+ case 'number': return parseNumberStateOp(state)
364
+ case 'eof': return eofStateOp(state)
423
365
  }
424
- return f()(input)
425
366
  }
426
367
 
427
- /** @type {(input: list.List<JsonCharacter>) => list.List<JsonToken>} */
368
+ /** @type {(state: TokenizerState) => readonly[list.List<JsonToken>, TokenizerState]} */
369
+ const tokenizeEofOp = state => {
370
+ switch(state.kind)
371
+ {
372
+ case 'initial': return[undefined, {kind: 'eof'}]
373
+ case 'keyword': return [[stringToKeywordToken(state.value)], {kind: 'eof'}]
374
+ case 'string':
375
+ case 'escapeChar':
376
+ case 'unicodeChar': return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
377
+ case 'invalidNumber': return [[{kind: 'error', message: 'invalid number'}], {kind: 'eof'}]
378
+ case 'number':
379
+ switch (state.numberKind)
380
+ {
381
+ case '-':
382
+ case '.':
383
+ case 'e':
384
+ case 'e+':
385
+ case 'e-': return [[{kind: 'error', message: 'invalid number'}], {kind: 'invalidNumber', }]
386
+ default: return [[{kind: 'number', value: state.value}], {kind: 'eof'}]
387
+ }
388
+ case 'eof': return [[{kind: 'error', message: 'eof'}], state]
389
+ }
390
+ }
391
+
392
+ /** @type {operator.StateScan<CharCodeOrEof, TokenizerState, list.List<JsonToken>>} */
393
+ const tokenizeOp = state => input => input === undefined ? tokenizeEofOp(state) : tokenizeCharCodeOp(state)(input)
394
+
395
+ /** @type {(input: list.List<CharCodeOrEof>) => list.List<JsonToken>} */
428
396
  const tokenize = input => list.flat(list.stateScan(tokenizeOp)({kind: 'initial'})(input))
429
397
 
430
398
  module.exports = {
@@ -3,17 +3,17 @@ const list = require('../../types/list')
3
3
  const json = require('..')
4
4
  const { sort } = require('../../types/object')
5
5
 
6
- /** @type {(s: string) => list.List<tokenizer.JsonCharacter>} */
6
+ /** @type {(s: string) => list.List<tokenizer.CharCodeOrEof>} */
7
7
  const toCharacters = s =>
8
8
  {
9
- /** @type {list.List<tokenizer.JsonCharacter>} */
9
+ /** @type {list.List<tokenizer.CharCodeOrEof>} */
10
10
  const charCodes = list.toCharCodes(s)
11
11
  return list.concat(charCodes)([undefined])
12
- }
12
+ }
13
13
 
14
14
  /** @type {(s: string) => readonly tokenizer.JsonToken[]} */
15
15
  const tokenizeString = s =>
16
- {
16
+ {
17
17
  const characters = toCharacters(s)
18
18
  return list.toArray(tokenizer.tokenize(characters))
19
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.327",
3
+ "version": "0.0.331",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {