module.exports = grammar({ name: 'jdg', extras: $ => [/\s+/, $.comment], word: $ => $.identifier, conflicts: $ => [], rules: { source_file: $ => repeat($._top_statement), comment: $ => token(seq('//', /[^\n]*/)), _top_statement: $ => choice( $.include, $.toolchains, $.build_defaults, $.structured_build, $.legacy_build_platform, $.legacy_build, $.binary_decl, $.sources_decl, $.bool_decl, $.timeout_decl, $.memory_limit_decl, $.group, ), include: $ => seq( 'include', field('path', $.string) ), legacy_build: $ => prec(1, seq( 'build', field('command', $.string) )), legacy_build_platform: $ => seq( field('keyword', choice('build_linux', 'build_windows', 'build_darwin')), field('command', $.string) ), structured_build: $ => prec(2, seq( 'build', field('name', $.string), field('body', $.build_block) )), build_defaults: $ => seq( 'build_defaults', field('body', $.build_block) ), build_block: $ => seq( '{', repeat($._build_field), '}' ), _build_field: $ => choice( $.build_scalar_field, $.build_list_field, $.build_profile_field, $.build_warnings_field, $.define_field, $.os_override, ), build_scalar_field: $ => seq( field('name', choice('language', 'standard', 'output', 'wrapper')), '=', field('value', $.string) ), build_list_field: $ => seq( field('name', choice('sources', 'includes', 'sanitize', 'link', 'extra', 'platforms', 'compilers')), '=', field('value', repeat1($.string)) ), build_profile_field: $ => seq( 'profile', '=', field('value', $.profile_value) ), profile_value: $ => choice('release', 'debug', 'sanitized'), build_warnings_field: $ => seq( 'warnings', '=', field('value', $.warnings_value) ), warnings_value: $ => choice('default', 'strict', 'pedantic'), define_field: $ => seq( 'define', '(', field('key', $.string), ')', '=', field('value', $.string) ), os_override: $ => seq( field('os', $.os_name), field('body', $.build_block) ), os_name: $ => choice('linux', 'windows', 'darwin'), toolchains: $ => seq( 'toolchains', '{', repeat($.toolchain_entry), '}' ), toolchain_entry: $ => seq( field('name', choice($.identifier, $.string)), '{', repeat($._toolchain_field), '}' ), _toolchain_field: $ => choice( $.toolchain_platforms_field, $.toolchain_binary_field, $.toolchain_class_field, ), toolchain_platforms_field: $ => seq( 'platforms', '=', field('value', repeat1($.string)) ), toolchain_binary_field: $ => seq( 'binary', '=', field('value', $.string) ), toolchain_class_field: $ => seq( 'class', '=', field('value', $.class_value) ), class_value: $ => choice('gnu', 'msvc'), binary_decl: $ => seq( 'binary', '=', field('value', $.string) ), sources_decl: $ => seq( 'sources', '=', field('value', $.string) ), bool_decl: $ => seq( field('name', choice('normalize_crlf', 'trim_trailing_ws')), '=', field('value', $.bool) ), timeout_decl: $ => seq( 'timeout', field('value', $.duration) ), memory_limit_decl: $ => seq( 'memory_limit', '=', field('value', $.size) ), group: $ => seq( 'group', '(', field('name', $.string), ')', '{', repeat($._group_field), '}' ), _group_field: $ => choice( $.group_weight_field, $.group_timeout_field, $.group_memory_field, $.group_scoring_field, $.group_wrapper_field, $.env_decl, $.test, $.pattern, ), group_weight_field: $ => seq('weight', '=', field('value', $.number)), group_timeout_field: $ => seq('timeout', '=', field('value', $.duration)), group_memory_field: $ => seq('memory_limit', '=', field('value', $.size)), group_scoring_field: $ => seq('scoring', '=', field('value', $.scoring_value)), scoring_value: $ => choice('partial', 'all_or_none'), group_wrapper_field: $ => seq('wrapper', '=', field('value', $.string)), env_decl: $ => seq( 'env', '(', field('key', $.string), ')', '=', field('value', $.string) ), test: $ => seq( 'test', '(', field('name', $.string), ')', '{', repeat($._test_field), '}' ), _test_field: $ => choice( $.test_stdin_field, $.test_stdout_field, $.test_stderr_field, $.test_args_field, $.test_exit_code_field, $.test_timeout_field, $.test_memory_field, $.test_wrapper_field, $.env_decl, $.file_decl, $.out_file_decl, ), test_stdin_field: $ => seq('stdin', '=', field('value', $.string)), test_stdout_field: $ => seq('stdout', $._matcher), test_stderr_field: $ => seq('stderr', $._matcher), test_args_field: $ => seq('args', '=', field('value', repeat1($.string))), test_exit_code_field: $ => seq('exitCode', '=', field('value', $.integer)), test_timeout_field: $ => seq('timeout', '=', field('value', $.duration)), test_memory_field: $ => seq('memory_limit', '=', field('value', $.size)), test_wrapper_field: $ => seq('wrapper', '=', field('value', $.string)), file_decl: $ => seq( 'file', '(', field('key', $.string), ')', '=', field('value', $.string) ), out_file_decl: $ => seq( 'outFile', '(', field('key', $.string), ')', '=', field('value', $.string) ), _matcher: $ => choice( $.exact_matcher, $.numeric_matcher, $.contains_matcher, $.regex_matcher, $.any_order_matcher, ), exact_matcher: $ => seq('=', field('value', $.string)), numeric_matcher: $ => seq( '~', field('epsilon', $.number), 'of', field('value', $.string) ), contains_matcher: $ => seq('contains', field('value', $.string)), regex_matcher: $ => seq('matches', field('pattern', $.regex_string)), any_order_matcher: $ => seq( 'anyOrder', '{', repeat1($.string), '}' ), pattern: $ => seq( 'pattern', '{', repeat($._pattern_field), '}' ), _pattern_field: $ => choice( $.pattern_input_field, $.pattern_output_field, $.pattern_dirs_field, $.pattern_args_field, ), pattern_input_field: $ => seq('input', '=', field('value', $.string)), pattern_output_field: $ => seq('output', '=', field('value', $.string)), pattern_dirs_field: $ => seq('dirs', '=', field('value', $.string)), pattern_args_field: $ => seq('args', '=', field('value', repeat1($.string))), bool: $ => choice('true', 'false'), number: $ => choice($.integer, $.float), string: $ => choice( $.heredoc_string, $.simple_string, ), simple_string: $ => token(seq( '"', repeat(choice( /[^"\\\n]/, seq('\\', /./) )), '"' )), heredoc_string: $ => token(seq( '"""', /([^"]|"[^"]|""[^"])*/, '"""' )), regex_string: $ => $.simple_string, identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/, integer: $ => token(/-?\d+/), float: $ => token(/-?\d+\.\d+/), duration: $ => token(/\d+(ms|s|m)/), size: $ => token(/\d+(KiB|MiB|GiB|KB|MB|GB|B|K|M|G)/), } });