| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- /*
- * Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- * Exceptions. See /LICENSE for license information.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- // This grammar is more permissive than toolchain because it is geared towards
- // editor use.
- function repeat_sep1(thing, sep) {
- return seq(thing, repeat(seq(sep, thing)));
- }
- function comma_sep(thing) {
- // Trailing comma is only allowed if there is at least one element.
- return optional(seq(repeat_sep1(thing, ','), optional(',')));
- }
- // This is based on toolchain/parser/precedence.cpp
- const PREC = {
- TermPrefix: 12,
- TermPostfix: 12,
- NumericPrefix: 11,
- NumericPostfix: 11,
- Multiplicative: 10,
- Additive: 9,
- BitwisePrefix: 8,
- BitwiseAnd: 7,
- BitwiseOr: 7,
- BitwiseXor: 7,
- BitShift: 7,
- TypePostfix: 6,
- LogicalPrefix: 5,
- Relational: 4,
- LogicalAnd: 3,
- LogicalOr: 3,
- IfExpression: 2,
- WhereClause: 1,
- };
- module.exports = grammar({
- name: 'carbon',
- word: ($) => $.ident,
- conflicts: ($) => [
- [$.paren_pattern, $.paren_expression],
- [$.struct_literal, $.struct_type_literal],
- ],
- extras: ($) => [/\s/, $.comment],
- // NOTE: This must match the order in src/scanner.c, names are not used for matching.
- externals: ($) => [$.binary_star, $.postfix_star, $.string],
- rules: {
- source_file: ($) =>
- seq(
- optional($.package_directive),
- repeat($.import_directive),
- repeat($.declaration)
- ),
- api_or_impl: ($) => choice('api', 'impl'),
- library_path: ($) => seq('library', $.string),
- package_directive: ($) =>
- seq('package', $.ident, optional($.library_path), $.api_or_impl, ';'),
- import_directive: ($) =>
- seq('import', $.ident, optional($.library_path), ';'),
- comment: ($) => token(seq('//', /.*/)),
- // NOTE: this must be before ident rule to increase its priority.
- // https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2015.md#syntax
- numeric_type_literal: ($) => /[iuf][1-9][0-9]*/,
- ident: ($) => /[A-Za-z_][A-Za-z0-9_]*/,
- bool_literal: ($) => choice('true', 'false'),
- numeric_literal: ($) => {
- // This is using variables because rules are not allowed in
- // token.immediate and token.
- // https://github.com/tree-sitter/tree-sitter/issues/449
- const decimal_integer_literal = choice('0', /[1-9](_?[0-9])*/);
- const hex_digits = /[0-9A-F](_?[0-9A-F])*/;
- const binary_integer_literal = /0b[01](_?[01])*/;
- const hex_integer_literal = seq('0x', token.immediate(hex_digits));
- const decimal_real_number_literal = seq(
- decimal_integer_literal,
- token.immediate(/\.[0-9](_?[0-9])*/),
- optional(
- seq(
- token.immediate(/e[+-]?/),
- token.immediate(decimal_integer_literal)
- )
- )
- );
- const hex_real_number_literal = seq(
- hex_integer_literal,
- token.immediate('.'),
- token.immediate(hex_digits),
- optional(
- seq(
- token.immediate(/p[+-]?/),
- token.immediate(decimal_integer_literal)
- )
- )
- );
- return token(
- choice(
- decimal_integer_literal,
- binary_integer_literal,
- hex_integer_literal,
- decimal_real_number_literal,
- hex_real_number_literal
- )
- );
- },
- array_literal: ($) =>
- seq(
- '[',
- field('type', $._expression),
- ';',
- optional(field('size', $._expression)),
- ']'
- ),
- struct_literal: ($) =>
- seq('{', comma_sep(seq($.designator, '=', $._expression)), '}'),
- struct_type_literal: ($) =>
- seq('{', comma_sep(seq($.designator, ':', $._expression)), '}'),
- builtin_type: ($) => choice('Self', 'String', 'bool', 'type'),
- literal: ($) =>
- choice(
- $.bool_literal,
- $.numeric_literal,
- $.numeric_type_literal,
- $.string,
- $.struct_literal,
- $.struct_type_literal
- ),
- binding_lhs: ($) => choice($.ident, '_'),
- paren_pattern: ($) =>
- seq(
- '(',
- comma_sep(choice($._pattern_without_expression, $._expression)),
- ')'
- ),
- _pattern_without_expression: ($) =>
- choice(
- 'auto',
- seq($.binding_lhs, ':', $._expression),
- seq($.binding_lhs, ':!', $._expression),
- seq('template', $.binding_lhs, ':!', $._expression),
- seq('var', $._pattern),
- $.paren_pattern,
- // alternative patterns
- // example: Optional(i32).Some(x: i32)
- seq($._simple_expression, $.paren_pattern)
- ),
- _pattern: ($) =>
- choice($._pattern_without_expression, $._simple_expression),
- unary_prefix_expression: ($) => {
- const table = [
- [PREC.NumericPrefix, '-'],
- [PREC.NumericPrefix, '--'],
- [PREC.NumericPrefix, '++'],
- [PREC.BitwisePrefix, '^'],
- [PREC.LogicalPrefix, 'not'],
- ];
- return choice(
- ...table.map(([precedence, operator]) =>
- prec(
- precedence,
- seq(field('operator', operator), field('value', $._expression))
- )
- )
- );
- },
- binary_expression: ($) => {
- const table = [
- [PREC.LogicalAnd, 'and'],
- [PREC.LogicalOr, 'or'],
- [PREC.BitwiseAnd, '&'],
- [PREC.BitwiseOr, '|'],
- [PREC.BitwiseXor, '^'],
- [PREC.BitShift, choice('<<', '>>')],
- [PREC.Relational, choice('==', '!=', '<', '<=', '>', '>=')],
- [PREC.Additive, choice('+', '-')],
- [PREC.Multiplicative, choice($.binary_star, '/', '%')],
- ];
- return choice(
- ...table.map(([precedence, operator]) =>
- prec.left(
- precedence,
- seq(
- field('left', $._expression),
- field('operator', operator),
- field('right', $._expression)
- )
- )
- )
- );
- },
- // This should be non-associative but conflicts are not allowed in tree-sitter
- as_expression: ($) => prec.left(seq($._expression, 'as', $._expression)),
- ref_expression: ($) =>
- prec.right(PREC.TermPrefix, seq('&', $._simple_expression)),
- deref_expression: ($) =>
- prec.right(PREC.TermPrefix, seq('*', $._simple_expression)),
- fn_type_expression: ($) =>
- prec.left(seq('__Fn', $.paren_expression, '->', $._simple_expression)),
- if_expression: ($) =>
- prec(
- PREC.IfExpression,
- seq('if', $._expression, 'then', $._expression, 'else', $._expression)
- ),
- paren_expression: ($) => seq('(', comma_sep($._expression), ')'),
- index_expression: ($) =>
- prec(
- PREC.TermPostfix,
- seq($._simple_expression, '[', $._expression, ']')
- ),
- designator: ($) => seq('.', choice('base', $.ident)),
- postfix_expression: ($) =>
- prec(
- PREC.TermPostfix,
- seq(
- $._simple_expression,
- choice(
- '++',
- '--',
- $.designator,
- seq('->', $.ident),
- seq(choice('.', '->'), '(', $._expression, ')')
- )
- )
- ),
- where_clause: ($) =>
- choice(
- seq($._simple_expression, '==', $._simple_expression),
- seq($._simple_expression, 'impls', $._simple_expression),
- seq($._simple_expression, '=', $._simple_expression),
- prec.left(
- PREC.WhereClause + 1,
- seq($.where_clause, 'and', $.where_clause)
- )
- ),
- where_expression: ($) =>
- prec.left(PREC.WhereClause, seq($._expression, 'where', $.where_clause)),
- call_expression: ($) =>
- prec(PREC.TermPostfix, seq($._simple_expression, $.paren_expression)),
- pointer_expression: ($) =>
- prec(PREC.TypePostfix, seq($._simple_expression, $.postfix_star)),
- _simple_expression: ($) =>
- choice(
- $.array_literal,
- $.builtin_type,
- $.call_expression,
- $.deref_expression,
- $.fn_type_expression,
- $.ident,
- $.index_expression,
- $.literal,
- $.paren_expression,
- $.pointer_expression,
- $.postfix_expression,
- $.ref_expression,
- 'self',
- '.Self',
- $.designator
- ),
- _expression: ($) =>
- choice(
- $.as_expression,
- $.binary_expression,
- $.if_expression,
- $.unary_prefix_expression,
- $.where_expression,
- $._simple_expression
- ),
- var_declaration: ($) =>
- seq(
- 'var',
- $._pattern_without_expression,
- optional(seq('=', $._expression)),
- ';'
- ),
- let_declaration: ($) =>
- seq('let', $._pattern_without_expression, '=', $._expression, ';'),
- assign_statement: ($) =>
- seq($._expression, $._assign_operator, $._expression, ';'),
- _assign_operator: ($) =>
- choice('=', '+=', '/=', '*=', '%=', '-=', '&=', '|=', '^=', '<<=', '>>='),
- match_clause: ($) =>
- seq(choice(seq('case', $._pattern), 'default'), '=>', $.block),
- match_statement: ($) =>
- seq('match', '(', $._expression, ')', '{', repeat($.match_clause), '}'),
- returned_var_statement: ($) => seq('returned', $.var_declaration),
- while_statement: ($) => seq('while', '(', $._expression, ')', $.block),
- break_statement: ($) => seq('break', ';'),
- continue_statement: ($) => seq('continue', ';'),
- return_statement: ($) =>
- seq('return', optional(choice('var', $._expression)), ';'),
- if_statement: ($) =>
- seq('if', '(', $._expression, ')', $.block, optional($.else)),
- else: ($) => choice(seq('else', $.if_statement), seq('else', $.block)),
- for_statement: ($) =>
- seq('for', '(', $._pattern, 'in', $._expression, ')', $.block),
- statement: ($) =>
- choice(
- seq($._expression, ';'),
- $.assign_statement,
- $.var_declaration,
- $.let_declaration,
- $.match_statement,
- $.returned_var_statement,
- $.if_statement,
- $.while_statement,
- $.break_statement,
- $.continue_statement,
- $.return_statement,
- $.for_statement
- ),
- block: ($) => seq('{', repeat($.statement), '}'),
- declared_name: ($) => repeat_sep1($.ident, '.'),
- generic_binding: ($) =>
- seq(optional('template'), $.ident, ':!', $._expression),
- deduced_param: ($) =>
- choice(
- $.generic_binding,
- seq(optional('addr'), 'self', ':', $._expression)
- ),
- deduced_params: ($) => seq('[', comma_sep($.deduced_param), ']'),
- return_type: ($) => seq('->', choice('auto', $._expression)),
- function_declaration: ($) =>
- seq(
- optional(choice('abstract', 'virtual', 'impl')),
- 'fn',
- $.declared_name,
- optional($.deduced_params),
- $.paren_pattern,
- optional($.return_type),
- choice($.block, ';')
- ),
- namespace_declaration: ($) => seq('namespace', $.declared_name, ';'),
- alias_declaration: ($) =>
- seq('alias', $.declared_name, '=', $._expression, ';'),
- type_params: ($) => $.paren_pattern,
- interface_body_item: ($) =>
- choice(
- $.function_declaration,
- seq('let', $.generic_binding, ';'),
- seq('extend', $._expression, ';'),
- seq('require', $._expression, 'impls', $._expression, ';')
- ),
- interface_body: ($) => seq('{', repeat($.interface_body_item), '}'),
- interface_declaration: ($) =>
- seq(
- 'interface',
- $.declared_name,
- optional($.deduced_params),
- optional($.type_params),
- choice(';', $.interface_body)
- ),
- constraint_declaration: ($) =>
- seq(
- 'constraint',
- $.declared_name,
- optional($.deduced_params),
- optional($.type_params),
- choice(';', $.interface_body)
- ),
- impl_body_item: ($) => choice($.function_declaration, $.alias_declaration),
- impl_body: ($) => seq('{', repeat($.impl_body_item), '}'),
- impl_declaration: ($) =>
- seq(
- 'impl',
- optional(seq('forall', $.deduced_params)),
- optional($._expression),
- 'as',
- $._expression,
- $.impl_body
- ),
- extend_impl_declaration: ($) =>
- seq('extend', 'impl', 'as', $._expression, $.impl_body),
- extend_base_declaration: ($) =>
- seq('extend', 'base', ':', $._expression, ';'),
- destructor_declaration: ($) =>
- seq(
- optional(choice('virtual', 'impl')),
- 'destructor',
- optional($.deduced_params),
- choice($.block, ';')
- ),
- class_body_item: ($) =>
- choice(
- $.declaration,
- $.extend_base_declaration,
- $.extend_impl_declaration,
- $.mix_declaration,
- $.destructor_declaration
- ),
- class_body: ($) => seq('{', repeat($.class_body_item), '}'),
- class_declaration: ($) =>
- seq(
- optional(choice('base', 'abstract')),
- 'class',
- $.declared_name,
- optional($.deduced_params),
- optional($.type_params),
- choice(';', $.class_body)
- ),
- choice_declaration: ($) =>
- seq(
- 'choice',
- $.declared_name,
- optional($.type_params),
- '{',
- comma_sep(seq($.ident, optional($.paren_expression))),
- '}'
- ),
- empty_declaration: ($) => ';',
- declaration: ($) =>
- choice(
- $.empty_declaration,
- $.namespace_declaration,
- $.var_declaration,
- $.let_declaration,
- $.function_declaration,
- $.alias_declaration,
- $.interface_declaration,
- $.constraint_declaration,
- $.impl_declaration,
- $.class_declaration,
- $.choice_declaration,
- $.mixin_declaration,
- $.match_first_declaration
- ),
- // Explorer only experimental featurues
- mix_declaration: ($) => seq('__mix', $._expression, ';'),
- mixin_declaration: ($) =>
- seq(
- '__mixin',
- $.declared_name,
- optional($.type_params),
- optional(seq('for', $._expression)),
- '{',
- repeat(choice($.function_declaration, $.mix_declaration)),
- '}'
- ),
- match_first_declaration: ($) =>
- seq('__match_first', '{', repeat($.impl_declaration), '}'),
- },
- });
|