Remove generated parsers' dependency on the runtime library

Generated parsers no longer export a parser constructor function.
They now export an opaque Language object which can be set on
Documents directly. This way, the logic for constructing parsers
lives entirely in the runtime. The Languages are just structs which
have no load-time dependency on the runtime
This commit is contained in:
Max Brunsfeld 2014-07-30 23:40:02 -07:00
parent 048a479b5f
commit eecbcccee0
21 changed files with 219 additions and 173 deletions

View file

@ -549,4 +549,4 @@ PARSE_TABLE = {
#pragma GCC diagnostic pop
EXPORT_PARSER(ts_parser_arithmetic);
EXPORT_LANGUAGE(ts_language_arithmetic);

View file

@ -6675,4 +6675,4 @@ PARSE_TABLE = {
#pragma GCC diagnostic pop
EXPORT_PARSER(ts_parser_golang);
EXPORT_LANGUAGE(ts_language_golang);

View file

@ -77412,4 +77412,4 @@ PARSE_TABLE = {
#pragma GCC diagnostic pop
EXPORT_PARSER(ts_parser_javascript);
EXPORT_LANGUAGE(ts_language_javascript);

View file

@ -736,4 +736,4 @@ PARSE_TABLE = {
#pragma GCC diagnostic pop
EXPORT_PARSER(ts_parser_json);
EXPORT_LANGUAGE(ts_language_json);

View file

@ -12,7 +12,7 @@ typedef struct TSTree TSTree;
#define ts_lex_state_error 0
typedef struct {
typedef struct TSLexer {
TSInput input;
int debug;
const char *chunk;
@ -22,11 +22,10 @@ typedef struct {
size_t token_end_position;
size_t token_start_position;
int reached_end;
} TSLexer;
TSLexer ts_lexer_make();
int ts_lexer_advance(TSLexer *lexer);
TSTree *ts_lexer_build_node(TSLexer *lexer, TSSymbol symbol, int is_hidden);
TSTree * (* accept_fn)(struct TSLexer *, TSSymbol, int);
int (* advance_fn)(struct TSLexer *);
} TSLexer;
static inline size_t ts_lexer_position(const TSLexer *lexer) {
return lexer->chunk_start + lexer->position_in_chunk;
@ -40,28 +39,16 @@ static inline void ts_lexer_start_token(TSLexer *lexer) {
lexer->token_start_position = ts_lexer_position(lexer);
}
static inline int ts_lexer_advance(TSLexer *lexer) {
return lexer->advance_fn(lexer);
}
static inline TSTree *ts_lexer_accept(TSLexer *lexer, TSSymbol symbol, int is_hidden) {
return lexer->accept_fn(lexer, symbol, is_hidden);
}
typedef unsigned short TSStateId;
typedef struct {
size_t size;
struct {
TSTree *node;
TSStateId state;
int is_extra;
} *entries;
} TSStack;
TSStack ts_stack_make();
void ts_stack_delete(TSStack *);
TSTree *ts_stack_reduce(TSStack *stack, TSSymbol symbol,
size_t immediate_child_count,
const int *hidden_symbol_flags, int gather_extras);
void ts_stack_shrink(TSStack *stack, size_t new_size);
void ts_stack_push(TSStack *stack, TSStateId state, TSTree *node);
TSStateId ts_stack_top_state(const TSStack *stack);
TSTree *ts_stack_top_node(const TSStack *stack);
size_t ts_stack_right_position(const TSStack *stack);
typedef enum {
TSParseActionTypeError,
TSParseActionTypeShift,
@ -82,32 +69,15 @@ typedef struct {
} data;
} TSParseAction;
typedef struct {
struct TSLanguage {
size_t symbol_count;
const char **symbol_names;
const int *hidden_symbol_flags;
const TSParseAction *parse_table;
const TSStateId *lex_states;
TSTree *(*lex_fn)(TSParser *, TSStateId);
} TSParserConfig;
struct TSParser {
TSLexer lexer;
TSStack stack;
int debug;
TSTree *lookahead;
TSTree *next_lookahead;
TSParserConfig config;
TSTree *(*lex_fn)(TSLexer *, TSStateId);
};
TSParser *ts_parser_make(TSParserConfig);
void ts_parser_free(TSParser *);
TSParserConfig ts_parser_config(TSParser *);
const TSTree *ts_parser_parse(TSParser *parser, TSInput input,
TSInputEdit *edit);
void ts_parser_start(TSParser *parser, TSInput input, TSInputEdit *edit);
TSTree *ts_parser_step(TSParser *parser);
#define SYMBOL_NAMES static const char *ts_symbol_names[]
#define HIDDEN_SYMBOLS static const int ts_hidden_symbol_flags[SYMBOL_COUNT]
@ -117,10 +87,10 @@ TSTree *ts_parser_step(TSParser *parser);
#define PARSE_TABLE \
static const TSParseAction ts_parse_actions[STATE_COUNT][SYMBOL_COUNT]
#define LEX_FN() static TSTree *ts_lex(TSParser *parser, TSStateId lex_state)
#define LEX_FN() static TSTree *ts_lex(TSLexer *lexer, TSStateId lex_state)
#define DEBUG_LEX(...) \
if (parser->lexer.debug) { \
if (lexer->debug) { \
fprintf(stderr, "\n" __VA_ARGS__); \
}
@ -128,15 +98,15 @@ TSTree *ts_parser_step(TSParser *parser);
DEBUG_LEX("LEX %d", lex_state); \
char lookahead; \
next_state: \
lookahead = ts_lexer_lookahead_char(&parser->lexer); \
lookahead = ts_lexer_lookahead_char(lexer); \
DEBUG_LEX("CHAR '%c'", lookahead);
#define START_TOKEN() ts_lexer_start_token(&parser->lexer);
#define START_TOKEN() ts_lexer_start_token(lexer);
#define ADVANCE(state_index) \
{ \
DEBUG_LEX("ADVANCE %d", state_index); \
if (!ts_lexer_advance(&parser->lexer)) \
if (!ts_lexer_advance(lexer)) \
ACCEPT_TOKEN(ts_builtin_sym_end); \
lex_state = state_index; \
goto next_state; \
@ -145,14 +115,14 @@ TSTree *ts_parser_step(TSParser *parser);
#define ACCEPT_TOKEN(symbol) \
{ \
DEBUG_LEX("TOKEN %s", ts_symbol_names[symbol]); \
return ts_lexer_build_node(&parser->lexer, symbol, \
return ts_lexer_accept(lexer, symbol, \
ts_hidden_symbol_flags[symbol]); \
}
#define LEX_ERROR() \
{ \
DEBUG_LEX("ERROR"); \
return ts_lexer_build_node(&parser->lexer, ts_builtin_sym_error, 0); \
return ts_lexer_accept(lexer, ts_builtin_sym_error, 0); \
}
#define LEX_PANIC() \
@ -183,17 +153,17 @@ TSTree *ts_parser_step(TSParser *parser);
#define ACCEPT_INPUT() \
{ .type = TSParseActionTypeAccept }
#define EXPORT_PARSER(constructor_name) \
TSParser *constructor_name() { \
return ts_parser_make((TSParserConfig) { \
.symbol_count = SYMBOL_COUNT, \
.hidden_symbol_flags = ts_hidden_symbol_flags, \
.parse_table = (const TSParseAction *)ts_parse_actions, \
.lex_states = ts_lex_states, \
.symbol_names = ts_symbol_names, \
.lex_fn = ts_lex, \
}); \
}
#define EXPORT_LANGUAGE(language_name) \
static TSLanguage language = (TSLanguage) { \
.symbol_count = SYMBOL_COUNT, \
.hidden_symbol_flags = ts_hidden_symbol_flags, \
.parse_table = (const TSParseAction *)ts_parse_actions, \
.lex_states = ts_lex_states, \
.symbol_names = ts_symbol_names, \
.lex_fn = ts_lex, \
}; \
\
const TSLanguage *language_name = &language;
#ifdef __cplusplus
}

View file

@ -21,11 +21,9 @@ typedef struct {
} TSInputEdit;
typedef unsigned short TSSymbol;
typedef struct TSLanguage TSLanguage;
typedef struct TSNode TSNode;
typedef struct TSParser TSParser;
typedef struct TSDocument TSDocument;
size_t ts_node_pos(const TSNode *);
size_t ts_node_size(const TSNode *);
TSSymbol ts_node_sym(const TSNode *);
@ -41,14 +39,15 @@ void ts_node_retain(TSNode *node);
void ts_node_release(TSNode *node);
int ts_node_eq(const TSNode *, const TSNode *);
typedef struct TSDocument TSDocument;
TSDocument *ts_document_make();
void ts_document_free(TSDocument *doc);
void ts_document_set_parser(TSDocument *doc, TSParser *parser);
void ts_document_set_input(TSDocument *doc, TSInput input);
void ts_document_set_input_string(TSDocument *doc, const char *text);
void ts_document_edit(TSDocument *doc, TSInputEdit edit);
const char *ts_document_string(const TSDocument *doc);
TSNode *ts_document_root_node(const TSDocument *document);
void ts_document_free(TSDocument *);
void ts_document_set_language(TSDocument *, const TSLanguage *);
void ts_document_set_input(TSDocument *, TSInput);
void ts_document_set_input_string(TSDocument *, const char *);
void ts_document_edit(TSDocument *, TSInputEdit);
const char *ts_document_string(const TSDocument *);
TSNode *ts_document_root_node(const TSDocument *);
#define ts_builtin_sym_error 0
#define ts_builtin_sym_end 1

View file

@ -2,7 +2,7 @@
#include "runtime/helpers/spy_reader.h"
#include "runtime/tree.h"
extern "C" TSParser * ts_parser_json();
extern "C" const TSLanguage * ts_language_json;
START_TEST
@ -11,7 +11,7 @@ describe("incremental parsing", [&]() {
before_each([&]() {
doc = ts_document_make();
ts_document_set_parser(doc, ts_parser_json());
ts_document_set_language(doc, ts_language_json);
});
after_each([&]() {

View file

@ -1,4 +1,4 @@
#include "runtime/helpers/dummy_parser.h"
#include "runtime/helpers/dummy_language.h"
#include "tree_sitter/parser.h"
const TSParseAction parse_table[3][5] = {
@ -30,9 +30,11 @@ const int hidden_symbols[5] = {
[dummy_sym3] = 1,
};
TSParserConfig dummy_parser = {
static TSLanguage language = {
.symbol_count = 5,
.parse_table = (const TSParseAction *)parse_table,
.lex_states = lex_states,
.hidden_symbol_flags = hidden_symbols,
};
TSLanguage *dummy_language = &language;

View file

@ -1,5 +1,5 @@
#ifndef HELPERS_DUMMY_PARSER_H_
#define HELPERS_DUMMY_PARSER_H_
#ifndef HELPERS_DUMMY_LANGUAGE_H_
#define HELPERS_DUMMY_LANGUAGE_H_
#ifdef __cplusplus
extern "C" {
@ -14,10 +14,10 @@ enum {
dummy_sym3 = 4,
};
extern TSParserConfig dummy_parser;
extern TSLanguage *dummy_language;
#ifdef __cplusplus
}
#endif
#endif // HELPERS_DUMMY_PARSER_H_
#endif // HELPERS_DUMMY_LANGUAGE_H_

View file

@ -1,10 +1,10 @@
#include "runtime/runtime_spec_helper.h"
#include "runtime/helpers/read_test_entries.h"
extern "C" TSParser * ts_parser_javascript();
extern "C" TSParser * ts_parser_json();
extern "C" TSParser * ts_parser_arithmetic();
extern "C" TSParser * ts_parser_golang();
extern "C" TSLanguage *ts_language_javascript;
extern "C" TSLanguage *ts_language_json;
extern "C" TSLanguage *ts_language_arithmetic;
extern "C" TSLanguage *ts_language_golang;
START_TEST
@ -19,13 +19,13 @@ describe("Languages", [&]() {
ts_document_free(doc);
});
auto run_tests_for_language = [&](string language, TSParser * (parser_constructor)()) {
describe(language.c_str(), [&]() {
auto run_tests_for_language = [&](string language_name, TSLanguage *language) {
describe(language_name.c_str(), [&]() {
before_each([&]() {
ts_document_set_parser(doc, parser_constructor());
ts_document_set_language(doc, language);
});
for (auto &entry : test_entries_for_language(language)) {
for (auto &entry : test_entries_for_language(language_name)) {
it(entry.description.c_str(), [&]() {
ts_document_set_input_string(doc, entry.input.c_str());
auto doc_string = ts_document_string(doc);
@ -36,10 +36,10 @@ describe("Languages", [&]() {
});
};
run_tests_for_language("json", ts_parser_json);
run_tests_for_language("arithmetic", ts_parser_arithmetic);
run_tests_for_language("javascript", ts_parser_javascript);
run_tests_for_language("golang", ts_parser_golang);
run_tests_for_language("json", ts_language_json);
run_tests_for_language("arithmetic", ts_language_arithmetic);
run_tests_for_language("javascript", ts_language_javascript);
run_tests_for_language("golang", ts_language_golang);
});
END_TEST

View file

@ -1,6 +1,6 @@
#include "runtime/runtime_spec_helper.h"
extern "C" TSParser * ts_parser_json();
extern "C" TSLanguage * ts_language_json;
START_TEST
@ -10,7 +10,7 @@ describe("Node", []() {
before_each([&]() {
document = ts_document_make();
ts_document_set_parser(document, ts_parser_json());
ts_document_set_language(document, ts_language_json);
ts_document_set_input_string(document, " [12, 5, 345]");
root = ts_document_root_node(document);

View file

@ -1,15 +1,16 @@
#include "runtime/runtime_spec_helper.h"
#include "runtime/helpers/spy_reader.h"
#include "runtime/helpers/dummy_parser.h"
#include "runtime/helpers/dummy_language.h"
#include "runtime/tree.h"
#include "runtime/parser.h"
#include "tree_sitter/parser.h"
TSTree *lex_fn_node_to_return;
TSStateId lex_fn_state_received;
TSParser *lex_fn_parser_received;
TSLexer *lex_fn_lexer_received;
TSTree * fake_lex(TSParser *parser, TSStateId state_id) {
lex_fn_parser_received = parser;
TSTree * fake_lex(TSLexer *lexer, TSStateId state_id) {
lex_fn_lexer_received = lexer;
lex_fn_state_received = state_id;
return lex_fn_node_to_return;
}
@ -17,31 +18,29 @@ TSTree * fake_lex(TSParser *parser, TSStateId state_id) {
START_TEST
describe("LR Parsers", [&]() {
TSParser *parser;
TSParser parser;
SpyReader *reader;
before_each([&]() {
TSParserConfig config = dummy_parser;
config.lex_fn = fake_lex;
parser = ts_parser_make(config);
dummy_language->lex_fn = fake_lex;
parser = ts_parser_make(dummy_language);
reader = new SpyReader("some structured text", 5);
});
after_each([&]() {
ts_parser_free(parser);
ts_parser_destroy(&parser);
delete reader;
});
describe("when starting at the beginning of the input (edit is NULL)", [&]() {
before_each([&]() {
ts_parser_start(parser, reader->input, nullptr);
ts_parser_start(&parser, reader->input, nullptr);
});
it("runs the lexer with the lex state corresponding to the initial state", [&]() {
lex_fn_node_to_return = ts_tree_make_leaf(dummy_sym2, 5, 1, 0);
ts_parser_step(parser);
ts_parser_step(&parser);
AssertThat(lex_fn_state_received, Equals(100));
});
@ -51,12 +50,12 @@ describe("LR Parsers", [&]() {
});
it("advances to the state specified in the action", [&]() {
ts_parser_step(parser);
AssertThat(ts_stack_top_state(&parser->stack), Equals(12));
ts_parser_step(&parser);
AssertThat(ts_stack_top_state(&parser.stack), Equals(12));
});
it("continues parsing (returns NULL)", [&]() {
auto result = ts_parser_step(parser);
auto result = ts_parser_step(&parser);
AssertThat(result, Equals((TSTree *)nullptr));
});
});
@ -67,7 +66,7 @@ describe("LR Parsers", [&]() {
});
it("ends the parse, returning an error tree", [&]() {
auto result = ts_parser_step(parser);
auto result = ts_parser_step(&parser);
AssertThat(result->symbol, Equals(ts_builtin_sym_error));
});
});

View file

@ -1,6 +1,6 @@
#include "runtime/runtime_spec_helper.h"
#include "runtime/tree.h"
#include "tree_sitter/parser.h"
#include "runtime/stack.h"
START_TEST

View file

@ -163,7 +163,7 @@ class CCodeGenerator {
}
void parser_export() {
line("EXPORT_PARSER(ts_parser_" + name + ");");
line("EXPORT_LANGUAGE(ts_language_" + name + ");");
line();
}

View file

@ -2,10 +2,11 @@
#include "tree_sitter/parser.h"
#include "runtime/tree.h"
#include "runtime/node.h"
#include "runtime/parser.h"
#include <string.h>
struct TSDocument {
TSParser *parser;
TSParser parser;
const TSTree *tree;
TSInput input;
};
@ -14,24 +15,21 @@ TSDocument *ts_document_make() {
TSDocument *document = malloc(sizeof(TSDocument));
*document = (TSDocument) {
.input = (TSInput) { .data = NULL, .read_fn = NULL, .seek_fn = NULL },
.parser = NULL,
.tree = NULL
};
return document;
}
void ts_document_free(TSDocument *document) {
if (document->parser)
ts_parser_free(document->parser);
ts_parser_destroy(&document->parser);
if (document->input.release_fn)
document->input.release_fn(document->input.data);
free(document);
}
void ts_document_set_parser(TSDocument *document, TSParser *parser) {
if (document->parser)
ts_parser_free(document->parser);
document->parser = parser;
void ts_document_set_language(TSDocument *document, const TSLanguage *language) {
ts_parser_destroy(&document->parser);
document->parser = ts_parser_make(language);
}
const TSTree *ts_document_tree(const TSDocument *document) {
@ -39,22 +37,21 @@ const TSTree *ts_document_tree(const TSDocument *document) {
}
const char *ts_document_string(const TSDocument *document) {
return ts_tree_string(document->tree,
ts_parser_config(document->parser).symbol_names);
return ts_tree_string(document->tree, document->parser.language->symbol_names);
}
void ts_document_set_input(TSDocument *document, TSInput input) {
document->input = input;
document->tree = ts_parser_parse(document->parser, document->input, NULL);
document->tree = ts_parser_parse(&document->parser, document->input, NULL);
}
void ts_document_edit(TSDocument *document, TSInputEdit edit) {
document->tree = ts_parser_parse(document->parser, document->input, &edit);
document->tree = ts_parser_parse(&document->parser, document->input, &edit);
}
const char *ts_document_symbol_name(const TSDocument *document,
const TSTree *tree) {
return ts_parser_config(document->parser).symbol_names[tree->symbol];
return document->parser.language->symbol_names[tree->symbol];
}
typedef struct {
@ -97,8 +94,7 @@ void ts_document_set_input_string(TSDocument *document, const char *text) {
}
TSNode *ts_document_root_node(const TSDocument *document) {
return ts_node_make_root(document->tree,
document->parser->config.symbol_names);
return ts_node_make_root(document->tree, document->parser.language->symbol_names);
}
TSNode *ts_document_get_node(const TSDocument *document, size_t pos) {

View file

@ -1,18 +1,7 @@
#include "tree_sitter/parser.h"
#include "runtime/tree.h"
TSLexer ts_lexer_make() {
return (TSLexer) { .chunk = NULL,
.debug = 0,
.chunk_start = 0,
.chunk_size = 0,
.position_in_chunk = 0,
.token_start_position = 0,
.token_end_position = 0,
.reached_end = 0 };
}
int ts_lexer_advance(TSLexer *lexer) {
static int advance(TSLexer *lexer) {
static const char *empty_chunk = "";
if (lexer->position_in_chunk + 1 < lexer->chunk_size) {
lexer->position_in_chunk++;
@ -31,10 +20,24 @@ int ts_lexer_advance(TSLexer *lexer) {
return 1;
}
TSTree *ts_lexer_build_node(TSLexer *lexer, TSSymbol symbol, int is_hidden) {
static TSTree * accept(TSLexer *lexer, TSSymbol symbol, int is_hidden) {
size_t current_position = ts_lexer_position(lexer);
size_t size = current_position - lexer->token_start_position;
size_t offset = lexer->token_start_position - lexer->token_end_position;
lexer->token_end_position = current_position;
return ts_tree_make_leaf(symbol, size, offset, is_hidden);
}
TSLexer ts_lexer_make() {
return (TSLexer) { .chunk = NULL,
.debug = 0,
.chunk_start = 0,
.chunk_size = 0,
.position_in_chunk = 0,
.token_start_position = 0,
.token_end_position = 0,
.reached_end = 0,
.advance_fn = advance,
.accept_fn = accept,
};
}

16
src/runtime/lexer.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef RUNTIME_LEXER_H_
#define RUNTIME_LEXER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "tree_sitter/parser.h"
TSLexer ts_lexer_make();
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_LEXER_H_

View file

@ -2,14 +2,17 @@
#include "tree_sitter/runtime.h"
#include "tree_sitter/parser.h"
#include "runtime/tree.h"
#include "runtime/lexer.h"
#include "runtime/stack.h"
#include "runtime/parser.h"
/*
* Private
*/
static const TSParseAction *actions_for_state(TSParserConfig config,
static const TSParseAction *actions_for_state(const TSLanguage *language,
TSStateId state) {
return config.parse_table + (state * config.symbol_count);
return language->parse_table + (state * language->symbol_count);
}
static size_t breakdown_stack(TSParser *parser, TSInputEdit *edit) {
@ -37,7 +40,7 @@ static size_t breakdown_stack(TSParser *parser, TSInputEdit *edit) {
TSTree *child = children[i];
TSStateId state = ts_stack_top_state(stack);
TSStateId next_state =
actions_for_state(parser->config, state)[child->symbol].data.to_state;
actions_for_state(parser->language, state)[child->symbol].data.to_state;
ts_stack_push(stack, next_state, child);
ts_tree_retain(child);
position += ts_tree_total_size(child);
@ -52,14 +55,14 @@ static size_t breakdown_stack(TSParser *parser, TSInputEdit *edit) {
static TSSymbol *expected_symbols(TSParser *parser, size_t *count) {
*count = 0;
const TSParseAction *actions =
actions_for_state(parser->config, ts_stack_top_state(&parser->stack));
for (size_t i = 0; i < parser->config.symbol_count; i++)
actions_for_state(parser->language, ts_stack_top_state(&parser->stack));
for (size_t i = 0; i < parser->language->symbol_count; i++)
if (actions[i].type != TSParseActionTypeError)
(*count)++;
size_t n = 0;
TSSymbol *result = malloc(*count * sizeof(*result));
for (TSSymbol i = 0; i < parser->config.symbol_count; i++)
for (TSSymbol i = 0; i < parser->language->symbol_count; i++)
if (actions[i].type != TSParseActionTypeError)
result[n++] = i;
@ -70,22 +73,19 @@ static TSSymbol *expected_symbols(TSParser *parser, size_t *count) {
* Public
*/
TSParser *ts_parser_make(TSParserConfig config) {
TSParser *result = malloc(sizeof(*result));
*result = (TSParser) { .lexer = ts_lexer_make(),
.stack = ts_stack_make(),
.debug = 0,
.config = config, };
return result;
TSParser ts_parser_make(const TSLanguage *language) {
return (TSParser) { .lexer = ts_lexer_make(),
.stack = ts_stack_make(),
.debug = 0,
.language = language, };
}
void ts_parser_free(TSParser *parser) {
void ts_parser_destroy(TSParser *parser) {
if (parser->lookahead)
ts_tree_release(parser->lookahead);
if (parser->next_lookahead)
ts_tree_release(parser->next_lookahead);
ts_stack_delete(&parser->stack);
free(parser);
}
void ts_parser_start(TSParser *parser, TSInput input, TSInputEdit *edit) {
@ -118,7 +118,7 @@ void ts_parser_shift_extra(TSParser *parser) {
void ts_parser_reduce(TSParser *parser, TSSymbol symbol, size_t child_count) {
parser->next_lookahead = parser->lookahead;
parser->lookahead = ts_stack_reduce(&parser->stack, symbol, child_count,
parser->config.hidden_symbol_flags, 1);
parser->language->hidden_symbol_flags, 1);
}
int ts_parser_reduce_extra(TSParser *parser, TSSymbol symbol) {
@ -141,7 +141,7 @@ int ts_parser_handle_error(TSParser *parser) {
for (;;) {
ts_tree_release(parser->lookahead);
size_t position = ts_lexer_position(&parser->lexer);
parser->lookahead = parser->config.lex_fn(parser, ts_lex_state_error);
parser->lookahead = parser->language->lex_fn(&parser->lexer, ts_lex_state_error);
int at_end = 0;
if (ts_lexer_position(&parser->lexer) == position)
@ -160,10 +160,10 @@ int ts_parser_handle_error(TSParser *parser) {
size_t i = parser->stack.size - 1 - j;
TSStateId stack_state = parser->stack.entries[i].state;
TSParseAction action_on_error =
actions_for_state(parser->config, stack_state)[ts_builtin_sym_error];
actions_for_state(parser->language, stack_state)[ts_builtin_sym_error];
if (action_on_error.type == TSParseActionTypeShift) {
TSStateId state_after_error = action_on_error.data.to_state;
if (actions_for_state(parser->config,
if (actions_for_state(parser->language,
state_after_error)[parser->lookahead->symbol]
.type != TSParseActionTypeError) {
ts_stack_shrink(&parser->stack, i + 1);
@ -180,13 +180,13 @@ TSTree *ts_parser_tree_root(TSParser *parser) {
size_t node_count = 0;
for (size_t i = 0; i < stack->size; i++) {
TSTree *node = stack->entries[i].node;
if (!parser->config.hidden_symbol_flags[node->symbol])
if (!parser->language->hidden_symbol_flags[node->symbol])
node_count++;
}
if (node_count > 1)
return ts_stack_reduce(stack, 2, stack->size,
parser->config.hidden_symbol_flags, 0);
parser->language->hidden_symbol_flags, 0);
else
return ts_stack_top_node(stack);
}
@ -195,8 +195,8 @@ TSParseAction ts_parser_next_action(TSParser *parser) {
TSStateId state = ts_stack_top_state(&parser->stack);
if (!parser->lookahead)
parser->lookahead =
parser->config.lex_fn(parser, parser->config.lex_states[state]);
return actions_for_state(parser->config, state)[parser->lookahead->symbol];
parser->language->lex_fn(&parser->lexer, parser->language->lex_states[state]);
return actions_for_state(parser->language, state)[parser->lookahead->symbol];
}
#define DEBUG_PARSE(...) \
@ -207,7 +207,7 @@ TSParseAction ts_parser_next_action(TSParser *parser) {
TSTree *ts_parser_step(TSParser *parser) {
TSParseAction action = ts_parser_next_action(parser);
DEBUG_PARSE("LOOKAHEAD %s",
parser->config.symbol_names[parser->lookahead->symbol]);
parser->language->symbol_names[parser->lookahead->symbol]);
switch (action.type) {
case TSParseActionTypeShift:
DEBUG_PARSE("SHIFT %d", action.data.to_state);
@ -219,7 +219,7 @@ TSTree *ts_parser_step(TSParser *parser) {
return NULL;
case TSParseActionTypeReduce:
DEBUG_PARSE("REDUCE %s %d",
parser->config.symbol_names[action.data.symbol],
parser->language->symbol_names[action.data.symbol],
action.data.child_count);
ts_parser_reduce(parser, action.data.symbol, action.data.child_count);
return NULL;
@ -255,5 +255,3 @@ const TSTree *ts_parser_parse(TSParser *parser, TSInput input,
return tree;
}
}
TSParserConfig ts_parser_config(TSParser *parser) { return parser->config; }

30
src/runtime/parser.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef RUNTIME_PARSER_H_
#define RUNTIME_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "runtime/stack.h"
typedef struct {
TSLexer lexer;
TSStack stack;
int debug;
TSTree *lookahead;
TSTree *next_lookahead;
const TSLanguage *language;
} TSParser;
TSParser ts_parser_make(const TSLanguage *);
void ts_parser_destroy(TSParser *);
const TSTree *ts_parser_parse(TSParser *parser, TSInput input,
TSInputEdit *edit);
void ts_parser_start(TSParser *parser, TSInput input, TSInputEdit *edit);
TSTree *ts_parser_step(TSParser *parser);
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_PARSER_H_

View file

@ -1,7 +1,6 @@
#include "tree_sitter/runtime.h"
#include "tree_sitter/parser.h"
#include "runtime/tree.h"
#include <string.h>
#include "runtime/stack.h"
static size_t INITIAL_STACK_SIZE = 100;
static TSStateId INITIAL_STATE = 0;

34
src/runtime/stack.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef RUNTIME_STACK_H_
#define RUNTIME_STACK_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "tree_sitter/parser.h"
typedef struct {
size_t size;
struct {
TSTree *node;
TSStateId state;
int is_extra;
} *entries;
} TSStack;
TSStack ts_stack_make();
void ts_stack_delete(TSStack *);
TSTree *ts_stack_reduce(TSStack *stack, TSSymbol symbol,
size_t immediate_child_count,
const int *hidden_symbol_flags, int gather_extras);
void ts_stack_shrink(TSStack *stack, size_t new_size);
void ts_stack_push(TSStack *stack, TSStateId state, TSTree *node);
TSStateId ts_stack_top_state(const TSStack *stack);
TSTree *ts_stack_top_node(const TSStack *stack);
size_t ts_stack_right_position(const TSStack *stack);
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_STACK_H_