Skip to content

Commit 4c2d824

Browse files
committed
version 1.0
0 parents  commit 4c2d824

12 files changed

+1945
-0
lines changed

.editorconfig

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[*]
2+
indent_style=tab
3+
tab_width=2
4+
charset=utf-8
5+
end_of_line=lf
6+
insert_final_newline=true

.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.idea
2+
.DS_Store
3+
*.log
4+
*.temp
5+
*.iml
6+
node_modules
7+
examples
8+
test/examples
9+
lib
10+
package-lock.json
11+
yarn.lock

.prettierrc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"tabWidth": 2,
3+
"bracketSpacing": true,
4+
"jsxBracketSameLine": false,
5+
"printWidth": 120,
6+
"proseWrap": "never",
7+
"singleQuote": true,
8+
"trailingComma": "all"
9+
}

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Haskell's parsec implemented in javaScript

jest.config.js

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module.exports = {
2+
preset: 'ts-jest',
3+
testEnvironment: 'node',
4+
roots: [
5+
'./test', // jest 扫描的目录
6+
],
7+
transform: {
8+
'^.+\\.tsx?$': 'ts-jest', // 哪些文件需要用 ts-jest 执行
9+
},
10+
testRegex: '(/__test__/.*|(\\.|/)(test|spec))\\.tsx?$',
11+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
12+
// globals: {
13+
// "ts-jest": {
14+
// tsConfig: 'config/tsconfig.dev.json',
15+
// },
16+
// },
17+
};

package.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "parserc",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "jest"
8+
},
9+
"keywords": [],
10+
"author": "zisu",
11+
"license": "ISC",
12+
"devDependencies": {
13+
"@types/jest": "^25.1.0",
14+
"jest": "^25.1.0",
15+
"ts-jest": "^25.0.0",
16+
"typescript": "^3.7.5"
17+
}
18+
}

src/State.ts

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
function eq<T>(a: T, b: T): boolean {
2+
return JSON.stringify(a) === JSON.stringify(b);
3+
}
4+
5+
export class State<U> {
6+
constructor(public source: string, public position: number = 0, public _userState?: U) {}
7+
8+
seek(delta: number) {
9+
return new State(this.source, this.position + delta, this._userState);
10+
}
11+
12+
getRowColumn(): { raw: number; column: number } {
13+
const lines = this.source.split('\n');
14+
let position = 0;
15+
let raw = 0;
16+
while (position < this.position) {
17+
if (this.position <= position + lines[raw].length) {
18+
break;
19+
}
20+
position += lines[raw].length + 1;
21+
raw++;
22+
}
23+
const column = this.position - position;
24+
return { raw, column };
25+
}
26+
27+
rest() {
28+
return this.source.slice(this.position);
29+
}
30+
31+
equals(src: State<U>): boolean {
32+
return src && this.source === src.source && this.position === src.position && eq(this._userState, src._userState);
33+
}
34+
35+
toString() {
36+
return `
37+
State: {
38+
source: ${this.source.length <= 100 ? `"${this.source}"` : `"${this.source.slice(0, 100)}"...`}
39+
position: ${this.position}
40+
userState: ${JSON.stringify(this._userState)}
41+
}
42+
`;
43+
}
44+
}
45+
46+
export class Reply<T, U> {
47+
constructor(public state: State<U>, public success: boolean, public value?: T, public expected?: () => string) {}
48+
49+
toString() {
50+
return `
51+
Reply {
52+
success: ${this.success}
53+
${this.success ? 'value: ' + String.raw`${this.value}` : 'expected: ' + this.expected!()}
54+
state: ${this.state.toString().replace(/^(?!\s*$)/gm, '\t\t')}
55+
}
56+
`;
57+
}
58+
59+
equals(st: Reply<T, U>): boolean {
60+
return (
61+
st &&
62+
this.state.equals(st.state) &&
63+
this.success === st.success &&
64+
(this.success
65+
? eq(this.value, st.value)
66+
: (this.expected === undefined && st.expected === undefined) || this.expected!() === st.expected!())
67+
);
68+
}
69+
}
70+
71+
export interface SeqController<U = any, T = any> {
72+
<S>(p: Parser<S>): S;
73+
74+
success: boolean;
75+
76+
state: State<T>;
77+
78+
_userState: U;
79+
}
80+
81+
export function ok<T, U>(state: State<U>, value?: T): Reply<T, U> {
82+
return new Reply<T, U>(state, true, value);
83+
}
84+
85+
export function error<T, U>(state: State<U>, expect?: () => string): Reply<T, U> {
86+
return new Reply<T, U>(state, false, undefined, expect);
87+
}
88+
89+
export class Parser<T> {
90+
constructor(public runParser: <U>(state: State<U>) => Reply<T, U>) {}
91+
92+
toString() {
93+
return this.runParser.toString();
94+
}
95+
}
96+
97+
export function parse<T, U>(parser: Parser<T>, state: State<U>) {
98+
return parser.runParser(state);
99+
}

0 commit comments

Comments
 (0)