functionalscript 0.0.258 → 0.0.267

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.
@@ -5,7 +5,6 @@ name: Node.js CI
5
5
 
6
6
  on:
7
7
  push:
8
- pull_request:
9
8
 
10
9
  jobs:
11
10
  build:
package/README.md CHANGED
@@ -3,34 +3,28 @@
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. JSON is also a subset of FunctionalScript.
6
+ - [JSON](https://en.wikipedia.org/wiki/JSON) as a subset of JavaScript. JSON is also a subset of FunctionalScript.
7
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
- Try FunctionalScript [here](https://functionalscript.com/).
11
-
12
10
  Create a new FunctionalScript repository on GitHub [here](https://github.com/functionalscript/template/generate).
13
11
 
14
- To install this repository as a library use:
15
-
16
- ```
17
- npm install -S github:functionalscript/functionalscript
18
- ```
12
+ Try FunctionalScript [here](https://functionalscript.com/).
19
13
 
20
14
  ## 1. Design Principles
21
15
 
22
16
  In FunctionalScript:
23
17
 
24
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.
25
20
  - A module can't depend on non FunctionalScript module.
26
- - A module can contain only pure functional statements. There are no exceptions to this rule, such as `unsafe` code in Rust or C#.
27
- - It also has no standard library, only a safe subset of standard JavaScript API is allowed.
21
+ - It also has no standard library, only a safe subset of standard JavaScript API can be used without referencing other modules.
28
22
 
29
23
  ## 2. Outlines
30
24
 
31
25
  ### 2.1. Module Ecosystem
32
26
 
33
- FunctionalScript uses Common.JS conventions as a module ecosystem. For example,
27
+ FunctionalScript uses [CommonJS](https://en.wikipedia.org/wiki/CommonJS) conventions as a module ecosystem. For example,
34
28
 
35
29
  ```js
36
30
  const thirdPartyModule = require('third-party-package/module')
@@ -40,20 +34,26 @@ const result = thirdPartyModule.someFunction('hello')
40
34
 
41
35
  ### 2.2. Packages
42
36
 
43
- FunctionalScript uses a `package.json` file to define a package. This file is compatible with Node.js `package.json`.
44
- The prefered way to refence dependencies is to use a GitHub URL. An example of dependencies in a `package.json` file:
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,
45
39
 
46
40
  ```json
47
41
  {
48
- ...
42
+ // ...
49
43
  "dependencies": {
50
44
  "third-party-package": "github:exampleorg/thirdpartypackage"
51
45
  }
52
- ...
46
+ // ...
53
47
  }
54
48
  ```
55
49
 
56
- ### 2.2. Module Structure
50
+ **Note:** this repository is also a FunctionalScript package, and it can be used as a library. To install this package, use
51
+
52
+ ```
53
+ npm install -S github:functionalscript/functionalscript
54
+ ```
55
+
56
+ ### 2.3. Module Structure
57
57
 
58
58
  A module is a file with the `.js` extention. It contains three parts: references to other modules, definitions, and exports. For example
59
59
 
@@ -64,6 +64,7 @@ const math = require('math')
64
64
 
65
65
  // 2. definitions
66
66
  const myConst = 42
67
+ // addition(a)(b) = a + b
67
68
  const addition = a => b => a + b
68
69
  const add42 = addition(42)
69
70
  const _10digitsOfPi = math.calculatePi(10)
@@ -81,12 +82,18 @@ module.exports = {
81
82
  // 1. references
82
83
  const first = require('./first.js')
83
84
 
85
+ // 2. definitions
84
86
  const _42plus7 = first.add42(7)
87
+
88
+ // 3. exports
89
+ module.exports = {
90
+ _42plus7,
91
+ }
85
92
  ```
86
93
 
87
- ### 2.3. References To Other Modules
94
+ ### 2.4. References To Other Modules
88
95
 
89
- The format of references is `const ANYNAME = require('PATH_TO_A_MODULE')`. For example
96
+ The format of references is `const ANYNAME = require('PATH_TO_A_MODULE')`. For example,
90
97
 
91
98
  ```js
92
99
  const math = require('math')
@@ -94,7 +101,7 @@ const algebra = require('math/algebra')
94
101
  const localFile = require('../some-directory/some-file.js')
95
102
  ```
96
103
 
97
- ### 2.4. Definitions
104
+ ### 2.5. Definitions
98
105
 
99
106
  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).
100
107
 
@@ -114,10 +121,12 @@ const nestedStructure = {
114
121
  }
115
122
  ```
116
123
 
117
- ### 2.5. Exports
124
+ See [3. Expressions](#3-Expressions).
125
+
126
+ ### 2.6. Exports
118
127
 
119
128
  The format of exports is `module.exports = { A_LIST_OF_EXPORTED_DEFINITIONS }`. There should be only one `module.exports` at
120
- the end of a FunctionalScript file. For example
129
+ the end of a FunctionalScript file. For example,
121
130
 
122
131
  ```js
123
132
  module.exports = {
@@ -126,3 +135,53 @@ module.exports = {
126
135
  structure,
127
136
  }
128
137
  ```
138
+
139
+ ## 3. Expressions
140
+
141
+ Expressions could fall under these categories:
142
+
143
+ - Literals:
144
+ - Number Literals, e.g. `0`, `3.14`, `4e8`
145
+ - Boolean Literals: `true` or `false`
146
+ - A `null` Literal
147
+ - An `undefined` Literal
148
+ - String Literals, e.g. `"Hello world!"`
149
+ - Complex Structures
150
+ - Arrays, e.g. `[2, 5]`
151
+ - Objects, e.g. `{ a: "Hello", b: "world!" }`
152
+ - Arrow functions, e.g. `x => x * 2`
153
+ - Operators
154
+ - Comparison Operators: `===`, `!==`, `>`, `>=`, `<`, `<=`
155
+ - Arithmetic Operators: `+`, `-`, `*`, `/`, `%`, `**`
156
+ - Bitwise Operators: `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>`
157
+ - Logical Operators: `&&`, `||`, `!`, `??`
158
+ - Conditional Operator, e.g. `condition ? val1 : val2`
159
+ - Template Literals, e.g. `string ${expression}`
160
+ - `typeof`
161
+ - Relations Operators: `in`, `instanceof`.
162
+ - Member Operators: `.`, `[]`.
163
+
164
+ 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.
165
+
166
+ ## 4. Arrow Functions
167
+
168
+ An arrow function is also known as [a lambda function](https://en.wikipedia.org/wiki/Anonymous_function).
169
+ 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
170
+
171
+ ```js
172
+ x => x * 2
173
+ a => a + 4
174
+ s => `template literal ${s}`
175
+ () => 'hello' // an arrow function with no arguments
176
+ ```
177
+
178
+ A function body is either an expression or a block statement. A block statement format is `{ A_LIST_OF_STATEMENTS }`. For example
179
+
180
+ ```js
181
+ // a function with one argument and a block statement
182
+ const f = x => {
183
+ const a = 2 + x
184
+ const r = a + 4
185
+ return r
186
+ }
187
+ ```
@@ -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.258",
3
+ "version": "0.0.267",
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 = {}