2019-08-19 11:58:20 -04:00
|
|
|
const { Charset } = require("regexp-util");
|
|
|
|
|
|
|
|
const getInverseRegex = charset =>
|
|
|
|
new RegExp(`[^${charset.toString().slice(1, -1)}]`);
|
2019-08-19 21:30:20 -04:00
|
|
|
const concatRegex = (...regexes) =>
|
|
|
|
new RegExp(regexes.reduce((a, b) => a.concat(`(${b.source})`), []).join(""));
|
2019-08-19 11:58:20 -04:00
|
|
|
|
|
|
|
const control_chars = new Charset([0x0, 0x1f], 0x7f);
|
2019-08-19 21:30:20 -04:00
|
|
|
const newline = /(\r?\n)+/;
|
|
|
|
|
|
|
|
const decimal_integer = /[+-]?(0|[1-9](_?[0-9])*)/;
|
|
|
|
const hexadecimal_integer = /0x[0-9a-fA-F](_?[0-9a-fA-F])*/;
|
|
|
|
const octal_integer = /0o[0-7](_?[0-7])*/;
|
|
|
|
const binary_integer = /0b[01](_?[01])*/;
|
|
|
|
const float_fractional_part = /[.][0-9](_?[0-9])*/;
|
|
|
|
const float_exponent_part = concatRegex(/[eE]/, decimal_integer);
|
|
|
|
|
|
|
|
const rfc3339_date = /([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])/;
|
|
|
|
const rfc3339_delimiter = /[ tT]/;
|
|
|
|
const rfc3339_time = /([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)([.][0-9]+)?/;
|
|
|
|
const rfc3339_offset = /([zZ])|([+-]([01][0-9]|2[0-3]):[0-5][0-9])/;
|
2019-08-19 11:58:20 -04:00
|
|
|
|
2019-08-18 06:30:34 -04:00
|
|
|
module.exports = grammar({
|
|
|
|
name: "toml",
|
|
|
|
|
2019-08-20 02:59:19 -04:00
|
|
|
externals: $ => [$._line_ending_or_eof],
|
2019-08-18 06:30:34 -04:00
|
|
|
|
|
|
|
extras: $ => [$.comment, /[ \t]/],
|
|
|
|
|
|
|
|
rules: {
|
2019-08-20 03:01:47 -04:00
|
|
|
file: $ => repeat(choice($.pair, $.table, $.table_array, $._newline)),
|
2019-08-18 06:30:34 -04:00
|
|
|
|
|
|
|
comment: $ => /#.*/,
|
2019-08-19 21:30:20 -04:00
|
|
|
_newline: $ => newline,
|
2019-08-18 06:30:34 -04:00
|
|
|
|
2019-08-20 02:59:19 -04:00
|
|
|
table: $ =>
|
|
|
|
seq("[", choice($.dotted_key, $.key), "]", $._line_ending_or_eof),
|
|
|
|
|
|
|
|
table_array: $ =>
|
|
|
|
seq("[[", choice($.dotted_key, $.key), "]]", $._line_ending_or_eof),
|
2019-08-18 06:30:34 -04:00
|
|
|
|
2019-08-20 02:59:19 -04:00
|
|
|
pair: $ => seq($._inline_pair, $._line_ending_or_eof),
|
2019-08-18 06:30:34 -04:00
|
|
|
_inline_pair: $ => seq(choice($.dotted_key, $.key), "=", $._inline_value),
|
|
|
|
|
|
|
|
key: $ => choice($._bare_key, $._quoted_key),
|
|
|
|
dotted_key: $ => seq(choice($.dotted_key, $.key), ".", $.key),
|
|
|
|
_bare_key: $ => /[A-Za-z0-9_-]+/,
|
2019-08-19 21:30:20 -04:00
|
|
|
_quoted_key: $ => choice($._basic_string, $._literal_string),
|
2019-08-18 06:30:34 -04:00
|
|
|
|
|
|
|
_inline_value: $ =>
|
|
|
|
choice(
|
|
|
|
$.string,
|
|
|
|
$.integer,
|
|
|
|
$.float,
|
|
|
|
$.boolean,
|
|
|
|
$.offset_date_time,
|
|
|
|
$.local_date_time,
|
|
|
|
$.local_date,
|
|
|
|
$.local_time,
|
|
|
|
$.array,
|
|
|
|
$.inline_table
|
|
|
|
),
|
|
|
|
|
|
|
|
string: $ =>
|
|
|
|
choice(
|
2019-08-19 21:30:20 -04:00
|
|
|
$._basic_string,
|
2019-08-18 06:30:34 -04:00
|
|
|
$._multiline_basic_string,
|
2019-08-19 21:30:20 -04:00
|
|
|
$._literal_string,
|
2019-08-18 06:30:34 -04:00
|
|
|
$._multiline_literal_string
|
|
|
|
),
|
2019-08-19 21:30:20 -04:00
|
|
|
_basic_string: $ =>
|
2019-08-18 06:30:34 -04:00
|
|
|
seq(
|
2019-08-19 11:58:20 -04:00
|
|
|
'"',
|
|
|
|
repeat(
|
|
|
|
choice(
|
|
|
|
token.immediate(
|
|
|
|
repeat1(getInverseRegex(control_chars.union('"', "\\")))
|
|
|
|
),
|
|
|
|
$.escape_sequence
|
|
|
|
)
|
|
|
|
),
|
|
|
|
token.immediate('"')
|
2019-08-18 06:30:34 -04:00
|
|
|
),
|
|
|
|
_multiline_basic_string: $ =>
|
|
|
|
seq(
|
2019-08-19 11:58:20 -04:00
|
|
|
'"""',
|
2019-08-18 06:30:34 -04:00
|
|
|
repeat(
|
|
|
|
choice(
|
2019-08-19 11:58:20 -04:00
|
|
|
token.immediate(
|
|
|
|
repeat1(getInverseRegex(control_chars.union('"', "\\")))
|
|
|
|
),
|
|
|
|
token.immediate(/"{1,2}/),
|
2019-08-19 21:30:20 -04:00
|
|
|
token.immediate(newline),
|
2019-08-18 06:30:34 -04:00
|
|
|
$.escape_sequence,
|
|
|
|
alias($._escape_line_ending, $.escape_sequence)
|
|
|
|
)
|
|
|
|
),
|
2019-08-19 11:58:20 -04:00
|
|
|
token.immediate('"""')
|
2019-08-18 06:30:34 -04:00
|
|
|
),
|
|
|
|
escape_sequence: $ =>
|
|
|
|
token.immediate(
|
|
|
|
seq("\\", choice(/[btnfr"\\]/, /u[0-9a-fA-F]{4}/, /U[0-9a-fA-F]{8}/))
|
|
|
|
),
|
|
|
|
_escape_line_ending: $ => token.immediate(seq("\\", /\r?\n/)),
|
2019-08-19 21:30:20 -04:00
|
|
|
_literal_string: $ =>
|
2019-08-18 06:30:34 -04:00
|
|
|
seq(
|
2019-08-19 11:58:20 -04:00
|
|
|
"'",
|
|
|
|
optional(
|
|
|
|
token.immediate(
|
|
|
|
repeat1(getInverseRegex(control_chars.union("'").subtract("\t")))
|
|
|
|
)
|
|
|
|
),
|
|
|
|
token.immediate("'")
|
2019-08-18 06:30:34 -04:00
|
|
|
),
|
|
|
|
_multiline_literal_string: $ =>
|
|
|
|
seq(
|
2019-08-19 11:58:20 -04:00
|
|
|
"'''",
|
|
|
|
repeat(
|
|
|
|
choice(
|
|
|
|
token.immediate(
|
|
|
|
repeat1(getInverseRegex(control_chars.union("'").subtract("\t")))
|
|
|
|
),
|
|
|
|
token.immediate(/'{1,2}/),
|
2019-08-19 21:30:20 -04:00
|
|
|
token.immediate(newline)
|
2019-08-19 11:58:20 -04:00
|
|
|
)
|
|
|
|
),
|
|
|
|
token.immediate("'''")
|
2019-08-18 06:30:34 -04:00
|
|
|
),
|
|
|
|
|
|
|
|
integer: $ =>
|
|
|
|
choice(
|
2019-08-19 21:30:20 -04:00
|
|
|
decimal_integer,
|
|
|
|
hexadecimal_integer,
|
|
|
|
octal_integer,
|
|
|
|
binary_integer
|
2019-08-18 06:30:34 -04:00
|
|
|
),
|
|
|
|
|
|
|
|
float: $ =>
|
|
|
|
choice(
|
|
|
|
seq(
|
2019-08-19 21:30:20 -04:00
|
|
|
decimal_integer,
|
2019-08-18 06:30:34 -04:00
|
|
|
choice(
|
2019-08-19 21:30:20 -04:00
|
|
|
seq(
|
|
|
|
token.immediate(float_fractional_part),
|
|
|
|
optional(token.immediate(float_exponent_part))
|
|
|
|
),
|
|
|
|
token.immediate(float_exponent_part)
|
2019-08-18 06:30:34 -04:00
|
|
|
)
|
|
|
|
),
|
|
|
|
/[+-]?(inf|nan)/
|
|
|
|
),
|
|
|
|
|
|
|
|
boolean: $ => /true|false/,
|
|
|
|
|
|
|
|
offset_date_time: $ =>
|
|
|
|
seq(
|
2019-08-19 21:30:20 -04:00
|
|
|
rfc3339_date,
|
|
|
|
token.immediate(rfc3339_delimiter),
|
|
|
|
token.immediate(rfc3339_time),
|
|
|
|
token.immediate(rfc3339_offset)
|
2019-08-18 06:30:34 -04:00
|
|
|
),
|
|
|
|
local_date_time: $ =>
|
2019-08-19 21:30:20 -04:00
|
|
|
seq(
|
|
|
|
rfc3339_date,
|
|
|
|
token.immediate(rfc3339_delimiter),
|
|
|
|
token.immediate(rfc3339_time)
|
|
|
|
),
|
|
|
|
local_date: $ => rfc3339_date,
|
|
|
|
local_time: $ => rfc3339_time,
|
2019-08-18 06:30:34 -04:00
|
|
|
|
|
|
|
array: $ =>
|
|
|
|
seq(
|
|
|
|
"[",
|
|
|
|
repeat($._newline),
|
|
|
|
optional(
|
|
|
|
seq(
|
|
|
|
$._inline_value,
|
|
|
|
repeat($._newline),
|
|
|
|
repeat(
|
|
|
|
seq(",", repeat($._newline), $._inline_value, repeat($._newline))
|
|
|
|
),
|
|
|
|
optional(seq(",", repeat($._newline)))
|
|
|
|
)
|
|
|
|
),
|
|
|
|
"]"
|
|
|
|
),
|
|
|
|
|
|
|
|
inline_table: $ =>
|
|
|
|
seq(
|
|
|
|
"{",
|
|
|
|
optional(
|
|
|
|
seq(
|
|
|
|
alias($._inline_pair, $.pair),
|
|
|
|
repeat(seq(",", alias($._inline_pair, $.pair)))
|
|
|
|
)
|
|
|
|
),
|
|
|
|
"}"
|
|
|
|
),
|
|
|
|
},
|
|
|
|
});
|