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.
- package/CHANGELOG.md +10 -0
- package/Cargo.lock +4 -0
- package/Cargo.toml +4 -2
- package/README.md +1 -1
- package/com/rust/nanocom/src/cobject.rs +1 -1
- package/com/test/rust/src/lib.rs +4 -4
- package/dev/module.mjs +1 -1
- package/dev/test/module.f.mjs +1 -1
- package/djs/parser/module.f.d.mts +51 -31
- package/djs/parser/module.f.mjs +275 -122
- package/djs/parser/test.f.d.mts +4 -0
- package/djs/parser/test.f.mjs +179 -63
- package/djs/tokenizer/module.f.d.mts +1 -1
- package/djs/tokenizer/module.f.mjs +3 -1
- package/djs/tokenizer/test.f.mjs +1 -1
- package/doc/LANGUAGE.md +17 -16
- package/doc/README.md +14 -50
- package/fsc/README.md +0 -3
- package/fsm/README.md +1 -1
- package/html/README.md +24 -0
- package/issues/01-test-debug.md +3 -0
- package/issues/{publish.md → 05-publish.md} +8 -8
- package/issues/17-djs-extension.md +6 -0
- package/issues/README.md +20 -13
- package/issues/lang/1000-json.md +38 -0
- package/issues/lang/2110-default-export.md +2 -2
- package/issues/lang/2310-undefined.md +1 -1
- package/issues/lang/2330-property-accessor.md +225 -0
- package/issues/lang/2360-built-in.md +54 -47
- package/issues/lang/3240-export.md +44 -0
- package/issues/lang/README.md +64 -22
- package/issues/test.f.d.mts +16 -0
- package/issues/test.f.mjs +57 -0
- package/js/tokenizer/module.f.d.mts +8 -2
- package/js/tokenizer/module.f.mjs +29 -3
- package/js/tokenizer/test.f.mjs +9 -6
- package/json/tokenizer/module.f.mjs +2 -1
- package/jsr.json +1 -1
- package/nanvm-lib/Cargo.toml +6 -0
- package/nanvm-lib/src/extension.rs +119 -0
- package/nanvm-lib/src/interface.rs +136 -0
- package/nanvm-lib/src/lib.rs +7 -0
- package/nanvm-lib/src/naive.rs +229 -0
- package/nanvm-lib/src/nanenum.rs +230 -0
- package/nanvm-lib/src/nullish.rs +7 -0
- package/nanvm-lib/src/sign.rs +5 -0
- package/nanvm-lib/src/simple.rs +32 -0
- package/nanvm-lib/tests/test.f.d.mts +36 -0
- package/nanvm-lib/tests/test.f.mjs +79 -0
- package/nanvm-lib/tests/test.rs +108 -0
- package/package.json +1 -1
- package/text/README.md +2 -2
- package/issues/lang/2351-property-accessor.md +0 -44
- package/issues/lang/2352-property-call.md +0 -43
- package/issues/lang/2353-property-at.md +0 -19
- package/issues/test-debug.md +0 -12
- /package/issues/{esm.md → 02-esm.md} +0 -0
- /package/issues/{djs.md → 03-djs.md} +0 -0
- /package/issues/{fs-load.md → 11-fs-load.md} +0 -0
- /package/issues/lang/{2330-grouping.md → 2350-grouping.md} +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** @type {(a: unknown) => (b: unknown) => void} */
|
|
2
|
+
const e = a => b => {
|
|
3
|
+
if (a === b) { } else { throw [a, '===', b] }
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** @type {(a: unknown) => (b: unknown) => void} */
|
|
7
|
+
const n = a => b => {
|
|
8
|
+
if (a !== b) { } else { throw [a, '!==', b] }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
eq: {
|
|
13
|
+
nullish: () => {
|
|
14
|
+
e(null)(null)
|
|
15
|
+
e(undefined)(undefined)
|
|
16
|
+
n(null)(undefined)
|
|
17
|
+
},
|
|
18
|
+
boolean: {
|
|
19
|
+
boolean: () => {
|
|
20
|
+
e(true)(true)
|
|
21
|
+
e(false)(false)
|
|
22
|
+
n(true)(false)
|
|
23
|
+
},
|
|
24
|
+
nullish: () => {
|
|
25
|
+
n(false)(undefined)
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
number: {
|
|
29
|
+
number: () => {
|
|
30
|
+
e(2.3)(2.3)
|
|
31
|
+
n(2.3)(-5.4)
|
|
32
|
+
n(NaN)(NaN)
|
|
33
|
+
e(0)(-0)
|
|
34
|
+
if (!Object.is(-0, -0)) { throw -0 }
|
|
35
|
+
if (Object.is(0, -0)) { throw -0 }
|
|
36
|
+
e(Infinity)(Infinity)
|
|
37
|
+
e(-Infinity)(-Infinity)
|
|
38
|
+
n(Infinity)(-Infinity)
|
|
39
|
+
},
|
|
40
|
+
nullish: () => {
|
|
41
|
+
n(undefined)(NaN)
|
|
42
|
+
n(undefined)(0)
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
string: {
|
|
46
|
+
string: () => {
|
|
47
|
+
e("hello")("hello")
|
|
48
|
+
n("hello")("world")
|
|
49
|
+
},
|
|
50
|
+
number: () => {
|
|
51
|
+
n(0)("0")
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
bigint: {
|
|
55
|
+
bigint: () => {
|
|
56
|
+
e(12n)(12n)
|
|
57
|
+
n(12n)(-12n)
|
|
58
|
+
n(12n)(13n)
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
array: {
|
|
62
|
+
array: () => {
|
|
63
|
+
/** @type {any} */
|
|
64
|
+
const a = []
|
|
65
|
+
e(a)(a)
|
|
66
|
+
n([])([])
|
|
67
|
+
const a0 = ['0']
|
|
68
|
+
e(a0)(a0)
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
object: {
|
|
72
|
+
object: () => {
|
|
73
|
+
const o = { '0': '0' }
|
|
74
|
+
e(o)(o)
|
|
75
|
+
n(o)({ '0': '0' })
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
use nanvm_lib::{interface::{Complex, Container, Extension, Any, Utf8}, naive, nullish::Nullish, sign::Sign, simple::Simple};
|
|
2
|
+
|
|
3
|
+
fn eq<A: Any>() {
|
|
4
|
+
// nullish
|
|
5
|
+
let null0: A = Simple::Nullish(Nullish::Null).to_unknown();
|
|
6
|
+
let null1 = Simple::Nullish(Nullish::Null).to_unknown();
|
|
7
|
+
let undefined0 = Simple::Nullish(Nullish::Undefined).to_unknown();
|
|
8
|
+
let undefined1 = Simple::Nullish(Nullish::Undefined).to_unknown();
|
|
9
|
+
{
|
|
10
|
+
assert_eq!(null0, null1);
|
|
11
|
+
assert_eq!(undefined0, undefined1);
|
|
12
|
+
assert_ne!(null1, undefined0);
|
|
13
|
+
}
|
|
14
|
+
// boolean
|
|
15
|
+
let true0: A = Simple::Boolean(true).to_unknown();
|
|
16
|
+
let true1 = Simple::Boolean(true).to_unknown();
|
|
17
|
+
let false0 = Simple::Boolean(false).to_unknown();
|
|
18
|
+
let false1 = Simple::Boolean(false).to_unknown();
|
|
19
|
+
{
|
|
20
|
+
// boolean
|
|
21
|
+
{
|
|
22
|
+
assert_eq!(true0, true1);
|
|
23
|
+
assert_eq!(false0, false1);
|
|
24
|
+
assert_ne!(true0, false0);
|
|
25
|
+
}
|
|
26
|
+
// nullish
|
|
27
|
+
{
|
|
28
|
+
assert_ne!(false0, undefined0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// number
|
|
32
|
+
let number00: A = Simple::Number(2.3).to_unknown();
|
|
33
|
+
let number01: A = Simple::Number(2.3).to_unknown();
|
|
34
|
+
let number1: A = Simple::Number(-5.4).to_unknown();
|
|
35
|
+
let number_nan: A = Simple::Number(f64::NAN).to_unknown();
|
|
36
|
+
let number_p0: A = Simple::Number(0.0).to_unknown();
|
|
37
|
+
let number_n0: A = Simple::Number(-0.0).to_unknown();
|
|
38
|
+
let number_p_inf0: A = Simple::Number(f64::INFINITY).to_unknown();
|
|
39
|
+
let number_p_inf1: A = Simple::Number(f64::INFINITY).to_unknown();
|
|
40
|
+
let number_n_inf0: A = Simple::Number(-f64::INFINITY).to_unknown();
|
|
41
|
+
let number_n_inf1: A = Simple::Number(-f64::INFINITY).to_unknown();
|
|
42
|
+
{
|
|
43
|
+
// number
|
|
44
|
+
{
|
|
45
|
+
assert_eq!(number00, number01);
|
|
46
|
+
assert_ne!(number00, number1);
|
|
47
|
+
assert_ne!(number_nan, number_nan);
|
|
48
|
+
assert_eq!(number_p0, number_n0);
|
|
49
|
+
// Object.is()
|
|
50
|
+
assert_eq!((-0f64).to_bits(), (-0f64).to_bits());
|
|
51
|
+
assert_ne!(0f64.to_bits(), (-0f64).to_bits());
|
|
52
|
+
assert_eq!(number_p_inf0, number_p_inf1);
|
|
53
|
+
assert_eq!(number_n_inf0, number_n_inf1);
|
|
54
|
+
assert_ne!(number_p_inf0, number_n_inf0);
|
|
55
|
+
}
|
|
56
|
+
// nullish
|
|
57
|
+
{
|
|
58
|
+
assert_ne!(number_nan, undefined0);
|
|
59
|
+
assert_ne!(number00, undefined0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// string
|
|
63
|
+
let string_hello0: A = "Hello!".to_unknown();
|
|
64
|
+
let string_hello1: A = "Hello!".to_unknown();
|
|
65
|
+
let string_world0: A = "world!".to_unknown();
|
|
66
|
+
let string0: A = "0".to_unknown();
|
|
67
|
+
let s0 = "0".to_string16::<A>();
|
|
68
|
+
{
|
|
69
|
+
{
|
|
70
|
+
assert_eq!(string_hello0, string_hello1);
|
|
71
|
+
assert_ne!(string_hello0, string_world0);
|
|
72
|
+
}
|
|
73
|
+
{
|
|
74
|
+
assert_ne!(number_p0, string0.clone());
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// bigint
|
|
78
|
+
let bigint12_0: A = A::BigInt::new(Sign::Positive, [12]).to_unknown();
|
|
79
|
+
let bigint12_1: A = A::BigInt::new(Sign::Positive, [12]).to_unknown();
|
|
80
|
+
let bigint12m: A = A::BigInt::new(Sign::Negative, [12]).to_unknown();
|
|
81
|
+
let bigint13: A = A::BigInt::new(Sign::Positive, [13]).to_unknown();
|
|
82
|
+
{
|
|
83
|
+
assert_eq!(bigint12_0, bigint12_1);
|
|
84
|
+
assert_ne!(bigint12_0, bigint12m);
|
|
85
|
+
assert_ne!(bigint12_0, bigint13);
|
|
86
|
+
}
|
|
87
|
+
// array
|
|
88
|
+
let array0: A = [].to_array_unknown();
|
|
89
|
+
let array1: A = [].to_array_unknown();
|
|
90
|
+
let array2: A = [string0.clone()].to_array_unknown();
|
|
91
|
+
{
|
|
92
|
+
assert_eq!(array0, array0);
|
|
93
|
+
assert_ne!(array0, array1);
|
|
94
|
+
assert_eq!(array2, array2);
|
|
95
|
+
}
|
|
96
|
+
// object
|
|
97
|
+
let object0: A = [(s0.clone(), string0.clone())].to_object_unknown();
|
|
98
|
+
let object1: A = [(s0, string0)].to_object_unknown();
|
|
99
|
+
{
|
|
100
|
+
assert_eq!(object0, object0);
|
|
101
|
+
assert_ne!(object0, object1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
#[test]
|
|
106
|
+
fn naive_eq() {
|
|
107
|
+
eq::<naive::Any>();
|
|
108
|
+
}
|
package/package.json
CHANGED
package/text/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Total error states:
|
|
|
34
34
|
- 34_432
|
|
35
35
|
- < 2^16
|
|
36
36
|
|
|
37
|
-
### utf8/module.f.
|
|
37
|
+
### utf8/module.f.mjs
|
|
38
38
|
|
|
39
39
|
```js
|
|
40
40
|
/** @type {(input: List<u8|null>) => List<i32>} */
|
|
@@ -69,7 +69,7 @@ Requirement: no loss for UTF16 => codepoint => UTF16
|
|
|
69
69
|
|
|
70
70
|
Total error states: 11 bit
|
|
71
71
|
|
|
72
|
-
### utf16/module.f.
|
|
72
|
+
### utf16/module.f.mjs
|
|
73
73
|
|
|
74
74
|
```js
|
|
75
75
|
/** @type {(input: List<u16|null>) => List<i32>} */
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Property Accessor
|
|
2
|
-
|
|
3
|
-
- `.`
|
|
4
|
-
- `?.`
|
|
5
|
-
|
|
6
|
-
FunctionalScript is a strict subset of JavaScript and should behave the same way as JavaScript or reject JS code during compilation as non-valid FS code. However, every object in JavaScript has inherited properties, such as [`constructor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor) and [`__proto__`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto). These properties can cause side effects. For example:
|
|
7
|
-
|
|
8
|
-
```js
|
|
9
|
-
const f = (() => {}).constructor
|
|
10
|
-
const g = f(`console.log('hello')`)
|
|
11
|
-
g() // we received direct access to I/O
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
According to FunctionScript principles, an FS compiler should reject such code during compilation. So, the compiler will prohibit the use of `construct` and `__proto__` after `.` and `?.`.
|
|
15
|
-
|
|
16
|
-
If an object has its own properties with such names (e.g. `constructor`) then we can access it using the [Object.getOwnPropertyDescriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor) function instead. The function doesn't return inherited properties.
|
|
17
|
-
|
|
18
|
-
```js
|
|
19
|
-
const f = (() => {}).constructor
|
|
20
|
-
const g = Object.getOwnPropertyDescriptor(f, 'constructor') // g === undefined
|
|
21
|
-
|
|
22
|
-
const myObject = { constructor: 42 }
|
|
23
|
-
const c = Object.getOwnPropertyDescriptor(myObject, 'constructor').value // c === 42
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Here's the reason why we prohibit `__proto__`:
|
|
27
|
-
|
|
28
|
-
```js
|
|
29
|
-
const p = (() => {}).__proto__
|
|
30
|
-
const f = Object.getOwnPropertyDescriptor(p, 'constructor').value
|
|
31
|
-
const g = f(`console.log('hello')`)
|
|
32
|
-
g() // side-effect
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Example
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
const a = { x: 3}
|
|
39
|
-
export default a.x
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Depends on [const](./2120-const.md), [default-import](./2130-default-import.md) and [undefined](./2310-undefined.md).
|
|
43
|
-
|
|
44
|
-
See <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors>.
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Function Call With Property Accessor
|
|
2
|
-
|
|
3
|
-
Operators `a.b()`, `a?.b()`.
|
|
4
|
-
|
|
5
|
-
```js
|
|
6
|
-
const x = a.b(5)
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
For `null?.b(x())`. We follow the same behavior as JS, so the `x` function will not be called.
|
|
10
|
-
|
|
11
|
-
Not allowed (additional to `constructor` and `__proto__`, see [property-accessor](./2351-property-accessor.md)):
|
|
12
|
-
|
|
13
|
-
- `__defineGetter__`
|
|
14
|
-
- `__defineSetter__`
|
|
15
|
-
- `__lookupGetter__`
|
|
16
|
-
- `__lookupSetter__`
|
|
17
|
-
- `isPrototypeOf` FS has no prototype concept because it has no inheritance.
|
|
18
|
-
- `toLocaleString` because it depends on the locale, which is a side-effect.
|
|
19
|
-
|
|
20
|
-
Also, from a function:
|
|
21
|
-
|
|
22
|
-
- `apply`
|
|
23
|
-
- `bind`
|
|
24
|
-
- `call`
|
|
25
|
-
|
|
26
|
-
Also, from an array:
|
|
27
|
-
|
|
28
|
-
- `copyWithin`
|
|
29
|
-
- `entries` - returns an iterator.
|
|
30
|
-
- `values` - returns an iterator.
|
|
31
|
-
- `keys` - returns an iterator.
|
|
32
|
-
- `pop`
|
|
33
|
-
- `push`
|
|
34
|
-
- `shift`
|
|
35
|
-
- `unshift`
|
|
36
|
-
- `sort`
|
|
37
|
-
- `reverse`
|
|
38
|
-
|
|
39
|
-
FunctionalScript doesn't allow direct access to iterators. An iterator can be mutated by `.next()` or `for()`. Indirect access to iterators is allowed through the `Iterable` interface. For example
|
|
40
|
-
```js
|
|
41
|
-
for (const i of [1, 2]) { }
|
|
42
|
-
```
|
|
43
|
-
In this example, the loop gets a temporary iterator from the iterable interface of `[1, 2]` then use it and discard it. A user can't have direct access to the iterator and can't make a copy of it.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# At
|
|
2
|
-
|
|
3
|
-
`a[42]`, `a['str']`, `a[+i]`.
|
|
4
|
-
|
|
5
|
-
```js
|
|
6
|
-
import m from './m.f.mjs'
|
|
7
|
-
const a = [2, 3]
|
|
8
|
-
export default {
|
|
9
|
-
"a": a[0],
|
|
10
|
-
// we don't know what is the type of `m` so we force it to be a `number` or `bigint`.
|
|
11
|
-
"b": a[+m]
|
|
12
|
-
}
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
In `a[i]`, `i` has to be a `number` or known `string`, which is not equal to prohibited words, see [property-accessor](./2351-property-accessor.md). If we don't know what is `i`, `+` requires before `i`.
|
|
16
|
-
|
|
17
|
-
It means that the byte code for the expression inside the `[]` should be either the unary `+`, a number literal, or a string literal (excluding some strings). If it references an object, FS gives up. In the future, FS may try deeper analyses and type inference can help a lot.
|
|
18
|
-
|
|
19
|
-
Depends on [property-accessor](./2351-property-accessor.md).
|
package/issues/test-debug.md
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Allow Debugging During Test Run
|
|
2
|
-
|
|
3
|
-
Currently, we read files as strings and then parse them as functions. See [dev/test.mjs](../dev/test.mjs). In this case, the
|
|
4
|
-
debugger doesn't know about the source code and can't debug the functions. The main reason for loading modules as functions was
|
|
5
|
-
that Deno v1 didn't support `.cjs` files. However, Deno v2 supports them.
|
|
6
|
-
|
|
7
|
-
We can fix the issue by changing our test runner. The test runner will scan all directories, find all `test.f.cjs` files, and
|
|
8
|
-
then load them using `require`.
|
|
9
|
-
|
|
10
|
-
Limitations: we will not able to check test module dependencies to have module coverage but, anyway, without a parser, we are not able to get full coverage. So, we can drop support for it right now.
|
|
11
|
-
|
|
12
|
-
**Note:** In this case, we may drop support for Deno v1. At least until we switch to [ESM](./esm.md).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|