| @ -1,272 +1,275 @@ | |||
| { grammar, rules } = require("tree-sitter-compiler") | |||
| { choice, err, repeat, seq, keyword, optional, token, prec } = rules | |||
| commaSep = (rule) -> | |||
| optional(commaSep1(rule)) | |||
| commaSep1 = (rule) -> | |||
| seq(rule, repeat(seq(",", rule))) | |||
| module.exports = grammar | |||
| name: 'c', | |||
| ubiquitous: -> [@comment, /\s/] | |||
| rules: | |||
| program: -> repeat(choice( | |||
| @preproc_ifdef, | |||
| @preproc_ifndef, | |||
| @preproc_endif, | |||
| @preproc_else, | |||
| @preproc_include, | |||
| @preproc_define, | |||
| @preproc_call, | |||
| # declarations | |||
| @struct_declaration, | |||
| @union_declaration, | |||
| @enum_declaration, | |||
| @function_declaration, | |||
| @var_declaration, | |||
| @typedef, | |||
| )) | |||
| preproc_include: -> seq( | |||
| keyword("#include"), | |||
| choice(@string, @system_lib_string)) | |||
| preproc_define: -> seq( | |||
| keyword("#define"), | |||
| @identifier, | |||
| token(seq(/.+/, repeat(seq("\\\n", /.+/))))) | |||
| preproc_call: -> choice( | |||
| seq(@preproc_directive, /.*/)) | |||
| preproc_ifdef: -> seq(keyword("#ifdef"), @identifier) | |||
| preproc_ifndef: -> seq(keyword("#ifndef"), @identifier) | |||
| preproc_else: -> keyword("#else") | |||
| preproc_endif: -> keyword("#endif") | |||
| preproc_directive: -> /#\a\w+/ | |||
| typedef: -> seq( | |||
| keyword("typedef"), | |||
| @type, | |||
| @type_expression, | |||
| ";") | |||
| var_declaration: -> seq( | |||
| repeat(choice( | |||
| keyword("static"), | |||
| keyword("extern"))), | |||
| @type, | |||
| commaSep1(choice( | |||
| @type_expression, | |||
| @var_assignment)), | |||
| ";") | |||
| function_declaration: -> seq( | |||
| @type, | |||
| @type_expression, | |||
| "(", @formal_parameters, ")", | |||
| choice(";", @statement_block)) | |||
| statement_block: -> seq( | |||
| "{", err(repeat(@statement)), "}") | |||
| statement: -> choice( | |||
| @var_declaration, | |||
| @return_statement, | |||
| @if_statement, | |||
| @for_statement, | |||
| @while_statement, | |||
| @expression_statement, | |||
| @statement_block), | |||
| return_statement: -> seq( | |||
| keyword("return"), @expression, ";") | |||
| expression_statement: -> seq( | |||
| @expression, ";") | |||
| if_statement: -> seq( | |||
| keyword("if"), "(", err(@expression), ")", | |||
| @statement, | |||
| optional(seq( | |||
| keyword("else"), | |||
| @statement))) | |||
| for_statement: -> seq( | |||
| keyword("for"), | |||
| "(", | |||
| choice( | |||
| module.exports = | |||
| ({choice, err, repeat, seq, keyword, optional, token, prec}) -> | |||
| commaSep = (rule) -> | |||
| optional(commaSep1(rule)) | |||
| commaSep1 = (rule) -> | |||
| seq(rule, repeat(seq(",", rule))) | |||
| { | |||
| name: 'c' | |||
| ubiquitous: -> [@comment, /\s/] | |||
| rules: | |||
| program: -> repeat(choice( | |||
| @preproc_ifdef, | |||
| @preproc_ifndef, | |||
| @preproc_endif, | |||
| @preproc_else, | |||
| @preproc_include, | |||
| @preproc_define, | |||
| @preproc_call, | |||
| # declarations | |||
| @struct_declaration, | |||
| @union_declaration, | |||
| @enum_declaration, | |||
| @function_declaration, | |||
| @var_declaration, | |||
| seq(optional(@expression), ";")), | |||
| optional(@expression), ";", | |||
| optional(@expression), | |||
| ")", | |||
| @statement) | |||
| while_statement: -> seq( | |||
| keyword("while"), | |||
| "(", @expression, ")", | |||
| @statement) | |||
| type: -> seq( | |||
| optional(keyword("const")), | |||
| choice( | |||
| @primitive_type, | |||
| @struct_type, | |||
| @enum_type, | |||
| @union_type)) | |||
| primitive_type: -> seq( | |||
| repeat(choice( | |||
| keyword("unsigned"), | |||
| keyword("short"), | |||
| keyword("long"))), | |||
| @identifier) | |||
| formal_parameters: -> | |||
| err(commaSep(@field)) | |||
| type_expression: -> choice( | |||
| @identifier, | |||
| @pointer_type) | |||
| pointer_type: -> seq( | |||
| "*", @type_expression) | |||
| struct_declaration: -> seq( | |||
| @struct_type, ";") | |||
| struct_type: -> seq( | |||
| keyword("struct"), | |||
| choice( | |||
| @identifier, | |||
| seq( | |||
| optional(@identifier), | |||
| "{", err(repeat(seq(@field, ";"))), "}"))) | |||
| union_declaration: -> seq( | |||
| @union_type, ";") | |||
| union_type: -> seq( | |||
| keyword("union"), | |||
| choice( | |||
| @identifier, | |||
| seq( | |||
| optional(@identifier), | |||
| "{", err(repeat(seq(@field, ";"))), "}"))) | |||
| @typedef, | |||
| )) | |||
| enum_declaration: -> seq( | |||
| @enum_type, ";") | |||
| preproc_include: -> seq( | |||
| keyword("#include"), | |||
| choice(@string, @system_lib_string)) | |||
| enum_type: -> seq( | |||
| keyword("enum"), | |||
| choice( | |||
| preproc_define: -> seq( | |||
| keyword("#define"), | |||
| @identifier, | |||
| seq( | |||
| optional(@identifier), | |||
| "{", err(commaSep(@enum_value)), "}"))) | |||
| enum_value: -> seq( | |||
| @identifier, optional(seq("=", @expression))) | |||
| field: -> seq(@type, @type_expression) | |||
| var_assignment: -> seq(@type_expression, "=", @expression) | |||
| type_modifier: -> choice( | |||
| keyword("const")) | |||
| expression: -> choice( | |||
| @bool_op, | |||
| @math_op, | |||
| @rel_op, | |||
| @function_call, | |||
| @compound_literal, | |||
| @number, | |||
| @char, | |||
| @string, | |||
| @deref, | |||
| @address_of, | |||
| @identifier, | |||
| @assignment, | |||
| @field_access, | |||
| @deref_field_access) | |||
| deref: -> prec(10, seq("*", @expression)) | |||
| address_of: -> prec(10, seq("&", @expression)) | |||
| field_access: -> seq( | |||
| @expression, ".", @identifier) | |||
| deref_field_access: -> seq( | |||
| @expression, "->", @identifier) | |||
| function_call: -> seq( | |||
| @expression, "(", err(commaSep(@expression)), ")") | |||
| math_op: -> choice( | |||
| prec(6, seq(@expression, "++")), | |||
| prec(6, seq(@expression, "++")), | |||
| prec(6, seq("-", @expression)), | |||
| prec(5, seq(@expression, "*", @expression)), | |||
| prec(2, seq(@expression, "/", @expression)), | |||
| prec(1, seq(@expression, "+", @expression)), | |||
| prec(1, seq(@expression, "-", @expression))) | |||
| bool_op: -> choice( | |||
| prec(3, seq("!", @expression)), | |||
| prec(2, seq(@expression, "&&", @expression)), | |||
| prec(1, seq(@expression, "||", @expression))) | |||
| rel_op: -> choice( | |||
| prec(1, seq(@expression, "<", @expression)), | |||
| prec(1, seq(@expression, "<=", @expression)), | |||
| prec(1, seq(@expression, "==", @expression)), | |||
| prec(1, seq(@expression, "!=", @expression)), | |||
| prec(1, seq(@expression, ">=", @expression)), | |||
| prec(1, seq(@expression, ">", @expression))) | |||
| assignment: -> prec(-1, seq( | |||
| choice( | |||
| @deref, | |||
| @identifier, | |||
| @field_access, | |||
| @deref_field_access), | |||
| "=", | |||
| @expression)) | |||
| compound_literal: -> seq( | |||
| "(", @type, ")", | |||
| "{", commaSep(choice(@struct_literal_field, @expression)), optional(","), "}") | |||
| token(seq(/.+/, repeat(seq("\\\n", /.+/))))) | |||
| struct_literal_field: -> seq( | |||
| ".", @identifier, | |||
| "=", | |||
| @expression) | |||
| preproc_call: -> choice( | |||
| seq(@preproc_directive, /.*/)) | |||
| number: -> /\d+(\.\d+)?/ | |||
| preproc_ifdef: -> seq(keyword("#ifdef"), @identifier) | |||
| preproc_ifndef: -> seq(keyword("#ifndef"), @identifier) | |||
| preproc_else: -> keyword("#else") | |||
| preproc_endif: -> keyword("#endif") | |||
| char: -> token(seq( | |||
| "'", | |||
| choice( | |||
| seq(optional("\\"), /[^']/), | |||
| seq("\\", "'")), | |||
| "'")) | |||
| preproc_directive: -> /#\a\w+/ | |||
| string: -> token(seq( | |||
| '"', repeat(choice(/[^"]/, '\\"')), '"')) | |||
| system_lib_string: -> token(seq( | |||
| '<', repeat(choice(/[^>]/, '\\>')), '>')) | |||
| typedef: -> seq( | |||
| keyword("typedef"), | |||
| @type, | |||
| @type_expression, | |||
| ";") | |||
| var_declaration: -> seq( | |||
| repeat(choice( | |||
| keyword("static"), | |||
| keyword("extern"))), | |||
| @type, | |||
| commaSep1(choice( | |||
| @type_expression, | |||
| @var_assignment)), | |||
| ";") | |||
| function_declaration: -> seq( | |||
| @type, | |||
| @type_expression, | |||
| "(", @formal_parameters, ")", | |||
| choice(";", @statement_block)) | |||
| identifier: -> /\a\w*/ | |||
| statement_block: -> seq( | |||
| "{", err(repeat(@statement)), "}") | |||
| comment: -> token(choice( | |||
| seq("//", /.*/), | |||
| seq("/*", repeat(choice(/[^\*]/, /\*[^/]/)), "*/"))) | |||
| statement: -> choice( | |||
| @var_declaration, | |||
| @return_statement, | |||
| @if_statement, | |||
| @for_statement, | |||
| @while_statement, | |||
| @expression_statement, | |||
| @statement_block), | |||
| return_statement: -> seq( | |||
| keyword("return"), @expression, ";") | |||
| expression_statement: -> seq( | |||
| @expression, ";") | |||
| if_statement: -> seq( | |||
| keyword("if"), "(", err(@expression), ")", | |||
| @statement, | |||
| optional(seq( | |||
| keyword("else"), | |||
| @statement))) | |||
| for_statement: -> seq( | |||
| keyword("for"), | |||
| "(", | |||
| choice( | |||
| @var_declaration, | |||
| seq(optional(@expression), ";")), | |||
| optional(@expression), ";", | |||
| optional(@expression), | |||
| ")", | |||
| @statement) | |||
| while_statement: -> seq( | |||
| keyword("while"), | |||
| "(", @expression, ")", | |||
| @statement) | |||
| type: -> seq( | |||
| optional(keyword("const")), | |||
| choice( | |||
| @primitive_type, | |||
| @struct_type, | |||
| @enum_type, | |||
| @union_type)) | |||
| primitive_type: -> seq( | |||
| repeat(choice( | |||
| keyword("unsigned"), | |||
| keyword("short"), | |||
| keyword("long"))), | |||
| @identifier) | |||
| formal_parameters: -> | |||
| err(commaSep(@field)) | |||
| type_expression: -> choice( | |||
| @identifier, | |||
| @pointer_type) | |||
| pointer_type: -> seq( | |||
| "*", @type_expression) | |||
| struct_declaration: -> seq( | |||
| @struct_type, ";") | |||
| struct_type: -> seq( | |||
| keyword("struct"), | |||
| choice( | |||
| @identifier, | |||
| seq( | |||
| optional(@identifier), | |||
| "{", err(repeat(seq(@field, ";"))), "}"))) | |||
| union_declaration: -> seq( | |||
| @union_type, ";") | |||
| union_type: -> seq( | |||
| keyword("union"), | |||
| choice( | |||
| @identifier, | |||
| seq( | |||
| optional(@identifier), | |||
| "{", err(repeat(seq(@field, ";"))), "}"))) | |||
| enum_declaration: -> seq( | |||
| @enum_type, ";") | |||
| enum_type: -> seq( | |||
| keyword("enum"), | |||
| choice( | |||
| @identifier, | |||
| seq( | |||
| optional(@identifier), | |||
| "{", err(commaSep(@enum_value)), "}"))) | |||
| enum_value: -> seq( | |||
| @identifier, optional(seq("=", @expression))) | |||
| field: -> seq(@type, @type_expression) | |||
| var_assignment: -> seq(@type_expression, "=", @expression) | |||
| type_modifier: -> choice( | |||
| keyword("const")) | |||
| expression: -> choice( | |||
| @bool_op, | |||
| @math_op, | |||
| @rel_op, | |||
| @function_call, | |||
| @compound_literal, | |||
| @number, | |||
| @char, | |||
| @string, | |||
| @deref, | |||
| @address_of, | |||
| @identifier, | |||
| @assignment, | |||
| @field_access, | |||
| @deref_field_access) | |||
| deref: -> prec(10, seq("*", @expression)) | |||
| address_of: -> prec(10, seq("&", @expression)) | |||
| field_access: -> seq( | |||
| @expression, ".", @identifier) | |||
| deref_field_access: -> seq( | |||
| @expression, "->", @identifier) | |||
| function_call: -> seq( | |||
| @expression, "(", err(commaSep(@expression)), ")") | |||
| math_op: -> choice( | |||
| prec(6, seq(@expression, "++")), | |||
| prec(6, seq(@expression, "--")), | |||
| prec(6, seq("++", @expression)), | |||
| prec(6, seq("--", @expression)), | |||
| prec(6, seq("-", @expression)), | |||
| prec(5, seq(@expression, "*", @expression)), | |||
| prec(2, seq(@expression, "/", @expression)), | |||
| prec(1, seq(@expression, "+", @expression)), | |||
| prec(1, seq(@expression, "-", @expression))) | |||
| bool_op: -> choice( | |||
| prec(3, seq("!", @expression)), | |||
| prec(2, seq(@expression, "&&", @expression)), | |||
| prec(1, seq(@expression, "||", @expression))) | |||
| rel_op: -> choice( | |||
| prec(1, seq(@expression, "<", @expression)), | |||
| prec(1, seq(@expression, "<=", @expression)), | |||
| prec(1, seq(@expression, "==", @expression)), | |||
| prec(1, seq(@expression, "!=", @expression)), | |||
| prec(1, seq(@expression, ">=", @expression)), | |||
| prec(1, seq(@expression, ">", @expression))) | |||
| assignment: -> prec(-1, seq( | |||
| choice( | |||
| @deref, | |||
| @identifier, | |||
| @field_access, | |||
| @deref_field_access), | |||
| "=", | |||
| @expression)) | |||
| compound_literal: -> seq( | |||
| "(", @type, ")", | |||
| "{", commaSep(choice(@struct_literal_field, @expression)), optional(","), "}") | |||
| struct_literal_field: -> seq( | |||
| ".", @identifier, | |||
| "=", | |||
| @expression) | |||
| number: -> /\d+(\.\d+)?/ | |||
| char: -> token(seq( | |||
| "'", | |||
| choice( | |||
| seq(optional("\\"), /[^']/), | |||
| seq("\\", "'")), | |||
| "'")) | |||
| string: -> token(seq( | |||
| '"', repeat(choice(/[^"]/, '\\"')), '"')) | |||
| system_lib_string: -> token(seq( | |||
| '<', repeat(choice(/[^>]/, '\\>')), '>')) | |||
| identifier: -> /\a\w*/ | |||
| comment: -> token(choice( | |||
| seq("//", /.*/), | |||
| seq("/*", repeat(choice(/[^\*]/, /\*[^/]/)), "*/"))) | |||
| } | |||