chore: import upstream snapshot with attribution
OpenSSF Scorecard / scorecard (push) Failing after 0s
DCO / dco (push) Failing after 0s
CodeQL SAST / analyze (push) Failing after 1s
Deploy Pages / deploy (push) Failing after 1s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:28:05 +08:00
commit 41cb1c0170
1830 changed files with 38276124 additions and 0 deletions
+276
View File
@@ -0,0 +1,276 @@
/// <reference types="tree-sitter-cli/dsl" />
// tree-sitter grammar for FORM (symbolic manipulation language)
// https://www.nikhef.nl/~form/
module.exports = grammar({
name: 'form',
extras: $ => [
/\s/,
$.line_comment,
$.block_comment,
],
word: $ => $.identifier,
// Tell tree-sitter to allow GLR parsing for these specific ambiguities
conflicts: $ => [
[$.procedure_definition],
[$.call_statement],
],
rules: {
source_file: $ => repeat($._statement),
_statement: $ => choice(
$.declaration_statement,
$.substitution_statement,
$.print_statement,
$.procedure_definition,
$.call_statement,
$.if_statement,
$.repeat_statement,
$.do_loop,
$.argument_block,
$.label_statement,
$.module_directive,
$.include_directive,
$.define_directive,
$.preproc_directive_with_arg,
$.preproc_directive_bare,
$.preproc_line_directive,
$.preproc_do,
$.expression_statement,
),
// Declarations: Symbols, Functions, CFunctions, Vectors, Indices, etc.
declaration_statement: $ => seq(
field('kind', choice(
'Symbols', 'Symbol',
'Functions', 'Function',
'CFunctions', 'CFunction',
'Tensors', 'Tensor',
'Vectors', 'Vector',
'Indices', 'Index',
'Sets', 'Set',
'Tables', 'Table',
'NTensors', 'NTensor',
'AutoDeclare',
'Dimension',
'FixIndex',
'Off', 'On',
)),
commaSep1($.identifier),
';',
),
// Substitution: id pattern = replacement;
substitution_statement: $ => seq(
optional(choice('Local', 'Global')),
'id',
$._expression,
'=',
$._expression,
';',
),
// Print/format statements
print_statement: $ => seq(
choice('Print', 'NoPrint', 'Format'),
optional($._expression),
';',
),
// Procedure definition: #procedure name(args) ... #endprocedure
// Parameters use a dedicated list to avoid expression ambiguity.
procedure_definition: $ => prec(10, seq(
'#procedure',
field('name', $.identifier),
optional($.parameter_list),
repeat($._statement),
'#endprocedure',
)),
parameter_list: $ => seq(
token.immediate('('),
optional(commaSep1(alias($.identifier, $.parameter))),
')',
),
// #call procedure(args)
call_statement: $ => prec(10, seq(
'#call',
field('name', $.identifier),
optional(seq(
token.immediate('('),
optional(commaSep1($._expression)),
')',
)),
)),
// #include filename
include_directive: $ => seq(
'#include',
choice($.string_literal, $.identifier),
),
// #define name "value"
define_directive: $ => seq(
choice('#define', '#redefine'),
$.identifier,
$.string_literal,
),
// Preprocessor directives that REQUIRE an argument
preproc_directive_with_arg: $ => seq(
choice('#ifdef', '#ifndef', '#if', '#case', '#switch', '#undefine'),
$._expression,
),
// Preprocessor directives with NO argument
preproc_directive_bare: _ => choice(
'#else', '#endif', '#break', '#endswitch',
),
// Preprocessor directives that consume rest of line
preproc_line_directive: $ => seq(
choice('#message', '#write', '#close', '#system',
'#optimize', '#Optimize', '#toexternal', '#fromexternal',
'#setexternal', '#rmexternal', '#external',
'#factdollar', '#pipe'),
/[^\n]*/,
),
// Preprocessor loop: #do var = start, end ... #enddo
preproc_do: $ => seq(
'#do',
$.identifier,
'=',
$._expression,
optional(seq(',', $._expression)),
repeat($._statement),
'#enddo',
),
// Module directives: .sort, .end, .clear, .store, .global
module_directive: _ => seq(
'.',
choice('sort', 'end', 'clear', 'store', 'global'),
),
// Label statement
label_statement: $ => seq(
choice('label', 'goto'),
$.identifier,
';',
),
// if ... endif;
if_statement: $ => seq(
'if',
'(',
$._expression,
')',
repeat($._statement),
optional(seq('else', repeat($._statement))),
'endif',
';',
),
// repeat; ... endrepeat;
repeat_statement: $ => seq(
'repeat',
';',
repeat($._statement),
'endrepeat',
';',
),
// argument ... endargument;
argument_block: $ => seq(
'argument',
';',
repeat($._statement),
'endargument',
';',
),
// do var = start, end; ... enddo;
do_loop: $ => seq(
'do',
$.identifier,
'=',
$._expression,
',',
$._expression,
';',
repeat($._statement),
'enddo',
';',
),
// Generic expression statement (catch-all)
expression_statement: $ => seq(
$._expression,
';',
),
// Expressions
_expression: $ => choice(
$.identifier,
$.number,
$.string_literal,
$.dollar_variable,
$.wildcard,
$.function_application,
$.binary_expression,
$.unary_expression,
$.parenthesized_expression,
$.index_expression,
),
function_application: $ => prec(2, seq(
field('name', $.identifier),
'(',
optional(commaSep1($._expression)),
')',
)),
binary_expression: $ => choice(
prec.left(1, seq($._expression, choice('+', '-'), $._expression)),
prec.left(2, seq($._expression, choice('*', '/'), $._expression)),
prec.left(0, seq($._expression, choice('==', '!=', '<=', '>=', '<', '>'), $._expression)),
prec.left(-1, seq($._expression, choice('&&', '||'), $._expression)),
prec.right(3, seq($._expression, '^', $._expression)),
),
unary_expression: $ => prec(4, seq(choice('-', '+', '!'), $._expression)),
parenthesized_expression: $ => seq('(', $._expression, ')'),
index_expression: $ => prec(1, seq(
$._expression,
'[',
commaSep1($._expression),
']',
)),
// Terminals
identifier: _ => /[a-zA-Z_][a-zA-Z0-9_]*/,
dollar_variable: _ => token(seq('$', /[a-zA-Z_][a-zA-Z0-9_]*/)),
wildcard: _ => token(choice(
seq(/[a-zA-Z_][a-zA-Z0-9_]*/, '?'),
seq('?', /[a-zA-Z_][a-zA-Z0-9_]*/),
)),
number: _ => /\d+(\.\d+)?/,
string_literal: _ => seq('"', /[^"]*/, '"'),
// Comments
line_comment: _ => token(seq('*', /[^\n]*/)),
block_comment: _ => token(seq('/*', /[^*]*\*+([^/*][^*]*\*+)*/, '/')),
},
});
function commaSep1(rule) {
return seq(rule, repeat(seq(',', rule)));
}
+21
View File
@@ -0,0 +1,21 @@
{
"name": "tree-sitter-form",
"version": "0.1.0",
"description": "FORM (symbolic manipulation) grammar for tree-sitter",
"main": "bindings/node",
"keywords": ["tree-sitter", "form", "symbolic-computation", "particle-physics"],
"license": "MIT",
"dependencies": {
"nan": "^2.18.0"
},
"devDependencies": {
"tree-sitter-cli": "^0.25.0"
},
"tree-sitter": [
{
"scope": "source.form",
"file-types": ["frm", "prc"],
"highlights": "queries/highlights.scm"
}
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,54 @@
#ifndef TREE_SITTER_ALLOC_H_
#define TREE_SITTER_ALLOC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
// Allow clients to override allocation functions
#ifdef TREE_SITTER_REUSE_ALLOCATOR
extern void *(*ts_current_malloc)(size_t size);
extern void *(*ts_current_calloc)(size_t count, size_t size);
extern void *(*ts_current_realloc)(void *ptr, size_t size);
extern void (*ts_current_free)(void *ptr);
#ifndef ts_malloc
#define ts_malloc ts_current_malloc
#endif
#ifndef ts_calloc
#define ts_calloc ts_current_calloc
#endif
#ifndef ts_realloc
#define ts_realloc ts_current_realloc
#endif
#ifndef ts_free
#define ts_free ts_current_free
#endif
#else
#ifndef ts_malloc
#define ts_malloc malloc
#endif
#ifndef ts_calloc
#define ts_calloc calloc
#endif
#ifndef ts_realloc
#define ts_realloc realloc
#endif
#ifndef ts_free
#define ts_free free
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ALLOC_H_
@@ -0,0 +1,314 @@
#ifndef TREE_SITTER_ARRAY_H_
#define TREE_SITTER_ARRAY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "./alloc.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4101)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#define Array(T) \
struct { \
T *contents; \
uint32_t size; \
uint32_t capacity; \
}
/// Initialize an array.
#define array_init(self) ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
/// Create an empty array.
#define array_new() {NULL, 0, 0}
/// Get a pointer to the element at a given `index` in the array.
#define array_get(self, _index) \
(assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
/// Get a pointer to the first element in the array.
#define array_front(self) array_get(self, 0)
/// Get a pointer to the last element in the array.
#define array_back(self) array_get(self, (self)->size - 1)
/// Clear the array, setting its size to zero. Note that this does not free any
/// memory allocated for the array's contents.
#define array_clear(self) ((self)->size = 0)
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
/// less than the array's current capacity, this function has no effect.
#define array_reserve(self, new_capacity) \
((self)->contents = _array__reserve((void *)(self)->contents, &(self)->capacity, \
array_elem_size(self), new_capacity))
/// Free any memory allocated for this array. Note that this does not free any
/// memory allocated for the array's contents.
#define array_delete(self) \
do { \
if ((self)->contents) \
ts_free((self)->contents); \
(self)->contents = NULL; \
(self)->size = 0; \
(self)->capacity = 0; \
} while (0)
/// Push a new `element` onto the end of the array.
#define array_push(self, element) \
do { \
(self)->contents = _array__grow((void *)(self)->contents, (self)->size, &(self)->capacity, \
1, array_elem_size(self)); \
(self)->contents[(self)->size++] = (element); \
} while (0)
/// Increase the array's size by `count` elements.
/// New elements are zero-initialized.
#define array_grow_by(self, count) \
do { \
if ((count) == 0) \
break; \
(self)->contents = _array__grow((self)->contents, (self)->size, &(self)->capacity, count, \
array_elem_size(self)); \
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
(self)->size += (count); \
} while (0)
/// Append all elements from one array to the end of another.
#define array_push_all(self, other) array_extend((self), (other)->size, (other)->contents)
/// Append `count` elements to the end of the array, reading their values from the
/// `contents` pointer.
#define array_extend(self, count, other_contents) \
(self)->contents = \
_array__splice((void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), (self)->size, 0, count, other_contents)
/// Remove `old_count` elements from the array starting at the given `index`. At
/// the same index, insert `new_count` new elements, reading their values from the
/// `new_contents` pointer.
#define array_splice(self, _index, old_count, new_count, new_contents) \
(self)->contents = \
_array__splice((void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, old_count, new_count, new_contents)
/// Insert one `element` into the array at the given `index`.
#define array_insert(self, _index, element) \
(self)->contents = _array__splice((void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, 0, 1, &(element))
/// Remove one element from the array at the given `index`.
#define array_erase(self, _index) \
_array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index)
/// Pop the last element off the array, returning the element by value.
#define array_pop(self) ((self)->contents[--(self)->size])
/// Assign the contents of one array to another, reallocating if necessary.
#define array_assign(self, other) \
(self)->contents = \
_array__assign((void *)(self)->contents, &(self)->size, &(self)->capacity, \
(const void *)(other)->contents, (other)->size, array_elem_size(self))
/// Swap one array with another
#define array_swap(self, other) \
do { \
void *_array_swap_tmp = (void *)(self)->contents; \
(self)->contents = (other)->contents; \
(other)->contents = _array_swap_tmp; \
_array__swap(&(self)->size, &(self)->capacity, &(other)->size, &(other)->capacity); \
} while (0)
/// Get the size of the array contents
#define array_elem_size(self) (sizeof *(self)->contents)
/// Search a sorted array for a given `needle` value, using the given `compare`
/// callback to determine the order.
///
/// If an existing element is found to be equal to `needle`, then the `index`
/// out-parameter is set to the existing value's index, and the `exists`
/// out-parameter is set to true. Otherwise, `index` is set to an index where
/// `needle` should be inserted in order to preserve the sorting, and `exists`
/// is set to false.
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
_array__search_sorted(self, 0, compare, , needle, _index, _exists)
/// Search a sorted array for a given `needle` value, using integer comparisons
/// of a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_with`.
#define array_search_sorted_by(self, field, needle, _index, _exists) \
_array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
/// Insert a given `value` into a sorted array, using the given `compare`
/// callback to determine the order.
#define array_insert_sorted_with(self, compare, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
if (!_exists) \
array_insert(self, _index, value); \
} while (0)
/// Insert a given `value` into a sorted array, using integer comparisons of
/// a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_by`.
#define array_insert_sorted_by(self, field, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_by(self, field, (value)field, &_index, &_exists); \
if (!_exists) \
array_insert(self, _index, value); \
} while (0)
// Private
// Pointers to individual `Array` fields (rather than the entire `Array` itself)
// are passed to the various `_array__*` functions below to address strict aliasing
// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`.
//
// The `Array` type itself was not altered as a solution in order to avoid breakage
// with existing consumers (in particular, parsers with external scanners).
/// This is not what you're looking for, see `array_erase`.
static inline void _array__erase(void *self_contents, uint32_t *size, size_t element_size,
uint32_t index) {
assert(index < *size);
char *contents = (char *)self_contents;
memmove(contents + index * element_size, contents + (index + 1) * element_size,
(*size - index - 1) * element_size);
(*size)--;
}
/// This is not what you're looking for, see `array_reserve`.
static inline void *_array__reserve(void *contents, uint32_t *capacity, size_t element_size,
uint32_t new_capacity) {
void *new_contents = contents;
if (new_capacity > *capacity) {
if (contents) {
new_contents = ts_realloc(contents, new_capacity * element_size);
} else {
new_contents = ts_malloc(new_capacity * element_size);
}
*capacity = new_capacity;
}
return new_contents;
}
/// This is not what you're looking for, see `array_assign`.
static inline void *_array__assign(void *self_contents, uint32_t *self_size,
uint32_t *self_capacity, const void *other_contents,
uint32_t other_size, size_t element_size) {
void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size);
*self_size = other_size;
memcpy(new_contents, other_contents, *self_size * element_size);
return new_contents;
}
/// This is not what you're looking for, see `array_swap`.
static inline void _array__swap(uint32_t *self_size, uint32_t *self_capacity, uint32_t *other_size,
uint32_t *other_capacity) {
uint32_t tmp_size = *self_size;
uint32_t tmp_capacity = *self_capacity;
*self_size = *other_size;
*self_capacity = *other_capacity;
*other_size = tmp_size;
*other_capacity = tmp_capacity;
}
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity, uint32_t count,
size_t element_size) {
void *new_contents = contents;
uint32_t new_size = size + count;
if (new_size > *capacity) {
uint32_t new_capacity = *capacity * 2;
if (new_capacity < 8)
new_capacity = 8;
if (new_capacity < new_size)
new_capacity = new_size;
new_contents = _array__reserve(contents, capacity, element_size, new_capacity);
}
return new_contents;
}
/// This is not what you're looking for, see `array_splice`.
static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity,
size_t element_size, uint32_t index, uint32_t old_count,
uint32_t new_count, const void *elements) {
uint32_t new_size = *size + new_count - old_count;
uint32_t old_end = index + old_count;
uint32_t new_end = index + new_count;
assert(old_end <= *size);
void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size);
char *contents = (char *)new_contents;
if (*size > old_end) {
memmove(contents + new_end * element_size, contents + old_end * element_size,
(*size - old_end) * element_size);
}
if (new_count > 0) {
if (elements) {
memcpy((contents + index * element_size), elements, new_count * element_size);
} else {
memset((contents + index * element_size), 0, new_count * element_size);
}
}
*size += new_count - old_count;
return new_contents;
}
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
do { \
*(_index) = start; \
*(_exists) = false; \
uint32_t size = (self)->size - *(_index); \
if (size == 0) \
break; \
int comparison; \
while (size > 1) { \
uint32_t half_size = size / 2; \
uint32_t mid_index = *(_index) + half_size; \
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
if (comparison <= 0) \
*(_index) = mid_index; \
size -= half_size; \
} \
comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
if (comparison == 0) \
*(_exists) = true; \
else if (comparison < 0) \
*(_index) += 1; \
} while (0)
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
/// parameter by reference in order to work with the generic sorting function above.
#define _compare_int(a, b) ((int)*(a) - (int)(b))
#ifdef _MSC_VER
#pragma warning(pop)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ARRAY_H_
@@ -0,0 +1,282 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol) - 1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSStateId;
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
typedef struct TSLanguageMetadata {
uint8_t major_version;
uint8_t minor_version;
uint8_t patch_version;
} TSLanguageMetadata;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
// Used to index the field and supertype maps.
typedef struct {
uint16_t index;
uint16_t length;
} TSMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
void (*log)(const TSLexer *, const char *, ...);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
uint16_t reserved_word_set_id;
} TSLexerMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
typedef struct {
int32_t start;
int32_t end;
} TSCharacterRange;
struct TSLanguage {
uint32_t abi_version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char *const *symbol_names;
const char *const *field_names;
const TSMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexerMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
const char *name;
const TSSymbol *reserved_words;
uint16_t max_reserved_word_set_size;
uint32_t supertype_count;
const TSSymbol *supertype_symbols;
const TSMapSlice *supertype_map_slices;
const TSSymbol *supertype_map_entries;
TSLanguageMetadata metadata;
};
static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {
uint32_t index = 0;
uint32_t size = len - index;
while (size > 1) {
uint32_t half_size = size / 2;
uint32_t mid_index = index + half_size;
const TSCharacterRange *range = &ranges[mid_index];
if (lookahead >= range->start && lookahead <= range->end) {
return true;
} else if (lookahead > range->end) {
index = mid_index;
}
size -= half_size;
}
const TSCharacterRange *range = &ranges[index];
return (lookahead >= range->start && lookahead <= range->end);
}
/*
* Lexer Macros
*/
#ifdef _MSC_VER
#define UNUSED __pragma(warning(suppress : 4101))
#else
#define UNUSED __attribute__((unused))
#endif
#define START_LEXER() \
bool result = false; \
bool skip = false; \
UNUSED \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define ADVANCE_MAP(...) \
{ \
static const uint16_t map[] = {__VA_ARGS__}; \
for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \
if (map[i] == lookahead) { \
state = map[i + 1]; \
goto next_state; \
} \
} \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT)
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{ \
{ \
.shift = {.type = TSParseActionTypeShift, .state = (state_value) } \
} \
}
#define SHIFT_REPEAT(state_value) \
{ \
{ \
.shift = {.type = TSParseActionTypeShift, .state = (state_value), .repetition = true } \
} \
}
#define SHIFT_EXTRA() \
{ \
{ \
.shift = {.type = TSParseActionTypeShift, .extra = true } \
} \
}
#define REDUCE(symbol_name, children, precedence, prod_id) \
{ \
{ \
.reduce = {.type = TSParseActionTypeReduce, \
.symbol = symbol_name, \
.child_count = children, \
.dynamic_precedence = precedence, \
.production_id = prod_id}, \
} \
}
#define RECOVER() \
{ \
{ .type = TSParseActionTypeRecover } \
}
#define ACCEPT_INPUT() \
{ \
{ .type = TSParseActionTypeAccept } \
}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_
@@ -0,0 +1,32 @@
==================
If statement
==================
if (count(x, 1) > 0)
id x = 0;
endif;
---
(source_file
(if_statement
(binary_expression
(function_application
name: (identifier)
(identifier)
(number))
(number))
(substitution_statement
(identifier)
(number))))
==================
Module sort
==================
.sort
---
(source_file
(module_directive))
@@ -0,0 +1,53 @@
==================
Symbol declaration
==================
Symbols a, b, c;
---
(source_file
(declaration_statement
(identifier)
(identifier)
(identifier)))
==================
Function declaration
==================
Functions f, g;
---
(source_file
(declaration_statement
(identifier)
(identifier)))
==================
Vector declaration
==================
Vectors p1, p2, q;
---
(source_file
(declaration_statement
(identifier)
(identifier)
(identifier)))
==================
Index declaration
==================
Indices mu, nu;
---
(source_file
(declaration_statement
(identifier)
(identifier)))
@@ -0,0 +1,30 @@
==================
Simple procedure
==================
#procedure simplify(expr)
id x = 1;
#endprocedure
---
(source_file
(procedure_definition
name: (identifier)
(identifier)
(substitution_statement
(identifier)
(number))))
==================
Procedure call
==================
#call simplify(result)
---
(source_file
(call_statement
name: (identifier)
(identifier)))
+16
View File
@@ -0,0 +1,16 @@
{
"grammars": [
{
"name": "form",
"camelcase": "Form",
"scope": "source.form",
"path": ".",
"file-types": ["frm", "prc"]
}
],
"metadata": {
"version": "0.1.0",
"license": "MIT",
"description": "FORM (symbolic manipulation) grammar for tree-sitter"
}
}
+411
View File
@@ -0,0 +1,411 @@
/// <reference types="tree-sitter-cli/dsl" />
// tree-sitter grammar for Magma (computational algebra system)
// https://magma.maths.usyd.edu.au/magma/
module.exports = grammar({
name: 'magma',
extras: $ => [
/\s/,
$.line_comment,
$.block_comment,
],
word: $ => $.identifier,
conflicts: $ => [
[$.function_definition],
[$.procedure_definition],
[$.intrinsic_definition],
],
rules: {
source_file: $ => repeat($._statement),
_statement: $ => choice(
$.function_definition,
$.procedure_definition,
$.intrinsic_definition,
$.if_statement,
$.for_statement,
$.while_statement,
$.repeat_statement,
$.case_statement,
$.try_statement,
$.assignment_statement,
$.return_statement,
$.load_statement,
$.print_statement,
$.require_statement,
$.error_statement,
$.delete_statement,
$.freeze_statement,
$.expression_statement,
),
// function Name(args) ... end function;
function_definition: $ => prec(10, seq(
'function',
field('name', $.identifier),
$.parameter_list,
optional(seq('->', $._type_expr)),
repeat($._statement),
'end', 'function', ';',
)),
// procedure Name(~args) ... end procedure;
procedure_definition: $ => prec(10, seq(
'procedure',
field('name', $.identifier),
$.parameter_list,
repeat($._statement),
'end', 'procedure', ';',
)),
// intrinsic Name(x::Type) -> Type { doc } ... end intrinsic;
intrinsic_definition: $ => prec(10, seq(
'intrinsic',
field('name', $.identifier),
$.parameter_list,
optional(seq('->', $._type_expr)),
optional($.doc_string),
repeat($._statement),
'end', 'intrinsic', ';',
)),
parameter_list: $ => seq(
token.immediate('('),
optional(commaSep1($.parameter)),
')',
),
parameter: $ => seq(
optional('~'),
$.identifier,
optional(seq('::', $._type_expr)),
),
doc_string: $ => seq('{', /[^}]*/, '}'),
// if cond then ... elif ... else ... end if;
if_statement: $ => seq(
'if',
$._expression,
'then',
repeat($._statement),
repeat($.elif_clause),
optional($.else_clause),
'end', 'if', ';',
),
elif_clause: $ => seq(
choice('elif', 'elsif'),
$._expression,
'then',
repeat($._statement),
),
else_clause: $ => seq(
'else',
repeat($._statement),
),
// for var in expr do ... end for;
// for var := start to end do ... end for;
for_statement: $ => seq(
'for',
$.identifier,
choice(
seq('in', $._expression),
seq(':=', $._expression, 'to', $._expression,
optional(seq('by', $._expression))),
),
'do',
repeat($._statement),
'end', 'for', ';',
),
// while cond do ... end while;
while_statement: $ => seq(
'while',
$._expression,
'do',
repeat($._statement),
'end', 'while', ';',
),
// repeat ... until cond;
repeat_statement: $ => seq(
'repeat',
repeat($._statement),
'until',
$._expression,
';',
),
// case expr: when val: ... end case;
case_statement: $ => seq(
'case',
$._expression,
':',
repeat($.when_clause),
optional($.else_clause),
'end', 'case', ';',
),
when_clause: $ => seq(
'when',
commaSep1($._expression),
':',
repeat($._statement),
),
// try ... catch e ... end try;
try_statement: $ => seq(
'try',
repeat($._statement),
'catch',
$.identifier,
repeat($._statement),
'end', 'try', ';',
),
// x := expr;
assignment_statement: $ => seq(
$._expression,
choice(':=', '+:=', '-:=', '*:=', 'cat:='),
$._expression,
';',
),
return_statement: $ => seq(
'return',
optional($._expression),
';',
),
load_statement: $ => seq(
'load',
field('path', $._expression),
';',
),
print_statement: $ => seq(
choice('print', 'printf', 'fprintf'),
commaSep1($._expression),
';',
),
require_statement: $ => seq(
'require',
$._expression,
':',
$._expression,
';',
),
error_statement: $ => seq(
'error',
$._expression,
';',
),
delete_statement: $ => seq(
'delete',
$._expression,
';',
),
freeze_statement: $ => seq(
'freeze',
$._expression,
';',
),
expression_statement: $ => seq(
$._expression,
';',
),
// Expressions
_expression: $ => choice(
$.identifier,
$.number,
$.string_literal,
$.boolean_literal,
$.call_expression,
$.binary_expression,
$.unary_expression,
$.parenthesized_expression,
$.index_expression,
$.member_expression,
$.sequence_expression,
$.set_expression,
$.tuple_expression,
$.range_expression,
$.comprehension,
$.anonymous_function,
$.format_string,
),
call_expression: $ => prec(8, seq(
field('name', $._expression),
'(',
optional(commaSep1(choice($._expression, $.named_argument))),
')',
)),
named_argument: $ => seq(
$.identifier,
':=',
$._expression,
),
binary_expression: $ => choice(
// Arithmetic
prec.left(4, seq($._expression, '+', $._expression)),
prec.left(4, seq($._expression, '-', $._expression)),
prec.left(5, seq($._expression, '*', $._expression)),
prec.left(5, seq($._expression, '/', $._expression)),
prec.right(6, seq($._expression, '^', $._expression)),
// Word operators
prec.left(5, seq($._expression, 'div', $._expression)),
prec.left(5, seq($._expression, 'mod', $._expression)),
prec.left(4, seq($._expression, 'cat', $._expression)),
// Comparison
prec.left(3, seq($._expression, choice('eq', 'ne', 'lt', 'gt', 'le', 'ge'), $._expression)),
prec.left(3, seq($._expression, choice('cmpeq', 'cmpne'), $._expression)),
prec.left(3, seq($._expression, 'in', $._expression)),
prec.left(3, seq($._expression, 'notin', $._expression)),
prec.left(3, seq($._expression, 'subset', $._expression)),
// Logical
prec.left(1, seq($._expression, 'and', $._expression)),
prec.left(0, seq($._expression, 'or', $._expression)),
// Magma also has: meet, join, diff, sdiff
prec.left(4, seq($._expression, 'meet', $._expression)),
prec.left(4, seq($._expression, 'join', $._expression)),
prec.left(4, seq($._expression, 'diff', $._expression)),
prec.left(4, seq($._expression, 'sdiff', $._expression)),
// String/sequence concatenation
prec.left(4, seq($._expression, '&', $._expression)),
// Coerce
prec.left(7, seq($._expression, '!', $._expression)),
),
unary_expression: $ => prec(9, seq(
choice('-', '+', 'not', '#', '~'),
$._expression,
)),
parenthesized_expression: $ => seq('(', $._expression, ')'),
index_expression: $ => prec(8, seq(
$._expression,
'[',
commaSep1($._expression),
']',
)),
member_expression: $ => prec(8, seq(
$._expression,
'`',
$.identifier,
)),
// [a, b, c]
sequence_expression: $ => seq(
'[',
optional(commaSep1($._expression)),
']',
),
// {a, b, c}
set_expression: $ => seq(
'{',
optional(commaSep1($._expression)),
'}',
),
// <a, b, c>
tuple_expression: $ => seq(
'<',
optional(commaSep1($._expression)),
'>',
),
// [a..b]
range_expression: $ => prec(7, seq(
'[',
$._expression,
'..',
$._expression,
']',
)),
// [expr : var in set | guard] or {expr : var in set | guard}
comprehension: $ => choice(
seq('[', $._expression, ':', $.comp_clause, ']'),
seq('{', $._expression, ':', $.comp_clause, '}'),
),
comp_clause: $ => seq(
$.identifier,
'in',
$._expression,
optional(seq('|', $._expression)),
),
// func<args | body>
anonymous_function: $ => seq(
'func',
'<',
optional(commaSep1($.identifier)),
'|',
$._expression,
'>',
),
// Sprintf("...", args) — format strings
format_string: $ => seq(
'Sprintf',
'(',
$.string_literal,
repeat(seq(',', $._expression)),
')',
),
// Type expressions for :: annotations
_type_expr: $ => choice(
$.identifier,
$.parameterized_type,
$.tuple_type,
),
parameterized_type: $ => prec(2, seq(
$.identifier,
'[',
commaSep1($._type_expr),
']',
)),
tuple_type: $ => seq(
'<',
commaSep1($._type_expr),
'>',
),
// Terminals
identifier: _ => /[a-zA-Z_][a-zA-Z0-9_]*/,
number: _ => /\d+(\.\d+)?([eE][+-]?\d+)?/,
string_literal: _ => seq('"', /[^"]*/, '"'),
boolean_literal: _ => choice('true', 'false'),
// Comments
line_comment: _ => token(seq('//', /[^\n]*/)),
block_comment: _ => token(seq('/*', /[^*]*\*+([^/*][^*]*\*+)*/, '/')),
},
});
function commaSep1(rule) {
return seq(rule, repeat(seq(',', rule)));
}
+21
View File
@@ -0,0 +1,21 @@
{
"name": "tree-sitter-magma",
"version": "0.1.0",
"description": "Magma computer algebra grammar for tree-sitter",
"main": "bindings/node",
"keywords": ["tree-sitter", "magma", "computer-algebra", "number-theory"],
"license": "MIT",
"dependencies": {
"nan": "^2.18.0"
},
"devDependencies": {
"tree-sitter-cli": "^0.25.0"
},
"tree-sitter": [
{
"scope": "source.magma",
"file-types": ["mag", "magma"],
"highlights": "queries/highlights.scm"
}
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,54 @@
#ifndef TREE_SITTER_ALLOC_H_
#define TREE_SITTER_ALLOC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
// Allow clients to override allocation functions
#ifdef TREE_SITTER_REUSE_ALLOCATOR
extern void *(*ts_current_malloc)(size_t size);
extern void *(*ts_current_calloc)(size_t count, size_t size);
extern void *(*ts_current_realloc)(void *ptr, size_t size);
extern void (*ts_current_free)(void *ptr);
#ifndef ts_malloc
#define ts_malloc ts_current_malloc
#endif
#ifndef ts_calloc
#define ts_calloc ts_current_calloc
#endif
#ifndef ts_realloc
#define ts_realloc ts_current_realloc
#endif
#ifndef ts_free
#define ts_free ts_current_free
#endif
#else
#ifndef ts_malloc
#define ts_malloc malloc
#endif
#ifndef ts_calloc
#define ts_calloc calloc
#endif
#ifndef ts_realloc
#define ts_realloc realloc
#endif
#ifndef ts_free
#define ts_free free
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ALLOC_H_
@@ -0,0 +1,314 @@
#ifndef TREE_SITTER_ARRAY_H_
#define TREE_SITTER_ARRAY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "./alloc.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4101)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#define Array(T) \
struct { \
T *contents; \
uint32_t size; \
uint32_t capacity; \
}
/// Initialize an array.
#define array_init(self) ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
/// Create an empty array.
#define array_new() {NULL, 0, 0}
/// Get a pointer to the element at a given `index` in the array.
#define array_get(self, _index) \
(assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
/// Get a pointer to the first element in the array.
#define array_front(self) array_get(self, 0)
/// Get a pointer to the last element in the array.
#define array_back(self) array_get(self, (self)->size - 1)
/// Clear the array, setting its size to zero. Note that this does not free any
/// memory allocated for the array's contents.
#define array_clear(self) ((self)->size = 0)
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
/// less than the array's current capacity, this function has no effect.
#define array_reserve(self, new_capacity) \
((self)->contents = _array__reserve((void *)(self)->contents, &(self)->capacity, \
array_elem_size(self), new_capacity))
/// Free any memory allocated for this array. Note that this does not free any
/// memory allocated for the array's contents.
#define array_delete(self) \
do { \
if ((self)->contents) \
ts_free((self)->contents); \
(self)->contents = NULL; \
(self)->size = 0; \
(self)->capacity = 0; \
} while (0)
/// Push a new `element` onto the end of the array.
#define array_push(self, element) \
do { \
(self)->contents = _array__grow((void *)(self)->contents, (self)->size, &(self)->capacity, \
1, array_elem_size(self)); \
(self)->contents[(self)->size++] = (element); \
} while (0)
/// Increase the array's size by `count` elements.
/// New elements are zero-initialized.
#define array_grow_by(self, count) \
do { \
if ((count) == 0) \
break; \
(self)->contents = _array__grow((self)->contents, (self)->size, &(self)->capacity, count, \
array_elem_size(self)); \
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
(self)->size += (count); \
} while (0)
/// Append all elements from one array to the end of another.
#define array_push_all(self, other) array_extend((self), (other)->size, (other)->contents)
/// Append `count` elements to the end of the array, reading their values from the
/// `contents` pointer.
#define array_extend(self, count, other_contents) \
(self)->contents = \
_array__splice((void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), (self)->size, 0, count, other_contents)
/// Remove `old_count` elements from the array starting at the given `index`. At
/// the same index, insert `new_count` new elements, reading their values from the
/// `new_contents` pointer.
#define array_splice(self, _index, old_count, new_count, new_contents) \
(self)->contents = \
_array__splice((void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, old_count, new_count, new_contents)
/// Insert one `element` into the array at the given `index`.
#define array_insert(self, _index, element) \
(self)->contents = _array__splice((void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, 0, 1, &(element))
/// Remove one element from the array at the given `index`.
#define array_erase(self, _index) \
_array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index)
/// Pop the last element off the array, returning the element by value.
#define array_pop(self) ((self)->contents[--(self)->size])
/// Assign the contents of one array to another, reallocating if necessary.
#define array_assign(self, other) \
(self)->contents = \
_array__assign((void *)(self)->contents, &(self)->size, &(self)->capacity, \
(const void *)(other)->contents, (other)->size, array_elem_size(self))
/// Swap one array with another
#define array_swap(self, other) \
do { \
void *_array_swap_tmp = (void *)(self)->contents; \
(self)->contents = (other)->contents; \
(other)->contents = _array_swap_tmp; \
_array__swap(&(self)->size, &(self)->capacity, &(other)->size, &(other)->capacity); \
} while (0)
/// Get the size of the array contents
#define array_elem_size(self) (sizeof *(self)->contents)
/// Search a sorted array for a given `needle` value, using the given `compare`
/// callback to determine the order.
///
/// If an existing element is found to be equal to `needle`, then the `index`
/// out-parameter is set to the existing value's index, and the `exists`
/// out-parameter is set to true. Otherwise, `index` is set to an index where
/// `needle` should be inserted in order to preserve the sorting, and `exists`
/// is set to false.
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
_array__search_sorted(self, 0, compare, , needle, _index, _exists)
/// Search a sorted array for a given `needle` value, using integer comparisons
/// of a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_with`.
#define array_search_sorted_by(self, field, needle, _index, _exists) \
_array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
/// Insert a given `value` into a sorted array, using the given `compare`
/// callback to determine the order.
#define array_insert_sorted_with(self, compare, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
if (!_exists) \
array_insert(self, _index, value); \
} while (0)
/// Insert a given `value` into a sorted array, using integer comparisons of
/// a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_by`.
#define array_insert_sorted_by(self, field, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_by(self, field, (value)field, &_index, &_exists); \
if (!_exists) \
array_insert(self, _index, value); \
} while (0)
// Private
// Pointers to individual `Array` fields (rather than the entire `Array` itself)
// are passed to the various `_array__*` functions below to address strict aliasing
// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`.
//
// The `Array` type itself was not altered as a solution in order to avoid breakage
// with existing consumers (in particular, parsers with external scanners).
/// This is not what you're looking for, see `array_erase`.
static inline void _array__erase(void *self_contents, uint32_t *size, size_t element_size,
uint32_t index) {
assert(index < *size);
char *contents = (char *)self_contents;
memmove(contents + index * element_size, contents + (index + 1) * element_size,
(*size - index - 1) * element_size);
(*size)--;
}
/// This is not what you're looking for, see `array_reserve`.
static inline void *_array__reserve(void *contents, uint32_t *capacity, size_t element_size,
uint32_t new_capacity) {
void *new_contents = contents;
if (new_capacity > *capacity) {
if (contents) {
new_contents = ts_realloc(contents, new_capacity * element_size);
} else {
new_contents = ts_malloc(new_capacity * element_size);
}
*capacity = new_capacity;
}
return new_contents;
}
/// This is not what you're looking for, see `array_assign`.
static inline void *_array__assign(void *self_contents, uint32_t *self_size,
uint32_t *self_capacity, const void *other_contents,
uint32_t other_size, size_t element_size) {
void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size);
*self_size = other_size;
memcpy(new_contents, other_contents, *self_size * element_size);
return new_contents;
}
/// This is not what you're looking for, see `array_swap`.
static inline void _array__swap(uint32_t *self_size, uint32_t *self_capacity, uint32_t *other_size,
uint32_t *other_capacity) {
uint32_t tmp_size = *self_size;
uint32_t tmp_capacity = *self_capacity;
*self_size = *other_size;
*self_capacity = *other_capacity;
*other_size = tmp_size;
*other_capacity = tmp_capacity;
}
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity, uint32_t count,
size_t element_size) {
void *new_contents = contents;
uint32_t new_size = size + count;
if (new_size > *capacity) {
uint32_t new_capacity = *capacity * 2;
if (new_capacity < 8)
new_capacity = 8;
if (new_capacity < new_size)
new_capacity = new_size;
new_contents = _array__reserve(contents, capacity, element_size, new_capacity);
}
return new_contents;
}
/// This is not what you're looking for, see `array_splice`.
static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity,
size_t element_size, uint32_t index, uint32_t old_count,
uint32_t new_count, const void *elements) {
uint32_t new_size = *size + new_count - old_count;
uint32_t old_end = index + old_count;
uint32_t new_end = index + new_count;
assert(old_end <= *size);
void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size);
char *contents = (char *)new_contents;
if (*size > old_end) {
memmove(contents + new_end * element_size, contents + old_end * element_size,
(*size - old_end) * element_size);
}
if (new_count > 0) {
if (elements) {
memcpy((contents + index * element_size), elements, new_count * element_size);
} else {
memset((contents + index * element_size), 0, new_count * element_size);
}
}
*size += new_count - old_count;
return new_contents;
}
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
do { \
*(_index) = start; \
*(_exists) = false; \
uint32_t size = (self)->size - *(_index); \
if (size == 0) \
break; \
int comparison; \
while (size > 1) { \
uint32_t half_size = size / 2; \
uint32_t mid_index = *(_index) + half_size; \
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
if (comparison <= 0) \
*(_index) = mid_index; \
size -= half_size; \
} \
comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
if (comparison == 0) \
*(_exists) = true; \
else if (comparison < 0) \
*(_index) += 1; \
} while (0)
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
/// parameter by reference in order to work with the generic sorting function above.
#define _compare_int(a, b) ((int)*(a) - (int)(b))
#ifdef _MSC_VER
#pragma warning(pop)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ARRAY_H_
@@ -0,0 +1,282 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol) - 1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSStateId;
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
typedef struct TSLanguageMetadata {
uint8_t major_version;
uint8_t minor_version;
uint8_t patch_version;
} TSLanguageMetadata;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
// Used to index the field and supertype maps.
typedef struct {
uint16_t index;
uint16_t length;
} TSMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
void (*log)(const TSLexer *, const char *, ...);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
uint16_t reserved_word_set_id;
} TSLexerMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
typedef struct {
int32_t start;
int32_t end;
} TSCharacterRange;
struct TSLanguage {
uint32_t abi_version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char *const *symbol_names;
const char *const *field_names;
const TSMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexerMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
const char *name;
const TSSymbol *reserved_words;
uint16_t max_reserved_word_set_size;
uint32_t supertype_count;
const TSSymbol *supertype_symbols;
const TSMapSlice *supertype_map_slices;
const TSSymbol *supertype_map_entries;
TSLanguageMetadata metadata;
};
static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {
uint32_t index = 0;
uint32_t size = len - index;
while (size > 1) {
uint32_t half_size = size / 2;
uint32_t mid_index = index + half_size;
const TSCharacterRange *range = &ranges[mid_index];
if (lookahead >= range->start && lookahead <= range->end) {
return true;
} else if (lookahead > range->end) {
index = mid_index;
}
size -= half_size;
}
const TSCharacterRange *range = &ranges[index];
return (lookahead >= range->start && lookahead <= range->end);
}
/*
* Lexer Macros
*/
#ifdef _MSC_VER
#define UNUSED __pragma(warning(suppress : 4101))
#else
#define UNUSED __attribute__((unused))
#endif
#define START_LEXER() \
bool result = false; \
bool skip = false; \
UNUSED \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define ADVANCE_MAP(...) \
{ \
static const uint16_t map[] = {__VA_ARGS__}; \
for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \
if (map[i] == lookahead) { \
state = map[i + 1]; \
goto next_state; \
} \
} \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT)
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{ \
{ \
.shift = {.type = TSParseActionTypeShift, .state = (state_value) } \
} \
}
#define SHIFT_REPEAT(state_value) \
{ \
{ \
.shift = {.type = TSParseActionTypeShift, .state = (state_value), .repetition = true } \
} \
}
#define SHIFT_EXTRA() \
{ \
{ \
.shift = {.type = TSParseActionTypeShift, .extra = true } \
} \
}
#define REDUCE(symbol_name, children, precedence, prod_id) \
{ \
{ \
.reduce = {.type = TSParseActionTypeReduce, \
.symbol = symbol_name, \
.child_count = children, \
.dynamic_precedence = precedence, \
.production_id = prod_id}, \
} \
}
#define RECOVER() \
{ \
{ .type = TSParseActionTypeRecover } \
}
#define ACCEPT_INPUT() \
{ \
{ .type = TSParseActionTypeAccept } \
}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_
@@ -0,0 +1,60 @@
================
For loop with in
================
for p in PrimesUpTo(100) do
print p;
end for;
---
(source_file
(for_statement
(identifier)
(call_expression
name: (identifier)
(number))
(print_statement (identifier))))
================
While loop
================
while n gt 0 do
n := n - 1;
end while;
---
(source_file
(while_statement
(binary_expression
(identifier)
(number))
(assignment_statement
(identifier)
(binary_expression
(identifier)
(number)))))
================
Case statement
================
case t:
when 1:
x := 10;
when 2:
x := 20;
else
x := 0;
end case;
---
(source_file
(case_statement
(identifier)
(when_clause (number) (assignment_statement (identifier) (number)))
(when_clause (number) (assignment_statement (identifier) (number)))
(else_clause (assignment_statement (identifier) (number)))))
@@ -0,0 +1,77 @@
================
Simple function
================
function Factorial(n)
if n le 1 then
return 1;
end if;
return n * Factorial(n - 1);
end function;
---
(source_file
(function_definition
name: (identifier)
(parameter_list
(parameter (identifier)))
(if_statement
(binary_expression
(identifier)
(number))
(return_statement (number)))
(return_statement
(binary_expression
(identifier)
(call_expression
name: (identifier)
(binary_expression
(identifier)
(number)))))))
================
Procedure with tilde
================
procedure Swap(~x, ~y)
t := x;
x := y;
y := t;
end procedure;
---
(source_file
(procedure_definition
name: (identifier)
(parameter_list
(parameter (identifier))
(parameter (identifier)))
(assignment_statement (identifier) (identifier))
(assignment_statement (identifier) (identifier))
(assignment_statement (identifier) (identifier))))
================
Intrinsic with type
================
intrinsic MyAdd(x::RngIntElt, y::RngIntElt) -> RngIntElt
{ Returns x+y }
return x + y;
end intrinsic;
---
(source_file
(intrinsic_definition
name: (identifier)
(parameter_list
(parameter (identifier) (identifier))
(parameter (identifier) (identifier)))
(identifier)
(doc_string)
(return_statement
(binary_expression
(identifier)
(identifier)))))
+16
View File
@@ -0,0 +1,16 @@
{
"grammars": [
{
"name": "magma",
"camelcase": "Magma",
"scope": "source.magma",
"path": ".",
"file-types": ["mag", "magma"]
}
],
"metadata": {
"version": "0.1.0",
"license": "MIT",
"description": "Magma computer algebra grammar for tree-sitter"
}
}