functionalscript 0.1.599 → 0.1.601
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/.github/workflows/npm-publish.yml +2 -0
- package/README.md +20 -9
- package/dev/module.mjs +20 -10
- package/dev/test/module.f.mjs +1 -1
- package/dev/test.mjs +3 -3
- package/djs/README.md +32 -8
- package/funding.json +61 -0
- package/issues/README.md +10 -6
- package/issues/djs.md +57 -0
- package/issues/fs-load.md +13 -0
- package/issues/lang/1000-json.md +12 -0
- package/issues/lang/2110-default-export.md +11 -0
- package/issues/lang/2120-const.md +14 -0
- package/issues/lang/2130-default-import.md +10 -0
- package/issues/lang/2210-block-comment.md +12 -0
- package/issues/lang/2220-namespace-import.md +25 -0
- package/issues/lang/2310-undefined.md +7 -0
- package/issues/lang/2320-bigint.md +7 -0
- package/issues/lang/2330-grouping.md +11 -0
- package/issues/lang/2340-operators.md +41 -0
- package/issues/lang/2351-property-accessor.md +44 -0
- package/issues/lang/2352-property-call.md +43 -0
- package/issues/lang/2353-property-at.md +19 -0
- package/issues/lang/2360-built-in.md +74 -0
- package/issues/lang/2410-identifier-property.md +9 -0
- package/issues/lang/2420-line-comment.md +10 -0
- package/issues/lang/2430-trailing-comma.md +13 -0
- package/issues/lang/2440-shorthand.md +8 -0
- package/issues/lang/2450-destructuring.md +12 -0
- package/issues/lang/3110-function.md +11 -0
- package/issues/lang/3120-parameters.md +9 -0
- package/issues/lang/3130-body-const.md +12 -0
- package/issues/lang/3220-let.md +11 -0
- package/issues/lang/3310-expression.md +12 -0
- package/issues/lang/3320-one-parameter.md +10 -0
- package/issues/lang/3330-assignments.md +23 -0
- package/issues/lang/README.md +80 -0
- package/jsr.json +116 -2
- package/nodejs/version/main.mjs +1 -2
- package/nodejs/version/module.f.d.mts +5 -6
- package/nodejs/version/module.f.mjs +15 -16
- package/nodejs/version/test.f.mjs +45 -36
- package/package.json +2 -1
- package/types/list/test.f.mjs +3 -2
package/README.md
CHANGED
|
@@ -12,11 +12,26 @@ FunctionalScript is a purely functional programming language and a strict subset
|
|
|
12
12
|
as a subset of JavaScript.
|
|
13
13
|
- [TypeScript](https://en.wikipedia.org/wiki/TypeScript), as a superset of JavaScript.
|
|
14
14
|
|
|
15
|
-
[A
|
|
15
|
+
[A working draft of the FunctionalScript specification](./issues/lang/README.md).
|
|
16
16
|
|
|
17
17
|
Learn more about
|
|
18
|
-
- [Purely Functional Programming in JavaScript](https://
|
|
19
|
-
- [FunctionalScript and I/O](https://medium.com/@sergeyshandar/functionalscript-5cf817345376).
|
|
18
|
+
- [Purely Functional Programming in JavaScript](https://blog.bitsrc.io/purely-functional-programming-in-javascript-91114b1b2dff?sk=5f7132e56902f38fcf4c6164bfa681ed),
|
|
19
|
+
- [FunctionalScript and I/O](https://medium.com/@sergeyshandar/functionalscript-5cf817345376?sk=30b32189a81d1a2dad16c2244f32328d).
|
|
20
|
+
|
|
21
|
+
FunctionalScript is distributed under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html#license-text). Let us know if you need another license by sending an [email](mailto:sergey.oss@proton.me).
|
|
22
|
+
|
|
23
|
+
## Vision
|
|
24
|
+
|
|
25
|
+
We aim to create a safe, cross-platform programming language that can work in any JS platform without any build step. There are thousands of programming languages, and we don't want to create another one that others must learn. Instead, we take the opposite approach: we remove everything that makes the most popular and cross-platform language unsafe, insecure, or less portable.
|
|
26
|
+
|
|
27
|
+
## Applications
|
|
28
|
+
|
|
29
|
+
FunctionalScript code can be used:
|
|
30
|
+
|
|
31
|
+
- safely in any JavaScript/TypeScript application or library;
|
|
32
|
+
- as a JSON with expressions, see [DJS](https://medium.com/@sasha.gil/bridging-the-gap-from-json-to-javascript-without-dsls-fee273573f1b);
|
|
33
|
+
- as a query language,
|
|
34
|
+
- as a smart contract programming language in DeFi.
|
|
20
35
|
|
|
21
36
|
## Design Principles
|
|
22
37
|
|
|
@@ -27,13 +42,9 @@ In FunctionalScript:
|
|
|
27
42
|
- A module can depend only on another FunctionalScript module.
|
|
28
43
|
- It also has no standard library. Only a safe subset of standard JavaScript API can be used without referencing other modules.
|
|
29
44
|
|
|
30
|
-
##
|
|
31
|
-
|
|
32
|
-
FunctionalScript code can be used:
|
|
45
|
+
## Our Next Step
|
|
33
46
|
|
|
34
|
-
-
|
|
35
|
-
- as a JSON with expressions,
|
|
36
|
-
- as a query language.
|
|
47
|
+
[Re-architecture of NaNVM](https://medium.com/@sergeyshandar/nanvm-re-architecture-8097f766ec1c?sk=d14ec1daf73ac5442f12ce20b2bc037a).
|
|
37
48
|
|
|
38
49
|
## Sponsors
|
|
39
50
|
|
package/dev/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdir, writeFile } from 'node:fs/promises'
|
|
1
|
+
import { readdir, writeFile, readFile } from 'node:fs/promises'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @typedef {{
|
|
@@ -66,12 +66,12 @@ export const exit = self.Deno ? self.Deno.exit : process.exit
|
|
|
66
66
|
/** @type {(v: string) => string|undefined} */
|
|
67
67
|
export const env =
|
|
68
68
|
self.Deno ? self.Deno.env.get :
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
a => {
|
|
70
|
+
const r = Object.getOwnPropertyDescriptor(process.env, a)
|
|
71
|
+
return r === void 0 ? void 0 :
|
|
72
|
+
typeof r.get === 'function' ? r.get() :
|
|
73
|
+
r.value
|
|
74
|
+
}
|
|
75
75
|
|
|
76
76
|
export const loadModuleMap = async () => {
|
|
77
77
|
/** @type {() => Promise<UnknownMap>} */
|
|
@@ -86,7 +86,7 @@ export const loadModuleMap = async () => {
|
|
|
86
86
|
const file = `${p}/${name}`
|
|
87
87
|
if (i.isDirectory()) {
|
|
88
88
|
await f(file)
|
|
89
|
-
} else if (name.endsWith('.f.cjs') || name.endsWith('.f.mjs')) {
|
|
89
|
+
} else if (name.endsWith('.f.cjs') || name.endsWith('.f.mjs') || name.endsWith('.f.js')) {
|
|
90
90
|
const source = await import(`../${file}`)
|
|
91
91
|
map.push([file, source.default])
|
|
92
92
|
}
|
|
@@ -178,13 +178,23 @@ const codeAdd = i => p => m => {
|
|
|
178
178
|
return [result, im]
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
export const index = async() => {
|
|
181
|
+
export const index = async () => {
|
|
182
|
+
{
|
|
183
|
+
const jj = './jsr.json'
|
|
184
|
+
const jsr_json = JSON.parse(await readFile(jj, { encoding: 'utf8' }))
|
|
185
|
+
const exports = Object.keys(await loadModuleMap())
|
|
186
|
+
await writeFile(
|
|
187
|
+
jj,
|
|
188
|
+
JSON.stringify({ ...jsr_json, exports }, null, 2))
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
//
|
|
182
192
|
/** @type {FolderMap} */
|
|
183
193
|
let m = {}
|
|
184
194
|
for (const k in await loadModuleMap()) {
|
|
185
195
|
const [, ...s] = k.split('/')
|
|
186
196
|
switch (s[s.length - 1]) {
|
|
187
|
-
case 'module.f.cjs': case 'module.f.mjs':
|
|
197
|
+
case 'module.f.cjs': case 'module.f.mjs': case 'module.f.js':
|
|
188
198
|
m = folderMapAdd(m)(s)
|
|
189
199
|
break
|
|
190
200
|
}
|
package/dev/test/module.f.mjs
CHANGED
|
@@ -46,7 +46,7 @@ import * as Result from '../../types/result/module.f.mjs'
|
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
48
|
/** @type {(s: string) => boolean} */
|
|
49
|
-
const isTest = s => s.endsWith('test.f.cjs') || s.endsWith('test.f.mjs')
|
|
49
|
+
const isTest = s => s.endsWith('test.f.cjs') || s.endsWith('test.f.mjs') || s.endsWith('test.f.js')
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* @typedef {{
|
package/dev/test.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadModuleMap, exit, env } from './module.mjs'
|
|
2
|
+
import test from './test/module.f.mjs'
|
|
2
3
|
|
|
3
4
|
/** @type {(f: (s: string) => void) => (s: string) => <T>(_: T) => T} */
|
|
4
5
|
const anyLog = f => s => state => {
|
|
@@ -44,15 +45,14 @@ const measure = f => state => {
|
|
|
44
45
|
const main = async() => {
|
|
45
46
|
const moduleMap = await loadModuleMap()
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
const f = moduleMap['./dev/test/module.f.mjs'].default
|
|
49
|
-
const r = f({
|
|
48
|
+
const r = test({
|
|
50
49
|
moduleMap,
|
|
51
50
|
log: anyLog(console.log),
|
|
52
51
|
error: anyLog(console.error),
|
|
53
52
|
measure,
|
|
54
53
|
tryCatch,
|
|
55
54
|
env,
|
|
55
|
+
state: void 0,
|
|
56
56
|
})
|
|
57
57
|
exit(r[0])
|
|
58
58
|
}
|
package/djs/README.md
CHANGED
|
@@ -9,15 +9,31 @@
|
|
|
9
9
|
|
|
10
10
|
## Next steps
|
|
11
11
|
|
|
12
|
-
- [ ] rename `fjson` to `djs` (data javascript), File extensions: `.d.
|
|
12
|
+
- [ ] rename `fjson` to `djs` (data javascript), File extensions: `.d.mjs`, `.d.js`.
|
|
13
13
|
- [x] use JS tokenizer
|
|
14
14
|
- [x] identifiers `{a:5}`
|
|
15
15
|
- [x] big int
|
|
16
|
-
- [ ] `
|
|
17
|
-
- [ ] constants
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
- [ ] `export default ...`
|
|
17
|
+
- [ ] constants
|
|
18
|
+
```js
|
|
19
|
+
const a = [3]
|
|
20
|
+
export default = { a: a, b: a }
|
|
21
|
+
```
|
|
22
|
+
Serialization
|
|
23
|
+
```js
|
|
24
|
+
const _0=[3]
|
|
25
|
+
export default {a:_0,b:_0}
|
|
26
|
+
```
|
|
27
|
+
- [ ] import
|
|
28
|
+
```js
|
|
29
|
+
import a from 'c.d.mjs'
|
|
30
|
+
export default { a: a, b: a}
|
|
31
|
+
```
|
|
32
|
+
- [ ] short form
|
|
33
|
+
```js
|
|
34
|
+
const a = 5;
|
|
35
|
+
export default { a }
|
|
36
|
+
```
|
|
21
37
|
|
|
22
38
|
Optional, for fun, syntax sugar:
|
|
23
39
|
|
|
@@ -26,5 +42,13 @@ Optional, for fun, syntax sugar:
|
|
|
26
42
|
|
|
27
43
|
## Decidable Language
|
|
28
44
|
|
|
29
|
-
- [ ] using operator and functions
|
|
30
|
-
|
|
45
|
+
- [ ] using operator and functions
|
|
46
|
+
```js
|
|
47
|
+
const a = 2+2+Math.abs(5)
|
|
48
|
+
export default { a: a }
|
|
49
|
+
```
|
|
50
|
+
- [ ] decidable functions?
|
|
51
|
+
```js
|
|
52
|
+
const f = a => b => a + b
|
|
53
|
+
export default f(1)(2)
|
|
54
|
+
```
|
package/funding.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "v1.0.0",
|
|
3
|
+
"entity": {
|
|
4
|
+
"type": "individual",
|
|
5
|
+
"role": "owner",
|
|
6
|
+
"name": "Sergey Shandar",
|
|
7
|
+
"email": "sergey.oss@proton.me",
|
|
8
|
+
"description": "Sergey is the main author of FunctionalScript, and other OSS projects related to content-addressable infrastructure",
|
|
9
|
+
"webpageUrl": {
|
|
10
|
+
"url": "https://github.com/functionalscript/functionalscript"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"projects": [
|
|
14
|
+
{
|
|
15
|
+
"guid": "functionalscript",
|
|
16
|
+
"name": "FunctionalScript",
|
|
17
|
+
"description": "FunctionalScript is a purely functional safe subset of JavaScript",
|
|
18
|
+
"webpageUrl": {
|
|
19
|
+
"url": "https://github.com/functionalscript/functionalscript"
|
|
20
|
+
},
|
|
21
|
+
"repositoryUrl": {
|
|
22
|
+
"url": "https://github.com/functionalscript/functionalscript"
|
|
23
|
+
},
|
|
24
|
+
"licenses": [
|
|
25
|
+
"spdx:AGPL-3.0-only"
|
|
26
|
+
],
|
|
27
|
+
"tags": [
|
|
28
|
+
"programming",
|
|
29
|
+
"web-development",
|
|
30
|
+
"software-engineering",
|
|
31
|
+
"developer-tools",
|
|
32
|
+
"programming-language",
|
|
33
|
+
"cryptography",
|
|
34
|
+
"smart-contract"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
"funding": {
|
|
39
|
+
"channels": [
|
|
40
|
+
{
|
|
41
|
+
"guid": "github",
|
|
42
|
+
"type": "other",
|
|
43
|
+
"address": "https://github.com/sponsors/sergey-shandar"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"plans": [
|
|
47
|
+
{
|
|
48
|
+
"guid": "nanvm",
|
|
49
|
+
"status": "active",
|
|
50
|
+
"name": "NaNVM",
|
|
51
|
+
"description": "NaNVM is a virtual machine for the FunctionalScript",
|
|
52
|
+
"amount": 0,
|
|
53
|
+
"currency": "USD",
|
|
54
|
+
"frequency": "one-time",
|
|
55
|
+
"channels": [
|
|
56
|
+
"github"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
package/issues/README.md
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
# Issues
|
|
2
2
|
|
|
3
3
|
1. [X] [test-debug](./test-debug.md).
|
|
4
|
-
2. [
|
|
5
|
-
3. [ ] [
|
|
6
|
-
4. [ ]
|
|
7
|
-
5. [ ]
|
|
4
|
+
2. [X] [esm](./esm.md)
|
|
5
|
+
3. [ ] [djs](./djs.md)
|
|
6
|
+
4. [ ] VM Rust project
|
|
7
|
+
5. [ ] [publish](publish.md)
|
|
8
|
+
6. [ ] fix index generation by including sub modules `{ ...m, add: mAdd, remove: mRemove}`.
|
|
9
|
+
7. [ ] Conventions:
|
|
8
10
|
```js
|
|
9
11
|
import list, * as List from 'list.mjs'
|
|
10
12
|
// list is for objects.
|
|
11
13
|
// List is for types and should be ignored by FJS or errored if used in code.
|
|
12
14
|
```
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
8. Move logic from `.mjs` files to `.f.mjs` files.
|
|
16
|
+
9. Two sets of property filters:
|
|
15
17
|
- usage `.b`:
|
|
16
18
|
- `constructor`
|
|
17
19
|
- ...
|
|
18
20
|
- call `.b()`:
|
|
19
21
|
- `push`
|
|
20
22
|
- ...
|
|
23
|
+
10. [ ] Replace file extensions from `.mjs` to `.js`. Make sure `package.json/type` is equal to `module`. May be later: https://v8.dev/features/modules#mjs
|
|
24
|
+
11. [ ] [fs-load](./fs-load.md)
|
package/issues/djs.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# DJS
|
|
2
|
+
|
|
3
|
+
Parse this code
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import a from 'c.d.mjs'
|
|
7
|
+
const c = [12, 'x']
|
|
8
|
+
export default { a: a, b: a, c: c}
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Into this structure:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
type Module = {
|
|
15
|
+
modules: string[]
|
|
16
|
+
func: Func
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// the last constant from the array is a return
|
|
20
|
+
type Func = Const[]
|
|
21
|
+
|
|
22
|
+
type Const = Primitive | CObject | CArray |CRef | ARef
|
|
23
|
+
|
|
24
|
+
type Primitive = number|string|boolean|null|bigint
|
|
25
|
+
|
|
26
|
+
type CRef = ['cref', number]
|
|
27
|
+
|
|
28
|
+
type ARef = ['aref', number]
|
|
29
|
+
|
|
30
|
+
type CObject = ['object', {
|
|
31
|
+
[k in string]: Const
|
|
32
|
+
}]
|
|
33
|
+
|
|
34
|
+
type CArray = ['array', [Const]]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Where `func` is a description of the function:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
(...args) => {
|
|
41
|
+
const const0 = [12, 'x']
|
|
42
|
+
return { a: args[0], b: args[0], c: const0}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Parsed Example
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
export default
|
|
50
|
+
// array of constants
|
|
51
|
+
[
|
|
52
|
+
// const const0
|
|
53
|
+
['array', [12, 'x']],
|
|
54
|
+
// return
|
|
55
|
+
['object', { 'a': ['aref', 0], 'b': ['aref', 0], c: ['cref', 0] }]
|
|
56
|
+
]
|
|
57
|
+
```
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# FS VM load/save
|
|
2
|
+
|
|
3
|
+
sketch / mention future documentation on errors / exceptions and execution scheme in general, for example:
|
|
4
|
+
|
|
5
|
+
The host environment has well defined operations like 'Load' (takes a "root" module path, optional extra parameters), 'Execute' (takes the successful result of 'Load', optional extra parameters), 'Save' (takes the successful result of 'Load', optional extra parameters).
|
|
6
|
+
|
|
7
|
+
'Load' time errors are communicated to the host environment (e.g. to output error diagnostics on the console). In presence of load time errors there is no successful result of 'Load', so there is nothing to pass to Execute, Save. However, it makes sense to have results of a partially successful 'Load' even though they cannot be used in 'Execute', 'Save' - for example, in language server protocol scenarios.
|
|
8
|
+
|
|
9
|
+
'Save' corresponds to code / data transformations other than 'Execute', e.g. bundling. 'Save' time errors are communicated to the host environment. It might make sense to have results of a partially successful 'Save' (similarly to abovementioned scenarios for partially successful 'Load' results).
|
|
10
|
+
|
|
11
|
+
'Execute' corresponds to calling the function that is the default export of the "root" module and that takes produces side effects on the environment. Execution ends with a halt caused either by the inner logic of the code (e.g. the root function successfully completes, or an unhandled error happens), or by external causes (e.g. the user stops the execution).
|
|
12
|
+
|
|
13
|
+
Now, does a proper FS system provide user code means to handle errors, e.g. an exception handling mechanism similar to JS's exception handling?
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Default Export
|
|
2
|
+
|
|
3
|
+
Parse `export default` and then JSON. This's enough to have the same functionality as JSON.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
export default 5
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Depends on [JSON](./1110-json.md)
|
|
10
|
+
|
|
11
|
+
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Constants
|
|
2
|
+
|
|
3
|
+
This is enough to provide basic DJS graph and serialization.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
const a = null
|
|
7
|
+
export default {
|
|
8
|
+
"a": a,
|
|
9
|
+
}
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Depends on [default-export](./2110-default-export.md).
|
|
13
|
+
|
|
14
|
+
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Block Comment
|
|
2
|
+
|
|
3
|
+
We need it to declare JSDoc/TypeScript types.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
/** @type {number} */
|
|
7
|
+
export default -42.5
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Depends on [default-export](./2110-default-export.md).
|
|
11
|
+
|
|
12
|
+
See <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#line_comments>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Namespace Import
|
|
2
|
+
|
|
3
|
+
We need it to import types from other modules.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import * as A from './a.d.mjs'
|
|
7
|
+
/** @type {A.Type} */
|
|
8
|
+
export default [5]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Where `./a.d.mjs` may look like this:
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
// this type can be used in other modules
|
|
15
|
+
/** @typedef {readonly [number]} Type */
|
|
16
|
+
|
|
17
|
+
// export nothing
|
|
18
|
+
export default null
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
FunctionalScript should use namespace import only as a mechanism to reference type definitions. Since, VM doesn't analyze types, namespace import can be ignored be VM. However different linters, such as TypeScript, can use the information.
|
|
22
|
+
|
|
23
|
+
Depends on [default-import](./2110-default-export.md).
|
|
24
|
+
|
|
25
|
+
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#namespace_import
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Operators
|
|
2
|
+
|
|
3
|
+
|Type |Operator |Priority |
|
|
4
|
+
|-----------|---------|-----------|
|
|
5
|
+
|Comparison |`==` |not allowed|
|
|
6
|
+
| |`!=` |not allowed|
|
|
7
|
+
| |`===` |1 |
|
|
8
|
+
| |`!==` |1 |
|
|
9
|
+
| |`>` |1 |
|
|
10
|
+
| |`>=` |1 |
|
|
11
|
+
| |`<` |1 |
|
|
12
|
+
| |`<=` |1 |
|
|
13
|
+
|Arithmetics|`+` |1 |
|
|
14
|
+
| |`-` |1 |
|
|
15
|
+
| |`*` |1 |
|
|
16
|
+
| |`/` |1 |
|
|
17
|
+
| |`%` |1 |
|
|
18
|
+
| |unary `-`|1 |
|
|
19
|
+
| |unary `+`|1 |
|
|
20
|
+
| |`**` |1 |
|
|
21
|
+
|Bitwise |`&` |1 |
|
|
22
|
+
| |`\|` |1 |
|
|
23
|
+
| |`^` |1 |
|
|
24
|
+
| |`~` |1 |
|
|
25
|
+
| |`<<` |1 |
|
|
26
|
+
| |`>>` |1 |
|
|
27
|
+
| |`>>>` |1 |
|
|
28
|
+
|Logical |`&&` |1 |
|
|
29
|
+
| |`\|\|` |1 |
|
|
30
|
+
| |`??` |1 |
|
|
31
|
+
| |`!` |1 |
|
|
32
|
+
|Conditional|`?:` |1 |
|
|
33
|
+
|Comma |`,` |not allowed|
|
|
34
|
+
|
|
35
|
+
[Comma operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_operator) is useful only when we want to mutate. We have only one case where we can mutate an object; it's [let](./3320-let.md), and we would like to keep it as simple as possible to track life-time. So, NO for the `,` comma operator.
|
|
36
|
+
|
|
37
|
+
Depends on [default-export](./2110-default-export.md) and [undefined](./2310-undefined.md).
|
|
38
|
+
|
|
39
|
+
For mutating operators, see [assignments](./3330-assignments.md).
|
|
40
|
+
|
|
41
|
+
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_operators
|
|
@@ -0,0 +1,44 @@
|
|
|
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>.
|
|
@@ -0,0 +1,43 @@
|
|
|
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.
|
|
@@ -0,0 +1,19 @@
|
|
|
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).
|