functionalscript 0.0.252 → 0.0.265

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
@@ -3,157 +3,179 @@
3
3
  FunctionalScript is a pure functional programming language and a strict subset of
4
4
  [ECMAScript](https://en.wikipedia.org/wiki/ECMAScript)/[JavaScript](https://en.wikipedia.org/wiki/JavaScript). It's inspired by
5
5
 
6
- - [JSON](https://en.wikipedia.org/wiki/JSON), as a subset of JavaScript; FunctionalScript is a superset of JSON.
7
- - [asm.JS](https://en.wikipedia.org/wiki/Asm.js)/[WebAssembly](https://en.wikipedia.org/wiki/WebAssembly), as a subset of JavaScript;
6
+ - [JSON](https://en.wikipedia.org/wiki/JSON) as a subset of JavaScript. JSON is also a subset of FunctionalScript.
7
+ - [asm.JS](https://en.wikipedia.org/wiki/Asm.js)/[WebAssembly](https://en.wikipedia.org/wiki/WebAssembly), as a subset of JavaScript.
8
8
  - [TypeScript](https://en.wikipedia.org/wiki/TypeScript), as a superset of JavaScript.
9
9
 
10
+ Create a new FunctionalScript repository on GitHub [here](https://github.com/functionalscript/template/generate).
11
+
10
12
  Try FunctionalScript [here](https://functionalscript.com/).
11
13
 
12
- Create a new FunctionalScript repository on GitHub [here](https://github.com/functionalscript/template/generate).
14
+ ## 1. Design Principles
13
15
 
14
- One of the main challenges is how to make a pure functional language when ES6 TCO is not supported by Chrome and Firefox.
15
- A workaround for this problem is to use `let` for renaming objects.
16
+ In FunctionalScript:
16
17
 
17
- ## Install FunctionalScript As A Library
18
+ - Any module is a valid JavaScript module
19
+ - Code should not have [side-effects](https://en.wikipedia.org/wiki/Side_effect_(computer_science)). Any JavaScript statement, expression, or function which has a side effect is not allowed in FunctionalScript. There are no exceptions to this rule, such as `unsafe` code which can be found in Rust, C#, and other languages.
20
+ - A module can't depend on non FunctionalScript module.
21
+ - It also has no standard library, only a safe subset of standard JavaScript API can be used without referencing other modules.
18
22
 
19
- ```
20
- npm install -S github:functionalscript/functionalscript
21
- ```
23
+ ## 2. Outlines
22
24
 
23
- ## JSON
25
+ ### 2.1. Module Ecosystem
26
+
27
+ FunctionalScript uses [CommonJS](https://en.wikipedia.org/wiki/CommonJS) conventions as a module ecosystem. For example,
24
28
 
25
29
  ```js
26
- jsonFile = expression
27
- expression = primitive | array | objects
28
- primitive = 'true' | 'false' | 'null' | number | string
29
- array = '[' (() | items) ']'
30
- items = expression (() | ',' items)
31
- object = '{' (() | properties) '}'
32
- properties = propertyId ':' expression (() | ',' properties)
33
- propertyId = string
30
+ const thirdPartyModule = require('third-party-package/module')
31
+
32
+ const result = thirdPartyModule.someFunction('hello')
34
33
  ```
35
34
 
36
- ## Stage 0
35
+ ### 2.2. Packages
37
36
 
38
- This stage can be used as an intermediate-code for VMs.
37
+ FunctionalScript uses a `package.json` file to define a package. This file is compatible with [Node.js `package.json`](https://nodejs.org/en/knowledge/getting-started/npm/what-is-the-file-package-json/).
38
+ The prefered way to refence dependencies is to use a GitHub URL. These dependencies in a `package.json` file could look like this,
39
39
 
40
- ```js
41
- fjsFile = expression
42
- expression = primitive | array | object | func | id | propertyAccessor
43
- func = ('()' | id) '=>' body
44
- body = '{' statements 'return' expression ';' '}'
45
- statements = () | (statement statements)
46
- statement = decl | ifStatement
47
- decl = `const` id `=` expression `;`
48
- ifStatement = `if` `(` expression `)` body
49
- propertyAccessor = expression `[` expression `]`
50
- call = expression `(` ( expression | ()) `)`
40
+ ```json
41
+ {
42
+ ...
43
+ "dependencies": {
44
+ "third-party-package": "github:exampleorg/thirdpartypackage"
45
+ }
46
+ ...
47
+ }
51
48
  ```
52
49
 
53
- ### Stage 0.1. Node.js
50
+ **Note:** this repository is also a FunctionalScript package, and it can be used as a library. To install this package, use
54
51
 
55
- ```js
56
- nodeFile = statements 'module.exports' '=' expression ';'
52
+ ```
53
+ npm install -S github:functionalscript/functionalscript
57
54
  ```
58
55
 
59
- ### Stage 0.2.
56
+ ### 2.3. Module Structure
60
57
 
61
- #### Operators
58
+ A module is a file with the `.js` extention. It contains three parts: references to other modules, definitions, and exports. For example
62
59
 
60
+ `./first.js`
63
61
  ```js
64
- expression = ... | 'undefined' | groupingOperator | binaryOperatorExpression | unaryOperator | conditionalOperator
65
- groupingOperator = '(' expression ')'
66
- binaryOperatorExpression = expression binaryOperator expression
67
- binaryOperator = comparisonOperator | arithmeticOperator | bitwiseOperator | logicalOperators | '??'
68
- comparisonBinaryOperator = '===' | '!==' | '>' | '<' | '>=' | '<='
69
- arithmeticBinaryOperator = '+' | '-' | '*' | '/' | '%' | '**'
70
- bitwiseBinaryOperator = '&' | '|' | '^' | '<<' | '>>' | '>>>'
71
- logicalBinaryOperator = '&&' | '||'
72
- unaryOperator = '-' | '~' | '!'
62
+ // 1. references
63
+ const math = require('math')
64
+
65
+ // 2. definitions
66
+ const myConst = 42
67
+ // addition(a)(b) = a + b
68
+ const addition = a => b => a + b
69
+ const add42 = addition(42)
70
+ const _10digitsOfPi = math.calculatePi(10)
71
+
72
+ // 3. exports
73
+ module.exports = {
74
+ addition,
75
+ add42,
76
+ _10digitsOfPi,
77
+ }
73
78
  ```
74
79
 
75
- Note: the syntax should be fixed to reflect operator precedents.
80
+ `./second.js`
81
+ ```js
82
+ // 1. references
83
+ const first = require('./first.js')
84
+
85
+ const _42plus7 = first.add42(7)
86
+ ```
76
87
 
77
- No `==`, `!=`, `=...` operators.
88
+ ### 2.4. References To Other Modules
78
89
 
79
- #### Function Expression
90
+ The format of references is `const ANYNAME = require('PATH_TO_A_MODULE')`. For example,
80
91
 
81
92
  ```js
82
- func = ('()' | id) '=>' (('{' statements 'return' expression ';' '}') | expression)
93
+ const math = require('math')
94
+ const algebra = require('math/algebra')
95
+ const localFile = require('../some-directory/some-file.js')
83
96
  ```
84
97
 
85
- #### PropertyAccessor
98
+ ### 2.5. Definitions
86
99
 
87
- ```js
88
- propertyAccessor = expression (('[' expression ']') | ('.' id))
89
- ```
100
+ The format of defintions is `const NAME = EXPRESSION`, where the `EXPRESSION` is a subset of [JavaScript expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators).
90
101
 
91
102
  ```js
92
- propertyId = string | id
103
+ const myConst = 42
104
+ const functionDouble = a => a * 2
105
+ const structure = { name: "John", surname: "Smith" }
106
+ const array = [1, 2, 3]
107
+ const nestedStructure = {
108
+ address: undefined,
109
+ serialNumber: "123-45-78",
110
+ sum: 14 + myConst + functionDouble(4),
111
+ moreInfo: {
112
+ name: "Ivan",
113
+ surname: "Terrible",
114
+ }
115
+ }
93
116
  ```
94
117
 
95
- #### BigInt
118
+ See [3. Expressions](#3-Expressions).
96
119
 
97
- For example `42n`.
120
+ ### 2.6. Exports
98
121
 
99
- #### Additional Operators
122
+ The format of exports is `module.exports = { A_LIST_OF_EXPORTED_DEFINITIONS }`. There should be only one `module.exports` at
123
+ the end of a FunctionalScript file. For example,
100
124
 
101
125
  ```js
102
- typeOfOperator = 'typeof' expression
103
- inOperator = expression 'in' expression
126
+ module.exports = {
127
+ nestedStructure,
128
+ array,
129
+ structure,
130
+ }
104
131
  ```
105
132
 
106
- ### Stage 0.3. Syntax sugar
107
-
108
- Hex, binary and octal literals
109
- Functions with multiple parameters.
110
- Spread syntax. For example `...object`.
111
- Destructing assignments. For example `const {a,b} = exp;`, `const [a, b] = exp`.
112
- Property Id expression `{ [exp]: exp }`.
113
- Allow no semicolons.
114
- Optional comma in arrays and objects.
115
- Template literals ``const r= `onst r = ${exp}`;``.
116
- An `if` statement `if (exp) { ... return exp }`
117
- Multiline strings
133
+ ## 3. Expressions
134
+
135
+ Expressions could fall under these categories:
136
+
137
+ - Literals:
138
+ - Number Literals, e.g. `0`, `3.14`, `4e8`
139
+ - Boolean Literals: `true` or `false`
140
+ - A `null` Literal
141
+ - An `undefined` Literal
142
+ - String Literals, e.g. `"Hello world!"`
143
+ - Complex Structures
144
+ - Arrays, e.g. `[2, 5]`
145
+ - Objects, e.g. `{ a: "Hello", b: "world!" }`
146
+ - Arrow functions, e.g. `x => x * 2`
147
+ - Operators
148
+ - Comparison Operators: `===`, `!==`, `>`, `>=`, `<`, `<=`
149
+ - Arithmetic Operators: `+`, `-`, `*`, `/`, `%`, `**`
150
+ - Bitwise Operators: `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>`
151
+ - Logical Operators: `&&`, `||`, `!`, `??`
152
+ - Conditional Operator, e.g. `condition ? val1 : val2`
153
+ - Template Literals, e.g. `string ${expression}`
154
+ - `typeof`
155
+ - Relations Operators: `in`, `instanceof`.
156
+ - Member Operators: `.`, `[]`.
157
+
158
+ Note: the `.` member operator has prohibitted property names, such as `constructor` and `push`. To access such properties, it's recommeded to use the `Object.getPropertyDescriptor` function.
159
+
160
+ ## 4. Arrow Functions
161
+
162
+ An arrow function is also known as [a lambda function](https://en.wikipedia.org/wiki/Anonymous_function).
163
+ The format of an arrow function is `ARGUMENT_NAME => FUNCTION_BODY`. An arrow function must have either a single argument or no arguments at all. For example
164
+
165
+ ```js
166
+ x => x * 2
167
+ a => a + 4
168
+ s => `template literal ${s}`
169
+ () => 'hello' // an arrow function with no arguments
170
+ ```
171
+
172
+ A function body is either an expression or a block statement. A block statement format is `{ A_LIST_OF_STATEMENTS }`. For example
173
+
118
174
  ```js
119
- 'sss\
120
- wwww'
175
+ // a function with one argument and a block statement
176
+ const f = x => {
177
+ const a = 2 + x
178
+ const r = a + 4
179
+ return r
180
+ }
121
181
  ```
122
- Regular expressions.
123
-
124
- ## Stage 1
125
-
126
- Typing using [JSDoc](https://jsdoc.app/) and TypeScript types.
127
-
128
- ## Stage 2
129
-
130
- Mutable types with exclusive ownership (similar to Rust mutability).
131
-
132
- - `let`, `for`, `while` etc.
133
- Note: `let` can work as an object name reuse.
134
- In this case, `let` objects can't be used in nested functions. It means we can't reference `let` object.
135
- ```js
136
- let x = 5 // ok
137
- f(x)
138
- x = 'hello!' // ok
139
- f(x)
140
- const r = () => {
141
- return x // compilation error
142
- }
143
- ```
144
- Translated into
145
- ```js
146
- const x0 = 5
147
- f(x0)
148
- const x1 = 'hello!'
149
- f(x1)
150
- ```
151
- - Generators `function*(){ ... yield ... }`.
152
- - Async `async () => f(await exp())`.
153
- - hopefully, we will have [ES pipe operator](https://tc39.es/proposal-pipeline-operator/) at this time.
154
- - [pattern matching](https://github.com/tc39/proposal-pattern-matching)
155
-
156
- Controversial ideas:
157
-
158
- - Import and export `import x from "..."`, `export const x = ...`, `export default = ` e.t.c. This may break `new Function` runners.
159
- - Functional-TypeScript as a subset of TypeScript. Note: FunctionalScript doesn't require an additional build step in contrast to TypeScript.
@@ -52,4 +52,8 @@ type BuildState<M> = {
52
52
  }
53
53
 
54
54
  const getOrBuild: <M>(buildConfig: BuildConfig<M>) => readonly[ModuleState, M];
55
+
56
+ //
57
+
58
+
55
59
  ```
@@ -0,0 +1,62 @@
1
+ const package_ = require('../package')
2
+ const module_ = require('../module')
3
+ const function_ = require('../module/function')
4
+ const { todo } = require('../../dev')
5
+
6
+ /**
7
+ * @template M
8
+ * @typedef {{
9
+ * readonly pagkageGet: package_.Get
10
+ * readonly moduleMapInterface: module_.MapInterface<M>
11
+ * readonly moduleId: module_.Id
12
+ * readonly moduleMap: M
13
+ * }} Config
14
+ */
15
+
16
+ /**
17
+ * @template M
18
+ * @typedef {readonly[module_.State, M]} Result
19
+ */
20
+
21
+ /**
22
+ * @type {(packageGet: package_.Get) =>
23
+ * <M>(moduleMapInterface: module_.MapInterface<M>) =>
24
+ * (compile: function_.Compile) =>
25
+ * (moduleId: module_.Id) =>
26
+ * (moduleMap: M) =>
27
+ * Result<M>
28
+ * }
29
+ */
30
+ const getOrBuild = packageGet => moduleMapInterface => compile => moduleId => moduleMap => {
31
+ const moduleIdStr = module_.idToString(moduleId)
32
+
33
+ /** @type {() => Result<typeof moduleMap>} */
34
+ const notFound = () => [['error', ['file not found']], moduleMap]
35
+
36
+ /** @type {(e: module_.Error) => Result<typeof moduleMap>} */
37
+ const error = e => {
38
+ /** @type {module_.State} */
39
+ const state = ['error', e]
40
+ moduleMapInterface.insert(moduleIdStr)(state)
41
+ return [state, moduleMap]
42
+ }
43
+
44
+ const m = moduleMapInterface.at(moduleIdStr)(moduleMap)
45
+ if (m !== undefined) { return [m, moduleMap] }
46
+
47
+ const p = packageGet(moduleId.packageId)
48
+ if (p === undefined) { return notFound() }
49
+
50
+ const source = p.file(moduleId.path.join('/'))
51
+ if (source === undefined) { return notFound() }
52
+
53
+ const compileResult = compile(source)
54
+ if (compileResult[0] === 'error') { return error(['compilation error', compileResult[1]]) }
55
+
56
+ return todo()
57
+ }
58
+
59
+ module.exports = {
60
+ /** @readonly */
61
+ getOrBuild,
62
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * An IO interface for creating and running module functions.
3
+ */
4
+
5
+ const result = require('../../../types/result')
6
+
7
+ /** @typedef {<M>(require: Require<M>) => (prior: M) => Result<M>} Function */
8
+
9
+ /**
10
+ * @template M
11
+ * @typedef {readonly[result.Result<unknown, unknown>, M]} Result
12
+ */
13
+
14
+ /**
15
+ * @template M
16
+ * @typedef {(path: string) => (prior: M) => Result<M>} Require
17
+ */
18
+
19
+ /** @typedef {(source: string) => result.Result<Function, unknown>} Compile */
20
+
21
+ module.exports = {}
@@ -3,17 +3,17 @@ const object = require('../../types/object')
3
3
  /**
4
4
  * @template M
5
5
  * @typedef {{
6
- * readonly at: (moduleId: string) => (moduleMap: M) => ModuleState | undefined
7
- * readonly insert: (moduleId: string) => (moduleState: ModuleState) => (moduleMap: M) => M
8
- * }} ModuleMapInterface
6
+ * readonly at: (moduleId: string) => (moduleMap: M) => State | undefined
7
+ * readonly insert: (moduleId: string) => (moduleState: State) => (moduleMap: M) => M
8
+ * }} MapInterface
9
9
  */
10
10
 
11
11
  /**
12
12
  * @typedef {|
13
13
  * readonly['ok', Module] |
14
- * readonly['error', ModuleError] |
14
+ * readonly['error', Error] |
15
15
  * readonly['building']
16
- * } ModuleState
16
+ * } State
17
17
  */
18
18
 
19
19
  /**
@@ -25,11 +25,24 @@ const object = require('../../types/object')
25
25
 
26
26
  /**
27
27
  * @typedef {|
28
- * 'file not found' |
29
- * 'compile error' |
30
- * 'runtime error' |
31
- * 'circular reference'
32
- * } ModuleError
28
+ * ['file not found'] |
29
+ * ['compilation error', unknown] |
30
+ * ['runtime error'] |
31
+ * ['circular reference']
32
+ * } Error
33
33
  */
34
34
 
35
- module.exports = {}
35
+ /**
36
+ * @typedef {{
37
+ * readonly packageId: string
38
+ * readonly path: readonly string[]
39
+ * }} Id
40
+ */
41
+
42
+ /** @type {(id: Id) => string} */
43
+ const idToString = ({ packageId, path }) => `${packageId}/${path.join('/')}`
44
+
45
+ module.exports = {
46
+ /** @readonly */
47
+ idToString,
48
+ }
@@ -1,13 +1,11 @@
1
1
  const json = require('../../json')
2
- const dep = require('./dependencies')
3
- const object = require('../../types/object')
4
- const run = require('../run')
2
+ const dependencies = require('./dependencies')
5
3
 
6
4
  /**
7
5
  * @typedef {{
8
6
  * readonly name: string
9
7
  * readonly version: string
10
- * readonly dependencies?: dep.DependenciesJson
8
+ * readonly dependencies?: dependencies.DependenciesJson
11
9
  * }} PackageJson
12
10
  */
13
11
 
@@ -16,7 +14,7 @@ const isPackageJson = j => {
16
14
  if (!json.isObject(j)) { return false }
17
15
  if (typeof j.name !== 'string') { return false }
18
16
  if (typeof j.version !== 'string') { return false }
19
- if (!dep.isDependenciesJson(j.dependencies)) { return false }
17
+ if (!dependencies.isDependenciesJson(j.dependencies)) { return false }
20
18
  return true
21
19
  }
22
20
 
@@ -27,7 +25,7 @@ const isPackageJson = j => {
27
25
  * }} Package
28
26
  */
29
27
 
30
- /** @typedef {(packageId: string) => Package | undefined} PackageGet */
28
+ /** @typedef {(packageId: string) => Package | undefined} Get */
31
29
 
32
30
  module.exports = {
33
31
  /** @readonly */
@@ -1,12 +1,14 @@
1
1
  const { tryCatch } = require('../result')
2
2
  const { unwrap } = require('../../types/result')
3
- const run = require('../../commonjs/run')
3
+ const moduleFunction = require('../../commonjs/module/function')
4
4
 
5
- /** @type {(f: Function) => run.Module} */
5
+ /** @type {(f: Function) => moduleFunction.Function} */
6
6
  const build = f => immutableRequire => mutableData => {
7
7
  /** @type {(path: string) => unknown} */
8
8
  const mutableRequire = path => {
9
9
  const [result, data] = immutableRequire(path)(mutableData)
10
+ // Side effect: setting a variable from a nested function (closure)
11
+ // is not allowed in FunctionalScript.
10
12
  mutableData = data
11
13
  return unwrap(result)
12
14
  }
@@ -18,8 +20,9 @@ const build = f => immutableRequire => mutableData => {
18
20
  return [result, mutableData]
19
21
  }
20
22
 
21
- /** @type {run.Compile} */
23
+ /** @type {moduleFunction.Compile} */
22
24
  const compile = source =>
25
+ // Side effect: a `Function` constructor is not allowed in FunctionalScript.
23
26
  tryCatch(() => build(Function('module', 'require', `"use strict";${source}`)))
24
27
 
25
28
  module.exports = {
@@ -1,5 +1,5 @@
1
1
  const _ = require('.')
2
- const run = require('../../commonjs/run')
2
+ const run = require('../../commonjs/module/function')
3
3
 
4
4
  // ok:
5
5
  {
@@ -2,6 +2,7 @@ const result = require('../../types/result')
2
2
 
3
3
  /** @type {<T>(f: () => T) => result.Result<T, unknown>} */
4
4
  const tryCatch = f => {
5
+ // Side effect: `try catch` is not allowed in FunctionalScript.
5
6
  try {
6
7
  return result.ok(f())
7
8
  } catch (e) {
@@ -12,4 +13,4 @@ const tryCatch = f => {
12
13
  module.exports = {
13
14
  /** @readonly */
14
15
  tryCatch,
15
- }
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.252",
3
+ "version": "0.0.265",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -19,7 +19,9 @@
19
19
  "functional-programming",
20
20
  "closure",
21
21
  "pure-functional",
22
- "typescript"
22
+ "typescript",
23
+ "programming-language",
24
+ "lazy-evaluation"
23
25
  ],
24
26
  "bugs": {
25
27
  "url": "https://github.com/functionalscript/functionalscript/issues"
@@ -1,17 +0,0 @@
1
- const result = require('../../types/result')
2
-
3
- /** @typedef {<T>(req: Require<T>) => (prior: T) => ModuleResult<T>} Module*/
4
-
5
- /**
6
- * @template T
7
- * @typedef {readonly[result.Result<unknown, unknown>, T]} ModuleResult
8
- */
9
-
10
- /**
11
- * @template T
12
- * @typedef {(path: string) => (prior: T) => ModuleResult<T>} Require
13
- */
14
-
15
- /** @typedef {(source: string) => result.Result<Module, unknown>} Compile */
16
-
17
- module.exports = {}