Skip to content

Instantly share code, notes, and snippets.

@huytd
Created October 4, 2018 01:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save huytd/7723304bbca0f410de367f44d4802082 to your computer and use it in GitHub Desktop.
Save huytd/7723304bbca0f410de367f44d4802082 to your computer and use it in GitHub Desktop.
interface Token {
success: boolean;
value?: string;
rest?: string;
data?: string;
};
interface ParserFn {
(input?: string): Token;
};
const match_char = (c: string): ParserFn => (input: string): Token => {
if (input[0] === c) {
return <Token>{
success: true,
value: input[0],
rest: input.slice(1),
data: null
};
}
throw new Error(`MatchCharError: Expected ${JSON.stringify(c)}, found ${JSON.stringify(input[0])}`);
};
const match_any_char_to_eol = (): ParserFn => (input: string): Token => {
let parsed: string = "";
while (input[0] !== "\n" && input.length) {
parsed += input[0];
input = input.slice(1);
}
return <Token>{
success: true,
value: parsed,
rest: input.slice(1),
data: null
};
};
const match_header_hashes = (): ParserFn => (input: string): Token => {
const hash_matcher: ParserFn = match_char('#');
let parsed: string = "";
let level_count: number = 0;
let match_result: Token = hash_matcher(input);
try {
while (match_result.success) {
level_count++;
parsed += match_result.value;
input = match_result.rest;
match_result = hash_matcher(input);
}
} catch {}
return <Token>{
success: true,
value: parsed,
rest: input,
data: `header=${level_count}`
};
};
const combine_parser = (parsers: ParserFn[]): ParserFn => (input: string): Token => {
let next = input;
let result: string[] = [];
let data: string[] = [];
for (let i = 0; i < parsers.length; i++) {
const parser: ParserFn = parsers[i];
const parse_result: Token = parser(next);
result.push(parse_result.value);
if (parse_result.data) {
data.push(parse_result.data);
}
next = parse_result.rest;
}
return <Token>{
success: true,
value: result.join(''),
rest: next,
data: `${data}`
};
};
const parse_header = (): ParserFn => {
return combine_parser([match_header_hashes(), match_char(' '), match_any_char_to_eol()]);
};
const parse_line = (): ParserFn => {
return match_any_char_to_eol();
};
const try_parser = (parsers: ParserFn[], input: string): Token => {
while (parsers.length) {
let parser: ParserFn = parsers.shift();
try {
return parser(input);
} catch {}
}
};
let input = `# First level header
## Second level header
Some **text** here
## Another second level header
More text here, with [a link](https://google.com) and _italic text_.`;
while (input.length) {
let result = try_parser([parse_header(), parse_line()], input);
console.log(result);
input = result.rest;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment