Files
Martin Vogelanddarkverbito 706bb2ce81 feat(lang): add Chialisp support with a first-party tree-sitter grammar
Chialisp (.clsp/.clib/.clinc) is the Chia smart-coin language. The only
public grammar, Quexington/tree-sitter-chialisp, cannot parse it: on the five
reference files from chia-blockchain@main it produced 3-34 ERROR nodes each.
Three defects account for all of them, and each desynchronised the rest of the
file rather than losing one node:

  * comments were `/;.*\r\n/` -- CRLF-only, while real files are LF;
  * `(include foo.clib)` was rejected because of the dot in the filename;
  * `(defconstant NAME <expr>)` accepted only a primitive after the name.

So the grammar is written here instead, in tools/tree-sitter-chialisp/, and
files as first-party: its vendored LICENSE is the project's own, byte-identical
to the repository root, carrying no third-party copyright.

It is deliberately GENERIC -- source_file / list / symbol / string / number /
hex / dot / comment, modelling the clvm_tools reader rather than the Chialisp
form vocabulary. `mod`, `defun`, `defconstant` and `include` are ordinary head
symbols; which lists are definitions is decided in extract_defs.c. A dialect
that adds a form (cl-21 -> cl-23 -> cl-26 each added several) therefore needs
no regenerated parser. Acceptance: all five reference files parse with zero
ERROR and zero MISSING nodes; the three defects above are pinned as tests.

Extraction, and the four decisions in it:

  * `Constant` is admitted to the cross-file name registry
    (cbm_label_is_registry_symbol). Chialisp's condition codes live as
    `(defconstant ...)` in a shared .clib and are referenced by name from every
    puzzle; labelled but unregistered they are seeded nowhere, and roughly half
    of a Chialisp graph would be present as nodes yet never the target of an
    edge. All three registry-seeding sites route through that one predicate, so
    they cannot diverge. No other language emits `Constant`, so the blast radius
    is exactly Chialisp. Pinned by a two-file graph test that goes red when the
    label is removed from the predicate.
  * `export` / `namespace` are NOT definition heads. `(export foo)` names a
    function already defined in the same file, so treating it as a def head
    mints a second node for one symbol. They stay in the not-a-call filter.
  * A parameter list is a `list` too, but it binds rather than invokes. Without
    that gate `(defun check_conditions (HEIGHTLOCK conditions) ...)` mints a
    phantom call to HEIGHTLOCK, and real Chialisp is mostly such definitions.
  * `(include *standard-cl-26*)` is a dialect directive, not a file dependency;
    recording it would invent a dependency on a file that does not exist.

Three helpers that the defs, calls and unified walks all need -- the quote-data
gate, comment-skipping named-child access, and the Chialisp def-head set -- live
in helpers.c rather than being copied per translation unit. They previously
existed as byte-identical duplicates that had already drifted: extract_defs.c
skipped comments when reading a def head while its mirror in extract_unified.c
did not, so a comment between a head and its name desynchronised defs from call
scope. Both now use the same accessor.

Ledger: 161 -> 162 grammars across the seven published surfaces, ABI-14 86 -> 87,
first-party 13 -> 14, CBM_LANG_COUNT 164 -> 165.

Distilled from PR #919 by darkverbito, whose extraction logic -- the CLVM
not-a-call vocabulary, the quoted-data gate, the filename-derived `mod` name and
the include/embed import handling -- is kept and is the substance of this change.
The grammar that PR vendored is not used.

Co-authored-by: darkverbito <8049985+darkverbito@users.noreply.github.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-08-28 21:30:06 +02:00

486 lines
14 KiB
C
Generated

/* Automatically @generated by tree-sitter v0.25.10 */
#include "tree_sitter/parser.h"
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
#define LANGUAGE_VERSION 14
#define STATE_COUNT 9
#define LARGE_STATE_COUNT 8
#define SYMBOL_COUNT 14
#define ALIAS_COUNT 0
#define TOKEN_COUNT 9
#define EXTERNAL_TOKEN_COUNT 0
#define FIELD_COUNT 0
#define MAX_ALIAS_SEQUENCE_LENGTH 3
#define MAX_RESERVED_WORD_SET_SIZE 0
#define PRODUCTION_ID_COUNT 1
#define SUPERTYPE_COUNT 0
enum ts_symbol_identifiers {
anon_sym_LPAREN = 1,
anon_sym_RPAREN = 2,
sym_comment = 3,
sym_hex = 4,
sym_number = 5,
sym_string = 6,
sym_dot = 7,
sym_symbol = 8,
sym_source_file = 9,
sym__form = 10,
sym__sexp = 11,
sym_list = 12,
aux_sym_source_file_repeat1 = 13,
};
static const char * const ts_symbol_names[] = {
[ts_builtin_sym_end] = "end",
[anon_sym_LPAREN] = "(",
[anon_sym_RPAREN] = ")",
[sym_comment] = "comment",
[sym_hex] = "hex",
[sym_number] = "number",
[sym_string] = "string",
[sym_dot] = "dot",
[sym_symbol] = "symbol",
[sym_source_file] = "source_file",
[sym__form] = "_form",
[sym__sexp] = "_sexp",
[sym_list] = "list",
[aux_sym_source_file_repeat1] = "source_file_repeat1",
};
static const TSSymbol ts_symbol_map[] = {
[ts_builtin_sym_end] = ts_builtin_sym_end,
[anon_sym_LPAREN] = anon_sym_LPAREN,
[anon_sym_RPAREN] = anon_sym_RPAREN,
[sym_comment] = sym_comment,
[sym_hex] = sym_hex,
[sym_number] = sym_number,
[sym_string] = sym_string,
[sym_dot] = sym_dot,
[sym_symbol] = sym_symbol,
[sym_source_file] = sym_source_file,
[sym__form] = sym__form,
[sym__sexp] = sym__sexp,
[sym_list] = sym_list,
[aux_sym_source_file_repeat1] = aux_sym_source_file_repeat1,
};
static const TSSymbolMetadata ts_symbol_metadata[] = {
[ts_builtin_sym_end] = {
.visible = false,
.named = true,
},
[anon_sym_LPAREN] = {
.visible = true,
.named = false,
},
[anon_sym_RPAREN] = {
.visible = true,
.named = false,
},
[sym_comment] = {
.visible = true,
.named = true,
},
[sym_hex] = {
.visible = true,
.named = true,
},
[sym_number] = {
.visible = true,
.named = true,
},
[sym_string] = {
.visible = true,
.named = true,
},
[sym_dot] = {
.visible = true,
.named = true,
},
[sym_symbol] = {
.visible = true,
.named = true,
},
[sym_source_file] = {
.visible = true,
.named = true,
},
[sym__form] = {
.visible = false,
.named = true,
},
[sym__sexp] = {
.visible = false,
.named = true,
},
[sym_list] = {
.visible = true,
.named = true,
},
[aux_sym_source_file_repeat1] = {
.visible = false,
.named = false,
},
};
static const TSSymbol ts_alias_sequences[PRODUCTION_ID_COUNT][MAX_ALIAS_SEQUENCE_LENGTH] = {
[0] = {0},
};
static const uint16_t ts_non_terminal_alias_map[] = {
0,
};
static const TSStateId ts_primary_state_ids[STATE_COUNT] = {
[0] = 0,
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4,
[5] = 5,
[6] = 6,
[7] = 7,
[8] = 8,
};
static bool ts_lex(TSLexer *lexer, TSStateId state) {
START_LEXER();
eof = lexer->eof(lexer);
switch (state) {
case 0:
if (eof) ADVANCE(5);
ADVANCE_MAP(
'"', 1,
'\'', 2,
'(', 6,
')', 7,
'-', 14,
'.', 13,
'0', 10,
';', 8,
);
if (('\t' <= lookahead && lookahead <= '\r') ||
lookahead == ' ') SKIP(0);
if (('1' <= lookahead && lookahead <= '9')) ADVANCE(11);
if (lookahead != 0) ADVANCE(16);
END_STATE();
case 1:
if (lookahead == '"') ADVANCE(12);
if (lookahead == '\\') ADVANCE(3);
if (lookahead != 0) ADVANCE(1);
END_STATE();
case 2:
if (lookahead == '\'') ADVANCE(12);
if (lookahead == '\\') ADVANCE(4);
if (lookahead != 0) ADVANCE(2);
END_STATE();
case 3:
if (lookahead != 0 &&
lookahead != '\n') ADVANCE(1);
END_STATE();
case 4:
if (lookahead != 0 &&
lookahead != '\n') ADVANCE(2);
END_STATE();
case 5:
ACCEPT_TOKEN(ts_builtin_sym_end);
END_STATE();
case 6:
ACCEPT_TOKEN(anon_sym_LPAREN);
END_STATE();
case 7:
ACCEPT_TOKEN(anon_sym_RPAREN);
END_STATE();
case 8:
ACCEPT_TOKEN(sym_comment);
if (lookahead != 0 &&
lookahead != '\n' &&
lookahead != '\r') ADVANCE(8);
END_STATE();
case 9:
ACCEPT_TOKEN(sym_hex);
if (('0' <= lookahead && lookahead <= '9') ||
('A' <= lookahead && lookahead <= 'F') ||
('a' <= lookahead && lookahead <= 'f')) ADVANCE(9);
if (lookahead != 0 &&
(lookahead < '\t' || '\r' < lookahead) &&
lookahead != ' ' &&
lookahead != '"' &&
(lookahead < '\'' || ')' < lookahead) &&
lookahead != ';') ADVANCE(16);
END_STATE();
case 10:
ACCEPT_TOKEN(sym_number);
if (lookahead == 'X' ||
lookahead == 'x') ADVANCE(15);
if (('0' <= lookahead && lookahead <= '9')) ADVANCE(11);
if (lookahead != 0 &&
(lookahead < '\t' || '\r' < lookahead) &&
lookahead != ' ' &&
lookahead != '"' &&
(lookahead < '\'' || ')' < lookahead) &&
lookahead != ';') ADVANCE(16);
END_STATE();
case 11:
ACCEPT_TOKEN(sym_number);
if (('0' <= lookahead && lookahead <= '9')) ADVANCE(11);
if (lookahead != 0 &&
(lookahead < '\t' || '\r' < lookahead) &&
lookahead != ' ' &&
lookahead != '"' &&
(lookahead < '\'' || ')' < lookahead) &&
lookahead != ';') ADVANCE(16);
END_STATE();
case 12:
ACCEPT_TOKEN(sym_string);
END_STATE();
case 13:
ACCEPT_TOKEN(sym_dot);
if (lookahead != 0 &&
(lookahead < '\t' || '\r' < lookahead) &&
lookahead != ' ' &&
lookahead != '"' &&
(lookahead < '\'' || ')' < lookahead) &&
lookahead != ';') ADVANCE(16);
END_STATE();
case 14:
ACCEPT_TOKEN(sym_symbol);
if (('0' <= lookahead && lookahead <= '9')) ADVANCE(11);
if (lookahead != 0 &&
(lookahead < '\t' || '\r' < lookahead) &&
lookahead != ' ' &&
lookahead != '"' &&
(lookahead < '\'' || ')' < lookahead) &&
lookahead != ';') ADVANCE(16);
END_STATE();
case 15:
ACCEPT_TOKEN(sym_symbol);
if (('0' <= lookahead && lookahead <= '9') ||
('A' <= lookahead && lookahead <= 'F') ||
('a' <= lookahead && lookahead <= 'f')) ADVANCE(9);
if (lookahead != 0 &&
(lookahead < '\t' || '\r' < lookahead) &&
lookahead != ' ' &&
lookahead != '"' &&
(lookahead < '\'' || ')' < lookahead) &&
lookahead != ';') ADVANCE(16);
END_STATE();
case 16:
ACCEPT_TOKEN(sym_symbol);
if (lookahead != 0 &&
(lookahead < '\t' || '\r' < lookahead) &&
lookahead != ' ' &&
lookahead != '"' &&
(lookahead < '\'' || ')' < lookahead) &&
lookahead != ';') ADVANCE(16);
END_STATE();
default:
return false;
}
}
static const TSLexMode ts_lex_modes[STATE_COUNT] = {
[0] = {.lex_state = 0},
[1] = {.lex_state = 0},
[2] = {.lex_state = 0},
[3] = {.lex_state = 0},
[4] = {.lex_state = 0},
[5] = {.lex_state = 0},
[6] = {.lex_state = 0},
[7] = {.lex_state = 0},
[8] = {.lex_state = 0},
};
static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = {
[STATE(0)] = {
[ts_builtin_sym_end] = ACTIONS(1),
[anon_sym_LPAREN] = ACTIONS(1),
[anon_sym_RPAREN] = ACTIONS(1),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(1),
[sym_number] = ACTIONS(1),
[sym_string] = ACTIONS(1),
[sym_dot] = ACTIONS(1),
[sym_symbol] = ACTIONS(1),
},
[STATE(1)] = {
[sym_source_file] = STATE(8),
[sym__form] = STATE(4),
[sym__sexp] = STATE(4),
[sym_list] = STATE(4),
[aux_sym_source_file_repeat1] = STATE(4),
[ts_builtin_sym_end] = ACTIONS(5),
[anon_sym_LPAREN] = ACTIONS(7),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(9),
[sym_number] = ACTIONS(9),
[sym_string] = ACTIONS(11),
[sym_dot] = ACTIONS(9),
[sym_symbol] = ACTIONS(9),
},
[STATE(2)] = {
[sym__form] = STATE(2),
[sym__sexp] = STATE(2),
[sym_list] = STATE(2),
[aux_sym_source_file_repeat1] = STATE(2),
[ts_builtin_sym_end] = ACTIONS(13),
[anon_sym_LPAREN] = ACTIONS(15),
[anon_sym_RPAREN] = ACTIONS(13),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(18),
[sym_number] = ACTIONS(18),
[sym_string] = ACTIONS(21),
[sym_dot] = ACTIONS(18),
[sym_symbol] = ACTIONS(18),
},
[STATE(3)] = {
[sym__form] = STATE(5),
[sym__sexp] = STATE(5),
[sym_list] = STATE(5),
[aux_sym_source_file_repeat1] = STATE(5),
[anon_sym_LPAREN] = ACTIONS(7),
[anon_sym_RPAREN] = ACTIONS(24),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(26),
[sym_number] = ACTIONS(26),
[sym_string] = ACTIONS(28),
[sym_dot] = ACTIONS(26),
[sym_symbol] = ACTIONS(26),
},
[STATE(4)] = {
[sym__form] = STATE(2),
[sym__sexp] = STATE(2),
[sym_list] = STATE(2),
[aux_sym_source_file_repeat1] = STATE(2),
[ts_builtin_sym_end] = ACTIONS(30),
[anon_sym_LPAREN] = ACTIONS(7),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(32),
[sym_number] = ACTIONS(32),
[sym_string] = ACTIONS(34),
[sym_dot] = ACTIONS(32),
[sym_symbol] = ACTIONS(32),
},
[STATE(5)] = {
[sym__form] = STATE(2),
[sym__sexp] = STATE(2),
[sym_list] = STATE(2),
[aux_sym_source_file_repeat1] = STATE(2),
[anon_sym_LPAREN] = ACTIONS(7),
[anon_sym_RPAREN] = ACTIONS(36),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(32),
[sym_number] = ACTIONS(32),
[sym_string] = ACTIONS(34),
[sym_dot] = ACTIONS(32),
[sym_symbol] = ACTIONS(32),
},
[STATE(6)] = {
[ts_builtin_sym_end] = ACTIONS(38),
[anon_sym_LPAREN] = ACTIONS(38),
[anon_sym_RPAREN] = ACTIONS(38),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(40),
[sym_number] = ACTIONS(40),
[sym_string] = ACTIONS(38),
[sym_dot] = ACTIONS(40),
[sym_symbol] = ACTIONS(40),
},
[STATE(7)] = {
[ts_builtin_sym_end] = ACTIONS(42),
[anon_sym_LPAREN] = ACTIONS(42),
[anon_sym_RPAREN] = ACTIONS(42),
[sym_comment] = ACTIONS(3),
[sym_hex] = ACTIONS(44),
[sym_number] = ACTIONS(44),
[sym_string] = ACTIONS(42),
[sym_dot] = ACTIONS(44),
[sym_symbol] = ACTIONS(44),
},
};
static const uint16_t ts_small_parse_table[] = {
[0] = 2,
ACTIONS(3), 1,
sym_comment,
ACTIONS(46), 1,
ts_builtin_sym_end,
};
static const uint32_t ts_small_parse_table_map[] = {
[SMALL_STATE(8)] = 0,
};
static const TSParseActionEntry ts_parse_actions[] = {
[0] = {.entry = {.count = 0, .reusable = false}},
[1] = {.entry = {.count = 1, .reusable = false}}, RECOVER(),
[3] = {.entry = {.count = 1, .reusable = true}}, SHIFT_EXTRA(),
[5] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_source_file, 0, 0, 0),
[7] = {.entry = {.count = 1, .reusable = true}}, SHIFT(3),
[9] = {.entry = {.count = 1, .reusable = false}}, SHIFT(4),
[11] = {.entry = {.count = 1, .reusable = true}}, SHIFT(4),
[13] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_source_file_repeat1, 2, 0, 0),
[15] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_source_file_repeat1, 2, 0, 0), SHIFT_REPEAT(3),
[18] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_source_file_repeat1, 2, 0, 0), SHIFT_REPEAT(2),
[21] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_source_file_repeat1, 2, 0, 0), SHIFT_REPEAT(2),
[24] = {.entry = {.count = 1, .reusable = true}}, SHIFT(6),
[26] = {.entry = {.count = 1, .reusable = false}}, SHIFT(5),
[28] = {.entry = {.count = 1, .reusable = true}}, SHIFT(5),
[30] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_source_file, 1, 0, 0),
[32] = {.entry = {.count = 1, .reusable = false}}, SHIFT(2),
[34] = {.entry = {.count = 1, .reusable = true}}, SHIFT(2),
[36] = {.entry = {.count = 1, .reusable = true}}, SHIFT(7),
[38] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_list, 2, 0, 0),
[40] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_list, 2, 0, 0),
[42] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_list, 3, 0, 0),
[44] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_list, 3, 0, 0),
[46] = {.entry = {.count = 1, .reusable = true}}, ACCEPT_INPUT(),
};
#ifdef __cplusplus
extern "C" {
#endif
#ifdef TREE_SITTER_HIDE_SYMBOLS
#define TS_PUBLIC
#elif defined(_WIN32)
#define TS_PUBLIC __declspec(dllexport)
#else
#define TS_PUBLIC __attribute__((visibility("default")))
#endif
TS_PUBLIC const TSLanguage *tree_sitter_chialisp(void) {
static const TSLanguage language = {
.abi_version = LANGUAGE_VERSION,
.symbol_count = SYMBOL_COUNT,
.alias_count = ALIAS_COUNT,
.token_count = TOKEN_COUNT,
.external_token_count = EXTERNAL_TOKEN_COUNT,
.state_count = STATE_COUNT,
.large_state_count = LARGE_STATE_COUNT,
.production_id_count = PRODUCTION_ID_COUNT,
.field_count = FIELD_COUNT,
.max_alias_sequence_length = MAX_ALIAS_SEQUENCE_LENGTH,
.parse_table = &ts_parse_table[0][0],
.small_parse_table = ts_small_parse_table,
.small_parse_table_map = ts_small_parse_table_map,
.parse_actions = ts_parse_actions,
.symbol_names = ts_symbol_names,
.symbol_metadata = ts_symbol_metadata,
.public_symbol_map = ts_symbol_map,
.alias_map = ts_non_terminal_alias_map,
.alias_sequences = &ts_alias_sequences[0][0],
.lex_modes = (const void*)ts_lex_modes,
.lex_fn = ts_lex,
.primary_state_ids = ts_primary_state_ids,
};
return &language;
}
#ifdef __cplusplus
}
#endif