Vendor the shackle MiniZinc tree-sitter grammar into nvim config
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
a88626755a
commit
ccd40cffac
@@ -781,7 +781,7 @@ require("lazy").setup({
|
|||||||
branch = "main",
|
branch = "main",
|
||||||
-- [[ Configure Treesitter ]] See `:help nvim-treesitter-intro`
|
-- [[ Configure Treesitter ]] See `:help nvim-treesitter-intro`
|
||||||
config = function()
|
config = function()
|
||||||
-- Register the MiniZinc parser from the local shackle clone.
|
-- Register the vendored MiniZinc parser (see parsers/tree-sitter-minizinc/README.md).
|
||||||
-- Must use a User TSUpdate autocmd because nvim-treesitter clears and
|
-- Must use a User TSUpdate autocmd because nvim-treesitter clears and
|
||||||
-- reloads the parsers module (firing TSUpdate) on every install call.
|
-- reloads the parsers module (firing TSUpdate) on every install call.
|
||||||
vim.api.nvim_create_autocmd("User", {
|
vim.api.nvim_create_autocmd("User", {
|
||||||
@@ -789,7 +789,7 @@ require("lazy").setup({
|
|||||||
callback = function()
|
callback = function()
|
||||||
require("nvim-treesitter.parsers").minizinc = {
|
require("nvim-treesitter.parsers").minizinc = {
|
||||||
install_info = {
|
install_info = {
|
||||||
path = "/home/pylon/shackle/parsers/tree-sitter-minizinc",
|
path = vim.fn.stdpath("config") .. "/parsers/tree-sitter-minizinc",
|
||||||
queries = "queries",
|
queries = "queries",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
/parser.so
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Vendored from https://github.com/shackle-rs/shackle
|
||||||
|
(`parsers/tree-sitter-minizinc`, commit d9f5d8243ec3b0424febf0247f83d30706369b00).
|
||||||
@@ -0,0 +1,890 @@
|
|||||||
|
/// <reference types="tree-sitter-cli/dsl" />
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
const PREC_ORDER = /** @type {const} */ ([
|
||||||
|
"call",
|
||||||
|
"annotation",
|
||||||
|
"quoted_operator",
|
||||||
|
"default",
|
||||||
|
"concatenation",
|
||||||
|
"negation",
|
||||||
|
"exponent",
|
||||||
|
"unary",
|
||||||
|
"multiplicative",
|
||||||
|
"additive",
|
||||||
|
"range",
|
||||||
|
"intersect",
|
||||||
|
"union_or_diff",
|
||||||
|
"membership",
|
||||||
|
"comparative",
|
||||||
|
"conjunction",
|
||||||
|
"disjunction",
|
||||||
|
"implication",
|
||||||
|
"equivalence",
|
||||||
|
])
|
||||||
|
|
||||||
|
const PREC = /** @type {{ [K in typeof PREC_ORDER[number]]: number }} */ (
|
||||||
|
PREC_ORDER.reduce(
|
||||||
|
(res, name, idx, array) => ({ ...res, [name]: 10 * (array.length - idx) }),
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const primitive_types = ["ann", "bool", "float", "int", "string"]
|
||||||
|
|
||||||
|
const EQUIVALENCE_OPERATORS = ["<->", "⟷", "⇔"]
|
||||||
|
const IMPLICATION_OPERATORS = ["->", "→", "⇒", "<-", "←", "⇐"]
|
||||||
|
const DISJUNCTION_OPERATORS = ["\\/", "∨", "xor", "⊻"]
|
||||||
|
const CONJUNCTION_OPERATORS = ["/\\", "∧"]
|
||||||
|
// prettier-ignore
|
||||||
|
const COMPARISON_OPERATORS = [
|
||||||
|
"=", "==", "!=", "≠", "<", "<=", "≤", ">", ">=", "≥",
|
||||||
|
"~=", "~!=",
|
||||||
|
]
|
||||||
|
const MEMBERSHIP_OPERATORS = ["in", "∈", "subset", "⊆", "superset", "⊇"]
|
||||||
|
const UNION_DIFF_OPERATORS = ["union", "∪", "diff", "∖", "symdiff"]
|
||||||
|
const INTERSECTION_OPERATORS = ["intersect", "∩"]
|
||||||
|
const RANGE_OPERATORS = ["..", "<..", "..<", "<..<"]
|
||||||
|
const ADDITIVE_OPERATORS = ["+", "-", "~+", "~-"]
|
||||||
|
const MULTIPLICATIVE_OPERATORS = ["*", "/", "div", "mod", "~*", "~div", "~/"]
|
||||||
|
const NEGATION_OPERATORS = ["not", "¬"]
|
||||||
|
const INVERSE_OPERATORS = ["^-1", "⁻¹"]
|
||||||
|
|
||||||
|
export default grammar({
|
||||||
|
name: "minizinc",
|
||||||
|
|
||||||
|
extras: ($) => [
|
||||||
|
/\s/,
|
||||||
|
$.line_comment,
|
||||||
|
$.doc_comment,
|
||||||
|
$.file_doc_comment,
|
||||||
|
$.block_comment,
|
||||||
|
],
|
||||||
|
|
||||||
|
word: ($) => $.identifier,
|
||||||
|
|
||||||
|
conflicts: ($) => [
|
||||||
|
[$._callable, $.assignment],
|
||||||
|
[$._callable, $._pattern],
|
||||||
|
[$._callable, $.pattern_call],
|
||||||
|
[$._callable, $.record_member],
|
||||||
|
[$._callable, $.inversed_identifier],
|
||||||
|
[$._callable, $._literal],
|
||||||
|
[$._callable, $._literal, $._pattern],
|
||||||
|
[$._literal, $._pattern],
|
||||||
|
[$._literal, $.pattern_numeric_literal],
|
||||||
|
[$.array_literal_2d, $.array_literal_2d_row],
|
||||||
|
[$._unannotated_expression, $.type_base],
|
||||||
|
[$._expression, $.type_base],
|
||||||
|
],
|
||||||
|
|
||||||
|
supertypes: ($) => [$._expression, $._item, $._type],
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
source_file: ($) => sepBy(";", field("item", $._item)),
|
||||||
|
|
||||||
|
_item: ($) =>
|
||||||
|
choice(
|
||||||
|
$.annotation,
|
||||||
|
$.assignment,
|
||||||
|
$.constraint,
|
||||||
|
$.declaration,
|
||||||
|
$.enumeration,
|
||||||
|
$.function_item,
|
||||||
|
$.goal,
|
||||||
|
$.include,
|
||||||
|
$.output,
|
||||||
|
$.predicate,
|
||||||
|
$.type_alias,
|
||||||
|
$.class_decl
|
||||||
|
),
|
||||||
|
|
||||||
|
annotation: ($) =>
|
||||||
|
seq(
|
||||||
|
"annotation",
|
||||||
|
field("name", $._identifier),
|
||||||
|
optional(field("parameters", $.annotation_parameters)),
|
||||||
|
optional(seq("=", field("body", $._expression)))
|
||||||
|
),
|
||||||
|
|
||||||
|
annotation_parameters: ($) =>
|
||||||
|
seq("(", sepBy1(",", field("parameter", $.parameter)), ")"),
|
||||||
|
|
||||||
|
assignment: ($) =>
|
||||||
|
seq(
|
||||||
|
field("name", $._identifier),
|
||||||
|
"=",
|
||||||
|
field("definition", $._expression)
|
||||||
|
),
|
||||||
|
|
||||||
|
constraint: ($) =>
|
||||||
|
seq(
|
||||||
|
"constraint",
|
||||||
|
optional(seq("::", field("annotation", $._adjacent_annotation))),
|
||||||
|
field("expression", $._expression)
|
||||||
|
),
|
||||||
|
|
||||||
|
declaration: ($) =>
|
||||||
|
seq(
|
||||||
|
field("type", $._type),
|
||||||
|
":",
|
||||||
|
field("name", $._pattern),
|
||||||
|
optional($._annotation_list),
|
||||||
|
optional(seq("=", field("definition", $._expression)))
|
||||||
|
),
|
||||||
|
|
||||||
|
enumeration: ($) =>
|
||||||
|
seq(
|
||||||
|
"enum",
|
||||||
|
field("name", $._identifier),
|
||||||
|
optional($._annotation_list),
|
||||||
|
optional(seq("=", sepBy1("++", field("case", $._enumeration_case))))
|
||||||
|
),
|
||||||
|
|
||||||
|
function_item: ($) =>
|
||||||
|
seq(
|
||||||
|
"function",
|
||||||
|
field("type", $._type),
|
||||||
|
":",
|
||||||
|
field("name", choice($._identifier, $.inversed_identifier)),
|
||||||
|
$._parameters,
|
||||||
|
optional($._ann_parameter),
|
||||||
|
optional($._annotation_list),
|
||||||
|
optional(seq("=", field("body", $._expression)))
|
||||||
|
),
|
||||||
|
|
||||||
|
// `ann: name` after the parameter list captures the item's own annotations
|
||||||
|
_ann_parameter: ($) =>
|
||||||
|
seq("ann", ":", field("annotation_parameter", $._identifier)),
|
||||||
|
|
||||||
|
goal: ($) =>
|
||||||
|
seq(
|
||||||
|
"solve",
|
||||||
|
optional($._annotation_list),
|
||||||
|
choice(
|
||||||
|
field("strategy", "satisfy"),
|
||||||
|
seq(
|
||||||
|
field("strategy", choice("maximize", "minimize")),
|
||||||
|
field("objective", $._expression)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
include: ($) => seq("include", field("file", $.string_literal)),
|
||||||
|
|
||||||
|
output: ($) =>
|
||||||
|
seq(
|
||||||
|
"output",
|
||||||
|
optional(seq("::", field("annotation", $._adjacent_annotation))),
|
||||||
|
field("expression", $._expression)
|
||||||
|
),
|
||||||
|
|
||||||
|
// An annotation written immediately before an expression. It must be a form
|
||||||
|
// that cannot continue. Otherwise, `output :: "a" ["b"]` would parse as the
|
||||||
|
// indexed access `"a"["b"]`.
|
||||||
|
_adjacent_annotation: ($) =>
|
||||||
|
choice(
|
||||||
|
$.string_literal,
|
||||||
|
$.string_interpolation,
|
||||||
|
alias($._adjacent_annotation_call, $.call),
|
||||||
|
$.parenthesised_expression
|
||||||
|
),
|
||||||
|
_adjacent_annotation_call: ($) =>
|
||||||
|
seq(
|
||||||
|
field("function", $._identifier),
|
||||||
|
"(",
|
||||||
|
sepBy(",", field("argument", $.arg_or_param)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
|
||||||
|
predicate: ($) =>
|
||||||
|
seq(
|
||||||
|
field("type", choice("predicate", "test")),
|
||||||
|
field("name", choice($._identifier, $.inversed_identifier)),
|
||||||
|
$._parameters,
|
||||||
|
optional($._ann_parameter),
|
||||||
|
optional($._annotation_list),
|
||||||
|
optional(seq("=", field("body", $._expression)))
|
||||||
|
),
|
||||||
|
|
||||||
|
_annotation_list: ($) =>
|
||||||
|
seq(
|
||||||
|
repeat1(
|
||||||
|
prec.left(
|
||||||
|
PREC.annotation,
|
||||||
|
seq("::", field("annotation", $._unannotated_expression))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
_parameters: ($) =>
|
||||||
|
seq("(", sepBy(",", field("parameter", $.parameter)), ")"),
|
||||||
|
parameter: ($) =>
|
||||||
|
seq(
|
||||||
|
field("type", $._type),
|
||||||
|
optional(
|
||||||
|
seq(
|
||||||
|
":",
|
||||||
|
field("name", $._pattern),
|
||||||
|
optional($._annotation_list),
|
||||||
|
optional(seq("=", field("default", $._expression)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
_enumeration_case: ($) =>
|
||||||
|
choice(
|
||||||
|
$.enumeration_members,
|
||||||
|
$.anonymous_enumeration,
|
||||||
|
$.enumeration_constructor,
|
||||||
|
$.array_literal
|
||||||
|
),
|
||||||
|
|
||||||
|
enumeration_members: ($) =>
|
||||||
|
seq("{", sepBy(",", field("member", $._identifier)), "}"),
|
||||||
|
anonymous_enumeration: ($) =>
|
||||||
|
seq(
|
||||||
|
field("name", $.anonymous),
|
||||||
|
"(",
|
||||||
|
sepBy1(",", field("parameter", $._type)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
enumeration_constructor: ($) =>
|
||||||
|
seq(
|
||||||
|
field("name", $._identifier),
|
||||||
|
"(",
|
||||||
|
sepBy1(",", field("parameter", $.parameter)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
|
||||||
|
type_alias: ($) =>
|
||||||
|
seq(
|
||||||
|
"type",
|
||||||
|
field("name", $._identifier),
|
||||||
|
optional($._annotation_list),
|
||||||
|
"=",
|
||||||
|
field("type", $._type)
|
||||||
|
),
|
||||||
|
|
||||||
|
class_decl: ($) =>
|
||||||
|
seq(
|
||||||
|
"class",
|
||||||
|
field("name", $._identifier),
|
||||||
|
optional(seq("extends", field("extends", $._identifier))),
|
||||||
|
"(",
|
||||||
|
sepBy(";", field("item", choice($.declaration, $.constraint))),
|
||||||
|
")",
|
||||||
|
optional($._annotation_list)
|
||||||
|
),
|
||||||
|
|
||||||
|
_expression: ($) =>
|
||||||
|
choice($._unannotated_expression, $.annotated_expression),
|
||||||
|
_unannotated_expression: ($) =>
|
||||||
|
choice(
|
||||||
|
$._non_concat_expression,
|
||||||
|
alias($._concatenation, $.infix_operator)
|
||||||
|
),
|
||||||
|
_non_concat_expression: ($) =>
|
||||||
|
choice(
|
||||||
|
$._literal,
|
||||||
|
|
||||||
|
$.array_comprehension,
|
||||||
|
$.if_then_else,
|
||||||
|
$.infix_operator,
|
||||||
|
$.case_expression,
|
||||||
|
$.lambda,
|
||||||
|
$.let_expression,
|
||||||
|
$.prefix_operator,
|
||||||
|
$.postfix_operator,
|
||||||
|
$.set_comprehension,
|
||||||
|
$.string_interpolation,
|
||||||
|
$._callable
|
||||||
|
),
|
||||||
|
// A `++` expression standing in for a type, so that a call argument keeps
|
||||||
|
// the same shape as any other expression argument.
|
||||||
|
_concatenated_domain: ($) =>
|
||||||
|
field("domain", alias($._concatenation, $.infix_operator)),
|
||||||
|
_concatenation: ($) =>
|
||||||
|
prec.left(
|
||||||
|
PREC.concatenation,
|
||||||
|
seq(
|
||||||
|
field("left", $._expression),
|
||||||
|
field("operator", "++"),
|
||||||
|
field("right", $._expression)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
_callable: ($) =>
|
||||||
|
choice(
|
||||||
|
$.anonymous,
|
||||||
|
$.inversed_identifier,
|
||||||
|
$._identifier,
|
||||||
|
$.call,
|
||||||
|
$.generator_call,
|
||||||
|
$.indexed_access,
|
||||||
|
$.tuple_access,
|
||||||
|
$.record_access,
|
||||||
|
$.parenthesised_expression
|
||||||
|
),
|
||||||
|
|
||||||
|
parenthesised_expression: ($) =>
|
||||||
|
seq("(", field("expression", $._expression), ")"),
|
||||||
|
|
||||||
|
array_comprehension: ($) =>
|
||||||
|
seq(
|
||||||
|
"[",
|
||||||
|
optional(seq(field("index", $._expression), ":")),
|
||||||
|
field("template", $._expression),
|
||||||
|
"|",
|
||||||
|
sepBy1(",", field("generator", $._generator)),
|
||||||
|
"]"
|
||||||
|
),
|
||||||
|
|
||||||
|
call: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.call,
|
||||||
|
seq(
|
||||||
|
field("function", $._callable),
|
||||||
|
"(",
|
||||||
|
sepBy(",", field("argument", $.arg_or_param)),
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
arg_or_param: ($) =>
|
||||||
|
seq(
|
||||||
|
field(
|
||||||
|
"type",
|
||||||
|
choice($._non_concat_type, alias($._concatenated_domain, $.type_base))
|
||||||
|
),
|
||||||
|
optional(
|
||||||
|
seq(
|
||||||
|
":",
|
||||||
|
field("expression", $._expression),
|
||||||
|
optional(seq("=", field("default", $._expression)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
generator_call: ($) =>
|
||||||
|
prec.dynamic(
|
||||||
|
PREC.call + 1,
|
||||||
|
seq(
|
||||||
|
field("function", $._callable),
|
||||||
|
"(",
|
||||||
|
sepBy1(",", field("generator", $._generator)),
|
||||||
|
")",
|
||||||
|
"(",
|
||||||
|
field("template", $._expression),
|
||||||
|
")"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
_generator: ($) => choice($.generator, $.assignment_generator),
|
||||||
|
generator: ($) =>
|
||||||
|
seq(
|
||||||
|
sepBy1(",", field("name", $._pattern)),
|
||||||
|
"in",
|
||||||
|
field("collection", $._expression),
|
||||||
|
optional(seq("where", field("where", $._expression)))
|
||||||
|
),
|
||||||
|
assignment_generator: ($) =>
|
||||||
|
seq(
|
||||||
|
field("name", $._pattern),
|
||||||
|
"=",
|
||||||
|
field("value", $._expression),
|
||||||
|
optional(seq("where", field("where", $._expression)))
|
||||||
|
),
|
||||||
|
|
||||||
|
if_then_else: ($) =>
|
||||||
|
seq(
|
||||||
|
"if",
|
||||||
|
field("condition", $._expression),
|
||||||
|
"then",
|
||||||
|
field("result", $._expression),
|
||||||
|
repeat(
|
||||||
|
seq(
|
||||||
|
"elseif",
|
||||||
|
field("condition", $._expression),
|
||||||
|
"then",
|
||||||
|
field("result", $._expression)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
optional(seq("else", field("else", $._expression))),
|
||||||
|
"endif"
|
||||||
|
),
|
||||||
|
|
||||||
|
indexed_access: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.call,
|
||||||
|
seq(
|
||||||
|
field("collection", $._unannotated_expression),
|
||||||
|
"[",
|
||||||
|
sepBy1(
|
||||||
|
",",
|
||||||
|
field("index", choice(...RANGE_OPERATORS, $._expression))
|
||||||
|
),
|
||||||
|
"]"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
tuple_access: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.call,
|
||||||
|
seq(
|
||||||
|
field("tuple", $._unannotated_expression),
|
||||||
|
".",
|
||||||
|
field("field", alias(/[0-9]+/, $.integer_literal))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
record_access: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.call,
|
||||||
|
seq(
|
||||||
|
field("record", $._unannotated_expression),
|
||||||
|
".",
|
||||||
|
field("field", $._identifier)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
infix_operator: ($) => {
|
||||||
|
const table = /** @type {const} */ ([
|
||||||
|
[prec.left, PREC.equivalence, choice(...EQUIVALENCE_OPERATORS)],
|
||||||
|
[prec.left, PREC.implication, choice(...IMPLICATION_OPERATORS)],
|
||||||
|
[prec.left, PREC.disjunction, choice(...DISJUNCTION_OPERATORS)],
|
||||||
|
[prec.left, PREC.conjunction, choice(...CONJUNCTION_OPERATORS)],
|
||||||
|
[nonAssoc, PREC.comparative, choice(...COMPARISON_OPERATORS)],
|
||||||
|
[nonAssoc, PREC.membership, choice(...MEMBERSHIP_OPERATORS)],
|
||||||
|
[prec.left, PREC.union_or_diff, choice(...UNION_DIFF_OPERATORS)],
|
||||||
|
[prec.left, PREC.intersect, choice(...INTERSECTION_OPERATORS)],
|
||||||
|
[nonAssoc, PREC.range, choice(...RANGE_OPERATORS)],
|
||||||
|
[prec.left, PREC.additive, choice(...ADDITIVE_OPERATORS)],
|
||||||
|
[prec.left, PREC.multiplicative, choice(...MULTIPLICATIVE_OPERATORS)],
|
||||||
|
[prec.left, PREC.exponent, "^"],
|
||||||
|
[prec.left, PREC.default, "default"],
|
||||||
|
[prec.left, PREC.quoted_operator, $.backtick_identifier],
|
||||||
|
])
|
||||||
|
|
||||||
|
return choice(
|
||||||
|
...table.map(([assoc, precedence, operator]) =>
|
||||||
|
assoc(
|
||||||
|
precedence,
|
||||||
|
seq(
|
||||||
|
field("left", $._expression),
|
||||||
|
field("operator", operator),
|
||||||
|
field("right", $._expression)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
annotated_expression: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.annotation,
|
||||||
|
seq(
|
||||||
|
field("expression", $._unannotated_expression),
|
||||||
|
repeat1(
|
||||||
|
prec.left(
|
||||||
|
PREC.annotation,
|
||||||
|
seq("::", field("annotation", $._unannotated_expression))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
case_expression: ($) =>
|
||||||
|
seq(
|
||||||
|
"case",
|
||||||
|
field("expression", $._expression),
|
||||||
|
"of",
|
||||||
|
sepBy1(",", field("case", $.case_expression_case)),
|
||||||
|
"endcase"
|
||||||
|
),
|
||||||
|
case_expression_case: ($) =>
|
||||||
|
seq(field("pattern", $._pattern), "=>", field("value", $._expression)),
|
||||||
|
|
||||||
|
lambda: ($) =>
|
||||||
|
seq(
|
||||||
|
"lambda",
|
||||||
|
optional(seq(field("return_type", $._type), ":")),
|
||||||
|
$._parameters,
|
||||||
|
"=>",
|
||||||
|
field("body", $._expression)
|
||||||
|
),
|
||||||
|
|
||||||
|
let_expression: ($) =>
|
||||||
|
seq(
|
||||||
|
"let",
|
||||||
|
"{",
|
||||||
|
field(
|
||||||
|
"let",
|
||||||
|
sepBy(
|
||||||
|
choice(",", ";"),
|
||||||
|
field("item", choice($.declaration, $.constraint))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"}",
|
||||||
|
"in",
|
||||||
|
field("in", $._expression)
|
||||||
|
),
|
||||||
|
|
||||||
|
prefix_operator: ($) =>
|
||||||
|
choice(
|
||||||
|
prec(
|
||||||
|
PREC.negation,
|
||||||
|
seq(
|
||||||
|
field("operator", choice(...NEGATION_OPERATORS)),
|
||||||
|
field("operand", $._expression)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
prec(
|
||||||
|
PREC.unary,
|
||||||
|
seq(
|
||||||
|
field("operator", choice("-", "+")),
|
||||||
|
field("operand", $._expression)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// TODO: Could be nonassoc, will always give type error
|
||||||
|
prec.left(
|
||||||
|
PREC.range,
|
||||||
|
seq(
|
||||||
|
field("operator", choice(...RANGE_OPERATORS)),
|
||||||
|
field("operand", $._expression)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
postfix_operator: ($) =>
|
||||||
|
choice(
|
||||||
|
// TODO: Could be nonassoc, will always give type error
|
||||||
|
prec.right(
|
||||||
|
PREC.range,
|
||||||
|
seq(
|
||||||
|
field("operand", $._expression),
|
||||||
|
field("operator", choice(...RANGE_OPERATORS))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
prec(
|
||||||
|
PREC.exponent,
|
||||||
|
seq(
|
||||||
|
field("operand", $._expression),
|
||||||
|
field("operator", choice(...INVERSE_OPERATORS))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
set_comprehension: ($) =>
|
||||||
|
seq(
|
||||||
|
"{",
|
||||||
|
field("template", $._expression),
|
||||||
|
"|",
|
||||||
|
sepBy1(",", field("generator", $._generator)),
|
||||||
|
"}"
|
||||||
|
),
|
||||||
|
|
||||||
|
// TODO: Decide if string_literal and string_interpolation should be combined
|
||||||
|
string_interpolation: ($) =>
|
||||||
|
seq(
|
||||||
|
'"',
|
||||||
|
optional(field("item", alias($._string_content, "string"))),
|
||||||
|
repeat1(
|
||||||
|
seq(
|
||||||
|
"\\(",
|
||||||
|
field("item", alias($._expression, "expression")),
|
||||||
|
")",
|
||||||
|
optional(field("item", alias($._string_content, "string")))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
'"'
|
||||||
|
),
|
||||||
|
|
||||||
|
_type: ($) => choice($._non_concat_type, $.type_concatenation),
|
||||||
|
// Every type except a concatenation. Call arguments use this: `a ++ b`
|
||||||
|
// there is an expression, never a type concatenation.
|
||||||
|
_non_concat_type: ($) =>
|
||||||
|
choice(
|
||||||
|
$.array_type,
|
||||||
|
$.set_type,
|
||||||
|
$.tuple_type,
|
||||||
|
$.record_type,
|
||||||
|
$.operation_type,
|
||||||
|
$.type_base,
|
||||||
|
$.any_type,
|
||||||
|
$.list_type
|
||||||
|
),
|
||||||
|
type_concatenation: ($) =>
|
||||||
|
prec.left(
|
||||||
|
PREC.concatenation,
|
||||||
|
seq(field("left", $._type), "++", field("right", $._type))
|
||||||
|
),
|
||||||
|
array_type: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.concatenation + 1,
|
||||||
|
seq(
|
||||||
|
"array",
|
||||||
|
"[",
|
||||||
|
sepBy1(",", field("dimension", $.array_dimension)),
|
||||||
|
"]",
|
||||||
|
"of",
|
||||||
|
field("type", $._type)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array_dimension: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.call,
|
||||||
|
seq(
|
||||||
|
optional(seq(field("name", $._identifier), "in")),
|
||||||
|
field("type", $._type)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
// Binds tighter than `++`, so `set of A ++ B` is `(set of A) ++ B`
|
||||||
|
set_type: ($) =>
|
||||||
|
prec(
|
||||||
|
PREC.concatenation + 1,
|
||||||
|
seq(
|
||||||
|
optional(field("var_par", choice("var", "par"))),
|
||||||
|
optional(field("opt", "opt")),
|
||||||
|
"set",
|
||||||
|
optional(seq("(", field("cardinality", $._expression), ")")),
|
||||||
|
"of",
|
||||||
|
field("type", $._type)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
tuple_type: ($) =>
|
||||||
|
seq(
|
||||||
|
optional(field("var_par", choice("var", "par"))),
|
||||||
|
optional(field("opt", "opt")),
|
||||||
|
"tuple",
|
||||||
|
"(",
|
||||||
|
sepBy1(",", field("field", $._type)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
record_type: ($) =>
|
||||||
|
seq(
|
||||||
|
optional(field("var_par", choice("var", "par"))),
|
||||||
|
optional(field("opt", "opt")),
|
||||||
|
"record",
|
||||||
|
"(",
|
||||||
|
sepBy1(",", field("field", $.record_type_field)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
record_type_field: ($) =>
|
||||||
|
seq(field("type", $._type), ":", field("name", $._identifier)),
|
||||||
|
operation_type: ($) =>
|
||||||
|
seq(
|
||||||
|
"op",
|
||||||
|
"(",
|
||||||
|
field("return_type", $._type),
|
||||||
|
":",
|
||||||
|
"(",
|
||||||
|
sepBy(",", field("parameter", $._type)),
|
||||||
|
")",
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
type_base: ($) =>
|
||||||
|
choice(
|
||||||
|
seq(
|
||||||
|
optional(field("var_par", choice("var", "par"))),
|
||||||
|
optional(field("opt", "opt")),
|
||||||
|
field(
|
||||||
|
"domain",
|
||||||
|
choice(
|
||||||
|
$.primitive_type,
|
||||||
|
$.new_type,
|
||||||
|
$.type_inst_id,
|
||||||
|
$.type_inst_enum_id,
|
||||||
|
$._non_concat_expression,
|
||||||
|
$.annotated_expression
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
seq(field("any", "any"), field("domain", $.type_inst_id))
|
||||||
|
),
|
||||||
|
primitive_type: ($) => choice(...primitive_types),
|
||||||
|
type_inst_id: ($) => /\$[A-Za-z][A-Za-z0-9_]*/,
|
||||||
|
type_inst_enum_id: ($) => /\$\$[A-Za-z][A-Za-z0-9_]*/,
|
||||||
|
new_type: ($) => seq("new", field("type", $._identifier)),
|
||||||
|
any_type: ($) => "any",
|
||||||
|
list_type: ($) =>
|
||||||
|
prec(PREC.concatenation + 1, seq("list", "of", field("type", $._type))),
|
||||||
|
|
||||||
|
_literal: ($) =>
|
||||||
|
choice(
|
||||||
|
$.absent,
|
||||||
|
$.anonymous,
|
||||||
|
$.array_literal_2d,
|
||||||
|
$.array_literal_3d,
|
||||||
|
$.array_literal,
|
||||||
|
$.boolean_literal,
|
||||||
|
$.float_literal,
|
||||||
|
$.infinity,
|
||||||
|
$.integer_literal,
|
||||||
|
$.set_literal,
|
||||||
|
$.string_literal,
|
||||||
|
$.tuple_literal,
|
||||||
|
$.record_literal
|
||||||
|
),
|
||||||
|
|
||||||
|
absent: ($) => "<>",
|
||||||
|
anonymous: ($) => "_",
|
||||||
|
// Only an indexed member needs the wrapper; a plain one stands for itself,
|
||||||
|
// as in `array_literal_2d_row`. Wrapping every member costs a subtree
|
||||||
|
// each, which is a quarter of the tree for a data file that is one long
|
||||||
|
// array.
|
||||||
|
array_literal: ($) =>
|
||||||
|
seq(
|
||||||
|
"[",
|
||||||
|
sepBy(
|
||||||
|
",",
|
||||||
|
field("member", choice($._expression, $.array_literal_member))
|
||||||
|
),
|
||||||
|
"]"
|
||||||
|
),
|
||||||
|
array_literal_member: ($) =>
|
||||||
|
seq(field("index", $._expression), ":", field("value", $._expression)),
|
||||||
|
array_literal_2d: ($) =>
|
||||||
|
seq(
|
||||||
|
"[|",
|
||||||
|
optional(
|
||||||
|
seq(
|
||||||
|
choice(
|
||||||
|
repeat1(seq(field("column_index", $._expression), ":")),
|
||||||
|
field("row", $.array_literal_2d_row)
|
||||||
|
),
|
||||||
|
repeat(seq("|", field("row", $.array_literal_2d_row))),
|
||||||
|
optional("|")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
"|]"
|
||||||
|
),
|
||||||
|
array_literal_2d_row: ($) =>
|
||||||
|
seq(
|
||||||
|
optional(seq(field("index", $._expression), ":")),
|
||||||
|
sepBy1(",", field("member", $._expression))
|
||||||
|
),
|
||||||
|
array_literal_3d: ($) =>
|
||||||
|
seq(
|
||||||
|
"[|",
|
||||||
|
choice(
|
||||||
|
seq("|", "|"),
|
||||||
|
sepBy1(",", field("slice", $.array_literal_3d_slice))
|
||||||
|
),
|
||||||
|
"|]"
|
||||||
|
),
|
||||||
|
array_literal_3d_slice: ($) =>
|
||||||
|
seq("|", sepBy1("|", field("row", $.array_literal_3d_row)), "|"),
|
||||||
|
array_literal_3d_row: ($) => sepBy1(",", field("member", $._expression)),
|
||||||
|
boolean_literal: ($) => choice("true", "false"),
|
||||||
|
float_literal: ($) =>
|
||||||
|
token(
|
||||||
|
choice(
|
||||||
|
/\d+\.\d+/,
|
||||||
|
/\d+(\.\d+)?[Ee][+-]?\d+/,
|
||||||
|
/0[xX]([0-9a-fA-F]*\.[0-9a-fA-F]+|[0-9a-fA-F]+\.?)[pP][+-]?[0-9]+/
|
||||||
|
)
|
||||||
|
),
|
||||||
|
integer_literal: ($) =>
|
||||||
|
token(choice(/[0-9]+/, /0[xX][0-9a-fA-F]+/, /0b[01]+/, /0o[0-7]+/)),
|
||||||
|
infinity: ($) => choice("infinity", "∞"),
|
||||||
|
set_literal: ($) =>
|
||||||
|
choice("∅", seq("{", sepBy(",", field("member", $._expression)), "}")),
|
||||||
|
|
||||||
|
string_literal: ($) => seq('"', optional($._string_content), '"'),
|
||||||
|
_string_content: ($) =>
|
||||||
|
repeat1(field("content", choice($.string_characters, $.escape_sequence))),
|
||||||
|
string_characters: ($) => token.immediate(prec(1, /[^"\n\\]+/)),
|
||||||
|
escape_sequence: ($) => {
|
||||||
|
const simpleEscape = [
|
||||||
|
["\\'", "'"],
|
||||||
|
['\\"', '"'],
|
||||||
|
["\\\\", "\\"],
|
||||||
|
["\\r", "\r"],
|
||||||
|
["\\n", "\n"],
|
||||||
|
["\\t", "\t"],
|
||||||
|
]
|
||||||
|
return choice(
|
||||||
|
field("escape", choice(...simpleEscape.map(([e, v]) => alias(e, v)))),
|
||||||
|
seq("\\", field("escape", alias(/[0-7]{1,3}/, "octal"))),
|
||||||
|
seq("\\x", field("escape", alias(/[0-9a-fA-F]{1,2}/, "hexadecimal"))),
|
||||||
|
seq("\\u", field("escape", alias(/[0-9a-fA-F]{4}/, "hexadecimal"))),
|
||||||
|
seq("\\U", field("escape", alias(/[0-9a-fA-F]{8}/, "hexadecimal")))
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
tuple_literal: ($) =>
|
||||||
|
seq(
|
||||||
|
"(",
|
||||||
|
field("member", $._expression),
|
||||||
|
",",
|
||||||
|
sepBy(",", field("member", $._expression)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
record_literal: ($) =>
|
||||||
|
seq("(", sepBy(",", field("member", $.record_member)), ")"),
|
||||||
|
record_member: ($) =>
|
||||||
|
seq(field("name", $._identifier), ":", field("value", $._expression)),
|
||||||
|
|
||||||
|
identifier: ($) => /[\p{L}_][\p{L}\p{N}_]*/u,
|
||||||
|
quoted_identifier: ($) => /'[^']*'/,
|
||||||
|
inversed_identifier: ($) =>
|
||||||
|
seq(field("identifier", $._identifier), choice(...INVERSE_OPERATORS)),
|
||||||
|
backtick_identifier: ($) => /`[^`\n]*`/,
|
||||||
|
_identifier: ($) => choice($.identifier, $.quoted_identifier),
|
||||||
|
|
||||||
|
_pattern: ($) =>
|
||||||
|
choice(
|
||||||
|
$._identifier,
|
||||||
|
$.absent,
|
||||||
|
$.anonymous,
|
||||||
|
$.boolean_literal,
|
||||||
|
$.string_literal,
|
||||||
|
$.pattern_numeric_literal,
|
||||||
|
$.pattern_call,
|
||||||
|
$.pattern_tuple,
|
||||||
|
$.pattern_record
|
||||||
|
),
|
||||||
|
pattern_numeric_literal: ($) =>
|
||||||
|
seq(
|
||||||
|
optional(field("negative", "-")),
|
||||||
|
field("value", choice($.integer_literal, $.float_literal, $.infinity))
|
||||||
|
),
|
||||||
|
pattern_call: ($) =>
|
||||||
|
seq(
|
||||||
|
field("identifier", $._identifier),
|
||||||
|
"(",
|
||||||
|
sepBy(",", field("argument", $._pattern)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
pattern_tuple: ($) =>
|
||||||
|
seq(
|
||||||
|
"(",
|
||||||
|
field("field", $._pattern),
|
||||||
|
",",
|
||||||
|
sepBy(",", field("field", $._pattern)),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
pattern_record: ($) =>
|
||||||
|
seq("(", sepBy1(",", field("field", $.pattern_record_field)), ")"),
|
||||||
|
pattern_record_field: ($) =>
|
||||||
|
seq(field("name", $._identifier), ":", field("value", $._pattern)),
|
||||||
|
|
||||||
|
line_comment: ($) => token(seq("%", /.*/)),
|
||||||
|
doc_comment: ($) => token(prec(1, /\/\*\*([^*]|\*+[^*\/])*\*+\//)),
|
||||||
|
file_doc_comment: ($) => token(prec(2, /\/\*\*\*([^*]|\*+[^*\/])*\*+\//)),
|
||||||
|
block_comment: ($) => token(/\/\*([^*]|\*+[^*\/])*\*+\//),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
function sepBy(sep, rule) {
|
||||||
|
return seq(repeat(seq(rule, sep)), optional(rule))
|
||||||
|
}
|
||||||
|
|
||||||
|
function sepBy1(sep, rule) {
|
||||||
|
return seq(rule, repeat(seq(sep, rule)), optional(sep))
|
||||||
|
}
|
||||||
|
|
||||||
|
function nonAssoc(p, rule) {
|
||||||
|
// Bump precedence by 5 to indicate this is non associative
|
||||||
|
return prec.left(p + 5, rule)
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"name": "tree-sitter-minizinc",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "MiniZinc grammar for tree-sitter",
|
||||||
|
"type": "module",
|
||||||
|
"repository": "git+https://github.com/shackle-rs/shackle.git",
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Jip J. Dekker",
|
||||||
|
"email": "jip.dekker@monash.edu",
|
||||||
|
"url": "https://dekker.one/"
|
||||||
|
},
|
||||||
|
"main": "bindings/node",
|
||||||
|
"types": "bindings/node",
|
||||||
|
"keywords": [
|
||||||
|
"incremental",
|
||||||
|
"parsing",
|
||||||
|
"tree-sitter",
|
||||||
|
"minizinc"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"grammar.js",
|
||||||
|
"tree-sitter.json",
|
||||||
|
"binding.gyp",
|
||||||
|
"prebuilds/**",
|
||||||
|
"bindings/node/*",
|
||||||
|
"queries/*",
|
||||||
|
"src/**",
|
||||||
|
"*.wasm"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"node-addon-api": "^8.9.2",
|
||||||
|
"node-gyp-build": "^4.8.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prebuildify": "^6.0.1",
|
||||||
|
"tree-sitter-cli": "^0.27.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"tree-sitter": "^0.25.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"tree-sitter": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "tree-sitter generate && node-gyp-build",
|
||||||
|
"install": "node-gyp-build",
|
||||||
|
"node-test": "node --test bindings/node/*_test.js",
|
||||||
|
"prestart": "tree-sitter build --wasm",
|
||||||
|
"start": "tree-sitter playground",
|
||||||
|
"test": "tree-sitter test"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
(case_expression) @case
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
(line_comment)
|
||||||
|
(doc_comment)
|
||||||
|
(file_doc_comment)
|
||||||
|
(block_comment)
|
||||||
|
] @comment
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
; Function calls
|
||||||
|
(call function: (identifier) @function)
|
||||||
|
; Function definitions
|
||||||
|
(function_item name: (identifier) @function)
|
||||||
|
(predicate name: (identifier) @function)
|
||||||
|
|
||||||
|
; Types
|
||||||
|
(primitive_type) @type.builtin
|
||||||
|
[
|
||||||
|
"array"
|
||||||
|
"list"
|
||||||
|
"of"
|
||||||
|
"par"
|
||||||
|
"set"
|
||||||
|
"var"
|
||||||
|
] @type.builtin
|
||||||
|
|
||||||
|
; Identifiers
|
||||||
|
(identifier) @variable
|
||||||
|
|
||||||
|
; Keywords
|
||||||
|
[
|
||||||
|
"annotation"
|
||||||
|
"constraint"
|
||||||
|
"else"
|
||||||
|
"elseif"
|
||||||
|
"endif"
|
||||||
|
"enum"
|
||||||
|
"function"
|
||||||
|
"if"
|
||||||
|
"include"
|
||||||
|
"let"
|
||||||
|
"maximize"
|
||||||
|
"minimize"
|
||||||
|
"output"
|
||||||
|
"predicate"
|
||||||
|
"satisfy"
|
||||||
|
"solve"
|
||||||
|
"test"
|
||||||
|
"then"
|
||||||
|
"where"
|
||||||
|
] @keyword
|
||||||
|
|
||||||
|
; Operators
|
||||||
|
[
|
||||||
|
"<->"
|
||||||
|
"->"
|
||||||
|
"<-"
|
||||||
|
"\\/"
|
||||||
|
"xor"
|
||||||
|
"/\\"
|
||||||
|
"="
|
||||||
|
"=="
|
||||||
|
"!="
|
||||||
|
"<"
|
||||||
|
"<="
|
||||||
|
">"
|
||||||
|
">="
|
||||||
|
"in"
|
||||||
|
"subset"
|
||||||
|
"superset"
|
||||||
|
"union"
|
||||||
|
"diff"
|
||||||
|
"symdiff"
|
||||||
|
"intersect"
|
||||||
|
".."
|
||||||
|
"+"
|
||||||
|
"-"
|
||||||
|
"++"
|
||||||
|
"*"
|
||||||
|
"/"
|
||||||
|
"div"
|
||||||
|
"mod"
|
||||||
|
"^"
|
||||||
|
"::"
|
||||||
|
] @operator
|
||||||
|
|
||||||
|
; Punctuation
|
||||||
|
[
|
||||||
|
","
|
||||||
|
":"
|
||||||
|
";"
|
||||||
|
"|"
|
||||||
|
] @punctuation.delimiter
|
||||||
|
[
|
||||||
|
"("
|
||||||
|
")"
|
||||||
|
"["
|
||||||
|
"]"
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
] @punctuation.bracket
|
||||||
|
|
||||||
|
; Literals
|
||||||
|
[
|
||||||
|
(integer_literal)
|
||||||
|
(float_literal)
|
||||||
|
] @number
|
||||||
|
|
||||||
|
[
|
||||||
|
(string_literal)
|
||||||
|
(string_interpolation)
|
||||||
|
] @string
|
||||||
|
(escape_sequence) @escape
|
||||||
|
|
||||||
|
[
|
||||||
|
(absent)
|
||||||
|
(boolean_literal)
|
||||||
|
] @constant.builtin
|
||||||
|
|
||||||
|
; Comments
|
||||||
|
[
|
||||||
|
(block_comment)
|
||||||
|
(line_comment)
|
||||||
|
] @comment
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
(identifier)
|
||||||
|
(quoted_identifier)
|
||||||
|
(type_inst_id)
|
||||||
|
(type_inst_enum_id)
|
||||||
|
] @identifier
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
(function_item name: (identifier) @name) @definition.function
|
||||||
|
(predicate name: (identifier) @name) @definition.function
|
||||||
|
(annotation name: (identifier) @name) @definition.function
|
||||||
|
|
||||||
|
(call function: (identifier) @name) @reference.call
|
||||||
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,336 @@
|
|||||||
|
#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)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define _array__cast(self, expr) (decltype((self)->contents))(expr)
|
||||||
|
#else
|
||||||
|
#define _array__cast(self, expr) (expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// 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__cast(self, _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__cast(self, _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__cast(self, _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__cast(self, _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__cast(self, _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__cast(self, _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__cast(self, _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__cast(other, _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,286 @@
|
|||||||
|
#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,37 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json",
|
||||||
|
"grammars": [
|
||||||
|
{
|
||||||
|
"name": "minizinc",
|
||||||
|
"camelcase": "Minizinc",
|
||||||
|
"scope": "source.minizinc",
|
||||||
|
"path": ".",
|
||||||
|
"file-types": ["mzn", "fzn"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"license": "MPL-2.0",
|
||||||
|
"description": "MiniZinc grammar for tree-sitter",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jip J. Dekker",
|
||||||
|
"email": "jip.dekker@monash.edu",
|
||||||
|
"url": "https://dekker.one/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": {
|
||||||
|
"repository": "git+https://github.com/shackle-rs/shackle.git"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"c": true,
|
||||||
|
"go": true,
|
||||||
|
"java": false,
|
||||||
|
"node": true,
|
||||||
|
"python": true,
|
||||||
|
"rust": true,
|
||||||
|
"swift": true,
|
||||||
|
"zig": false
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user