Created
October 4, 2018 01:15
-
-
Save huytd/7723304bbca0f410de367f44d4802082 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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