Skip to content

Commit 74c4a60

Browse files
committed
beginning of a new parser
1 parent e0d5952 commit 74c4a60

File tree

8 files changed

+900
-7
lines changed

8 files changed

+900
-7
lines changed

exampleVault/Input Fields/Select and Multi Select.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
select: 1
2+
select: 2
33
multiSelect:
44
- option 1
55
- option 3

exampleVault/examples.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
---
2-
slider1: 6
2+
slider1: 5
33
suggest: test
44
toggle1: false
55
Domestic_tasks:
66
- Lunch 🍲
77
Meditate: 100
88
Slept: 00:00
9+
select: option a
910
---
1011

1112
## In callouts
@@ -68,7 +69,8 @@ Lorem ipsum dolor sit amet, `INPUT[date():other note#date]` consectetur adipisci
6869
## Error Messages
6970
- `INPUT[text():meta bind/nonExistantFile#title]`
7071
- `INPUT[slider(nonExistantArgument)]`
71-
- `INPUT[select(option(option a),option(option b),option(option c),option(option d)):select]`
72+
73+
- `INPUT[inlineSelect(option(option a),option(option b),option(option c),option(option d)):select]`
7274

7375

7476
Lorem ipsum dolor sit amet, `INPUT[text():meta bind/nonExistantFile#title]` consectetur adipiscing elit. Pellentesque sit amet porttitor arcu. Quisque scelerisque dolor augue, et posuere nulla bibendum nec. `INPUT[slider(nonExistantArgument)]` Curabitur sed rhoncus nisl. Maecenas nisi justo, viverra vel tempus vel, hendrerit at metus. `INPUT[select(option(option a),option(option b),option(option c),option(option d)):select]` asdasd asdasdasd

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"build-publish": "tsc -noEmit -skipLibCheck && node esbuild.publish.config.mjs production",
1111
"version": "node version-bump.mjs && git add manifest.json versions.json",
1212
"test": "jest",
13+
"update-snapshots": "jest --updateSnapshot",
1314
"format": "prettier --write .",
1415
"lint": "eslint --max-warnings=0 src/**",
1516
"types": "tsc -p \"./tsconfig.types.json\""
Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
export const InputFieldTokenType = {
2+
ILLEGAL: 'ILLEGAL',
3+
EOF: 'EOF',
4+
WORD: 'WORD',
5+
L_PAREN: '(',
6+
R_PAREN: ')',
7+
L_SQUARE: '[',
8+
R_SQUARE: ']',
9+
COLON: ':',
10+
HASHTAG: '#',
11+
DOT: '.',
12+
COMMA: ',',
13+
QUOTE: '"',
14+
} as const;
15+
16+
type InputFieldTokenItem = typeof InputFieldTokenType[keyof typeof InputFieldTokenType];
17+
18+
export interface Range {
19+
from: number;
20+
to: number;
21+
}
22+
23+
export interface InputFieldToken {
24+
type: InputFieldTokenItem;
25+
literal: string;
26+
range: Range;
27+
}
28+
29+
function createToken(type: InputFieldTokenItem, literal: string, from: number, to: number): InputFieldToken {
30+
return {
31+
type: type,
32+
literal: literal,
33+
range: {
34+
from: from,
35+
to: to,
36+
},
37+
};
38+
}
39+
40+
export class InputFieldTokenizer {
41+
private readonly input: string;
42+
private readonly tokens: InputFieldToken[];
43+
private currentToken: InputFieldToken | undefined;
44+
private inQuotes: boolean;
45+
private position: number;
46+
private readPosition: number;
47+
private ch!: string;
48+
49+
constructor(input: string) {
50+
this.input = input;
51+
52+
this.tokens = [];
53+
this.currentToken = undefined;
54+
this.inQuotes = false;
55+
this.position = 0;
56+
this.readPosition = 0;
57+
58+
this.readChar();
59+
}
60+
61+
public getTokens(): InputFieldToken[] {
62+
while (this.currentToken?.type !== InputFieldTokenType.EOF) {
63+
this.readNextToken();
64+
}
65+
66+
return this.tokens;
67+
}
68+
69+
private readNextToken(): void {
70+
let token: InputFieldToken | undefined;
71+
72+
if (this.inQuotes) {
73+
if (this.ch === '"') {
74+
token = this.createToken(InputFieldTokenType.QUOTE);
75+
this.inQuotes = false;
76+
} else if (this.currentToken && this.currentToken.type === InputFieldTokenType.WORD) {
77+
this.currentToken.literal += this.ch;
78+
this.currentToken.range.to = this.position;
79+
} else {
80+
token = this.createToken(InputFieldTokenType.WORD);
81+
}
82+
} else {
83+
if (this.ch === '(') {
84+
token = this.createToken(InputFieldTokenType.L_PAREN);
85+
} else if (this.ch === ')') {
86+
token = this.createToken(InputFieldTokenType.R_PAREN);
87+
} else if (this.ch === '[') {
88+
token = this.createToken(InputFieldTokenType.L_SQUARE);
89+
} else if (this.ch === ']') {
90+
token = this.createToken(InputFieldTokenType.R_SQUARE);
91+
} else if (this.ch === ':') {
92+
token = this.createToken(InputFieldTokenType.COLON);
93+
} else if (this.ch === '#') {
94+
token = this.createToken(InputFieldTokenType.HASHTAG);
95+
} else if (this.ch === '.') {
96+
token = this.createToken(InputFieldTokenType.DOT);
97+
} else if (this.ch === ',') {
98+
token = this.createToken(InputFieldTokenType.COMMA);
99+
} else if (this.ch === '"') {
100+
token = this.createToken(InputFieldTokenType.QUOTE);
101+
this.inQuotes = true;
102+
} else if (this.ch === '\0') {
103+
token = this.createToken(InputFieldTokenType.EOF, 'eof');
104+
} else {
105+
if (this.currentToken && this.currentToken.type === InputFieldTokenType.WORD) {
106+
this.currentToken.literal += this.ch;
107+
this.currentToken.range.to = this.position;
108+
} else {
109+
token = this.createToken(InputFieldTokenType.WORD);
110+
}
111+
}
112+
}
113+
114+
if (token) {
115+
this.currentToken = token;
116+
this.tokens.push(token);
117+
}
118+
119+
this.readChar();
120+
}
121+
122+
private readChar(): void {
123+
this.ch = this.peek();
124+
125+
this.position = this.readPosition;
126+
this.readPosition += 1;
127+
}
128+
129+
private peek(): string {
130+
if (this.readPosition >= this.input.length) {
131+
return '\0';
132+
} else {
133+
return this.input[this.readPosition];
134+
}
135+
}
136+
137+
private createToken(type: InputFieldTokenItem, char?: string): InputFieldToken {
138+
return createToken(type, char !== undefined ? char : this.ch, this.position, this.position);
139+
}
140+
}
141+
142+
const ASTEL_type = {
143+
LITERAL: 'LITERAL',
144+
CLOSURE: 'CLOSURE',
145+
ROOT: 'ROOT',
146+
} as const;
147+
148+
type ASTEL_item = typeof ASTEL_type[keyof typeof ASTEL_type];
149+
150+
export abstract class AbstractASTEL {
151+
type: ASTEL_item;
152+
153+
protected constructor(type: ASTEL_item) {
154+
this.type = type;
155+
}
156+
157+
abstract toDebugString(): string;
158+
}
159+
160+
export class ASTEL_Literal extends AbstractASTEL {
161+
token: InputFieldToken;
162+
163+
constructor(token: InputFieldToken) {
164+
super(ASTEL_type.LITERAL);
165+
166+
this.token = token;
167+
}
168+
169+
toDebugString(): string {
170+
return this.token.literal;
171+
}
172+
}
173+
174+
export class ASTEL_Closure extends AbstractASTEL {
175+
startLiteral: ASTEL_Literal;
176+
endLiteral: ASTEL_Literal;
177+
children: AbstractASTEL[];
178+
179+
constructor(startLiteral: ASTEL_Literal, endLiteral: ASTEL_Literal, children: AbstractASTEL[]) {
180+
super(ASTEL_type.CLOSURE);
181+
182+
this.startLiteral = startLiteral;
183+
this.endLiteral = endLiteral;
184+
this.children = children;
185+
}
186+
187+
getRange(): Range {
188+
return {
189+
from: this.startLiteral.token.range.from,
190+
to: this.startLiteral.token.range.to,
191+
};
192+
}
193+
194+
toDebugString(): string {
195+
return `${this.startLiteral.token.literal}\n${this.children
196+
.map(x => x.toDebugString())
197+
.join('\n')
198+
.split('\n')
199+
.map(x => ' ' + x)
200+
.join('\n')}\n${this.startLiteral.token.literal}`;
201+
}
202+
}
203+
204+
export class ASTEL_Root extends AbstractASTEL {
205+
str: string;
206+
children: AbstractASTEL[];
207+
208+
constructor(str: string) {
209+
super(ASTEL_type.ROOT);
210+
211+
this.str = str;
212+
this.children = [];
213+
}
214+
215+
toDebugString(): string {
216+
return `root\n${this.children
217+
.map(x => x.toDebugString())
218+
.join('\n')
219+
.split('\n')
220+
.map(x => ' ' + x)
221+
.join('\n')}`;
222+
}
223+
}
224+
225+
export class InputFieldASTParser {
226+
private readonly tokens: InputFieldToken[];
227+
private astRoot: ASTEL_Root;
228+
229+
constructor(str: string, tokens: InputFieldToken[]) {
230+
this.tokens = tokens;
231+
this.astRoot = new ASTEL_Root(str);
232+
}
233+
234+
public parse(): ASTEL_Root {
235+
let i = 0;
236+
while (this.tokens[i].type !== InputFieldTokenType.EOF) {
237+
const res = this.parseAt(i);
238+
this.astRoot.children.push(res.astel);
239+
i = res.index;
240+
241+
if (i >= this.tokens.length) {
242+
throw new Error('index to big');
243+
}
244+
}
245+
246+
return this.astRoot;
247+
}
248+
249+
private parseAt(index: number): { astel: AbstractASTEL; index: number } {
250+
const token = this.tokens[index];
251+
252+
const astelLiteral = new ASTEL_Literal(token);
253+
254+
// start of L_PAREN closure
255+
const closures = [
256+
{
257+
openingTokenType: InputFieldTokenType.L_PAREN,
258+
closingTokenType: InputFieldTokenType.R_PAREN,
259+
},
260+
{
261+
openingTokenType: InputFieldTokenType.L_SQUARE,
262+
closingTokenType: InputFieldTokenType.R_SQUARE,
263+
},
264+
] as const;
265+
266+
for (const closure of closures) {
267+
const closureRes = this.parseClosure(index, astelLiteral, closure.openingTokenType, closure.closingTokenType);
268+
if (closureRes) {
269+
return closureRes;
270+
}
271+
}
272+
273+
return {
274+
astel: astelLiteral,
275+
index: index + 1,
276+
};
277+
}
278+
279+
private parseClosure(
280+
index: number,
281+
openingLiteral: ASTEL_Literal,
282+
openingTokenType: InputFieldTokenItem,
283+
closingTokenType: InputFieldTokenItem
284+
): { astel: AbstractASTEL; index: number } | undefined {
285+
if (openingLiteral.token.type !== openingTokenType) {
286+
return undefined;
287+
}
288+
289+
let closingLiteral: ASTEL_Literal | undefined;
290+
const children: AbstractASTEL[] = [];
291+
292+
index += 1;
293+
while (this.tokens[index].type !== InputFieldTokenType.EOF) {
294+
const nestedRes = this.parseAt(index);
295+
296+
if (nestedRes.astel.type === ASTEL_type.LITERAL && (nestedRes.astel as ASTEL_Literal).token.type === closingTokenType) {
297+
closingLiteral = nestedRes.astel as ASTEL_Literal;
298+
break;
299+
} else {
300+
children.push(nestedRes.astel);
301+
}
302+
303+
index = nestedRes.index;
304+
}
305+
306+
if (!closingLiteral) {
307+
// ERROR
308+
throw new Error('Closure is not closed');
309+
}
310+
311+
const closure = new ASTEL_Closure(openingLiteral, closingLiteral, children);
312+
313+
return {
314+
astel: closure,
315+
index: index + 1,
316+
};
317+
}
318+
}
319+
320+
// export class InputFieldParser {
321+
// /**
322+
// * This expects the full declaration.
323+
// * @example `INPUT[slider(addLabels, minValue(-10), maxValue(10)):bind target#frontmatter field]`
324+
// *
325+
// * @param fullDeclaration
326+
// */
327+
// static parseString(fullDeclaration: string): InputFieldDeclaration {
328+
// const tokenizer = new InputFieldTokenizer(fullDeclaration);
329+
// const tokens = tokenizer.getTokens();
330+
// }
331+
// }

tests/DateParser.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
test('placeholder', () => {
2+
expect(true).toEqual(true);
3+
});
4+
15
/*
26
import {Date, DateParser} from '../src/parsers/DateParser';
37

tests/InputFieldDeclarationParser.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { InputFieldArgumentContainer } from '../src/inputFieldArguments/InputFie
22
import { InputFieldArgumentType, InputFieldDeclaration, InputFieldDeclarationParser, InputFieldType } from '../src/parsers/InputFieldDeclarationParser';
33
import { MetaBindParsingError } from '../src/utils/errors/MetaBindErrors';
44

5-
// test('placeholder', () => {
6-
// expect(true).toEqual(true);
7-
// });
8-
//
5+
test('placeholder', () => {
6+
expect(true).toEqual(true);
7+
});
8+
99
// describe('apply template', () => {
1010
// test('found', () => {
1111
// InputFieldDeclarationParser.templates = [

0 commit comments

Comments
 (0)