2014-10-12 12:27:19 -07:00
|
|
|
#include <functional>
|
2014-02-10 18:38:01 -08:00
|
|
|
#include <map>
|
|
|
|
|
#include <set>
|
2014-03-09 22:45:33 -07:00
|
|
|
#include <string>
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <vector>
|
2014-03-09 21:37:21 -07:00
|
|
|
#include "compiler/generate_code/c_code.h"
|
2014-10-12 12:27:19 -07:00
|
|
|
#include "compiler/lex_table.h"
|
|
|
|
|
#include "compiler/parse_table.h"
|
2015-01-12 23:01:52 -08:00
|
|
|
#include "compiler/syntax_grammar.h"
|
2015-10-01 17:10:39 -07:00
|
|
|
#include "compiler/lexical_grammar.h"
|
2014-10-12 12:27:19 -07:00
|
|
|
#include "compiler/rules/built_in_symbols.h"
|
|
|
|
|
#include "compiler/util/string_helpers.h"
|
2013-12-15 19:33:34 -08:00
|
|
|
|
|
|
|
|
namespace tree_sitter {
|
2014-07-20 21:43:27 -07:00
|
|
|
namespace generate_code {
|
|
|
|
|
using std::function;
|
|
|
|
|
using std::map;
|
2015-10-01 17:10:39 -07:00
|
|
|
using std::pair;
|
2014-07-20 21:43:27 -07:00
|
|
|
using std::set;
|
2014-10-12 12:27:19 -07:00
|
|
|
using std::string;
|
|
|
|
|
using std::to_string;
|
|
|
|
|
using std::vector;
|
2014-07-20 21:43:27 -07:00
|
|
|
using util::escape_char;
|
|
|
|
|
|
2015-10-01 17:10:39 -07:00
|
|
|
static Variable EOF_ENTRY("end", VariableTypeNamed, rule_ptr());
|
2015-09-06 16:46:29 -07:00
|
|
|
|
2015-07-27 18:29:48 -07:00
|
|
|
static const map<char, string> REPLACEMENTS({
|
|
|
|
|
{ '~', "TILDE" },
|
|
|
|
|
{ '`', "BQUOTE" },
|
|
|
|
|
{ '!', "BANG" },
|
|
|
|
|
{ '@', "AT" },
|
|
|
|
|
{ '#', "POUND" },
|
|
|
|
|
{ '$', "DOLLAR" },
|
|
|
|
|
{ '%', "PERCENT" },
|
|
|
|
|
{ '^', "CARET" },
|
|
|
|
|
{ '&', "AMP" },
|
|
|
|
|
{ '*', "STAR" },
|
|
|
|
|
{ '(', "LPAREN" },
|
|
|
|
|
{ ')', "RPAREN" },
|
|
|
|
|
{ '-', "DASH" },
|
|
|
|
|
{ '+', "PLUS" },
|
|
|
|
|
{ '=', "EQ" },
|
|
|
|
|
{ '{', "LBRACE" },
|
|
|
|
|
{ '}', "RBRACE" },
|
|
|
|
|
{ '[', "LBRACK" },
|
|
|
|
|
{ ']', "RBRACK" },
|
|
|
|
|
{ '\\', "BSLASH" },
|
|
|
|
|
{ '|', "PIPE" },
|
|
|
|
|
{ ':', "COLON" },
|
|
|
|
|
{ ';', "SEMI" },
|
|
|
|
|
{ '"', "DQUOTE" },
|
|
|
|
|
{ '\'', "SQUOTE" },
|
|
|
|
|
{ '<', "LT" },
|
|
|
|
|
{ '>', "GT" },
|
|
|
|
|
{ ',', "COMMA" },
|
|
|
|
|
{ '.', "DOT" },
|
|
|
|
|
{ '?', "QMARK" },
|
|
|
|
|
{ '/', "SLASH" },
|
2015-10-26 16:55:59 -07:00
|
|
|
{ '\n', "LF" },
|
2015-07-27 18:29:48 -07:00
|
|
|
{ '\r', "CR" },
|
|
|
|
|
{ '\t', "TAB" },
|
|
|
|
|
});
|
2014-10-31 08:18:28 -07:00
|
|
|
|
2014-07-20 21:43:27 -07:00
|
|
|
class CCodeGenerator {
|
|
|
|
|
string buffer;
|
|
|
|
|
size_t indent_level;
|
|
|
|
|
|
|
|
|
|
const string name;
|
|
|
|
|
const ParseTable parse_table;
|
|
|
|
|
const LexTable lex_table;
|
|
|
|
|
const SyntaxGrammar syntax_grammar;
|
|
|
|
|
const LexicalGrammar lexical_grammar;
|
|
|
|
|
map<string, string> sanitized_names;
|
2016-06-21 07:28:04 -07:00
|
|
|
vector<pair<size_t, ParseTableEntry>> parse_table_entries;
|
2016-02-18 20:22:18 -08:00
|
|
|
vector<pair<size_t, set<rules::Symbol>>> in_progress_symbols;
|
2015-12-29 11:20:52 -08:00
|
|
|
size_t next_parse_action_list_index;
|
2016-02-18 20:22:18 -08:00
|
|
|
size_t next_in_progress_symbol_list_index;
|
2014-07-20 21:43:27 -07:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
CCodeGenerator(string name, const ParseTable &parse_table,
|
|
|
|
|
const LexTable &lex_table, const SyntaxGrammar &syntax_grammar,
|
|
|
|
|
const LexicalGrammar &lexical_grammar)
|
|
|
|
|
: indent_level(0),
|
|
|
|
|
name(name),
|
|
|
|
|
parse_table(parse_table),
|
|
|
|
|
lex_table(lex_table),
|
|
|
|
|
syntax_grammar(syntax_grammar),
|
2015-12-29 11:20:52 -08:00
|
|
|
lexical_grammar(lexical_grammar),
|
2016-02-18 20:22:18 -08:00
|
|
|
next_parse_action_list_index(0),
|
|
|
|
|
next_in_progress_symbol_list_index(0) {}
|
2014-07-20 21:43:27 -07:00
|
|
|
|
|
|
|
|
string code() {
|
|
|
|
|
buffer = "";
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
add_includes();
|
|
|
|
|
add_state_and_symbol_counts();
|
|
|
|
|
add_symbol_enum();
|
|
|
|
|
add_symbol_names_list();
|
2015-09-05 22:29:17 -07:00
|
|
|
add_symbol_node_types_list();
|
2014-10-12 12:27:19 -07:00
|
|
|
add_lex_function();
|
|
|
|
|
add_lex_states_list();
|
2016-04-27 14:14:56 -07:00
|
|
|
add_recovery_parse_states_list();
|
2014-10-12 12:27:19 -07:00
|
|
|
add_parse_table();
|
|
|
|
|
add_parser_export();
|
2014-07-20 21:43:27 -07:00
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_includes() {
|
2014-07-20 21:43:27 -07:00
|
|
|
add("#include \"tree_sitter/parser.h\"");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_state_and_symbol_counts() {
|
2014-07-20 21:43:27 -07:00
|
|
|
line("#define STATE_COUNT " + to_string(parse_table.states.size()));
|
|
|
|
|
line("#define SYMBOL_COUNT " + to_string(parse_table.symbols.size()));
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_symbol_enum() {
|
2014-07-20 21:43:27 -07:00
|
|
|
line("enum {");
|
|
|
|
|
indent([&]() {
|
|
|
|
|
bool at_start = true;
|
2015-12-02 07:36:31 -08:00
|
|
|
for (const auto &entry : parse_table.symbols) {
|
|
|
|
|
const rules::Symbol &symbol = entry.first;
|
2014-07-20 21:43:27 -07:00
|
|
|
if (!symbol.is_built_in()) {
|
|
|
|
|
if (at_start)
|
2014-08-08 23:58:59 -07:00
|
|
|
line(symbol_id(symbol) + " = ts_builtin_sym_start,");
|
2014-07-20 21:43:27 -07:00
|
|
|
else
|
|
|
|
|
line(symbol_id(symbol) + ",");
|
|
|
|
|
at_start = false;
|
2013-12-15 19:33:34 -08:00
|
|
|
}
|
2015-12-02 07:36:31 -08:00
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_symbol_names_list() {
|
2014-09-05 23:47:38 -07:00
|
|
|
line("static const char *ts_symbol_names[] = {");
|
2014-07-20 21:43:27 -07:00
|
|
|
indent([&]() {
|
2015-12-02 07:36:31 -08:00
|
|
|
for (const auto &entry : parse_table.symbols)
|
|
|
|
|
line("[" + symbol_id(entry.first) + "] = \"" +
|
|
|
|
|
sanitize_name_for_string(symbol_name(entry.first)) + "\",");
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-05 22:29:17 -07:00
|
|
|
void add_symbol_node_types_list() {
|
2015-11-22 13:32:20 -08:00
|
|
|
line("static const TSSymbolMetadata ts_symbol_metadata[SYMBOL_COUNT] = {");
|
2014-07-20 21:43:27 -07:00
|
|
|
indent([&]() {
|
2015-12-02 07:36:31 -08:00
|
|
|
for (const auto &entry : parse_table.symbols) {
|
|
|
|
|
const rules::Symbol &symbol = entry.first;
|
2015-11-22 13:32:20 -08:00
|
|
|
line("[" + symbol_id(symbol) + "] = {");
|
2016-06-21 07:28:04 -07:00
|
|
|
indent([&]() {
|
|
|
|
|
switch (symbol_type(symbol)) {
|
|
|
|
|
case VariableTypeNamed:
|
|
|
|
|
line(".visible = true,");
|
|
|
|
|
line(".named = true,");
|
|
|
|
|
break;
|
|
|
|
|
case VariableTypeAnonymous:
|
|
|
|
|
line(".visible = true,");
|
|
|
|
|
line(".named = false,");
|
|
|
|
|
break;
|
|
|
|
|
case VariableTypeHidden:
|
|
|
|
|
case VariableTypeAuxiliary:
|
|
|
|
|
line(".visible = false,");
|
|
|
|
|
line(".named = false,");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-09-05 22:29:17 -07:00
|
|
|
|
2016-06-21 07:28:04 -07:00
|
|
|
line(".structural = " + _boolean(entry.second.structural) + ",");
|
|
|
|
|
line(".extra = " + _boolean(entry.second.extra) + ",");
|
|
|
|
|
});
|
2015-12-02 07:36:31 -08:00
|
|
|
|
2016-06-21 07:28:04 -07:00
|
|
|
line("},");
|
2015-09-05 22:29:17 -07:00
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_lex_function() {
|
2016-01-10 20:04:41 -08:00
|
|
|
line(
|
2016-06-17 21:26:03 -07:00
|
|
|
"static bool ts_lex(TSLexer *lexer, TSStateId state, bool error_mode) {");
|
2014-07-20 21:43:27 -07:00
|
|
|
indent([&]() {
|
|
|
|
|
line("START_LEXER();");
|
2015-12-30 09:37:40 -08:00
|
|
|
_switch("state", [&]() {
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
for (const LexState &state : lex_table.states)
|
|
|
|
|
_case(to_string(i++), [&]() { add_lex_state(state); });
|
2014-10-12 12:27:19 -07:00
|
|
|
_default([&]() { line("LEX_ERROR();"); });
|
|
|
|
|
});
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("}");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_lex_states_list() {
|
2014-09-05 23:47:38 -07:00
|
|
|
line("static TSStateId ts_lex_states[STATE_COUNT] = {");
|
2014-07-20 21:43:27 -07:00
|
|
|
indent([&]() {
|
|
|
|
|
size_t state_id = 0;
|
2014-10-12 11:57:52 -07:00
|
|
|
for (const auto &state : parse_table.states)
|
2014-07-20 21:43:27 -07:00
|
|
|
line("[" + to_string(state_id++) + "] = " +
|
2015-12-29 20:58:50 -08:00
|
|
|
to_string(state.lex_state_id) + ",");
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-27 14:14:56 -07:00
|
|
|
void add_recovery_parse_states_list() {
|
2016-05-09 14:31:44 -07:00
|
|
|
line("static TSParseAction ts_recovery_actions[SYMBOL_COUNT] = {");
|
2016-02-13 14:02:22 -08:00
|
|
|
indent([&]() {
|
2016-06-21 07:28:04 -07:00
|
|
|
for (const auto &entry : parse_table.error_state.entries) {
|
|
|
|
|
if (!entry.second.actions.empty()) {
|
|
|
|
|
line("[" + symbol_id(entry.first) + "] = ");
|
|
|
|
|
ParseAction action = entry.second.actions[0];
|
2016-06-18 20:35:33 -07:00
|
|
|
if (action.extra) {
|
|
|
|
|
add("RECOVER_EXTRA(),");
|
|
|
|
|
} else {
|
|
|
|
|
add("RECOVER(" + to_string(action.state_index) + "),");
|
|
|
|
|
}
|
2016-04-25 21:59:40 -07:00
|
|
|
}
|
2016-02-13 14:02:22 -08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_parse_table() {
|
2016-06-21 07:28:04 -07:00
|
|
|
add_parse_action_list_id(
|
|
|
|
|
ParseTableEntry{ { ParseAction::Error() }, true, false });
|
2015-12-29 11:20:52 -08:00
|
|
|
|
2014-07-20 21:43:27 -07:00
|
|
|
size_t state_id = 0;
|
|
|
|
|
line("#pragma GCC diagnostic push");
|
|
|
|
|
line("#pragma GCC diagnostic ignored \"-Wmissing-field-initializers\"");
|
|
|
|
|
line();
|
2015-12-29 11:20:52 -08:00
|
|
|
line("static unsigned short ts_parse_table[STATE_COUNT][SYMBOL_COUNT] = {");
|
2014-07-20 21:43:27 -07:00
|
|
|
|
|
|
|
|
indent([&]() {
|
2014-10-12 11:57:52 -07:00
|
|
|
for (const auto &state : parse_table.states) {
|
2014-07-20 21:43:27 -07:00
|
|
|
line("[" + to_string(state_id++) + "] = {");
|
|
|
|
|
indent([&]() {
|
2016-06-21 07:28:04 -07:00
|
|
|
for (const auto &entry : state.entries) {
|
|
|
|
|
line("[" + symbol_id(entry.first) + "] = ");
|
|
|
|
|
add(to_string(add_parse_action_list_id(entry.second)));
|
2015-12-29 11:20:52 -08:00
|
|
|
add(",");
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("},");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
2015-12-29 11:20:52 -08:00
|
|
|
add_parse_action_list();
|
|
|
|
|
line();
|
2014-07-20 21:43:27 -07:00
|
|
|
line("#pragma GCC diagnostic pop");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_parser_export() {
|
2014-07-30 23:40:02 -07:00
|
|
|
line("EXPORT_LANGUAGE(ts_language_" + name + ");");
|
2014-07-20 21:43:27 -07:00
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_lex_state(const LexState &lex_state) {
|
|
|
|
|
if (lex_state.is_token_start)
|
|
|
|
|
line("START_TOKEN();");
|
2016-01-22 22:16:47 -07:00
|
|
|
|
|
|
|
|
for (const auto &pair : lex_state.advance_actions)
|
2014-10-12 12:27:19 -07:00
|
|
|
if (!pair.first.is_empty())
|
|
|
|
|
_if([&]() { add_character_set_condition(pair.first); },
|
2016-01-22 22:16:47 -07:00
|
|
|
[&]() { add_advance_action(pair.second); });
|
|
|
|
|
|
|
|
|
|
if (lex_state.accept_action.is_present())
|
|
|
|
|
add_accept_token_action(lex_state.accept_action);
|
|
|
|
|
else
|
|
|
|
|
line("LEX_ERROR();");
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_character_set_condition(const rules::CharacterSet &rule) {
|
|
|
|
|
if (rule.includes_all) {
|
|
|
|
|
add("!(");
|
|
|
|
|
add_character_range_conditions(rule.excluded_ranges());
|
|
|
|
|
add(")");
|
2014-07-20 21:43:27 -07:00
|
|
|
} else {
|
2014-10-12 12:27:19 -07:00
|
|
|
add_character_range_conditions(rule.included_ranges());
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_character_range_conditions(const vector<rules::CharacterRange> &ranges) {
|
2014-08-23 14:25:45 -07:00
|
|
|
if (ranges.size() == 1) {
|
2014-10-12 12:27:19 -07:00
|
|
|
add_character_range_condition(*ranges.begin());
|
2014-07-20 21:43:27 -07:00
|
|
|
} else {
|
|
|
|
|
bool first = true;
|
2014-10-12 11:57:52 -07:00
|
|
|
for (const auto &range : ranges) {
|
2014-10-12 12:27:19 -07:00
|
|
|
if (!first) {
|
2014-07-20 21:43:27 -07:00
|
|
|
add(" ||");
|
2014-10-12 12:27:19 -07:00
|
|
|
line();
|
|
|
|
|
add_padding();
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
2014-10-12 12:27:19 -07:00
|
|
|
|
|
|
|
|
add("(");
|
|
|
|
|
add_character_range_condition(range);
|
|
|
|
|
add(")");
|
|
|
|
|
|
2014-07-20 21:43:27 -07:00
|
|
|
first = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_character_range_condition(const rules::CharacterRange &range) {
|
|
|
|
|
string lookahead("lookahead");
|
|
|
|
|
if (range.min == range.max) {
|
|
|
|
|
add(lookahead + " == " + escape_char(range.min));
|
2014-08-23 14:25:45 -07:00
|
|
|
} else {
|
2014-10-12 12:27:19 -07:00
|
|
|
add(escape_char(range.min) + string(" <= ") + lookahead + " && " +
|
|
|
|
|
lookahead + " <= " + escape_char(range.max));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-22 22:16:47 -07:00
|
|
|
void add_advance_action(const AdvanceAction &action) {
|
2016-05-19 16:25:44 -07:00
|
|
|
if (action.in_main_token)
|
|
|
|
|
line("ADVANCE(" + to_string(action.state_index) + ");");
|
|
|
|
|
else
|
|
|
|
|
line("SKIP(" + to_string(action.state_index) + ");");
|
2016-01-22 22:16:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void add_accept_token_action(const AcceptTokenAction &action) {
|
2016-06-21 07:28:04 -07:00
|
|
|
line("ACCEPT_TOKEN(" + symbol_id(action.symbol) + ");");
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
|
2015-12-29 11:20:52 -08:00
|
|
|
void add_parse_action_list() {
|
|
|
|
|
line("static TSParseActionEntry ts_parse_actions[] = {");
|
|
|
|
|
|
|
|
|
|
indent([&]() {
|
2016-06-21 07:28:04 -07:00
|
|
|
for (const auto &pair : parse_table_entries) {
|
2015-12-29 11:20:52 -08:00
|
|
|
size_t index = pair.first;
|
2015-12-29 20:58:50 -08:00
|
|
|
line("[" + to_string(index) + "] = {.count = " +
|
2016-06-21 07:28:04 -07:00
|
|
|
to_string(pair.second.actions.size()) + ", .reusable = " +
|
|
|
|
|
_boolean(pair.second.reusable) + ", .depends_on_lookahead = " +
|
|
|
|
|
_boolean(pair.second.depends_on_lookahead) + "},");
|
2015-12-29 11:20:52 -08:00
|
|
|
|
2016-06-21 07:28:04 -07:00
|
|
|
for (const ParseAction &action : pair.second.actions) {
|
2015-12-29 11:20:52 -08:00
|
|
|
add(" ");
|
|
|
|
|
switch (action.type) {
|
|
|
|
|
case ParseActionTypeError:
|
|
|
|
|
add("ERROR()");
|
|
|
|
|
break;
|
|
|
|
|
case ParseActionTypeAccept:
|
|
|
|
|
add("ACCEPT_INPUT()");
|
|
|
|
|
break;
|
|
|
|
|
case ParseActionTypeShift:
|
|
|
|
|
if (action.extra) {
|
|
|
|
|
add("SHIFT_EXTRA()");
|
|
|
|
|
} else {
|
2016-06-21 07:28:04 -07:00
|
|
|
add("SHIFT(" + to_string(action.state_index) + ")");
|
2015-12-29 11:20:52 -08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ParseActionTypeReduce:
|
|
|
|
|
if (action.extra) {
|
|
|
|
|
add("REDUCE_EXTRA(" + symbol_id(action.symbol) + ")");
|
2016-06-21 07:28:04 -07:00
|
|
|
} else if (action.fragile) {
|
|
|
|
|
add("REDUCE_FRAGILE(" + symbol_id(action.symbol) + ", " +
|
|
|
|
|
to_string(action.consumed_symbol_count) + ")");
|
2015-12-29 11:20:52 -08:00
|
|
|
} else {
|
|
|
|
|
add("REDUCE(" + symbol_id(action.symbol) + ", " +
|
2016-06-21 07:28:04 -07:00
|
|
|
to_string(action.consumed_symbol_count) + ")");
|
2015-12-29 11:20:52 -08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default: {}
|
2015-12-17 12:48:55 -08:00
|
|
|
}
|
2015-12-29 11:20:52 -08:00
|
|
|
add(",");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2015-12-29 20:58:50 -08:00
|
|
|
line("};");
|
2015-12-29 11:20:52 -08:00
|
|
|
}
|
|
|
|
|
|
2016-06-21 07:28:04 -07:00
|
|
|
size_t add_parse_action_list_id(const ParseTableEntry &entry) {
|
|
|
|
|
for (const auto &pair : parse_table_entries) {
|
|
|
|
|
if (pair.second == entry) {
|
2015-12-29 11:20:52 -08:00
|
|
|
return pair.first;
|
2015-06-28 16:22:31 -05:00
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
2015-12-29 11:20:52 -08:00
|
|
|
|
|
|
|
|
size_t result = next_parse_action_list_index;
|
2016-06-21 07:28:04 -07:00
|
|
|
parse_table_entries.push_back({ next_parse_action_list_index, entry });
|
|
|
|
|
next_parse_action_list_index += 1 + entry.actions.size();
|
2015-12-29 11:20:52 -08:00
|
|
|
return result;
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
|
2016-02-18 20:22:18 -08:00
|
|
|
size_t add_in_progress_symbol_list_id(const set<rules::Symbol> &symbols) {
|
|
|
|
|
for (const auto &pair : in_progress_symbols) {
|
|
|
|
|
if (pair.second == symbols) {
|
|
|
|
|
return pair.first;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t result = next_in_progress_symbol_list_index;
|
|
|
|
|
in_progress_symbols.push_back({ result, symbols });
|
|
|
|
|
next_in_progress_symbol_list_index += 1 + symbols.size();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
// Helper functions
|
|
|
|
|
|
|
|
|
|
string symbol_id(const rules::Symbol &symbol) {
|
2015-10-01 17:10:39 -07:00
|
|
|
if (symbol == rules::END_OF_INPUT())
|
|
|
|
|
return "ts_builtin_sym_end";
|
2015-09-06 16:46:29 -07:00
|
|
|
|
2015-10-01 17:10:39 -07:00
|
|
|
auto entry = entry_for_symbol(symbol);
|
|
|
|
|
string name = sanitize_name(entry.first);
|
|
|
|
|
|
|
|
|
|
switch (entry.second) {
|
|
|
|
|
case VariableTypeAuxiliary:
|
2015-09-05 22:29:17 -07:00
|
|
|
return "aux_sym_" + name;
|
2015-10-01 17:10:39 -07:00
|
|
|
case VariableTypeAnonymous:
|
2015-09-06 16:46:29 -07:00
|
|
|
return "anon_sym_" + name;
|
|
|
|
|
default:
|
|
|
|
|
return "sym_" + name;
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
string symbol_name(const rules::Symbol &symbol) {
|
2015-09-06 16:46:29 -07:00
|
|
|
if (symbol == rules::END_OF_INPUT())
|
|
|
|
|
return "END";
|
2015-10-01 17:10:39 -07:00
|
|
|
return entry_for_symbol(symbol).first;
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
|
2015-10-01 17:10:39 -07:00
|
|
|
VariableType symbol_type(const rules::Symbol &symbol) {
|
2015-09-06 16:46:29 -07:00
|
|
|
if (symbol == rules::END_OF_INPUT())
|
2015-10-01 17:10:39 -07:00
|
|
|
return VariableTypeHidden;
|
|
|
|
|
return entry_for_symbol(symbol).second;
|
2015-09-05 17:05:37 -07:00
|
|
|
}
|
|
|
|
|
|
2015-10-01 17:10:39 -07:00
|
|
|
pair<string, VariableType> entry_for_symbol(const rules::Symbol &symbol) {
|
|
|
|
|
if (symbol.is_token) {
|
|
|
|
|
const Variable &variable = lexical_grammar.variables[symbol.index];
|
|
|
|
|
return { variable.name, variable.type };
|
2014-10-12 12:27:19 -07:00
|
|
|
} else {
|
2015-10-01 17:10:39 -07:00
|
|
|
const SyntaxVariable &variable = syntax_grammar.variables[symbol.index];
|
|
|
|
|
return { variable.name, variable.type };
|
2014-10-12 12:27:19 -07:00
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
// C-code generation functions
|
|
|
|
|
|
2014-07-20 21:43:27 -07:00
|
|
|
void _switch(string condition, function<void()> body) {
|
|
|
|
|
line("switch (" + condition + ") {");
|
|
|
|
|
indent(body);
|
|
|
|
|
line("}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _case(string value, function<void()> body) {
|
|
|
|
|
line("case " + value + ":");
|
|
|
|
|
indent(body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _default(function<void()> body) {
|
|
|
|
|
line("default:");
|
|
|
|
|
indent(body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _if(function<void()> condition, function<void()> body) {
|
|
|
|
|
line("if (");
|
|
|
|
|
indent(condition);
|
|
|
|
|
add(")");
|
|
|
|
|
indent(body);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-26 13:36:13 -07:00
|
|
|
string sanitize_name_for_string(string name) {
|
2015-11-09 09:33:24 -08:00
|
|
|
util::str_replace(&name, "\\", "\\\\");
|
2015-10-26 13:36:13 -07:00
|
|
|
util::str_replace(&name, "\n", "\\n");
|
|
|
|
|
util::str_replace(&name, "\r", "\\r");
|
2015-11-09 09:33:24 -08:00
|
|
|
util::str_replace(&name, "\"", "\\\"");
|
2015-10-26 13:36:13 -07:00
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
string sanitize_name(string name) {
|
|
|
|
|
auto existing = sanitized_names.find(name);
|
|
|
|
|
if (existing != sanitized_names.end())
|
|
|
|
|
return existing->second;
|
|
|
|
|
|
|
|
|
|
string stripped_name;
|
|
|
|
|
for (char c : name) {
|
|
|
|
|
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
|
|
|
|
|
('0' <= c && c <= '9') || (c == '_')) {
|
|
|
|
|
stripped_name += c;
|
2015-09-05 17:05:37 -07:00
|
|
|
} else {
|
|
|
|
|
auto replacement = REPLACEMENTS.find(c);
|
|
|
|
|
size_t i = stripped_name.size();
|
|
|
|
|
if (replacement != REPLACEMENTS.end()) {
|
|
|
|
|
if (i > 0 && stripped_name[i - 1] != '_')
|
|
|
|
|
stripped_name += "_";
|
|
|
|
|
stripped_name += replacement->second;
|
|
|
|
|
}
|
2014-10-12 12:27:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (size_t extra_number = 0;; extra_number++) {
|
|
|
|
|
string suffix = extra_number ? to_string(extra_number) : "";
|
|
|
|
|
string unique_name = stripped_name + suffix;
|
|
|
|
|
if (unique_name == "")
|
|
|
|
|
continue;
|
|
|
|
|
if (!has_sanitized_name(unique_name)) {
|
|
|
|
|
sanitized_names.insert({ name, unique_name });
|
|
|
|
|
return unique_name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-19 16:25:44 -07:00
|
|
|
string _boolean(bool value) {
|
|
|
|
|
return value ? "true" : "false";
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
bool has_sanitized_name(string name) {
|
|
|
|
|
for (const auto &pair : sanitized_names)
|
|
|
|
|
if (pair.second == name)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// General code generation functions
|
|
|
|
|
|
2015-07-31 16:32:24 -07:00
|
|
|
void line() {
|
|
|
|
|
line("");
|
|
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
|
|
|
|
|
void line(string input) {
|
|
|
|
|
add("\n");
|
|
|
|
|
if (!input.empty()) {
|
2014-10-12 12:27:19 -07:00
|
|
|
add_padding();
|
|
|
|
|
add(input);
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_padding() {
|
|
|
|
|
for (size_t i = 0; i < indent_level; i++)
|
|
|
|
|
add(" ");
|
|
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void indent(function<void()> body) {
|
|
|
|
|
indent_level++;
|
2014-07-20 21:43:27 -07:00
|
|
|
body();
|
2014-10-12 12:27:19 -07:00
|
|
|
indent_level--;
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
2014-10-12 12:27:19 -07:00
|
|
|
|
2015-07-31 16:32:24 -07:00
|
|
|
void add(string input) {
|
|
|
|
|
buffer += input;
|
|
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
string c_code(string name, const ParseTable &parse_table,
|
|
|
|
|
const LexTable &lex_table, const SyntaxGrammar &syntax_grammar,
|
|
|
|
|
const LexicalGrammar &lexical_grammar) {
|
|
|
|
|
return CCodeGenerator(name, parse_table, lex_table, syntax_grammar,
|
2015-07-27 18:29:48 -07:00
|
|
|
lexical_grammar)
|
|
|
|
|
.code();
|
2014-04-28 21:46:43 -07:00
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
|
|
|
|
|
} // namespace generate_code
|
|
|
|
|
} // namespace tree_sitter
|