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"
|
2017-03-17 12:52:01 -07:00
|
|
|
#include "compiler/rule.h"
|
2014-10-12 12:27:19 -07:00
|
|
|
#include "compiler/util/string_helpers.h"
|
2017-01-31 10:21:47 -08:00
|
|
|
#include "tree_sitter/runtime.h"
|
2013-12-15 19:33:34 -08:00
|
|
|
|
|
|
|
|
namespace tree_sitter {
|
2014-07-20 21:43:27 -07:00
|
|
|
namespace generate_code {
|
2016-11-30 09:34:47 -08:00
|
|
|
|
2014-07-20 21:43:27 -07:00
|
|
|
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;
|
2016-11-30 09:34:47 -08:00
|
|
|
using rules::Symbol;
|
2014-07-20 21:43:27 -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-12-21 11:24:41 -08:00
|
|
|
vector<set<Symbol::Index>> external_scanner_states;
|
2015-12-29 11:20:52 -08:00
|
|
|
size_t next_parse_action_list_index;
|
2017-07-13 17:17:22 -07:00
|
|
|
set<string> unique_replacement_names;
|
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-11-30 09:34:47 -08:00
|
|
|
next_parse_action_list_index(0) {}
|
2014-07-20 21:43:27 -07:00
|
|
|
|
|
|
|
|
string code() {
|
|
|
|
|
buffer = "";
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
add_includes();
|
2016-11-30 09:34:47 -08:00
|
|
|
add_warning_pragma();
|
|
|
|
|
add_stats();
|
2014-10-12 12:27:19 -07:00
|
|
|
add_symbol_enum();
|
|
|
|
|
add_symbol_names_list();
|
2016-11-30 09:34:47 -08:00
|
|
|
add_symbol_metadata_list();
|
2017-07-13 17:17:22 -07:00
|
|
|
add_rename_sequences();
|
2014-10-12 12:27:19 -07:00
|
|
|
add_lex_function();
|
2016-11-30 09:34:47 -08:00
|
|
|
add_lex_modes_list();
|
|
|
|
|
|
2016-12-21 11:24:41 -08:00
|
|
|
if (!syntax_grammar.external_tokens.empty()) {
|
2016-11-30 09:34:47 -08:00
|
|
|
add_external_token_enum();
|
2016-12-21 11:24:41 -08:00
|
|
|
add_external_scanner_symbol_map();
|
|
|
|
|
add_external_scanner_states_list();
|
|
|
|
|
}
|
2016-11-30 09:34:47 -08:00
|
|
|
|
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() {
|
2016-11-17 17:29:10 -08:00
|
|
|
add("#include <tree_sitter/parser.h>");
|
2014-07-20 21:43:27 -07:00
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
void add_warning_pragma() {
|
|
|
|
|
line("#pragma GCC diagnostic push");
|
|
|
|
|
line("#pragma GCC diagnostic ignored \"-Wmissing-field-initializers\"");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void add_stats() {
|
2017-03-09 21:16:37 -08:00
|
|
|
size_t token_count = 0;
|
|
|
|
|
for (const auto &entry : parse_table.symbols) {
|
|
|
|
|
const Symbol &symbol = entry.first;
|
2017-03-17 12:52:01 -07:00
|
|
|
if (symbol.is_terminal()) {
|
2016-12-21 10:49:55 -08:00
|
|
|
token_count++;
|
2017-03-09 21:16:37 -08:00
|
|
|
} else if (symbol.is_external()) {
|
|
|
|
|
const ExternalToken &external_token = syntax_grammar.external_tokens[symbol.index];
|
|
|
|
|
if (external_token.corresponding_internal_token == rules::NONE()) {
|
|
|
|
|
token_count++;
|
|
|
|
|
}
|
2016-12-21 10:49:55 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-13 17:17:22 -07:00
|
|
|
unsigned max_rename_sequence_length = 0;
|
|
|
|
|
for (const RenameSequence &rename_sequence : parse_table.rename_sequences) {
|
|
|
|
|
if (rename_sequence.size() > max_rename_sequence_length) {
|
|
|
|
|
max_rename_sequence_length = rename_sequence.size();
|
|
|
|
|
}
|
|
|
|
|
for (const string &name_replacement : rename_sequence) {
|
|
|
|
|
unique_replacement_names.insert(name_replacement);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 10:21:47 -08:00
|
|
|
line("#define LANGUAGE_VERSION " + to_string(TREE_SITTER_LANGUAGE_VERSION));
|
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()));
|
2016-12-21 10:49:55 -08:00
|
|
|
line("#define TOKEN_COUNT " + to_string(token_count));
|
|
|
|
|
line("#define EXTERNAL_TOKEN_COUNT " + to_string(syntax_grammar.external_tokens.size()));
|
2017-07-13 17:17:22 -07:00
|
|
|
line("#define MAX_RENAME_SEQUENCE_LENGTH " + to_string(max_rename_sequence_length));
|
2014-07-20 21:43:27 -07:00
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_symbol_enum() {
|
2014-07-20 21:43:27 -07:00
|
|
|
line("enum {");
|
|
|
|
|
indent([&]() {
|
2016-08-26 17:40:22 -07:00
|
|
|
size_t i = 1;
|
2015-12-02 07:36:31 -08:00
|
|
|
for (const auto &entry : parse_table.symbols) {
|
2016-11-30 09:34:47 -08:00
|
|
|
const Symbol &symbol = entry.first;
|
2014-07-20 21:43:27 -07:00
|
|
|
if (!symbol.is_built_in()) {
|
2016-08-26 17:40:22 -07:00
|
|
|
line(symbol_id(symbol) + " = " + to_string(i) + ",");
|
|
|
|
|
i++;
|
2013-12-15 19:33:34 -08:00
|
|
|
}
|
2015-12-02 07:36:31 -08:00
|
|
|
}
|
2017-07-13 17:17:22 -07:00
|
|
|
|
|
|
|
|
for (const string &replacement_name : unique_replacement_names) {
|
|
|
|
|
line(rename_id(replacement_name) + " = " + to_string(i) + ",");
|
|
|
|
|
i++;
|
|
|
|
|
}
|
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([&]() {
|
2017-07-13 17:17:22 -07:00
|
|
|
for (const auto &entry : parse_table.symbols) {
|
|
|
|
|
line(
|
|
|
|
|
"[" + symbol_id(entry.first) + "] = \"" +
|
|
|
|
|
sanitize_name_for_string(symbol_name(entry.first)) + "\","
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const string &replacement_name : unique_replacement_names) {
|
|
|
|
|
line(
|
|
|
|
|
"[" + rename_id(replacement_name) + "] = \"" +
|
|
|
|
|
sanitize_name_for_string(replacement_name) + "\","
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void add_rename_sequences() {
|
|
|
|
|
|
|
|
|
|
line(
|
|
|
|
|
"static TSSymbol ts_rename_sequences[" +
|
|
|
|
|
to_string(parse_table.rename_sequences.size()) +
|
|
|
|
|
"][MAX_RENAME_SEQUENCE_LENGTH] = {"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
indent([&]() {
|
|
|
|
|
for (unsigned i = 1, n = parse_table.rename_sequences.size(); i < n; i++) {
|
|
|
|
|
const RenameSequence &sequence = parse_table.rename_sequences[i];
|
|
|
|
|
line("[" + to_string(i) + "] = {");
|
|
|
|
|
indent([&]() {
|
|
|
|
|
for (unsigned j = 0, n = sequence.size(); j < n; j++) {
|
|
|
|
|
if (!sequence[j].empty()) {
|
|
|
|
|
line("[" + to_string(j) + "] = " + rename_id(sequence[j]) + ",");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("},");
|
|
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
void add_symbol_metadata_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) {
|
2016-11-30 09:34:47 -08:00
|
|
|
const 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:
|
2016-07-17 08:16:03 -07:00
|
|
|
line(".visible = false,");
|
|
|
|
|
line(".named = true,");
|
|
|
|
|
break;
|
2016-06-21 07:28:04 -07:00
|
|
|
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-10-05 14:02:49 -07:00
|
|
|
line("static bool ts_lex(TSLexer *lexer, TSStateId state) {");
|
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;
|
2017-03-13 17:03:47 -07:00
|
|
|
for (const LexState &state : lex_table.states) {
|
2015-12-30 09:37:40 -08:00
|
|
|
_case(to_string(i++), [&]() { add_lex_state(state); });
|
2017-03-13 17:03:47 -07:00
|
|
|
}
|
|
|
|
|
_default([&]() { line("return false;"); });
|
2014-10-12 12:27:19 -07:00
|
|
|
});
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("}");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
void add_lex_modes_list() {
|
2016-12-08 22:35:16 -08:00
|
|
|
add_external_scanner_state({});
|
2016-11-30 09:34:47 -08:00
|
|
|
|
2016-12-21 10:49:55 -08:00
|
|
|
map<Symbol::Index, Symbol::Index> external_tokens_by_corresponding_internal_token;
|
|
|
|
|
for (size_t i = 0, n = lexical_grammar.variables.size(); i < n; i++) {
|
|
|
|
|
for (size_t j = 0; j < syntax_grammar.external_tokens.size(); j++) {
|
|
|
|
|
const ExternalToken &external_token = syntax_grammar.external_tokens[j];
|
2017-01-31 10:21:47 -08:00
|
|
|
if (external_token.corresponding_internal_token.index == Symbol::Index(i)) {
|
2016-12-21 10:49:55 -08:00
|
|
|
external_tokens_by_corresponding_internal_token.insert({i, j});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
line("static TSLexMode ts_lex_modes[STATE_COUNT] = {");
|
2014-07-20 21:43:27 -07:00
|
|
|
indent([&]() {
|
|
|
|
|
size_t state_id = 0;
|
2016-11-30 09:34:47 -08:00
|
|
|
|
|
|
|
|
for (const auto &state : parse_table.states) {
|
|
|
|
|
line("[" + to_string(state_id++) + "] = {.lex_state = ");
|
|
|
|
|
add(to_string(state.lex_state_id));
|
|
|
|
|
|
2016-12-21 10:49:55 -08:00
|
|
|
bool needs_external_scanner = false;
|
2016-11-30 09:34:47 -08:00
|
|
|
set<Symbol::Index> external_token_indices;
|
|
|
|
|
for (const auto &pair : state.terminal_entries) {
|
|
|
|
|
Symbol symbol = pair.first;
|
2016-12-08 22:35:16 -08:00
|
|
|
if (symbol.is_external()) {
|
2016-12-21 10:49:55 -08:00
|
|
|
needs_external_scanner = true;
|
2016-11-30 09:34:47 -08:00
|
|
|
external_token_indices.insert(symbol.index);
|
2017-03-17 12:52:01 -07:00
|
|
|
} else if (symbol.is_terminal()) {
|
2016-12-21 10:49:55 -08:00
|
|
|
auto corresponding_external_token =
|
|
|
|
|
external_tokens_by_corresponding_internal_token.find(symbol.index);
|
|
|
|
|
if (corresponding_external_token != external_tokens_by_corresponding_internal_token.end()) {
|
|
|
|
|
external_token_indices.insert(corresponding_external_token->second);
|
2016-12-08 22:35:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-21 10:49:55 -08:00
|
|
|
if (needs_external_scanner) {
|
2016-12-21 11:24:41 -08:00
|
|
|
add(", .external_lex_state = " + add_external_scanner_state(external_token_indices));
|
2016-11-30 09:34:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add("},");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 22:35:16 -08:00
|
|
|
string add_external_scanner_state(set<Symbol::Index> external_token_ids) {
|
2016-12-21 11:24:41 -08:00
|
|
|
for (size_t i = 0, n = external_scanner_states.size(); i < n; i++)
|
|
|
|
|
if (external_scanner_states[i] == external_token_ids)
|
2016-11-30 09:34:47 -08:00
|
|
|
return to_string(i);
|
2016-12-21 11:24:41 -08:00
|
|
|
external_scanner_states.push_back(external_token_ids);
|
|
|
|
|
return to_string(external_scanner_states.size() - 1);
|
2016-11-30 09:34:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void add_external_token_enum() {
|
|
|
|
|
line("enum {");
|
|
|
|
|
indent([&]() {
|
|
|
|
|
for (size_t i = 0; i < syntax_grammar.external_tokens.size(); i++)
|
|
|
|
|
line(external_token_id(i) + ",");
|
|
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-21 11:24:41 -08:00
|
|
|
void add_external_scanner_symbol_map() {
|
2017-03-24 18:38:21 -04:00
|
|
|
line("static TSSymbol ts_external_scanner_symbol_map[EXTERNAL_TOKEN_COUNT] = {");
|
2016-11-30 09:34:47 -08:00
|
|
|
indent([&]() {
|
|
|
|
|
for (size_t i = 0; i < syntax_grammar.external_tokens.size(); i++) {
|
2017-03-17 12:52:01 -07:00
|
|
|
line("[" + external_token_id(i) + "] = " + symbol_id(Symbol::external(i)) + ",");
|
2016-11-30 09:34:47 -08:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-21 11:24:41 -08:00
|
|
|
void add_external_scanner_states_list() {
|
|
|
|
|
line("static bool ts_external_scanner_states[");
|
|
|
|
|
add(to_string(external_scanner_states.size()));
|
2016-11-30 09:34:47 -08:00
|
|
|
add("][EXTERNAL_TOKEN_COUNT] = {");
|
|
|
|
|
indent([&]() {
|
|
|
|
|
size_t i = 0;
|
2016-12-21 11:24:41 -08:00
|
|
|
for (const auto &valid_external_lookaheads : external_scanner_states) {
|
|
|
|
|
if (!valid_external_lookaheads.empty()) {
|
2016-11-30 09:34:47 -08:00
|
|
|
line("[" + to_string(i) + "] = {");
|
|
|
|
|
indent([&]() {
|
2016-12-21 11:24:41 -08:00
|
|
|
for (Symbol::Index id : valid_external_lookaheads) {
|
2016-11-30 09:34:47 -08:00
|
|
|
line("[" + external_token_id(id) + "] = true,");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("},");
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2014-07-20 21:43:27 -07:00
|
|
|
});
|
|
|
|
|
line("};");
|
|
|
|
|
line();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_parse_table() {
|
2016-07-17 07:25:13 -07:00
|
|
|
add_parse_action_list_id(ParseTableEntry{ {}, false, false });
|
2015-12-29 11:20:52 -08:00
|
|
|
|
2014-07-20 21:43:27 -07:00
|
|
|
size_t state_id = 0;
|
2017-07-13 17:17:22 -07:00
|
|
|
line("static uint16_t 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-11-14 08:36:06 -08:00
|
|
|
for (const auto &entry : state.nonterminal_entries) {
|
2017-03-17 12:52:01 -07:00
|
|
|
line("[" + symbol_id(Symbol::non_terminal(entry.first)) + "] = STATE(");
|
2016-11-14 08:36:06 -08:00
|
|
|
add(to_string(entry.second));
|
|
|
|
|
add("),");
|
|
|
|
|
}
|
|
|
|
|
for (const auto &entry : state.terminal_entries) {
|
2016-11-30 09:34:47 -08:00
|
|
|
line("[" + symbol_id(entry.first) + "] = ACTIONS(");
|
2016-06-21 07:28:04 -07:00
|
|
|
add(to_string(add_parse_action_list_id(entry.second)));
|
2016-11-14 08:36:06 -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
|
|
|
}
|
|
|
|
|
|
2014-10-12 12:27:19 -07:00
|
|
|
void add_parser_export() {
|
2017-01-31 10:29:25 -08:00
|
|
|
string language_function_name = "tree_sitter_" + name;
|
|
|
|
|
string external_scanner_name = language_function_name + "_external_scanner";
|
2016-11-30 09:34:47 -08:00
|
|
|
|
2016-12-21 11:24:41 -08:00
|
|
|
if (!syntax_grammar.external_tokens.empty()) {
|
2016-11-30 09:34:47 -08:00
|
|
|
line("void *" + external_scanner_name + "_create();");
|
2016-12-21 11:24:41 -08:00
|
|
|
line("void " + external_scanner_name + "_destroy();");
|
2016-12-20 13:12:01 -08:00
|
|
|
line("void " + external_scanner_name + "_reset(void *);");
|
2016-12-21 11:24:41 -08:00
|
|
|
line("bool " + external_scanner_name + "_scan(void *, TSLexer *, const bool *);");
|
2016-12-20 13:12:01 -08:00
|
|
|
line("bool " + external_scanner_name + "_serialize(void *, TSExternalTokenState);");
|
2016-12-21 13:58:18 -08:00
|
|
|
line("void " + external_scanner_name + "_deserialize(void *, const TSExternalTokenState);");
|
2016-11-30 09:34:47 -08:00
|
|
|
line();
|
|
|
|
|
}
|
2016-12-21 11:24:41 -08:00
|
|
|
|
2017-01-31 10:29:25 -08:00
|
|
|
line("const TSLanguage *" + language_function_name + "() {");
|
2016-12-21 11:24:41 -08:00
|
|
|
indent([&]() {
|
|
|
|
|
line("GET_LANGUAGE(");
|
|
|
|
|
if (syntax_grammar.external_tokens.empty()) {
|
|
|
|
|
add(");");
|
|
|
|
|
} else {
|
|
|
|
|
indent([&]() {
|
|
|
|
|
line("(const bool *)ts_external_scanner_states,");
|
2017-03-24 18:38:21 -04:00
|
|
|
line("ts_external_scanner_symbol_map,");
|
2016-12-21 11:24:41 -08:00
|
|
|
line(external_scanner_name + "_create,");
|
|
|
|
|
line(external_scanner_name + "_destroy,");
|
|
|
|
|
line(external_scanner_name + "_reset,");
|
|
|
|
|
line(external_scanner_name + "_scan,");
|
|
|
|
|
line(external_scanner_name + "_serialize,");
|
|
|
|
|
line(external_scanner_name + "_deserialize,");
|
|
|
|
|
});
|
|
|
|
|
line(");");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
line("}");
|
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) {
|
2017-03-13 17:03:47 -07:00
|
|
|
if (lex_state.accept_action.is_present()) {
|
|
|
|
|
add_accept_token_action(lex_state.accept_action);
|
|
|
|
|
}
|
2016-01-22 22:16:47 -07:00
|
|
|
|
2017-07-10 14:09:31 -07:00
|
|
|
set<uint32_t> ruled_out_characters;
|
2017-03-13 17:03:47 -07:00
|
|
|
for (const auto &pair : lex_state.advance_actions) {
|
2017-07-10 14:09:31 -07:00
|
|
|
if (pair.first.is_empty()) continue;
|
|
|
|
|
|
|
|
|
|
size_t current_length = buffer.size();
|
|
|
|
|
|
|
|
|
|
line("if (");
|
|
|
|
|
if (add_character_set_condition(pair.first, ruled_out_characters)) {
|
|
|
|
|
add(")");
|
|
|
|
|
indent([&]() { add_advance_action(pair.second); });
|
|
|
|
|
ruled_out_characters.insert(pair.first.included_chars.begin(), pair.first.included_chars.end());
|
|
|
|
|
} else {
|
|
|
|
|
buffer.resize(current_length);
|
|
|
|
|
add_advance_action(pair.second);
|
2017-03-13 17:03:47 -07:00
|
|
|
}
|
|
|
|
|
}
|
2016-01-22 22:16:47 -07:00
|
|
|
|
2017-03-13 17:03:47 -07:00
|
|
|
line("END_STATE();");
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-07-10 14:09:31 -07:00
|
|
|
bool add_character_set_condition(const rules::CharacterSet &rule, const set<uint32_t> &ruled_out_characters) {
|
2014-10-12 12:27:19 -07:00
|
|
|
if (rule.includes_all) {
|
2017-07-10 14:09:31 -07:00
|
|
|
return add_character_range_conditions(rule.excluded_ranges(), ruled_out_characters, true);
|
2014-07-20 21:43:27 -07:00
|
|
|
} else {
|
2017-07-10 14:09:31 -07:00
|
|
|
return add_character_range_conditions(rule.included_ranges(), ruled_out_characters, false);
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-10 14:09:31 -07:00
|
|
|
bool add_character_range_conditions(const vector<rules::CharacterRange> &ranges,
|
|
|
|
|
const set<uint32_t> &ruled_out_characters,
|
|
|
|
|
bool is_negated) {
|
|
|
|
|
bool first = true;
|
|
|
|
|
for (auto iter = ranges.begin(), end = ranges.end(); iter != end;) {
|
|
|
|
|
auto range = *iter;
|
|
|
|
|
|
|
|
|
|
bool range_is_ruled_out = true;
|
|
|
|
|
for (uint32_t c = range.min; c <= range.max; c++) {
|
|
|
|
|
if (!ruled_out_characters.count(c)) {
|
|
|
|
|
range_is_ruled_out = false;
|
|
|
|
|
break;
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
2017-07-10 14:09:31 -07:00
|
|
|
}
|
2014-10-12 12:27:19 -07:00
|
|
|
|
2017-07-10 14:09:31 -07:00
|
|
|
if (range_is_ruled_out) {
|
|
|
|
|
++iter;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto next_iter = iter + 1;
|
|
|
|
|
while (next_iter != end) {
|
|
|
|
|
bool can_join_ranges = true;
|
|
|
|
|
for (uint32_t character = range.max + 1; character < next_iter->min; character++) {
|
|
|
|
|
if (!ruled_out_characters.count(character)) {
|
|
|
|
|
can_join_ranges = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-10-12 12:27:19 -07:00
|
|
|
|
2017-07-10 14:09:31 -07:00
|
|
|
if (can_join_ranges) {
|
|
|
|
|
range.max = next_iter->max;
|
|
|
|
|
++next_iter;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!first) {
|
|
|
|
|
add(is_negated ? " &&" : " ||");
|
|
|
|
|
line(" ");
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
2017-07-10 14:09:31 -07:00
|
|
|
|
|
|
|
|
add_character_range_condition(range, is_negated);
|
|
|
|
|
first = false;
|
|
|
|
|
iter = next_iter;
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
2017-07-10 14:09:31 -07:00
|
|
|
|
|
|
|
|
return !first;
|
2014-07-20 21:43:27 -07:00
|
|
|
}
|
|
|
|
|
|
2017-07-10 14:09:31 -07:00
|
|
|
void add_character_range_condition(const rules::CharacterRange &range, bool is_negated) {
|
|
|
|
|
auto min = escape_char(range.min);
|
|
|
|
|
auto max = escape_char(range.max);
|
|
|
|
|
if (is_negated) {
|
|
|
|
|
if (range.max == range.min) {
|
|
|
|
|
add("lookahead != " + min);
|
|
|
|
|
} else if (range.max == range.min + 1) {
|
|
|
|
|
add("lookahead != " + min + " &&");
|
|
|
|
|
line(" lookahead != " + max);
|
|
|
|
|
} else {
|
|
|
|
|
add("(lookahead < " + min + " || lookahead > " + max + ")");
|
|
|
|
|
}
|
2014-08-23 14:25:45 -07:00
|
|
|
} else {
|
2017-07-10 14:09:31 -07:00
|
|
|
if (range.max == range.min) {
|
|
|
|
|
add("lookahead == " + min);
|
|
|
|
|
} else if (range.max == range.min + 1) {
|
|
|
|
|
add("lookahead == " + min + " ||");
|
|
|
|
|
line(" lookahead == " + max);
|
|
|
|
|
} else {
|
|
|
|
|
add("(" + min + " <= lookahead && lookahead <= " + max + ")");
|
|
|
|
|
}
|
2014-10-12 12:27:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-22 22:16:47 -07:00
|
|
|
void add_advance_action(const AdvanceAction &action) {
|
2017-03-13 17:03:47 -07:00
|
|
|
if (action.in_main_token) {
|
2016-05-19 16:25:44 -07:00
|
|
|
line("ADVANCE(" + to_string(action.state_index) + ");");
|
2017-03-13 17:03:47 -07:00
|
|
|
} else {
|
2016-05-19 16:25:44 -07:00
|
|
|
line("SKIP(" + to_string(action.state_index) + ");");
|
2017-03-13 17:03:47 -07:00
|
|
|
}
|
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:
|
|
|
|
|
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:
|
2017-07-13 17:17:22 -07:00
|
|
|
add("REDUCE(");
|
2017-07-06 15:20:11 -07:00
|
|
|
add(symbol_id(action.symbol));
|
|
|
|
|
add(", ");
|
|
|
|
|
add(to_string(action.consumed_symbol_count));
|
2017-07-13 17:17:22 -07:00
|
|
|
|
|
|
|
|
if (action.fragile) {
|
|
|
|
|
add(", .fragile = true");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action.dynamic_precedence != 0) {
|
|
|
|
|
add(", .dynamic_precedence = " + to_string(action.dynamic_precedence));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action.rename_sequence_id != 0) {
|
|
|
|
|
add(", .rename_sequence_id = " + to_string(action.rename_sequence_id));
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-06 15:20:11 -07:00
|
|
|
add(")");
|
2015-12-29 11:20:52 -08:00
|
|
|
break;
|
2016-06-27 14:07:47 -07:00
|
|
|
case ParseActionTypeRecover:
|
|
|
|
|
add("RECOVER(" + to_string(action.state_index) + ")");
|
|
|
|
|
break;
|
2015-12-29 11:20:52 -08:00
|
|
|
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-11-30 09:34:47 -08:00
|
|
|
// Helper functions
|
2016-02-18 20:22:18 -08:00
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
string external_token_id(Symbol::Index index) {
|
2017-03-17 16:31:29 -07:00
|
|
|
return "ts_external_token_" + sanitize_name(syntax_grammar.external_tokens[index].name);
|
2016-02-18 20:22:18 -08:00
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
string symbol_id(const 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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-13 17:17:22 -07:00
|
|
|
string rename_id(const string &name) {
|
|
|
|
|
return "rename_sym_" + sanitize_name(name);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
string symbol_name(const 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
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
VariableType symbol_type(const 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
|
|
|
}
|
|
|
|
|
|
2016-11-30 09:34:47 -08:00
|
|
|
pair<string, VariableType> entry_for_symbol(const Symbol &symbol) {
|
|
|
|
|
switch (symbol.type) {
|
|
|
|
|
case Symbol::NonTerminal: {
|
|
|
|
|
const SyntaxVariable &variable = syntax_grammar.variables[symbol.index];
|
|
|
|
|
return { variable.name, variable.type };
|
|
|
|
|
}
|
|
|
|
|
case Symbol::Terminal: {
|
2017-02-27 22:54:38 -08:00
|
|
|
const LexicalVariable &variable = lexical_grammar.variables[symbol.index];
|
2016-11-30 09:34:47 -08:00
|
|
|
return { variable.name, variable.type };
|
|
|
|
|
}
|
2017-01-31 11:46:28 -08:00
|
|
|
case Symbol::External:
|
|
|
|
|
default: {
|
2016-12-05 17:26:11 -08:00
|
|
|
const ExternalToken &token = syntax_grammar.external_tokens[symbol.index];
|
|
|
|
|
return { token.name, token.type };
|
2016-11-30 09:34:47 -08:00
|
|
|
}
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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++)
|
2017-03-13 17:03:47 -07:00
|
|
|
add(" ");
|
2014-10-12 12:27:19 -07:00
|
|
|
}
|
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) {
|
2017-03-17 12:52:01 -07:00
|
|
|
return CCodeGenerator(
|
|
|
|
|
name,
|
|
|
|
|
parse_table,
|
|
|
|
|
lex_table,
|
|
|
|
|
syntax_grammar,
|
|
|
|
|
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
|