functionalscript 0.6.9 → 0.6.11

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 (58) hide show
  1. package/README.md +2 -2
  2. package/bnf/data/module.f.d.ts +3 -1
  3. package/bnf/data/module.f.js +4 -2
  4. package/bnf/data/test.f.d.ts +3 -1
  5. package/bnf/data/test.f.js +71 -3
  6. package/bnf/module.f.d.ts +8 -0
  7. package/bnf/module.f.js +1 -1
  8. package/bnf/testlib.f.js +1 -0
  9. package/crypto/hmac/module.f.js +9 -4
  10. package/crypto/sha2/module.f.d.ts +1 -1
  11. package/crypto/sign/module.f.d.ts +5 -0
  12. package/crypto/sign/module.f.js +53 -0
  13. package/crypto/sign/test.f.d.ts +2 -0
  14. package/crypto/sign/test.f.js +1 -0
  15. package/deno/module.d.ts +8 -0
  16. package/deno/module.js +53 -0
  17. package/deno/test.d.ts +1 -0
  18. package/deno/test.js +2 -0
  19. package/dev/module.f.d.ts +1 -1
  20. package/dev/module.f.js +7 -4
  21. package/dev/test/module.f.d.ts +3 -1
  22. package/dev/test/module.f.js +12 -12
  23. package/djs/module.f.js +2 -1
  24. package/djs/parser/module.f.d.ts +7 -2
  25. package/djs/parser/module.f.js +80 -52
  26. package/djs/parser/test.f.d.ts +1 -0
  27. package/djs/parser/test.f.js +104 -76
  28. package/djs/tokenizer/module.f.d.ts +6 -2
  29. package/djs/tokenizer/module.f.js +12 -7
  30. package/djs/tokenizer/test.f.d.ts +1 -0
  31. package/djs/tokenizer/test.f.js +103 -87
  32. package/djs/transpiler/module.f.d.ts +3 -2
  33. package/djs/transpiler/module.f.js +3 -3
  34. package/djs/transpiler/test.f.js +2 -2
  35. package/io/module.f.d.ts +7 -0
  36. package/io/module.js +5 -1
  37. package/io/virtual/module.f.js +3 -0
  38. package/issues/31-json.f.d.ts +1 -1
  39. package/issues/31-json.f.js +1 -1
  40. package/issues/demo/data/data.f.js +12 -0
  41. package/issues/demo/data/shared.f.js +3 -0
  42. package/issues/demo/fs/app.js +4 -0
  43. package/issues/demo/fs/math.f.js +4 -0
  44. package/issues/demo/test/test.f.js +13 -0
  45. package/js/tokenizer/module.f.d.ts +14 -2
  46. package/js/tokenizer/module.f.js +30 -17
  47. package/js/tokenizer/test.f.d.ts +1 -0
  48. package/js/tokenizer/test.f.js +159 -149
  49. package/json/parser/module.f.js +18 -9
  50. package/json/parser/test.f.js +16 -16
  51. package/json/tokenizer/module.f.d.ts +1 -1
  52. package/json/tokenizer/module.f.js +7 -6
  53. package/json/tokenizer/test.f.js +68 -68
  54. package/package.json +10 -11
  55. package/text/sgr/module.f.d.ts +5 -0
  56. package/text/sgr/module.f.js +10 -1
  57. package/types/bit_vec/module.f.d.ts +1 -0
  58. package/types/bit_vec/module.f.js +1 -0
package/README.md CHANGED
@@ -8,7 +8,7 @@ FunctionalScript is a safe, purely functional programming language and a strict
8
8
 
9
9
  - [JSON](https://en.wikipedia.org/wiki/JSON) and [JSON5](https://json5.org/) as subsets of JavaScript.
10
10
  JSON is also a subset of FunctionalScript.
11
- - [asm.JS](https://en.wikipedia.org/wiki/Asm.js)/[WebAssembly](https://en.wikipedia.org/wiki/WebAssembly),
11
+ - [asm.JS](https://en.wikipedia.org/wiki/Asm.js) (a precursor of [WebAssembly](https://en.wikipedia.org/wiki/WebAssembly)),
12
12
  as a subset of JavaScript.
13
13
  - [TypeScript](https://en.wikipedia.org/wiki/TypeScript), as a superset of JavaScript.
14
14
 
@@ -19,7 +19,7 @@ Learn more about
19
19
  - [Purely Functional Programming in JavaScript](https://blog.bitsrc.io/purely-functional-programming-in-javascript-91114b1b2dff?sk=5f7132e56902f38fcf4c6164bfa681ed),
20
20
  - [FunctionalScript and I/O](https://medium.com/@sergeyshandar/functionalscript-5cf817345376?sk=30b32189a81d1a2dad16c2244f32328d).
21
21
 
22
- This repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) and distributted 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
+ This repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) and 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).
23
23
 
24
24
  ## Getting Started
25
25
 
@@ -1,10 +1,12 @@
1
- import type { Rule as FRule } from '../module.f.ts';
1
+ import { type Rule as FRule } from '../module.f.ts';
2
2
  export type TerminalRange = number;
3
3
  export type Sequence = readonly string[];
4
+ /** A variant of rule names. */
4
5
  export type Variant = {
5
6
  readonly [k in string]: string;
6
7
  };
7
8
  export type Rule = Variant | Sequence | TerminalRange;
9
+ /** The full grammar */
8
10
  export type RuleSet = Readonly<Record<string, Rule>>;
9
11
  export declare const toData: (fr: FRule) => readonly [RuleSet, string];
10
12
  /**
@@ -1,5 +1,6 @@
1
1
  import { stringToCodePointList } from "../../text/utf16/module.f.js";
2
- import { toArray } from "../../types/list/module.f.js";
2
+ import { map, toArray } from "../../types/list/module.f.js";
3
+ import { oneEncode, } from "../module.f.js";
3
4
  const { entries } = Object;
4
5
  const find = (map) => (fr) => {
5
6
  for (const [k, v] of entries(map)) {
@@ -40,10 +41,11 @@ const variant = (fr) => map => {
40
41
  }
41
42
  return [map, set, rule];
42
43
  };
44
+ const mapOneEncode = map(oneEncode);
43
45
  const data = (dr) => {
44
46
  switch (typeof dr) {
45
47
  case 'string': {
46
- return sequence(toArray(stringToCodePointList(dr)));
48
+ return sequence(toArray(mapOneEncode(stringToCodePointList(dr))));
47
49
  }
48
50
  case 'number':
49
51
  return m => [m, {}, dr];
@@ -1,4 +1,6 @@
1
1
  declare const _default: {
2
- toData: () => void;
2
+ toData: (() => void)[];
3
+ variantTest: () => void;
4
+ example: () => void;
3
5
  };
4
6
  export default _default;
@@ -1,8 +1,76 @@
1
+ import { stringify } from "../../json/module.f.js";
2
+ import { sort } from "../../types/object/module.f.js";
3
+ import { range } from "../module.f.js";
1
4
  import { classic, deterministic } from "../testlib.f.js";
2
5
  import { toData } from "./module.f.js";
3
6
  export default {
4
- toData: () => {
5
- const c = toData(classic());
6
- const d = toData(deterministic());
7
+ toData: [
8
+ () => {
9
+ const c = toData(classic());
10
+ const d = toData(deterministic());
11
+ },
12
+ () => {
13
+ const stringRule = 'true';
14
+ const result = stringify(sort)(toData(stringRule));
15
+ if (result != '[{"":["0","1","2","3"],"0":1946157172,"1":1912602738,"2":1962934389,"3":1694498917},""]') {
16
+ throw result;
17
+ }
18
+ },
19
+ () => {
20
+ const terminalRangeRule = range('AF');
21
+ const result = stringify(sort)(toData(terminalRangeRule));
22
+ if (result != '[{"":1090519110},""]') {
23
+ throw result;
24
+ } //1090519110 = 65 * 2^24 + 70
25
+ },
26
+ () => {
27
+ const sequenceRangeRule = [range('AF'), range('af')];
28
+ const result = stringify(sort)(toData(sequenceRangeRule));
29
+ if (result != '[{"":["0","1"],"0":1090519110,"1":1627390054},""]') {
30
+ throw result;
31
+ }
32
+ },
33
+ () => {
34
+ const lazyRule = () => 'true';
35
+ const result = stringify(sort)(toData(lazyRule));
36
+ if (result != '[{"":1946157172,"0":1912602738,"1":1962934389,"2":1694498917,"lazyRule":["","0","1","2"]},"lazyRule"]') {
37
+ throw result;
38
+ }
39
+ },
40
+ () => {
41
+ const varintRule = { true: 'true', false: 'false' };
42
+ const result = stringify(sort)(toData(varintRule));
43
+ const expected = '[{"":{"false":"5","true":"0"},"0":["1","2","3","4"],"1":1946157172,"2":1912602738,"3":1962934389,"4":1694498917,"5":["6","7","8","9","4"],"6":1711276134,"7":1627390049,"8":1811939436,"9":1929379955},""]';
44
+ if (result != expected) {
45
+ throw [result, expected];
46
+ }
47
+ },
48
+ () => {
49
+ const lazyRule = () => 'true';
50
+ const lazyRule0 = () => 'false';
51
+ const result = stringify(sort)(toData([lazyRule, lazyRule0]));
52
+ const expected = '[{"":["lazyRule","lazyRule0"],"0":1946157172,"1":1912602738,"2":1962934389,"3":1694498917,"4":1711276134,"5":1627390049,"6":1811939436,"7":1929379955,"lazyRule":["0","1","2","3"],"lazyRule0":["4","5","6","7","3"]},""]';
53
+ if (result != expected) {
54
+ throw [result, expected];
55
+ }
56
+ },
57
+ ],
58
+ variantTest: () => {
59
+ const varintRule = { a: 'a', b: 'b' };
60
+ const result = stringify(sort)(toData(varintRule));
61
+ if (result != '[{"":{"a":"0","b":"2"},"0":["1"],"1":1627390049,"2":["3"],"3":1644167266},""]') {
62
+ throw result;
63
+ }
64
+ },
65
+ example: () => {
66
+ const grammar = {
67
+ space: 0x000020_000020,
68
+ digit: 0x000030_000039,
69
+ sequence: ['space', 'digit'],
70
+ spaceOrDigit: {
71
+ 'whiteSpace': 'space',
72
+ 'digit': 'digit',
73
+ }
74
+ };
7
75
  }
8
76
  };
package/bnf/module.f.d.ts CHANGED
@@ -1,6 +1,14 @@
1
1
  import { type Array2 } from '../types/array/module.f.ts';
2
+ /**
3
+ * A range of symbols (48 bits)
4
+ * For example: 0xBBBBBB_EEEEEE
5
+ * - 0xBBBBBB is the first symbol
6
+ * - 0xEEEEEE is the last symbol
7
+ */
2
8
  export type TerminalRange = number;
9
+ /** A sequence of rules. */
3
10
  export type Sequence = readonly Rule[];
11
+ /** A variant */
4
12
  export type Variant = {
5
13
  readonly [k in string]: Rule;
6
14
  };
package/bnf/module.f.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { codePointListToString, stringToCodePointList } from "../text/utf16/module.f.js";
2
2
  import { isArray2 } from "../types/array/module.f.js";
3
3
  import { map, toArray, repeat as listRepeat } from "../types/list/module.f.js";
4
- //
4
+ // Internals:
5
5
  const { fromEntries, values } = Object;
6
6
  const { fromCodePoint } = String;
7
7
  /**
package/bnf/testlib.f.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { join0Plus, max, none, option, range, remove, repeat, repeat0Plus, set } from "./module.f.js";
2
2
  export const classic = () => {
3
+ // https://www.json.org/json-en.html
3
4
  const json = () => [element];
4
5
  const value = () => ({
5
6
  object,
@@ -48,13 +48,18 @@ export const hmac = (sha2) => {
48
48
  const op = p(oPad);
49
49
  const c = computeSync(sha2);
50
50
  const vbl = vec(blockLength);
51
+ // a and b should have the same size
51
52
  const xor = (a) => (b) => vbl(a ^ b);
52
- return k => m => {
53
+ return k => {
53
54
  const k1 = length(k) > blockLength ? c([k]) : k;
54
55
  const k2 = concat(k1)(vec(blockLength - length(k1))(0n));
55
56
  const xk2 = xor(k2);
56
- const f = (p, msg) => c([xk2(p), msg]);
57
- const m1 = f(ip, m);
58
- return f(op, m1);
57
+ const f = (p) => {
58
+ const x = xk2(p);
59
+ return (msg) => c([x, msg]);
60
+ };
61
+ const fip = f(ip);
62
+ const fop = f(op);
63
+ return m => fop(fip(m));
59
64
  };
60
65
  };
@@ -37,7 +37,7 @@ export type Base = {
37
37
  * const s = msbUtf8("The quick brown fox jumps over the lazy dog.")
38
38
  * let state = sha224.init
39
39
  * state = sha224.append(state)(s)
40
- * const h = sha224.end(state) // 0x619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4cn
40
+ * const h = sha224.end(state) // 0x1_619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4cn
41
41
  * ```
42
42
  */
43
43
  export type Sha2 = {
@@ -0,0 +1,5 @@
1
+ import { type Vec } from '../../types/bit_vec/module.f.ts';
2
+ import { type Init } from '../secp/module.f.ts';
3
+ import type { Sha2 } from '../sha2/module.f.ts';
4
+ export declare const newPrivateKey: (i: Init) => (random: Vec) => Vec;
5
+ export declare const sign: (sha2: Sha2) => (curveInit: Init) => (privateKey: Vec) => (messageHash: Vec) => readonly [bigint, bigint];
@@ -0,0 +1,53 @@
1
+ import { listToVec, msb, uint, vec, vec8, length } from "../../types/bit_vec/module.f.js";
2
+ import { hmac } from "../hmac/module.f.js";
3
+ import { curve } from "../secp/module.f.js";
4
+ const concat = listToVec(msb);
5
+ const v00 = vec8(0x00n);
6
+ const v01 = vec8(0x01n);
7
+ /**
8
+ * The size of the result equals the size of the hash.
9
+ *
10
+ * @param sha2 SHA2 hash function
11
+ * @returns A function that accepts a private key, a message hash and returns `k`.
12
+ */
13
+ const createK = (sha2) => {
14
+ const h = hmac(sha2);
15
+ let vs = vec(sha2.hashLength);
16
+ let k0 = vs(0x00n);
17
+ let v0 = vs(0x01n);
18
+ return (privateKey) => (messageHash) => {
19
+ const pm = concat([privateKey, messageHash]);
20
+ let k = k0;
21
+ let v = v0;
22
+ k = h(k)(concat([v, v00, pm]));
23
+ v = h(k)(v);
24
+ k = h(k)(concat([v, v01, pm]));
25
+ v = h(k)(v);
26
+ return uint(h(k)(v));
27
+ };
28
+ };
29
+ export const newPrivateKey = (i) => (random) => {
30
+ const { nf } = curve(i);
31
+ if (length(nf.max) < length(random)) {
32
+ throw "need more random bits";
33
+ }
34
+ return uint(random) % nf.p;
35
+ };
36
+ export const sign = (sha2) => (curveInit) => (privateKey) => (messageHash) => {
37
+ const { mul, pf } = curve(curveInit);
38
+ // const curveVec = vec(length(pf.max))
39
+ //`k` is a unique for each `z` and secret.
40
+ const k = createK(sha2)(privateKey)(messageHash) % pf.p;
41
+ // `R = G * k`.
42
+ const rp = mul(curveInit.g)(k);
43
+ // `r = R.x`
44
+ const r = rp === null ? 0n : rp[0];
45
+ // `s = ((z + r * d) / k)`.
46
+ const d = uint(privateKey);
47
+ const z = uint(messageHash);
48
+ const rd = pf.mul(r)(d);
49
+ const zrd = pf.add(z)(rd);
50
+ const kn1 = pf.reciprocal(k);
51
+ const s = pf.mul(zrd)(kn1);
52
+ return [r, s];
53
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: {};
2
+ export default _default;
@@ -0,0 +1 @@
1
+ export default {};
@@ -0,0 +1,8 @@
1
+ type DenoTestStep = {
2
+ readonly step: (name: string, f: () => void | Promise<void>) => Promise<void>;
3
+ };
4
+ type DenoFunc = (t: DenoTestStep) => void | Promise<void>;
5
+ type DenoArg = readonly [string, DenoFunc];
6
+ export type DenoTest = (...arg: DenoArg) => void;
7
+ declare const _default: () => Promise<void>;
8
+ export default _default;
package/deno/module.js ADDED
@@ -0,0 +1,53 @@
1
+ import { io } from "../io/module.js";
2
+ import { loadModuleMap } from "../dev/module.f.js";
3
+ import { isTest } from "../dev/test/module.f.js";
4
+ const denoTest = (x) => async (t) => {
5
+ let subTests = [x];
6
+ while (true) {
7
+ const [first, ...rest] = subTests;
8
+ if (first === undefined) {
9
+ break;
10
+ }
11
+ subTests = rest;
12
+ //
13
+ const [name, value] = first;
14
+ if (value === null) {
15
+ continue;
16
+ }
17
+ switch (typeof value) {
18
+ case "function": {
19
+ if (value.length === 0) {
20
+ const g = value.name === 'throw'
21
+ ? () => {
22
+ try {
23
+ value();
24
+ throw new Error(`Expected ${name} to throw, but it did not.`);
25
+ }
26
+ catch { }
27
+ }
28
+ : () => {
29
+ const r = value();
30
+ subTests = [...subTests, [`${name}()`, r]];
31
+ };
32
+ await t.step(name, g);
33
+ }
34
+ break;
35
+ }
36
+ case "object": {
37
+ for (const [j, y] of Object.entries(value)) {
38
+ const pr = `${name}/${j}`;
39
+ subTests = [...subTests, [pr, y]];
40
+ }
41
+ break;
42
+ }
43
+ }
44
+ }
45
+ };
46
+ export default async () => {
47
+ const x = await loadModuleMap(io);
48
+ for (const [i, v] of Object.entries(x)) {
49
+ if (isTest(i)) {
50
+ Deno.test(i, denoTest(['', v.default]));
51
+ }
52
+ }
53
+ };
package/deno/test.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/deno/test.js ADDED
@@ -0,0 +1,2 @@
1
+ import run from "./module.js";
2
+ await run();
package/dev/module.f.d.ts CHANGED
@@ -7,6 +7,6 @@ export type ModuleMap = {
7
7
  readonly [k in string]: Module;
8
8
  };
9
9
  export declare const env: (io: Io) => (v: string) => string | undefined;
10
- export declare const allFiles: ({ fs: { promises: { readdir } } }: Io) => Promise<readonly string[]>;
10
+ export declare const allFiles: (io: Io) => (s: string) => Promise<readonly string[]>;
11
11
  export declare const loadModuleMap: (io: Io) => Promise<ModuleMap>;
12
12
  export declare const index: (io: Io) => Promise<number>;
package/dev/module.f.js CHANGED
@@ -7,7 +7,8 @@ export const env = ({ process: { env } }) => a => {
7
7
  typeof r.get === 'function' ? r.get() :
8
8
  r.value;
9
9
  };
10
- export const allFiles = ({ fs: { promises: { readdir } } }) => {
10
+ export const allFiles = (io) => (s) => {
11
+ const { fs: { promises: { readdir } }, process: { cwd } } = io;
11
12
  const load = async (p) => {
12
13
  let result = [];
13
14
  for (const i of await readdir(p, { withFileTypes: true })) {
@@ -29,12 +30,14 @@ export const allFiles = ({ fs: { promises: { readdir } } }) => {
29
30
  }
30
31
  return result;
31
32
  };
32
- return load('.');
33
+ return load(s);
33
34
  };
34
35
  export const loadModuleMap = async (io) => {
35
36
  const { fs: { existsSync }, asyncImport } = io;
36
37
  let map = [];
37
- for (const f of await allFiles(io)) {
38
+ const initCwd = env(io)('INIT_CWD');
39
+ const s = initCwd === undefined ? '.' : `${initCwd.replaceAll('\\', '/')}`;
40
+ for (const f of await allFiles(io)(s)) {
38
41
  if (f.endsWith('.f.js') ||
39
42
  (f.endsWith('.f.ts') && !existsSync(f.substring(0, f.length - 3) + '.js'))) {
40
43
  const source = await asyncImport(f);
@@ -47,7 +50,7 @@ export const index = async (io) => {
47
50
  updateVersion(io);
48
51
  const jj = './deno.json';
49
52
  const jsr_json = JSON.parse(await io.fs.promises.readFile(jj, 'utf8'));
50
- const list = (await allFiles(io)).filter(v => v.endsWith('/module.f.ts') || v.endsWith('/module.ts'));
53
+ const list = (await allFiles(io)('.')).filter(v => v.endsWith('/module.f.ts') || v.endsWith('/module.ts'));
51
54
  //console.log(list)
52
55
  const exportsA = list.map(v => [v, `./${v.substring(2)}`]);
53
56
  // console.log(exportsA)
@@ -1,7 +1,8 @@
1
+ import { type CsiConsole } from '../../text/sgr/module.f.ts';
1
2
  import type * as Result from '../../types/result/module.f.ts';
2
3
  import type { Io, Performance } from '../../io/module.f.ts';
3
4
  import { type ModuleMap } from '../module.f.ts';
4
- type Log<T> = (v: string) => (state: T) => T;
5
+ type Log<T> = CsiConsole;
5
6
  type Measure<T> = <R>(f: () => R) => (state: T) => readonly [R, number, T];
6
7
  type Input<T> = {
7
8
  readonly moduleMap: ModuleMap;
@@ -12,6 +13,7 @@ type Input<T> = {
12
13
  readonly tryCatch: <R>(f: () => R) => Result.Result<R, unknown>;
13
14
  readonly env: (n: string) => string | undefined;
14
15
  };
16
+ export declare const isTest: (s: string) => boolean;
15
17
  export declare const test: <T>(input: Input<T>) => readonly [number, T];
16
18
  export declare const anyLog: (f: (s: string) => void) => (s: string) => <T>(state: T) => T;
17
19
  export declare const measure: (p: Performance) => <R>(f: () => R) => <T>(state: T) => readonly [R, number, T];
@@ -1,7 +1,7 @@
1
1
  import { entries, fold } from "../../types/list/module.f.js";
2
- import { reset, fgGreen, fgRed, bold } from "../../text/sgr/module.f.js";
2
+ import { reset, fgGreen, fgRed, bold, stdio, stderr } from "../../text/sgr/module.f.js";
3
3
  import { env, loadModuleMap } from "../module.f.js";
4
- const isTest = (s) => s.endsWith('test.f.js') || s.endsWith('test.f.ts');
4
+ export const isTest = (s) => s.endsWith('test.f.js') || s.endsWith('test.f.ts');
5
5
  const addPass = (delta) => (ts) => ({ ...ts, time: ts.time + delta, pass: ts.pass + 1 });
6
6
  const addFail = (delta) => (ts) => ({ ...ts, time: ts.time + delta, fail: ts.fail + 1 });
7
7
  const timeFormat = (a) => {
@@ -30,16 +30,16 @@ export const test = (input) => {
30
30
  if (isGitHub) {
31
31
  // https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions
32
32
  // https://github.com/OndraM/ci-detector/blob/main/src/Ci/GitHubActions.php
33
- state = error(`::error file=${k},line=1,title=[3]['a']()::${r}`)(state);
33
+ error(`::error file=${k},line=1,title=[3]['a']()::${r}`);
34
34
  }
35
35
  else {
36
- state = error(`${i}() ${fgRed}error${reset}, ${timeFormat(delta)}`)(state);
37
- state = error(`${fgRed}${r}${reset}`)(state);
36
+ error(`${i}() ${fgRed}error${reset}, ${timeFormat(delta)}`);
37
+ error(`${fgRed}${r}${reset}`);
38
38
  }
39
39
  }
40
40
  else {
41
41
  ts = addPass(delta)(ts);
42
- state = log(`${i}() ${fgGreen}ok${reset}, ${timeFormat(delta)}`)(state);
42
+ log(`${i}() ${fgGreen}ok${reset}, ${timeFormat(delta)}`);
43
43
  }
44
44
  [ts, state] = next(r)([ts, state]);
45
45
  }
@@ -48,7 +48,7 @@ export const test = (input) => {
48
48
  case 'object': {
49
49
  if (v !== null) {
50
50
  const f = ([k, v]) => ([time, state]) => {
51
- state = log(`${i}${k}:`)(state);
51
+ log(`${i}${k}:`);
52
52
  [time, state] = next(v)([time, state]);
53
53
  return [time, state];
54
54
  };
@@ -61,7 +61,7 @@ export const test = (input) => {
61
61
  };
62
62
  return ([ts, state]) => {
63
63
  if (isTest(k)) {
64
- state = log(`testing ${k}`)(state);
64
+ log(`testing ${k}`);
65
65
  [ts, state] = test('| ')(v.default)([ts, state]);
66
66
  }
67
67
  return [ts, state];
@@ -70,8 +70,8 @@ export const test = (input) => {
70
70
  let ts = { time: 0, pass: 0, fail: 0 };
71
71
  [ts, state] = fold(f)([ts, state])(Object.entries(moduleMap));
72
72
  const fgFail = ts.fail === 0 ? fgGreen : fgRed;
73
- state = log(`${bold}Number of tests: pass: ${fgGreen}${ts.pass}${reset}${bold}, fail: ${fgFail}${ts.fail}${reset}${bold}, total: ${ts.pass + ts.fail}${reset}`)(state);
74
- state = log(`${bold}Time: ${timeFormat(ts.time)}${reset}`)(state);
73
+ log(`${bold}Number of tests: pass: ${fgGreen}${ts.pass}${reset}${bold}, fail: ${fgFail}${ts.fail}${reset}${bold}, total: ${ts.pass + ts.fail}${reset}`);
74
+ log(`${bold}Time: ${timeFormat(ts.time)}${reset}`);
75
75
  return [ts.fail !== 0 ? 1 : 0, state];
76
76
  };
77
77
  export const anyLog = (f) => (s) => (state) => {
@@ -86,8 +86,8 @@ export const measure = (p) => (f) => (state) => {
86
86
  };
87
87
  export const main = async (io) => test({
88
88
  moduleMap: await loadModuleMap(io),
89
- log: anyLog(io.console.log),
90
- error: anyLog(io.console.error),
89
+ log: stdio(io), // anyLog(io.console.log),
90
+ error: stderr(io), // anyLog(io.console.error),
91
91
  measure: measure(io.performance),
92
92
  tryCatch: io.tryCatch,
93
93
  env: env(io),
package/djs/module.f.js CHANGED
@@ -22,7 +22,8 @@ export const compile = ({ console: { error }, fs, process: { argv } }) => {
22
22
  break;
23
23
  }
24
24
  case 'error': {
25
- error(`Parse error: ${result[1]}`);
25
+ const metadata = result[1].metadata;
26
+ error(`${metadata?.path}:${metadata?.line}:${metadata?.column} - error: ${result[1].message}`);
26
27
  break;
27
28
  }
28
29
  }
@@ -1,12 +1,17 @@
1
1
  import * as result from '../../types/result/module.f.ts';
2
2
  import { type List } from '../../types/list/module.f.ts';
3
- import type { DjsToken } from '../tokenizer/module.f.ts';
3
+ import type { DjsTokenWithMetadata } from '../tokenizer/module.f.ts';
4
4
  import { type OrderedMap } from '../../types/ordered_map/module.f.ts';
5
5
  import type { Fs } from '../../io/module.f.ts';
6
6
  import type { AstModule } from '../ast/module.f.ts';
7
+ import type { TokenMetadata } from '../../js/tokenizer/module.f.ts';
7
8
  export type ParseContext = {
8
9
  readonly fs: Fs;
9
10
  readonly complete: OrderedMap<result.Result<AstModule, string>>;
10
11
  readonly stack: List<string>;
11
12
  };
12
- export declare const parseFromTokens: (tokenList: List<DjsToken>) => result.Result<AstModule, string>;
13
+ export type ParseError = {
14
+ readonly message: string;
15
+ readonly metadata: TokenMetadata | null;
16
+ };
17
+ export declare const parseFromTokens: (tokenList: List<DjsTokenWithMetadata>) => result.Result<AstModule, ParseError>;