functionalscript 0.1.608 → 0.1.609

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 (60) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/Cargo.lock +4 -0
  3. package/Cargo.toml +4 -2
  4. package/README.md +1 -1
  5. package/com/rust/nanocom/src/cobject.rs +1 -1
  6. package/com/test/rust/src/lib.rs +4 -4
  7. package/dev/module.mjs +1 -1
  8. package/dev/test/module.f.mjs +1 -1
  9. package/djs/parser/module.f.d.mts +51 -31
  10. package/djs/parser/module.f.mjs +275 -122
  11. package/djs/parser/test.f.d.mts +4 -0
  12. package/djs/parser/test.f.mjs +179 -63
  13. package/djs/tokenizer/module.f.d.mts +1 -1
  14. package/djs/tokenizer/module.f.mjs +3 -1
  15. package/djs/tokenizer/test.f.mjs +1 -1
  16. package/doc/LANGUAGE.md +17 -16
  17. package/doc/README.md +14 -50
  18. package/fsc/README.md +0 -3
  19. package/fsm/README.md +1 -1
  20. package/html/README.md +24 -0
  21. package/issues/01-test-debug.md +3 -0
  22. package/issues/{publish.md → 05-publish.md} +8 -8
  23. package/issues/17-djs-extension.md +6 -0
  24. package/issues/README.md +20 -13
  25. package/issues/lang/1000-json.md +38 -0
  26. package/issues/lang/2110-default-export.md +2 -2
  27. package/issues/lang/2310-undefined.md +1 -1
  28. package/issues/lang/2330-property-accessor.md +225 -0
  29. package/issues/lang/2360-built-in.md +54 -47
  30. package/issues/lang/3240-export.md +44 -0
  31. package/issues/lang/README.md +64 -22
  32. package/issues/test.f.d.mts +16 -0
  33. package/issues/test.f.mjs +57 -0
  34. package/js/tokenizer/module.f.d.mts +8 -2
  35. package/js/tokenizer/module.f.mjs +29 -3
  36. package/js/tokenizer/test.f.mjs +9 -6
  37. package/json/tokenizer/module.f.mjs +2 -1
  38. package/jsr.json +1 -1
  39. package/nanvm-lib/Cargo.toml +6 -0
  40. package/nanvm-lib/src/extension.rs +119 -0
  41. package/nanvm-lib/src/interface.rs +136 -0
  42. package/nanvm-lib/src/lib.rs +7 -0
  43. package/nanvm-lib/src/naive.rs +229 -0
  44. package/nanvm-lib/src/nanenum.rs +230 -0
  45. package/nanvm-lib/src/nullish.rs +7 -0
  46. package/nanvm-lib/src/sign.rs +5 -0
  47. package/nanvm-lib/src/simple.rs +32 -0
  48. package/nanvm-lib/tests/test.f.d.mts +36 -0
  49. package/nanvm-lib/tests/test.f.mjs +79 -0
  50. package/nanvm-lib/tests/test.rs +108 -0
  51. package/package.json +1 -1
  52. package/text/README.md +2 -2
  53. package/issues/lang/2351-property-accessor.md +0 -44
  54. package/issues/lang/2352-property-call.md +0 -43
  55. package/issues/lang/2353-property-at.md +0 -19
  56. package/issues/test-debug.md +0 -12
  57. /package/issues/{esm.md → 02-esm.md} +0 -0
  58. /package/issues/{djs.md → 03-djs.md} +0 -0
  59. /package/issues/{fs-load.md → 11-fs-load.md} +0 -0
  60. /package/issues/lang/{2330-grouping.md → 2350-grouping.md} +0 -0
@@ -0,0 +1,44 @@
1
+ # Non-default Export
2
+
3
+ In FunctionalScript we use `export default`:
4
+
5
+ ```js
6
+ export default 17
7
+ ```
8
+
9
+ The main reason is that it's compatible with other module types, such as JSON and CommonJS.
10
+
11
+ ECMAScript supports `export` of other non-default objects. We wouldn't have much reasons to support but systems as JSR doesn't really like `default` exports.
12
+
13
+ To implement `export` we should change our definition of a module from `unknown` to
14
+
15
+ ```ts
16
+ type Module = {
17
+ readonly [k in string]?: unknonwn
18
+ readonly default?: unknown
19
+ }
20
+ ```
21
+
22
+ Or, more strict version, which allows either `export` or `export default` but not both:
23
+
24
+ ```ts
25
+ type Module = ExportMap | ExportDefault
26
+ type ExportMap = Omit<{
27
+ readonly[k in string]: unknown
28
+ }, 'default'>
29
+ type DefaultExport = {
30
+ readonly default: unknown
31
+ }
32
+ ```
33
+
34
+ We don't need to change `import` for now if we implement `import * as X from ...`. For example
35
+
36
+ ```js
37
+ // types/list/module.d.mjs
38
+ export const map = ...
39
+ ```
40
+
41
+ ```js
42
+ import * as List from 'types/list/module.f.mjs'
43
+ const { map } = List
44
+ ```
@@ -1,5 +1,9 @@
1
1
  # FunctionalScript Language
2
2
 
3
+ Two main FunctionsScript princples:
4
+ 1. if FS code pass validation/compilation, then it doesn't have side-effects,
5
+ 2. the code that passed validation/compilation should behave on FunctionalScript VM the same way as on any other modern JavaScript engine.
6
+
3
7
  When we implement features of FunctionalScript, the first priority is a simplification of the VM.
4
8
 
5
9
  File Types:
@@ -16,44 +20,67 @@ File Types:
16
20
 
17
21
  - [ ] [JSON](./1000-json.md).
18
22
 
23
+ **VM**:
24
+
25
+ We are introducing new commands in the order that every new command depends only on previous commands.
26
+
27
+ |format|any |Tag| |
28
+ |------|--------------|---|----------|
29
+ |JSON |null | 00| |
30
+ | |number | 01|u64 |
31
+ | |false | 02| |
32
+ | |true | 03| |
33
+ | |string | 04|String |
34
+ | |array | 05|Array<Any>|
35
+ | |object | 06|Object |
36
+
19
37
  ## 2. DJS
20
38
 
21
39
  The DJS form a graph of values. It can be serialized without additional run-time information.
22
40
 
23
41
  File extensions: `.d.js` and `.d.mjs`.
24
42
 
43
+ |format|any |Tag| |Notes |
44
+ |------|------------------------|---|----------|------------------------------------------------|
45
+ |DJS |const_ref | 07|u32 |[const](./2120-const.md) |
46
+ | |bigint_plus | 08|Array<u64>|[bigint](./2320-bigint.md) |
47
+ | |bigint_minus | 09|Array<u64>|[bigint](./2320-bigint.md) |
48
+ | |undefined | 0A| |[undefined](./2310-undefined.md) |
49
+ | |own_property | 0B| |[property-accessor](./2330-property-accessor.md)|
50
+ | |instance_property | 0C| |[property-accessor](./2330-property-accessor.md)|
51
+ | |instance_method_call | 0D| |[property-accessor](./2330-property-accessor.md)|
52
+ | |at | 0E| |[property-accessor](./2330-property-accessor.md)|
53
+ | |operators | | |[operators](./2340-operators.md) |
54
+
25
55
  ### 2.1. Required
26
56
 
27
- 1. [ ] [default-export](./2110-default-export.md)
28
- 2. [ ] [const](./2120-const.md)
29
- 3. [ ] [default-import](./2130-default-import.md)
57
+ 1. [ ] [default-export](./2110-default-export.md),
58
+ 2. [ ] [const](./2120-const.md),
59
+ 3. [ ] [default-import](./2130-default-import.md).
30
60
 
31
61
  ### 2.2. Priority 1
32
62
 
33
63
  We need it to use JSDoc and TypeScript.
34
64
 
35
- 1. [ ] [block-comment](./2210-block-comment.md)
36
- 2. [ ] [namespace-import](./2220-namespace-import.md)
65
+ 1. [ ] [block-comment](./2210-block-comment.md),
66
+ 2. [ ] [namespace-import](./2220-namespace-import.md).
37
67
 
38
68
  ### 2.3. Priority 2
39
69
 
40
- 1. [ ] [undefined](./231-undefined.md)
41
- 2. [ ] [bigint](./232-bigint.md)
42
- 3. [ ] [grouping](./233-grouping.md)
43
- 4. [ ] [operators](./234-operators.md)
44
- 5. [ ] Property Accessors:
45
- 1. [ ] [property-accessor](./2351-property-accessor.md)
46
- 2. [ ] [property-call](./2352-property-call.md)
47
- 3. [ ] [at](./2353-at.md)
48
- 6. [ ] [global](./2360-built-in.md)
70
+ 1. [ ] [undefined](./2310-undefined.md),
71
+ 2. [ ] [bigint](./2320-bigint.md),
72
+ 3. [ ] [property-accessor](./2330-property-accessor.md),
73
+ 4. [ ] [operators](./2340-operators.md),
74
+ 5. [ ] [grouping](./2350-grouping.md),
75
+ 6. [ ] [built-in](./2360-built-in.md).
49
76
 
50
77
  ### 2.4. Syntactic Sugar
51
78
 
52
- 1. [ ] [identifier-property](./2410-identifier-property.md)
53
- 2. [ ] [line-comment](./2420-line-comment.md)
54
- 3. [ ] [trailing-comma](./2430-trailing-comma.md)
55
- 4. [ ] [shorthand](./2440-shorthand.md)
56
- 5. [ ] [destructuring](./2450-destructuring.md)
79
+ 1. [ ] [identifier-property](./2410-identifier-property.md),
80
+ 2. [ ] [line-comment](./2420-line-comment.md),
81
+ 3. [ ] [trailing-comma](./2430-trailing-comma.md),
82
+ 4. [ ] [shorthand](./2440-shorthand.md),
83
+ 5. [ ] [destructuring](./2450-destructuring.md).
57
84
 
58
85
  ## 3. FJS
59
86
 
@@ -61,6 +88,10 @@ The FJS can have functions. The format requires additional run-time information
61
88
 
62
89
  File extensions: `.f.js` and `.f.mjs`.
63
90
 
91
+ |format|any |Tag| |Notes |
92
+ |------|--------|---|----|--------------------------------|
93
+ |FJS |function| |Func|[function](./3110-function.md) |
94
+
64
95
  ### 3.1. Required
65
96
 
66
97
  1. [ ] [function](./3110-function.md)
@@ -69,12 +100,23 @@ File extensions: `.f.js` and `.f.mjs`.
69
100
 
70
101
  ### 3.2. Priority 1
71
102
 
72
- 1. [ ] `if`
103
+ 1. [ ] `if`. See https://developer.mozilla.org/en-US/docs/Glossary/Falsy
73
104
  2. [ ] [let](./3220-let.md)
74
105
  3. [ ] `while`
106
+ 4. [ ] [export](./3240-export.md)
75
107
 
76
108
  ### 3.3. Syntactic Sugar
77
109
 
78
- 1. [ ] [expression](./321-expression.md)
79
- 2. [ ] [one-parameter](./322-one-parameter.md)
110
+ 1. [ ] [expression](./3210-expression.md)
111
+ 2. [ ] [one-parameter](./3220-one-parameter.md)
80
112
  3. [ ] [assignments](./3330-assignments.md)
113
+
114
+ ## 4. ECMAScript Proposals
115
+
116
+ 1. [ ] [Type Annotations](https://github.com/tc39/proposal-type-annotations), Stage 1:
117
+ - [Node.js](https://nodejs.org/en/learn/typescript/run-natively),
118
+ - `Deno` supports TypeScript,
119
+ - `Bun` supports TypeScript,
120
+ - most browsers don't support the feature.
121
+ 2. [ ] [Pipe Operator `|>`](https://github.com/tc39/proposal-pipeline-operator), Stage 2.
122
+ 3. [ ] [Records and Tuples](https://github.com/tc39/proposal-record-tuple), Stage 2.
@@ -0,0 +1,16 @@
1
+ declare namespace _default {
2
+ namespace ownProperty {
3
+ function nullish(): void;
4
+ function bool(): void;
5
+ function array(): void;
6
+ namespace object {
7
+ export function _null(): void;
8
+ export { _null as null };
9
+ export function undefined(): void;
10
+ }
11
+ namespace string {
12
+ function number(): void;
13
+ }
14
+ }
15
+ }
16
+ export default _default;
@@ -0,0 +1,57 @@
1
+ /** @type {(a: unknown) => (i: any) =>unknown} */
2
+ const at = a => i => Object.getOwnPropertyDescriptor(a, i)?.value
3
+
4
+ export default {
5
+ ownProperty: {
6
+ nullish: () => {
7
+ /* // panic
8
+ const v = Object.getOwnPropertyDescriptor(null, 0)
9
+ if (v !== undefined) {
10
+ throw v
11
+ }
12
+ */
13
+ /* // panic
14
+ const v = Object.getOwnPropertyDescriptor(undefined, 0)
15
+ if (v !== undefined) {
16
+ throw v
17
+ }
18
+ */
19
+ },
20
+ bool: () => {
21
+ const v = at(true)('x')
22
+ if (v !== undefined) {
23
+ throw v
24
+ }
25
+ },
26
+ array: () => {
27
+ const a = ['42']
28
+ {
29
+ const v = at(a)('0')
30
+ if (v !== '42') { throw v }
31
+ }
32
+ {
33
+ const v = at(a)(0)
34
+ if (v !== '42') { throw v }
35
+ }
36
+ },
37
+ object: {
38
+ null: () => {
39
+ const o = { null: 'hello' }
40
+ const v = at(o)(null)
41
+ if (v !== 'hello') { throw v }
42
+ },
43
+ undefined: () => {
44
+ const o = { undefined: 'hello' }
45
+ const v = at(o)(undefined)
46
+ if (v !== 'hello') { throw v }
47
+ }
48
+ },
49
+ string: {
50
+ number: () => {
51
+ const o = 'hello'
52
+ const v = at(o)(1)
53
+ if (v !== 'e') { throw v }
54
+ }
55
+ }
56
+ }
57
+ }
@@ -23,6 +23,9 @@ export type ErrorToken = {
23
23
  export type WhitespaceToken = {
24
24
  readonly kind: "ws";
25
25
  };
26
+ export type NewLineToken = {
27
+ readonly kind: "nl";
28
+ };
26
29
  export type TrueToken = {
27
30
  readonly kind: "true";
28
31
  };
@@ -72,8 +75,8 @@ export type OperatorToken = {
72
75
  } | {
73
76
  readonly kind: "?" | "?." | "=>";
74
77
  };
75
- export type JsToken = KeywordToken | TrueToken | FalseToken | NullToken | WhitespaceToken | StringToken | NumberToken | ErrorToken | IdToken | BigIntToken | OperatorToken;
76
- export type TokenizerState = InitialState | ParseIdState | ParseStringState | ParseEscapeCharState | ParseUnicodeCharState | ParseNumberState | InvalidNumberState | ParseOperatorState | ParseMinusState | ParseWhitespaceState | EofState;
78
+ export type JsToken = KeywordToken | TrueToken | FalseToken | NullToken | WhitespaceToken | NewLineToken | StringToken | NumberToken | ErrorToken | IdToken | BigIntToken | OperatorToken;
79
+ export type TokenizerState = InitialState | ParseIdState | ParseStringState | ParseEscapeCharState | ParseUnicodeCharState | ParseNumberState | InvalidNumberState | ParseOperatorState | ParseMinusState | ParseWhitespaceState | ParseNewLineState | EofState;
77
80
  export type ErrorMessage = "\" are missing" | "unescaped character" | "invalid hex value" | "unexpected character" | "invalid number" | "invalid token" | "eof";
78
81
  export type InitialState = {
79
82
  readonly kind: "initial";
@@ -85,6 +88,9 @@ export type ParseIdState = {
85
88
  export type ParseWhitespaceState = {
86
89
  readonly kind: "ws";
87
90
  };
91
+ export type ParseNewLineState = {
92
+ readonly kind: "nl";
93
+ };
88
94
  export type ParseStringState = {
89
95
  readonly kind: "string";
90
96
  readonly value: string;
@@ -96,6 +96,8 @@ const {
96
96
 
97
97
  /** @typedef {{readonly kind: 'ws'}} WhitespaceToken */
98
98
 
99
+ /** @typedef {{readonly kind: 'nl'}} NewLineToken */
100
+
99
101
  /** @typedef {{readonly kind: 'true'}} TrueToken */
100
102
 
101
103
  /** @typedef {{readonly kind: 'false'}} FalseToken */
@@ -143,6 +145,7 @@ const {
143
145
  * FalseToken |
144
146
  * NullToken |
145
147
  * WhitespaceToken |
148
+ * NewLineToken |
146
149
  * StringToken |
147
150
  * NumberToken |
148
151
  * ErrorToken |
@@ -154,15 +157,19 @@ const {
154
157
 
155
158
  const rangeOneNine = range('19')
156
159
 
160
+ const rangeSetNewLine = [
161
+ one(lf),
162
+ one(cr)
163
+ ]
164
+
157
165
  const rangeSetWhiteSpace = [
158
166
  one(ht),
159
- one(lf),
160
- one(cr),
161
167
  one(space)
162
168
  ]
163
169
 
164
170
  const rangeSetTerminalForNumber = [
165
171
  ...rangeSetWhiteSpace,
172
+ ...rangeSetNewLine,
166
173
  one(exclamationMark),
167
174
  one(percentSign),
168
175
  one(ampersand),
@@ -235,6 +242,7 @@ const rangeId = [digitRange, ...rangeIdStart]
235
242
  * ParseOperatorState |
236
243
  * ParseMinusState |
237
244
  * ParseWhitespaceState |
245
+ * ParseNewLineState |
238
246
  * EofState
239
247
  * } TokenizerState
240
248
  */
@@ -257,6 +265,8 @@ const rangeId = [digitRange, ...rangeIdStart]
257
265
 
258
266
  /** @typedef {{ readonly kind: 'ws'}} ParseWhitespaceState */
259
267
 
268
+ /** @typedef {{ readonly kind: 'nl'}} ParseNewLineState */
269
+
260
270
  /** @typedef {{ readonly kind: 'string', readonly value: string}} ParseStringState */
261
271
 
262
272
  /** @typedef {{ readonly kind: 'escapeChar', readonly value: string}} ParseEscapeCharState */
@@ -525,6 +535,7 @@ const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpe
525
535
  rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: 'int' }]),
526
536
  rangeSetFunc(rangeIdStart)(() => input => [empty, { kind: 'id', value: fromCharCode(input) }]),
527
537
  rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, { kind: 'ws' }]),
538
+ rangeSetFunc(rangeSetNewLine)(state => () => [empty, { kind: 'nl' }]),
528
539
  rangeFunc(one(quotationMark))(() => () => [empty, { kind: 'string', value: '' }]),
529
540
  rangeFunc(one(digit0))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: '0' }]),
530
541
  rangeSetFunc(rangeOpStart)(() => input => [empty, { kind: 'op', value: fromCharCode(input) }])
@@ -739,7 +750,20 @@ const parseWhitespaceDefault = state => input => {
739
750
 
740
751
  /** @type {(state: ParseWhitespaceState) => (input: number) => readonly[List.List<JsToken>, TokenizerState]} */
741
752
  const parseWhitespaceStateOp = create(parseWhitespaceDefault)([
742
- rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state])
753
+ rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state]),
754
+ rangeSetFunc(rangeSetNewLine)(state => () => [empty, { kind: 'nl' }])
755
+ ])
756
+
757
+ /** @type {(state: ParseNewLineState) => (input: number) => readonly[List.List<JsToken>, TokenizerState]} */
758
+ const parseNewLineDefault = state => input => {
759
+ const next = tokenizeOp({ kind: 'initial' })(input)
760
+ return [{ first: { kind: 'nl' }, tail: next[0] }, next[1]]
761
+ }
762
+
763
+ /** @type {(state: ParseNewLineState) => (input: number) => readonly[List.List<JsToken>, TokenizerState]} */
764
+ const parseNewLineStateOp = create(parseNewLineDefault)([
765
+ rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state]),
766
+ rangeSetFunc(rangeSetNewLine)(state => () => [empty, state])
743
767
  ])
744
768
 
745
769
  /** @type {(state: EofState) => (input: number) => readonly[List.List<JsToken>, TokenizerState]} */
@@ -758,6 +782,7 @@ const tokenizeCharCodeOp = state => {
758
782
  case 'op': return parseOperatorStateOp(state)
759
783
  case '-': return parseMinusStateOp(state)
760
784
  case 'ws': return parseWhitespaceStateOp(state)
785
+ case 'nl': return parseNewLineStateOp(state)
761
786
  case 'eof': return eofStateOp(state)
762
787
  }
763
788
  }
@@ -782,6 +807,7 @@ const tokenizeEofOp = state => {
782
807
  case 'op': return [[getOperatorToken(state.value)], { kind: 'eof' }]
783
808
  case '-': return [[{kind: '-'}], { kind: 'eof' }]
784
809
  case 'ws': return [[{kind: 'ws'}], { kind: 'eof' }]
810
+ case 'nl': return [[{kind: 'nl'}], { kind: 'eof' }]
785
811
  case 'eof': return [[{ kind: 'error', message: 'eof' }], state]
786
812
  }
787
813
  }
@@ -47,9 +47,8 @@ export default {
47
47
  },
48
48
  () => {
49
49
  const result = stringify(tokenizeString('{ \t\n\r}'))
50
- if (result !== '[{"kind":"{"},{"kind":"ws"},{"kind":"}"}]') { throw result }
50
+ if (result !== '[{"kind":"{"},{"kind":"nl"},{"kind":"}"}]') { throw result }
51
51
  },
52
-
53
52
  () => {
54
53
  const result = stringify(tokenizeString('""'))
55
54
  if (result !== '[{"kind":"string","value":""}]') { throw result }
@@ -344,16 +343,20 @@ export default {
344
343
  if (result !== '[{"kind":"ws"}]') { throw result }
345
344
  },
346
345
  () => {
347
- const result = stringify(tokenizeString('\n'))
346
+ const result = stringify(tokenizeString(' \t'))
348
347
  if (result !== '[{"kind":"ws"}]') { throw result }
349
348
  },
349
+ () => {
350
+ const result = stringify(tokenizeString('\n'))
351
+ if (result !== '[{"kind":"nl"}]') { throw result }
352
+ },
350
353
  () => {
351
354
  const result = stringify(tokenizeString('\r'))
352
- if (result !== '[{"kind":"ws"}]') { throw result }
355
+ if (result !== '[{"kind":"nl"}]') { throw result }
353
356
  },
354
357
  () => {
355
- const result = stringify(tokenizeString(' \t\n\r'))
356
- if (result !== '[{"kind":"ws"}]') { throw result }
358
+ const result = stringify(tokenizeString(' \t\n\r '))
359
+ if (result !== '[{"kind":"nl"}]') { throw result }
357
360
  },
358
361
  ],
359
362
  id: [
@@ -45,7 +45,8 @@ const mapToken = input =>
45
45
  case 'string':
46
46
  case 'number':
47
47
  case 'error': return [input]
48
- case 'ws': return empty
48
+ case 'ws':
49
+ case 'nl': return empty
49
50
  default: return [{ kind: 'error', message: 'invalid token' }]
50
51
  }
51
52
  }
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@functionalscript/functionalscript",
3
- "version": "0.1.608",
3
+ "version": "0.1.609",
4
4
  "exports": {
5
5
  "./com/cpp": "./com/cpp/module.f.mjs",
6
6
  "./com/cs": "./com/cs/module.f.mjs",
@@ -0,0 +1,6 @@
1
+ [package]
2
+ name = "nanvm-lib"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+
6
+ [dependencies]
@@ -0,0 +1,119 @@
1
+ use crate::{interface::{Any, Container, Extension, Unpacked}, nullish::Nullish::*, simple::Simple};
2
+
3
+ pub trait AnyExtension: Any {
4
+ fn string(c: &str) -> Self::String16 {
5
+ c.encode_utf16().into_iter().to_complex()
6
+ }
7
+ fn to_string(self) -> Self::String16 {
8
+ match self.unpack() {
9
+ Unpacked::Nullish(v) => Self::string(match v {
10
+ Null => "null",
11
+ Undefined => "undefined",
12
+ }),
13
+ Unpacked::Bool(v) => Self::string(match v {
14
+ true => "true",
15
+ false => "false",
16
+ }),
17
+ Unpacked::Number(_) => todo!(),
18
+ Unpacked::String16(v) => v,
19
+ Unpacked::BigInt(_) => todo!(),
20
+ Unpacked::Array(_) => [].to_complex(),
21
+ Unpacked::Object(_) => Self::string("[object Object"),
22
+ Unpacked::Function(_) => todo!(),
23
+ }
24
+ }
25
+ fn own_property(self, i: Self) -> Self {
26
+ match self.unpack() {
27
+ Unpacked::Nullish(_) => panic!("own_property(\"nullish\")"),
28
+ Unpacked::Bool(_) => Simple::Nullish(Undefined).to_unknown(),
29
+ Unpacked::Number(_) => todo!(),
30
+ Unpacked::String16(_) => todo!(),
31
+ Unpacked::BigInt(_) => todo!(),
32
+ Unpacked::Array(_) => match i.unpack() {
33
+ Unpacked::Nullish(_) => todo!(),
34
+ Unpacked::Bool(_) => todo!(),
35
+ Unpacked::Number(_) => todo!(),
36
+ Unpacked::String16(_) => todo!(),
37
+ Unpacked::BigInt(_) => todo!(),
38
+ Unpacked::Array(_) => todo!(),
39
+ Unpacked::Object(_) => todo!(),
40
+ Unpacked::Function(_) => todo!(),
41
+ },
42
+ Unpacked::Object(_) => todo!(),
43
+ Unpacked::Function(_) => todo!(),
44
+ }
45
+ }
46
+ }
47
+
48
+ impl<T: Any> AnyExtension for T {}
49
+
50
+ #[cfg(test)]
51
+ mod test {
52
+ mod to_string {
53
+ use crate::{
54
+ extension::AnyExtension, interface::{Complex, Extension}, naive::{Any, Array, Object}, nullish::Nullish::*, simple::Simple
55
+ };
56
+
57
+ #[test]
58
+ fn test_string() {
59
+ let s = Any::string("Hello world!");
60
+ let xs: Any = s.clone().to_unknown();
61
+ let sxs = xs.to_string();
62
+ assert_eq!(s, sxs);
63
+ }
64
+
65
+ #[test]
66
+ fn test_nullish() {
67
+ {
68
+ let x: Any = Simple::Nullish(Null).to_unknown();
69
+ assert_eq!(Any::string("null"), x.to_string());
70
+ }
71
+ {
72
+ let x: Any = Simple::Nullish(Undefined).to_unknown();
73
+ assert_eq!(Any::string("undefined"), x.to_string());
74
+ }
75
+ }
76
+
77
+ #[test]
78
+ fn test_boolean() {
79
+ {
80
+ let x: Any = Simple::Boolean(true).to_unknown();
81
+ assert_eq!(Any::string("true"), x.to_string());
82
+ }
83
+ {
84
+ let x: Any = Simple::Boolean(false).to_unknown();
85
+ assert_eq!(Any::string("false"), x.to_string());
86
+ }
87
+ }
88
+
89
+ #[test]
90
+ fn test_object() {
91
+ let x: Any = [].to_object_unknown();
92
+ assert_eq!(Any::string("[object Object"), x.to_string());
93
+ }
94
+
95
+ #[test]
96
+ fn test_array() {
97
+ let x: Any = [].to_array_unknown();
98
+ assert_eq!(Any::string(""), x.to_string());
99
+ }
100
+ }
101
+
102
+ mod own_property {
103
+ use crate::{extension::AnyExtension, interface::Complex, naive::Any, nullish::Nullish::*, simple::Simple};
104
+
105
+ #[test]
106
+ #[should_panic]
107
+ fn test_own_property_null() {
108
+ let x: Any = Simple::Nullish(Null).to_unknown();
109
+ x.own_property(Any::string("hello").to_unknown());
110
+ }
111
+
112
+ #[test]
113
+ fn test_own_property_bool() {
114
+ let x: Any = Simple::Boolean(true).to_unknown();
115
+ let undefined: Any = Simple::Nullish(Undefined).to_unknown();
116
+ assert_eq!(undefined, x.own_property(Any::string("hello").to_unknown()));
117
+ }
118
+ }
119
+ }