Parcourir la source

Use new javascript grammar API

pull/2/head
Max Brunsfeld il y a 10 ans
Parent
révision
603224433a
2 fichiers modifiés avec 609 ajouts et 496 suppressions
  1. +0
    -496
      grammar.coffee
  2. +609
    -0
      grammar.js

+ 0
- 496
grammar.coffee Voir le fichier

@ -1,496 +0,0 @@
commaSep = (rule) ->
optional(commaSep1(rule))
commaSep1 = (rule) ->
seq(rule, repeat(seq(",", rule)))
# Avoid conflict between optional trailing comma and the comma separator.
# TODO: maybe abstract this in tree-sitter core somehow
commaSepTrailing = (recurSymbol, rule) ->
choice(rule, seq(recurSymbol, ',', rule))
PREC =
assignment: -1
conditional: -2
default: 0
logical_or: 1
logical_and: 2
inclusive_or: 3
exclusive_or: 4
bitwise_and: 5
equal: 6
relational: 7
sizeof: 8
shift: 9
add: 10
multiply: 11
call: 12
cast: 13
unary: 14
field: 15
subscript: 16
module.exports = grammar
name: 'c'
ubiquitous: -> [@comment, /\s/]
expectedConflicts: -> [
[@_type_specifier, @_expression]
[@_type_specifier, @direct_declarator]
[@sizeof_expression, @cast_expression]
]
rules:
translation_unit: -> repeat(choice(
@_preproc_statement,
@function_definition,
@declaration))
# Section - Preprocesser
_preproc_statement: -> choice(
@preproc_ifdef,
@preproc_include,
@preproc_def,
@preproc_function_def,
@preproc_call)
preproc_include: -> seq(
"#include",
choice(@string_literal, @system_lib_string))
preproc_def: -> seq(
"#define",
@identifier,
optional(@preproc_arg),
'\n')
preproc_function_def: -> seq(
"#define",
@identifier,
@preproc_params,
optional(@preproc_arg),
'\n')
preproc_params: -> seq(
'(',
commaSep(choice(@identifier, '...')),
')')
preproc_call: -> seq(
@preproc_directive,
@preproc_arg)
preproc_arg: -> token(prec(-1, repeat1(choice(/./, "\\\n"))))
preproc_ifdef: -> seq(
choice("#ifdef", "#ifndef"),
@identifier,
err(repeat(choice(
@_preproc_statement,
@function_definition,
@declaration))),
optional(@preproc_else),
"#endif")
preproc_else: -> seq(
"#else",
repeat(choice(
@_preproc_statement,
@function_definition,
@declaration)))
preproc_directive: -> /#\a\w*/
# Section - Main Grammar
function_definition: -> seq(
optional(@_declaration_specifiers),
@_type_specifier,
@_declarator,
@compound_statement)
declaration: -> seq(
err(seq(
optional(@_declaration_specifiers),
@_type_specifier,
commaSep(choice(
@_declarator,
@init_declarator)))),
";")
_declaration_specifiers: -> repeat1(choice(
@storage_class_specifier,
@type_qualifier,
@function_specifier))
_declarator: -> choice(
@pointer_declarator,
@function_declarator,
@array_declarator,
seq('(', @_declarator, ')'),
@identifier,
)
_abstract_declarator: -> choice(
@abstract_pointer_declarator,
@abstract_function_declarator,
@abstract_array_declarator,
prec(1, seq('(', @_abstract_declarator, ')')),
)
pointer_declarator: -> seq('*', @_declarator)
abstract_pointer_declarator: -> seq('*', optional(@_abstract_declarator))
function_declarator: -> prec(1, seq(
@_declarator,
'(',
optional(@parameter_type_list),
')'))
abstract_function_declarator: -> prec(1, seq(
@_abstract_declarator,
'(',
optional(@parameter_type_list),
')'))
array_declarator: -> prec(1, seq(
@_declarator,
'[',
choice(
seq(optional("static"), repeat(@type_qualifier), optional(@_expression)),
seq(repeat(@type_qualifier), "static", @_expression))
']'))
abstract_array_declarator: -> prec(1, seq(
optional(@_abstract_declarator),
'[',
choice(
seq(optional("static"), repeat(@type_qualifier), optional(@_expression)),
seq(repeat(@type_qualifier), "static", @_expression))
']'))
init_declarator: -> seq(
@_declarator,
"=",
choice(@initializer_list, @_expression))
compound_statement: -> seq(
"{",
err(repeat(choice(@declaration, @_statement))),
"}")
storage_class_specifier: -> choice(
"typedef",
"extern",
"static" ,
"auto",
"register")
type_qualifier: -> choice(
"const",
"restrict",
"volatile")
function_specifier: -> "inline"
_type_specifier: -> choice(
@struct_specifier,
@union_specifier,
@enum_specifier,
@sized_type_specifier,
@identifier)
sized_type_specifier: -> seq(
repeat1(choice(
"unsigned",
"long",
"short")),
@identifier)
enum_specifier: -> seq(
"enum",
choice(
@identifier,
seq(
optional(@identifier),
"{",
@_enum_specifier_contents,
optional(',')
"}")))
_enum_specifier_contents: -> commaSepTrailing(
@_enum_specifier_contents,
@enumerator)
struct_specifier: -> seq(
"struct",
choice(
@identifier,
seq(
optional(@identifier),
"{", repeat(@struct_declaration), "}")))
union_specifier: -> seq(
"union",
choice(
@identifier,
seq(
optional(@identifier),
"{", repeat(@struct_declaration), "}")))
struct_declaration: -> seq(
repeat(@type_qualifier),
@_type_specifier,
commaSep(@_declarator),
optional(seq(':', @_expression))
";")
enumerator: -> choice(
@identifier,
seq(@identifier, "=", @_expression))
parameter_type_list: -> commaSep1(choice(@parameter_declaration, '...'))
parameter_declaration: -> seq(
optional(@_declaration_specifiers),
@_type_specifier,
optional(choice(@_declarator, @_abstract_declarator)))
# Statements
_statement: -> choice(
@labeled_statement,
@compound_statement,
@expression_statement,
@if_statement,
@switch_statement,
@case_statement,
@do_statement,
@while_statement,
@for_statement,
@return_statement,
@break_statement,
@continue_statement,
@goto_statement)
labeled_statement: -> seq(
@identifier,
":",
@_statement)
expression_statement: -> seq(
optional(@_expression), ";")
if_statement: -> prec.right(seq(
"if",
"(", @_expression, ")",
@_statement,
optional(seq(
"else",
@_statement))))
switch_statement: -> seq(
"switch",
"(", @_expression, ")",
@_statement)
case_statement: -> seq(
choice(
seq("case", @_expression),
"default"),
":",
@_statement)
while_statement: -> seq(
"while",
"(", @_expression, ")",
@_statement)
do_statement: -> seq(
"do",
@_statement,
"while",
"(", @_expression, ")")
for_statement: -> seq(
"for",
"(",
choice(
@declaration,
seq(optional(@_expression), ";")),
optional(@_expression), ";"
commaSep(@_expression),
")",
@_statement)
return_statement: -> seq(
"return",
optional(@_expression)
";")
break_statement: -> seq(
"break", ";")
continue_statement: -> seq(
"continue", ";")
goto_statement: -> seq(
"goto", @identifier, ";")
# Expressions
_expression: -> choice(
@conditional_expression,
@assignment_expression,
@logical_expression,
@bitwise_expression,
@equality_expression,
@relational_expression,
@shift_expression,
@math_expression,
@cast_expression,
@pointer_expression,
@sizeof_expression,
@subscript_expression,
@call_expression,
@field_expression,
@compound_literal_expression,
@identifier,
@number_literal,
@string_literal,
@char_literal,
seq("(", err(@_expression), ")"))
conditional_expression: -> prec.right(PREC.conditional, seq(
@_expression,
"?",
@_expression,
":",
@_expression))
assignment_expression: ->
prec.right(PREC.assignment, seq(
@_expression,
choice(
"=",
"*=",
"/=",
"%=",
"+=",
"-=",
"<<=",
">>=",
"&=",
"^=",
"|="),
@_expression))
pointer_expression: -> choice(
prec.left(PREC.unary, seq("*", @_expression)),
prec.left(PREC.unary, seq("&", @_expression)))
logical_expression: -> choice(
prec.left(PREC.logical_or, seq(@_expression, "||", @_expression)),
prec.left(PREC.logical_and, seq(@_expression, "&&", @_expression)),
prec.left(PREC.unary, seq("!", @_expression)))
bitwise_expression: -> choice(
prec.left(PREC.inclusive_or, seq(@_expression, "|", @_expression)),
prec.left(PREC.exclusive_or, seq(@_expression, "^", @_expression)),
prec.left(PREC.bitwise_and, seq(@_expression, "&", @_expression)),
prec.left(PREC.unary, seq("~", @_expression)))
equality_expression: ->
prec.left(PREC.equal, seq(@_expression, choice("==", "!="), @_expression))
relational_expression: ->
prec.left(PREC.relational, seq(@_expression, choice("<", ">", "<=", ">="), @_expression))
shift_expression: ->
prec.left(PREC.shift, seq(@_expression, choice("<<", ">>"), @_expression))
math_expression: -> choice(
prec.left(PREC.add, seq(@_expression, "+", @_expression)),
prec.left(PREC.add, seq(@_expression, "-", @_expression)),
prec.left(PREC.multiply, seq(@_expression, "*", @_expression)),
prec.left(PREC.multiply, seq(@_expression, "/", @_expression)),
prec.left(PREC.multiply, seq(@_expression, "%", @_expression)),
prec.right(PREC.unary, seq("-", @_expression)),
prec.right(PREC.unary, seq("+", @_expression)),
prec.right(PREC.unary, seq(choice("--", "++"), @_expression)),
prec.right(PREC.unary, seq(@_expression, choice("++", "--"))))
cast_expression: ->
prec(PREC.cast, seq("(", @type_name, ")", @_expression))
sizeof_expression: -> choice(
prec(PREC.sizeof, seq("sizeof", @_expression)),
prec(PREC.sizeof, seq("sizeof", "(", @type_name, ")")))
subscript_expression: ->
prec(PREC.subscript, seq(@_expression, "[", @_expression, "]"))
call_expression: ->
prec(PREC.call, seq(@_expression, "(", commaSep(@_expression), ")"))
field_expression: -> choice(
prec.left(PREC.field, seq(@_expression, ".", @_expression)),
prec.left(PREC.field, seq(@_expression, "->", @_expression)))
compound_literal_expression: -> seq(
prec(PREC.cast, seq("(", @type_name, ")")),
@initializer_list)
type_name: -> seq(
repeat(@type_qualifier),
@_type_specifier,
optional(@_abstract_declarator))
initializer_list: -> seq(
"{",
@_initializer_list_contents,
optional(",")
"}")
_initializer_list_contents: -> commaSepTrailing(
@_initializer_list_contents,
seq(
optional(seq(repeat1(@designator), "=")),
choice(@_expression, @initializer_list)))
designator: -> choice(
seq("[", @_expression, "]"),
seq(".", @identifier))
initializer: -> choice(
@_expression,
@initializer_list)
number_literal: -> token(choice(
/\d+(\.\d+)?/,
/\d+u/,
seq("0x", /[0-9a-fA-f]+/),
seq("0b", /[01]+/),
))
char_literal: -> token(seq(
"'",
choice(
seq(optional("\\"), /[^']/),
seq("\\", "'")),
"'"))
string_literal: -> token(seq(
'"', repeat(choice(/[^"]/, '\\"')), '"'))
system_lib_string: -> token(seq(
'<', repeat(choice(/[^>]/, '\\>')), '>'))
identifier: -> /[\a_][\a\d_]*/
comment: -> token(choice(
seq("//", /.*/),
seq("/*", repeat(choice(/[^\*]/, /\*[^/]/)), "*/")))

+ 609
- 0
grammar.js Voir le fichier

@ -0,0 +1,609 @@
const PREC = {
ASSIGNMENT: -1,
CONDITIONAL: -2,
DEFAULT: 0,
LOGICAL_OR: 1,
LOGICAL_AND: 2,
INCLUSIVE_OR: 3,
EXCLUSIVE_OR: 4,
BITWISE_AND: 5,
EQUAL: 6,
RELATIONAL: 7,
SIZEOF: 8,
SHIFT: 9,
ADD: 10,
MULTIPLY: 11,
CALL: 12,
CAST: 13,
UNARY: 14,
FIELD: 15,
SUBSCRIPT: 16,
};
module.exports = grammar({
name: 'c',
extras: $ => [
/\s/,
$.comment,
],
conflicts: $ => [
[$._type_specifier, $._expression],
[$._type_specifier, $.direct_declarator],
[$.sizeof_expression, $.cast_expression],
],
rules: {
translation_unit: $ => repeat(choice(
$._preproc_statement,
$.function_definition,
$.declaration
)),
// Preprocesser
_preproc_statement: $ => choice(
$.preproc_ifdef,
$.preproc_include,
$.preproc_def,
$.preproc_function_def,
$.preproc_call
),
preproc_include: $ => seq(
'#include',
choice(
$.string_literal,
$.system_lib_string
)
),
preproc_def: $ => seq(
'#define',
$.identifier,
optional($.preproc_arg),
'\n'
),
preproc_function_def: $ => seq(
'#define',
$.identifier,
$.preproc_params,
optional($.preproc_arg),
'\n'
),
preproc_params: $ => seq(
'(', commaSep(choice($.identifier, '...')), ')'
),
preproc_call: $ => seq(
$.preproc_directive,
$.preproc_arg
),
preproc_arg: $ => token(prec(-1, repeat1(choice(/./, '\\\n')))),
preproc_ifdef: $ => seq(
choice('#ifdef', '#ifndef'),
$.identifier,
err(repeat(choice(
$._preproc_statement,
$.function_definition,
$.declaration
))),
optional($.preproc_else),
'#endif'
),
preproc_else: $ => seq(
'#else',
repeat(choice(
$._preproc_statement,
$.function_definition,
$.declaration
))
),
preproc_directive: $ => (/#\a\w*/),
// Main Grammar
function_definition: $ => seq(
optional($._declaration_specifiers),
$._type_specifier,
$._declarator,
$.compound_statement
),
declaration: $ => seq(
err(seq(
optional($._declaration_specifiers),
$._type_specifier,
commaSep(choice(
$._declarator,
$.init_declarator)))),
';'),
_declaration_specifiers: $ => repeat1(choice(
$.storage_class_specifier,
$.type_qualifier,
$.function_specifier
)),
_declarator: $ => choice(
$.pointer_declarator,
$.function_declarator,
$.array_declarator,
seq('(', $._declarator, ')'),
$.identifier
),
_abstract_declarator: $ => choice(
$.abstract_pointer_declarator,
$.abstract_function_declarator,
$.abstract_array_declarator,
prec(1, seq('(', $._abstract_declarator, ')'))
),
pointer_declarator: $ => seq(
'*', $._declarator
),
abstract_pointer_declarator: $ => seq(
'*',
optional($._abstract_declarator)
),
function_declarator: $ => prec(1, seq(
$._declarator,
'(',
optional($.parameter_type_list),
')'
)),
abstract_function_declarator: $ => prec(1, seq(
$._abstract_declarator,
'(',
optional($.parameter_type_list),
')'
)),
array_declarator: $ => prec(1, seq(
$._declarator,
'[',
choice(
seq(optional('static'), repeat($.type_qualifier), optional($._expression)),
seq(repeat($.type_qualifier), 'static', $._expression)
),
']'
)),
abstract_array_declarator: $ => prec(1, seq(
optional($._abstract_declarator),
'[',
choice(
seq(optional('static'), repeat($.type_qualifier), optional($._expression)),
seq(repeat($.type_qualifier), 'static', $._expression)
),
']'
)),
init_declarator: $ => seq(
$._declarator,
'=',
choice($.initializer_list, $._expression)
),
compound_statement: $ => seq(
'{',
err(repeat(choice($.declaration, $._statement))),
'}'
),
storage_class_specifier: $ => choice(
'typedef',
'extern',
'static' ,
'auto',
'register'
),
type_qualifier: $ => choice(
'const',
'restrict',
'volatile'
),
function_specifier: $ => 'inline',
_type_specifier: $ => choice(
$.struct_specifier,
$.union_specifier,
$.enum_specifier,
$.sized_type_specifier,
$.identifier
),
sized_type_specifier: $ => seq(
repeat1(choice(
'unsigned',
'long',
'short'
)),
$.identifier
),
enum_specifier: $ => seq(
'enum',
choice(
$.identifier,
seq(
optional($.identifier),
'{',
$._enum_specifier_contents,
optional(','),
'}'
)
)
),
_enum_specifier_contents: $ => commaSepTrailing(
$._enum_specifier_contents,
$.enumerator
),
struct_specifier: $ => seq(
'struct',
choice(
$.identifier,
seq(
optional($.identifier),
'{',
repeat($.struct_declaration),
'}'
)
)
),
union_specifier: $ => seq(
'union',
choice(
$.identifier,
seq(
optional($.identifier),
'{',
repeat($.struct_declaration),
'}'
)
)
),
struct_declaration: $ => seq(
repeat($.type_qualifier),
$._type_specifier,
commaSep($._declarator),
optional(seq(':', $._expression)),
';'
),
enumerator: $ => choice(
$.identifier,
seq($.identifier, '=', $._expression)
),
parameter_type_list: $ => commaSep1(choice(
$.parameter_declaration,
'...'
)),
parameter_declaration: $ => seq(
optional($._declaration_specifiers),
$._type_specifier,
optional(choice($._declarator, $._abstract_declarator))
),
// Statements
_statement: $ => choice(
$.labeled_statement,
$.compound_statement,
$.expression_statement,
$.if_statement,
$.switch_statement,
$.case_statement,
$.do_statement,
$.while_statement,
$.for_statement,
$.return_statement,
$.break_statement,
$.continue_statement,
$.goto_statement
),
labeled_statement: $ => seq(
$.identifier,
':',
$._statement
),
expression_statement: $ => seq(
optional($._expression), ';'
),
if_statement: $ => prec.right(seq(
'if',
'(', $._expression, ')',
$._statement,
optional(seq(
'else',
$._statement
))
)),
switch_statement: $ => seq(
'switch',
'(', $._expression, ')',
$._statement
),
case_statement: $ => seq(
choice(
seq('case', $._expression),
'default'
),
':',
$._statement
),
while_statement: $ => seq(
'while',
'(', $._expression, ')',
$._statement
),
do_statement: $ => seq(
'do',
$._statement,
'while',
'(', $._expression, ')'
),
for_statement: $ => seq(
'for',
'(',
choice(
$.declaration,
seq(optional($._expression), ';')
),
optional($._expression), ';',
commaSep($._expression),
')',
$._statement
),
return_statement: $ => seq(
'return',
optional($._expression),
';'
),
break_statement: $ => seq(
'break', ';'
),
continue_statement: $ => seq(
'continue', ';'
),
goto_statement: $ => seq(
'goto', $.identifier, ';'
),
// Expressions
_expression: $ => choice(
$.conditional_expression,
$.assignment_expression,
$.logical_expression,
$.bitwise_expression,
$.equality_expression,
$.relational_expression,
$.shift_expression,
$.math_expression,
$.cast_expression,
$.pointer_expression,
$.sizeof_expression,
$.subscript_expression,
$.call_expression,
$.field_expression,
$.compound_literal_expression,
$.identifier,
$.number_literal,
$.string_literal,
$.char_literal,
seq('(', err($._expression), ')')
),
conditional_expression: $ => prec.right(PREC.CONDITIONAL, seq(
$._expression,
'?',
$._expression,
':',
$._expression
)),
assignment_expression: $ => prec.right(PREC.ASSIGNMENT, seq(
$._expression,
choice(
'=',
'*=',
'/=',
'%=',
'+=',
'-=',
'<<=',
'>>=',
'&=',
'^=',
'|='
),
$._expression
)),
pointer_expression: $ => choice(
prec.left(PREC.UNARY, seq('*', $._expression)),
prec.left(PREC.UNARY, seq('&', $._expression))
),
logical_expression: $ => choice(
prec.left(PREC.LOGICAL_OR, seq($._expression, '||', $._expression)),
prec.left(PREC.LOGICAL_AND, seq($._expression, '&&', $._expression)),
prec.left(PREC.UNARY, seq('!', $._expression))
),
bitwise_expression: $ => choice(
prec.left(PREC.INCLUSIVE_OR, seq($._expression, '|', $._expression)),
prec.left(PREC.EXCLUSIVE_OR, seq($._expression, '^', $._expression)),
prec.left(PREC.BITWISE_AND, seq($._expression, '&', $._expression)),
prec.left(PREC.UNARY, seq('~', $._expression))
),
equality_expression: $ => prec.left(PREC.EQUAL, seq(
$._expression, choice('==', '!='), $._expression
)),
relational_expression: $ => prec.left(PREC.RELATIONAL, seq(
$._expression, choice('<', '>', '<=', '>='), $._expression
)),
shift_expression: $ => prec.left(PREC.SHIFT, seq(
$._expression, choice('<<', '>>'), $._expression)
),
math_expression: $ => choice(
prec.left(PREC.ADD, seq($._expression, '+', $._expression)),
prec.left(PREC.ADD, seq($._expression, '-', $._expression)),
prec.left(PREC.MULTIPLY, seq($._expression, '*', $._expression)),
prec.left(PREC.MULTIPLY, seq($._expression, '/', $._expression)),
prec.left(PREC.MULTIPLY, seq($._expression, '%', $._expression)),
prec.right(PREC.UNARY, seq('-', $._expression)),
prec.right(PREC.UNARY, seq('+', $._expression)),
prec.right(PREC.UNARY, seq(choice('--', '++'), $._expression)),
prec.right(PREC.UNARY, seq($._expression, choice('++', '--')))
),
cast_expression: $ => prec(PREC.CAST, seq(
'(', $.type_name, ')', $._expression
)),
sizeof_expression: $ => choice(
prec(PREC.SIZEOF, seq('sizeof', $._expression)),
prec(PREC.SIZEOF, seq('sizeof', '(', $.type_name, ')'))
),
subscript_expression: $ => prec(PREC.SUBSCRIPT, seq(
$._expression, '[', $._expression, ']')
),
call_expression: $ => prec(PREC.CALL, seq(
$._expression, '(', commaSep($._expression), ')')
),
field_expression: $ => choice(
prec.left(PREC.FIELD, seq($._expression, '.', $._expression)),
prec.left(PREC.FIELD, seq($._expression, '->', $._expression))
),
compound_literal_expression: $ => seq(
prec(PREC.CAST, seq('(', $.type_name, ')')),
$.initializer_list
),
type_name: $ => seq(
repeat($.type_qualifier),
$._type_specifier,
optional($._abstract_declarator)
),
initializer_list: $ => seq(
'{',
$._initializer_list_contents,
optional(','),
'}'
),
_initializer_list_contents: $ => commaSepTrailing(
$._initializer_list_contents,
seq(
optional(seq(repeat1($.designator), '=')),
choice($._expression, $.initializer_list)
)
),
designator: $ => choice(
seq('[', $._expression, ']'),
seq('.', $.identifier)
),
initializer: $ => choice(
$._expression,
$.initializer_list
),
number_literal: $ => token(choice(
/\d+(\.\d+)?/,
/\d+u/,
seq('0x', /[0-9a-fA-f]+/),
seq('0b', /[01]+/)
)),
char_literal: $ => token(seq(
'\'',
choice(
seq(optional('\\'), /[^']/),
seq('\\', '\'')
),
'\''
)),
string_literal: $ => token(seq(
'"',
repeat(choice(/[^"]/, '\\"')),
'"')
),
system_lib_string: $ => token(seq(
'<',
repeat(choice(/[^>]/, '\\>')),
'>')
),
identifier: $ => (/[\a_][\a\d_]*/),
comment: $ => token(choice(
seq(
'//',
/.*/
),
seq(
'/*',
repeat(choice(/[^\*]/, /\*[^/]/)),
'*/'
)
)),
}
});
function commaSep (rule) {
return optional(commaSep1(rule))
}
function commaSep1 (rule) {
return seq(rule, repeat(seq(',', rule)))
}
function commaSepTrailing (recurSymbol, rule) {
return choice(rule, seq(recurSymbol, ',', rule))
}

Chargement…
Annuler
Enregistrer