Add basic parser combinators
This commit is contained in:
parent
5d28c51cf1
commit
94ac826cde
75
src/parser_combinators.c
Normal file
75
src/parser_combinators.c
Normal file
@ -0,0 +1,75 @@
|
||||
#include "parser_combinators.h"
|
||||
|
||||
parse_result_t parse_any(tokenlist_entry_t *current, parser_t parsers[]) {
|
||||
for (parser_t parser = *parsers; parser; parser = *parsers++) {
|
||||
parse_result_t result = parser(current);
|
||||
if (result.err == nullptr)
|
||||
return result;
|
||||
}
|
||||
return parse_no_match();
|
||||
}
|
||||
|
||||
// parse as many of the giver parsers objects in a row as possible, potentially
|
||||
// allowing none wraps the found objects in a new ast node with the given note
|
||||
// id
|
||||
parse_result_t parse_many(tokenlist_entry_t *current, node_id_t id,
|
||||
bool allow_none, parser_t parser) {
|
||||
ast_node_t *many;
|
||||
error_t *err = ast_node_alloc(&many);
|
||||
parse_result_t result;
|
||||
if (err)
|
||||
return parse_error(err);
|
||||
many->id = id;
|
||||
|
||||
while (current) {
|
||||
result = parser(current);
|
||||
if (result.err == err_parse_no_match)
|
||||
break;
|
||||
if (result.err) {
|
||||
ast_node_free(many);
|
||||
return result;
|
||||
}
|
||||
err = ast_node_add_child(many, result.node);
|
||||
if (err) {
|
||||
ast_node_free(many);
|
||||
ast_node_free(result.node);
|
||||
return parse_error(err);
|
||||
}
|
||||
current = result.next;
|
||||
}
|
||||
|
||||
if (!allow_none && many->len == 0) {
|
||||
ast_node_free(many);
|
||||
return parse_no_match();
|
||||
}
|
||||
return parse_success(many, current);
|
||||
}
|
||||
|
||||
// Parse all tries to parse all parsers consecutively and if it succeeds it
|
||||
// wraps the parsed nodes in a new parent node.
|
||||
parse_result_t parse_consecutive(tokenlist_entry_t *current, node_id_t id,
|
||||
parser_t parsers[]) {
|
||||
ast_node_t *all;
|
||||
error_t *err = ast_node_alloc(&all);
|
||||
parse_result_t result;
|
||||
if (err)
|
||||
return parse_no_match();
|
||||
|
||||
all->id = id;
|
||||
|
||||
for (parser_t parser = *parsers; parser && current; parser = *parsers++) {
|
||||
result = parser(current);
|
||||
if (result.err) {
|
||||
ast_node_free(all);
|
||||
return result;
|
||||
}
|
||||
err = ast_node_add_child(all, result.node);
|
||||
if (err) {
|
||||
ast_node_free(result.node);
|
||||
ast_node_free(all);
|
||||
return parse_error(err);
|
||||
}
|
||||
current = result.next;
|
||||
}
|
||||
return parse_success(all, current);
|
||||
}
|
16
src/parser_combinators.h
Normal file
16
src/parser_combinators.h
Normal file
@ -0,0 +1,16 @@
|
||||
#include "parser_util.h"
|
||||
|
||||
typedef parse_result_t (*parser_t)(tokenlist_entry_t *);
|
||||
|
||||
parse_result_t parse_any(tokenlist_entry_t *current, parser_t parsers[]);
|
||||
|
||||
// parse as many of the giver parsers objects in a row as possible, potentially
|
||||
// allowing none wraps the found objects in a new ast node with the given note
|
||||
// id
|
||||
parse_result_t parse_many(tokenlist_entry_t *current, node_id_t id,
|
||||
bool allow_none, parser_t parser);
|
||||
|
||||
// Parse all tries to parse all parsers consecutively and if it succeeds it
|
||||
// wraps the parsed nodes in a new parent node.
|
||||
parse_result_t parse_consecutive(tokenlist_entry_t *current, node_id_t id,
|
||||
parser_t parsers[]);
|
Loading…
x
Reference in New Issue
Block a user