342 lines
7.6 KiB
JavaScript
342 lines
7.6 KiB
JavaScript
const PREC = {
|
|
COMMENT: -2,
|
|
UNQUOTED_STRING: 0,
|
|
CONTAINER: 2,
|
|
CONNECTION: 2,
|
|
SHAPE: 3,
|
|
IDENTIFIER: 0,
|
|
ARROW: 0,
|
|
ATTRIBUTE: 0,
|
|
ATTRIBUTE_KEY: 0,
|
|
};
|
|
|
|
spaces = /[ \t]/;
|
|
|
|
module.exports = grammar({
|
|
name: "d2",
|
|
|
|
extras: ($) => [
|
|
/[ \f\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/,
|
|
$.line_comment,
|
|
],
|
|
|
|
word: ($) => $._identifier,
|
|
|
|
conflicts: ($) => [
|
|
[$._connection_path, $.container],
|
|
//[$.shape_key],
|
|
/*
|
|
[$._shape_path],
|
|
[$._shape_block],
|
|
[$._shape_block_definition],
|
|
[$._style_attr_block],
|
|
[$._inner_style_attribute],
|
|
[$._emptyline],
|
|
*/
|
|
],
|
|
|
|
rules: {
|
|
source_file: ($) => repeat($._new_root_definition),
|
|
|
|
_new_root_definition: ($) =>
|
|
choice(
|
|
$._eol,
|
|
seq(
|
|
choice(
|
|
alias($._new_root_attribute, $.attribute),
|
|
$.shape,
|
|
$.container,
|
|
$.connection
|
|
),
|
|
$._end
|
|
)
|
|
),
|
|
|
|
// connections
|
|
|
|
connection: ($) =>
|
|
seq(
|
|
$._connection_path,
|
|
repeat1(seq($._arrow, $._connection_path)),
|
|
optional(seq($._colon, $.label))
|
|
),
|
|
|
|
_connection_path: ($) =>
|
|
seq(
|
|
repeat(
|
|
prec(
|
|
PREC.CONNECTION,
|
|
seq(alias($.shape_key, $.container_key), $._dot)
|
|
)
|
|
),
|
|
$.shape_key
|
|
),
|
|
|
|
// containers
|
|
|
|
container: ($) =>
|
|
prec(
|
|
PREC.CONTAINER,
|
|
seq(
|
|
alias($.shape_key, $.container_key),
|
|
choice(
|
|
seq($._dot, choice($.shape, $.container)),
|
|
seq(
|
|
seq(
|
|
optional(seq($._colon, optional($.label))),
|
|
optional(seq(alias($._new_container_block, $.block)))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
_new_container_block: ($) =>
|
|
prec(
|
|
PREC.CONTAINER,
|
|
seq("{", repeat($._new_container_block_definition), "}")
|
|
),
|
|
|
|
_new_container_block_definition: ($) =>
|
|
prec(
|
|
PREC.CONTAINER,
|
|
choice($._eol, seq(choice($.shape, $.container, $.connection), $._end))
|
|
),
|
|
|
|
// shapes
|
|
|
|
shape: ($) =>
|
|
prec(
|
|
PREC.SHAPE,
|
|
seq(
|
|
$.shape_key,
|
|
optional(
|
|
choice(
|
|
seq($._dot, alias($._style_attribute, $.attribute)),
|
|
seq(
|
|
optional(seq($._colon, optional($.label))),
|
|
optional(seq(alias($._new_shape_block, $.block)))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
),
|
|
|
|
shape_key: ($) => choice($.string, seq($._identifier, optional($._dash))),
|
|
|
|
_identifier: ($) =>
|
|
token(prec(PREC.IDENTIFIER, /\-?([\w\d]+|([\w\d]+( +|\-)[\w\d]+)+)/)),
|
|
|
|
_new_shape_block: ($) =>
|
|
prec(PREC.SHAPE, seq("{", repeat($._new_shape_block_definition), "}")),
|
|
|
|
_new_shape_block_definition: ($) => prec(PREC.SHAPE, choice($._eol)),
|
|
|
|
// attributes
|
|
|
|
_new_root_attribute: ($) =>
|
|
seq(alias($._root_attr_key, $.attr_key), $._colon, $.attr_value),
|
|
|
|
_root_attr_key: ($) =>
|
|
choice(
|
|
"direction",
|
|
// reserved but doesn't affected for root
|
|
alias(
|
|
choice(
|
|
"shape",
|
|
"label",
|
|
"constraint",
|
|
"icon",
|
|
"style",
|
|
$._common_style_attr_key,
|
|
$._text_attr_key
|
|
),
|
|
$.reserved
|
|
)
|
|
),
|
|
|
|
_shape_attr_key: ($) =>
|
|
prec(
|
|
PREC.ATTRIBUTE_KEY,
|
|
choice(
|
|
"shape",
|
|
"label",
|
|
// sql
|
|
"constraint",
|
|
// image
|
|
"icon",
|
|
"width",
|
|
"height"
|
|
)
|
|
),
|
|
|
|
_style_attribute: ($) =>
|
|
prec(
|
|
PREC.ATTRIBUTE,
|
|
seq(
|
|
alias("style", $.attr_key),
|
|
choice(
|
|
seq($._dot, alias($._inner_style_attribute, $.attribute)),
|
|
seq($._colon, alias($._style_attribute_block, $.block))
|
|
)
|
|
)
|
|
),
|
|
|
|
_style_attribute_block: ($) =>
|
|
seq(
|
|
"{",
|
|
repeat(
|
|
choice(
|
|
$._eol,
|
|
seq(alias($._inner_style_attribute, $.attribute), $._end)
|
|
)
|
|
),
|
|
"}"
|
|
),
|
|
|
|
_inner_style_attribute: ($) =>
|
|
prec(
|
|
PREC.ATTRIBUTE,
|
|
seq(alias($._style_attr_key, $.attr_key), $._colon, $.attr_value)
|
|
),
|
|
|
|
_style_attr_key: ($) => choice($._common_style_attr_key, "3d"),
|
|
|
|
_common_style_attr_key: ($) =>
|
|
choice(
|
|
"opacity",
|
|
"fill",
|
|
"stroke",
|
|
"stroke-width",
|
|
"stroke-dash",
|
|
"border-radius",
|
|
"font-color",
|
|
"shadow",
|
|
"multiple",
|
|
"animated",
|
|
"link"
|
|
),
|
|
|
|
_text_attr_key: ($) => "near",
|
|
|
|
_connection_attr_key: ($) => choice("source-arrowhead", "target-arrowhead"),
|
|
|
|
//
|
|
|
|
label: ($) => choice($.string, $._unquoted_string),
|
|
|
|
attr_value: ($) => seq(choice($.string, $._unquoted_string)),
|
|
|
|
// --------------------------------------------
|
|
|
|
// source_file: ($) => repeat($._root_definition),
|
|
/*
|
|
|
|
_root_definition: ($) =>
|
|
choice(
|
|
$._emptyline,
|
|
$._root_attribute,
|
|
$.connection,
|
|
$._shape_definition
|
|
),
|
|
|
|
_shape_definition: ($) =>
|
|
seq(
|
|
$._shape_path,
|
|
optional(
|
|
choice(
|
|
seq($.dot, $._shape_attribute),
|
|
seq(
|
|
optional(seq($._colon, optional(seq(spaces, $.label)))),
|
|
optional(alias($._shape_block, $.block))
|
|
)
|
|
)
|
|
),
|
|
$._end
|
|
),
|
|
|
|
_shape_path: ($) =>
|
|
seq(
|
|
spaces,
|
|
repeat(seq(alias($.shape_key, $.container_key), spaces, $.dot, spaces)),
|
|
$.shape_key
|
|
),
|
|
|
|
|
|
_shape_block: ($) =>
|
|
seq(
|
|
spaces,
|
|
"{",
|
|
repeat(choice($._emptyline, seq(spaces, $._shape_block_definition))),
|
|
optional(seq($._shape_block_definition, optional($._end))),
|
|
spaces,
|
|
"}"
|
|
),
|
|
|
|
_shape_block_definition: ($) =>
|
|
choice($.connection, $._shape_definition, $._shape_attribute),
|
|
|
|
_shape_attribute: ($) =>
|
|
choice(
|
|
seq(alias($._shape_attr_key, $.attr_key), $._colon, $.attr_value),
|
|
$._style_attribute
|
|
),
|
|
|
|
_style_attribute: ($) =>
|
|
seq(
|
|
alias("style", $.attr_key),
|
|
choice(
|
|
seq($.dot, $._inner_style_attribute),
|
|
seq($._colon, alias($._style_attr_block, $.block))
|
|
)
|
|
),
|
|
|
|
_style_attr_block: ($) =>
|
|
seq(
|
|
spaces,
|
|
"{",
|
|
spaces,
|
|
repeat(choice($._emptyline, seq($._inner_style_attribute, $._end))),
|
|
optional(seq($._inner_style_attribute, optional($._end))),
|
|
spaces,
|
|
"}"
|
|
),
|
|
|
|
_inner_style_attribute: ($) =>
|
|
seq(spaces, alias($._style_attr_key, $.attr_key), $._colon, $.attr_value),
|
|
|
|
_connection_attribute: ($) =>
|
|
seq(alias($._connection_attr_key, $.attr_key), $._colon, $.attr_value),
|
|
*/
|
|
|
|
_dash: ($) => token.immediate("-"),
|
|
|
|
_colon: ($) => seq(":"),
|
|
|
|
_arrow: ($) => seq($.arrow),
|
|
|
|
arrow: ($) => token(prec(PREC.ARROW, choice(/-+>/, /--+/, /<-+/, /<-+>/))),
|
|
|
|
_dot: ($) => seq($.dot),
|
|
dot: ($) => token("."),
|
|
|
|
_unquoted_string: ($) =>
|
|
token(prec(PREC.UNQUOTED_STRING, /[\w\-?!]([^'"`\n;{}]*[\w\-?!])?/)),
|
|
|
|
string: ($) =>
|
|
choice(
|
|
seq("'", repeat(token.immediate(/[^'\n]+/)), "'"),
|
|
seq('"', repeat(token.immediate(/[^"\n]+/)), '"'),
|
|
seq("`", repeat(token.immediate(/[^`\n]+/)), "`")
|
|
),
|
|
|
|
line_comment: ($) => token(prec(PREC.COMMENT, seq("#", /.*/))),
|
|
|
|
_word: ($) => /[\w\d]+/,
|
|
|
|
_emptyline: ($) => prec(-1, seq(spaces, $._eol)),
|
|
_eol: ($) => choice("\n", "\0"),
|
|
_end: ($) => seq(choice(";", $._eol)),
|
|
},
|
|
});
|