diff --git a/.gitignore b/.gitignore index 48cf99a..21dbc97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,13 @@ binding.gyp +bindings/node/binding.cc +bindings/node/index.js +bindings/rust/build.rs +bindings/rust/lib.rs +Cargo.lock Cargo.toml +log.html node_modules/ src/grammar.json src/node-types.json src/parser.c src/tree_sitter/parser.h -bindings/node/binding.cc -bindings/node/index.js -bindings/rust/build.rs -bindings/rust/lib.rs diff --git a/corpus/packages.txt b/corpus/packages.txt index 5939a4c..7e4c92b 100644 --- a/corpus/packages.txt +++ b/corpus/packages.txt @@ -1,16 +1,12 @@ ================================================================================ -packages +with clauses ================================================================================ -with Ada.Text_IO; -package P1 is - package Nested is - end Nested; -end P1; - -PriVaTe PACKAGE P2 is -- comment to be ignored -private -end; +with Ada.Text_IO, System; -- multiple names, and fully qualified +limited with Ada; -- limited with +private with Ada; +limited private with Ada; +use Ada.Text_IO, System; -------------------------------------------------------------------------------- @@ -25,57 +21,174 @@ end; (identifier))) (selector_name (direct_name - (identifier)))))))) + (identifier))))) + (name + (direct_name + (identifier)))))) + (comment) (compilation_unit - (package_specification - (identifier) - (package_specification - (identifier) - (identifier)) - (identifier))) + (with_clause + (name_list + (name + (direct_name + (identifier)))))) + (comment) (compilation_unit - (package_specification - (identifier) - (comment)))) + (with_clause + (name_list + (name + (direct_name + (identifier)))))) + (compilation_unit + (with_clause + (name_list + (name + (direct_name + (identifier)))))) + (compilation_unit + (use_clause + (name_list + (name + (selected_component + (name + (direct_name + (identifier))) + (selector_name + (direct_name + (identifier))))) + (name + (direct_name + (identifier))))))) -================================================================================ -Types -================================================================================ +===== +Case insensitive +===== -package P is - type A is range 1 .. 2; - type B is new Integer; -end P; +PACkaGe P1 Is +enD; -------------------------------------------------------------------------------- (compilation (compilation_unit (package_specification - (identifier) - (type_declaration - (full_type_declaration - (identifier) - (type_definition - (integer_type_definition - (signed_integer_type_definition - (simple_expression - (term - (factor - (primary - (numeric_literal))))) - (simple_expression - (term - (factor - (primary - (numeric_literal)))))))))) - (type_declaration - (full_type_declaration - (identifier) - (type_definition - (derived_type_definition - (subtype_indication + (name)))) + +================================================================================ +multiple compilation units +================================================================================ + +package P1 is + package Nested is + end Nested; +end P1; + +private package Child.P2 is -- comment to be ignored +private +end; + +-------------------------------------------------------------------------------- + +(compilation + (compilation_unit + (package_specification + (name + (direct_name + (identifier))) + (package_specification + (name + (direct_name + (identifier))) + (name + (direct_name + (identifier)))) + (name + (direct_name + (identifier))))) + (compilation_unit + (package_specification + (name + (selected_component + (name + (direct_name + (identifier))) + (selector_name + (direct_name + (identifier))))) + (comment)))) + +========= +body +========= + +package body Child.P2 is + package body Nested is + begin + null; + end Nested; +begin + null; +end Child.P2; + +--- +(compilation + (compilation_unit + (proper_body + (package_body + (name + (selected_component + (name + (direct_name + (identifier))) + (selector_name + (direct_name + (identifier))))) + (non_empty_declarative_part + (declarative_item_pragma + (proper_body + (package_body (name (direct_name - (identifier)))))))) - (identifier)))) + (identifier))) + (handled_sequence_of_statements + (sequence_of_statements + (statement + (simple_statement + (null_statement))))) + (name + (direct_name + (identifier))))))) + (handled_sequence_of_statements + (sequence_of_statements + (statement + (simple_statement + (null_statement))))) + (name + (selected_component + (name + (direct_name + (identifier))) + (selector_name + (direct_name + (identifier))))))))) + +================================================================================ +separate +================================================================================ + +separate (Child) package body P2 is +end; + +-------------------------------------------------------------------------------- + +(compilation + (compilation_unit + (subunit + (name + (direct_name + (identifier))) + (proper_body + (package_body + (name + (direct_name + (identifier)))))))) diff --git a/corpus/types.txt b/corpus/types.txt index 5939a4c..7a79588 100644 --- a/corpus/types.txt +++ b/corpus/types.txt @@ -1,50 +1,9 @@ ================================================================================ -packages -================================================================================ - -with Ada.Text_IO; -package P1 is - package Nested is - end Nested; -end P1; - -PriVaTe PACKAGE P2 is -- comment to be ignored -private -end; - --------------------------------------------------------------------------------- - -(compilation - (compilation_unit - (with_clause - (name_list - (name - (selected_component - (name - (direct_name - (identifier))) - (selector_name - (direct_name - (identifier)))))))) - (compilation_unit - (package_specification - (identifier) - (package_specification - (identifier) - (identifier)) - (identifier))) - (compilation_unit - (package_specification - (identifier) - (comment)))) - -================================================================================ -Types +Range type ================================================================================ package P is type A is range 1 .. 2; - type B is new Integer; end P; -------------------------------------------------------------------------------- @@ -52,7 +11,9 @@ end P; (compilation (compilation_unit (package_specification - (identifier) + (name + (direct_name + (identifier))) (type_declaration (full_type_declaration (identifier) @@ -69,6 +30,26 @@ end P; (factor (primary (numeric_literal)))))))))) + (name + (direct_name + (identifier)))))) + +================================================================================ +Derived type +================================================================================ + +package P is + type B is new Integer; +end P; + +-------------------------------------------------------------------------------- + +(compilation + (compilation_unit + (package_specification + (name + (direct_name + (identifier))) (type_declaration (full_type_declaration (identifier) @@ -78,4 +59,6 @@ end P; (name (direct_name (identifier)))))))) - (identifier)))) + (name + (direct_name + (identifier)))))) diff --git a/grammar.js b/grammar.js index 354745f..79d9d8c 100644 --- a/grammar.js +++ b/grammar.js @@ -5,7 +5,7 @@ function toCaseInsensitive(a) { return a; } -function caseInsensitive (keyword) { +function caseInsensitive(keyword) { //return keyword; // Easier to read conflict messages return new RegExp(keyword .split('') @@ -14,6 +14,26 @@ function caseInsensitive (keyword) { ) } +/** + * A list of rules + */ +function list_of(separator, rule) { + return seq( + rule, + repeat(seq( + separator, + rule, + )), + ); +} + +/** + * Handles comma-separated lists of rules + */ +function comma_separated_list_of(rule) { + return list_of(',', rule) +} + module.exports = grammar({ name: 'ada', @@ -22,14 +42,45 @@ module.exports = grammar({ $.comment, ], +// word: $ => $.keyword, word: $ => $.identifier, + conflicts: $ => [ + // "name" can be either a simple name, or a defining_identifier_list +// [$.direct_name, $.defining_identifier_list], + + // "function_specification is" could be either an expression function + // specification, or a function specification + // ??? Maybe we can merge both in the grammar + [$.expression_function_declaration, $.subprogram_specification], + + // ??? Maybe we can merge these + [$.null_procedure_declaration, $.subprogram_specification], + + // "'for' direct_name * 'use'" could also be "'for' name * 'use'" as + // specified in at_clause. + [$.at_clause, $.name], + + // "procedure name is" could be either a procedure specification, or + // a generic_instantiation. + [$.generic_instantiation, $.procedure_specification], + + // Same for "package_specification ;" + [$.generic_package_declaration, $._package_declaration], + + [$.attribute_definition_clause, $.attribute_reference], + [$.record_extension_part, $.derived_type_definition], + + ], + rules: { compilation: $ => repeat( $.compilation_unit, ), - identifier: $ => /[a-zA-Z_]\w*/, + keyword: $ => /[a-zA-Z]+/, + identifier: $ => + /[a-zA-Z\u{80}-\u{10FFFF}][0-9a-zA-Z_\u{80}-\u{10FFFF}]*/u, comment: $ => token(seq('--', /.*/)), string_literal: $ => token(/"[^"]*"/), character_literal: $ => token(/'.'/), @@ -44,8 +95,11 @@ module.exports = grammar({ binary_adding_operator: $ => choice('+', '-', '&'), unary_adding_operator: $ => choice('+', '-'), multiplying_operator: $ => choice('*', '/', 'mod', 'rem'), + tick: $ => choice( + '\'', // But is not the start of a character_literal + ), - name_list: $ => repeat1($.name), + name_list: $ => comma_separated_list_of($.name), name: $ => choice( $.direct_name, $.explicit_dereference, @@ -56,6 +110,7 @@ module.exports = grammar({ $.qualified_expression, '@', ), + defining_identifier_list: $ => comma_separated_list_of($.identifier), direct_name: $ => choice( $.identifier, $.string_literal, @@ -78,14 +133,14 @@ module.exports = grammar({ attribute_reference: $ => choice( seq( $.name, - '\'', + $.tick, $.attribute_designator, ), // $.reduction_attribute_reference, ), // reduction_attribute_reference: $ => seq( // $.value_sequence, -// '\'', +// $.tick, // $.reduction_attribute_designator, // ), reduction_attribute_designator: $ => seq( @@ -178,7 +233,7 @@ module.exports = grammar({ ), qualified_expression: $ => seq( $.name, - '\'', + $.tick, $.aggregate, ), compilation_unit: $ => choice( @@ -222,7 +277,7 @@ module.exports = grammar({ ), package_specification: $ => seq( caseInsensitive('package'), - field('name', $.identifier), + field('name', $.name), // $.defining_program_unit_name), optional($.aspect_specification), caseInsensitive('is'), optional($._basic_declarative_item_list), @@ -231,7 +286,7 @@ module.exports = grammar({ optional($._basic_declarative_item_list), )), caseInsensitive('end'), - field('endname', optional($.identifier)), + field('endname', optional($.name)), ), with_clause: $ => seq( field('is_limited', optional(caseInsensitive('limited'))), @@ -240,6 +295,43 @@ module.exports = grammar({ field('names', $.name_list), ';', ), + use_clause: $ => seq( + caseInsensitive('use'), + optional(seq( + field('is_all', optional(caseInsensitive('all'))), + field('is_type', caseInsensitive('type')), + )), + $.name_list, + ';', + ), + subunit: $ => seq( + caseInsensitive('separate'), + '(', + $.name, + ')', + $.proper_body, + ), + proper_body: $ => choice( +// $.subprogram_body, + $.package_body, +// $.task_body, +// $.protected_body, + ), + package_body: $ => seq( + caseInsensitive('package'), + caseInsensitive('body'), + $.name, + optional($.aspect_specification), + caseInsensitive('is'), + optional($.non_empty_declarative_part), + optional(seq( + caseInsensitive('begin'), + $.handled_sequence_of_statements, + )), + caseInsensitive('end'), + optional($.name), + ';', + ), subtype_indication: $ => seq( optional($.null_exclusion), $.name, @@ -362,38 +454,30 @@ module.exports = grammar({ $.name, // $.allocator, ), - access_definition: $ => choice( - seq( - optional($.null_exclusion), - caseInsensitive('access'), - optional(caseInsensitive('constrant')), - $.name, - ), - seq( - optional($.null_exclusion), - caseInsensitive('access'), - optional(caseInsensitive('protected')), - caseInsensitive('procedure'), -// $.parameter_profile, - ), - seq( - optional($.null_exclusion), - caseInsensitive('access'), - optional(caseInsensitive('protected')), - caseInsensitive('function'), -// $.parameter__and_result_profile, + access_definition: $ => seq( + optional($.null_exclusion), + caseInsensitive('access'), + choice( + seq( + optional(caseInsensitive('constant')), + $.name, + ), + seq( + optional(caseInsensitive('protected')), + caseInsensitive('procedure'), + optional($.non_empty_parameter_profile), + ), + seq( + optional(caseInsensitive('protected')), + caseInsensitive('function'), + $.parameter_and_result_profile, + ), ), ), actual_parameter_part: $ => seq( '(', choice( - seq( - $.parameter_association, - repeat(seq( - ',', - $.parameter_association, - )), - ), + comma_separated_list_of($.parameter_association), // $.conditional_expression, // $.quantified_expression, // $.declare_expression, @@ -437,13 +521,7 @@ module.exports = grammar({ ')', ), record_component_association_list: $ => choice( -// seq( -// $.record_component_association, -// repeat(seq( -// ',', -// $.record_component_association, -// )), -// ), +// comma_separated_list_of($.record_component_association), seq( caseInsensitive('null'), caseInsensitive('record'), @@ -455,11 +533,7 @@ module.exports = grammar({ ), index_constraint: $ => seq( '(', -// $.discrete_range, -// repeat1(seq( -// ',', -// discrete_range, -// )), +// comma_separated_list_of($.discrete_range), ')', ), digits_constraint: $ => seq( @@ -477,12 +551,7 @@ module.exports = grammar({ ), _basic_declarative_item_pragma: $ => choice( $._basic_declarative_item, -// $.pragma_g, - ), - _basic_declarative_item: $ => choice( - $._basic_declaration, - $.aspect_clause, - $.use_clause, + $.pragma_g, ), type_declaration: $ => choice( $.full_type_declaration, @@ -570,16 +639,9 @@ module.exports = grammar({ ':', $.component_definition, // optional($.assign_value), -// optional($.aspect_specification), + optional($.aspect_specification), ';' ), - defining_identifier_list: $ => seq( - $.identifier, - repeat(seq( - ',', - $.identifier, - )), - ), component_definition: $ => seq( optional(caseInsensitive('aliased')), choice( @@ -589,27 +651,399 @@ module.exports = grammar({ ), - // TODO - - abstract_subprogram_declaration: $ => 'foo1', - aspect_clause: $ => "foo2", - aspect_specification: $ => 'foo3', - body_stub: $ => "foo6", - entry_declaration: $ => 'foo7', - exception_declaration: $ => 'foo8', - expression_function_declaration: $ => 'foo9', - generic_declaration: $ => 'foo10', - generic_instantiation: $ => 'foo11', - null_procedure_declaration: $ => 'foo24', - number_declaration: $ => 'foo12', - object_declaration: $ => 'foo13', - proper_body: $ => "foo15", - renaming_declaration: $ => 'foo16', - statement: $ => 'foo17', - subprogram_declaration: $ => 'foo18', - subtype_declaration: $ => 'foo19', - subunit: $ => 'foo20', - use_clause: $ => "foo22", - + abstract_subprogram_declaration: $ => seq( + optional($.overriding_indicator), + $.subprogram_specification, + caseInsensitive('is'), + caseInsensitive('abstract'), + $.aspect_specification, + ';', + ), + array_aggregate: $ => choice( +// $.position_array_aggregate, +// $.null_array_aggregate, +// $.named_array_aggregate, + ), + aspect_association: $ => seq( + $.aspect_mark, + optional(seq( + '=>', + $.aspect_definition, + )), + ), + aspect_clause: $ => choice( + $.attribute_definition_clause, + $.enumeration_representation_clause, + $.record_representation_clause, + $.at_clause, + ), + aspect_definition: $ => choice( + $.expression, + $.global_aspect_definition, + ), + aspect_mark: $ => seq( + $.identifier, + optional(seq( + $.tick, + $.identifier, + )), + ), + aspect_mark_list: $ => comma_separated_list_of($.aspect_association), + aspect_specification: $ => seq( + caseInsensitive('with'), + $.aspect_mark_list, + ), + at_clause: $ => seq( + caseInsensitive('for'), + $.direct_name, + caseInsensitive('use'), + caseInsensitive('at'), + $.expression, + ';', + ), + attribute_definition_clause: $ => seq( + caseInsensitive('for'), + $.name, + $.tick, + $.attribute_designator, + caseInsensitive('use'), + $.expression, + ';', + ), + body_stub: $ => choice( +// $.subprogram_body_stub, +// $.package_body_stub, +// $.task_body_stub, +// $.protected_body_stub, + ), + choice_parameter_specification: $ => $.identifier, // ??? inline + component_clause: $ => seq( + $.name, + caseInsensitive('at'), + field('position', $.expression), + caseInsensitive('range'), + field('first_bit', $.simple_expression), + '..', + field('last_bit', $.simple_expression), + ';', + ), + declarative_item_pragma: $ => choice( + $._declarative_item, + $.pragma_g, + ), + non_empty_declarative_part: $ => repeat1( + $.declarative_item_pragma, + ), + entry_declaration: $ => seq( + optional($.overriding_indicator), + caseInsensitive('entry'), + $.identifier, + optional(seq( + '(', + $.discrete_subtype_definition, + ')', + )), + optional($.non_empty_parameter_profile), + optional($.aspect_specification), + ';', + ), + enumeration_aggregate: $ => $.array_aggregate, // ??? inline + enumeration_representation_clause: $ => seq( + caseInsensitive('for'), + $.name, + caseInsensitive('use'), + $.enumeration_aggregate, + ';', + ), + exception_choice_list: $ => list_of('|', $.exception_choice), + exception_choice: $ => choice( + $.name, + caseInsensitive('others'), + ), + exception_declaration: $ => seq( + $.defining_identifier_list, + ':', + caseInsensitive('exception'), + optional($.aspect_specification), + ';', + ), + exception_handler: $ => seq( + caseInsensitive('when'), + optional(seq( + $.choice_parameter_specification, + ':', + )), + $.exception_choice_list, + '=>', + $.sequence_of_statements, + ), + exception_handler_list: $ => repeat1(choice( + $.exception_handler, + $.pragma_g, + )), + expression_function_declaration: $ => seq( + optional($.overriding_indicator), + $.function_specification, + caseInsensitive('is'), + '(', + $.expression, + ')', + optional($.aspect_specification), + ';', + ), + formal_part: $ => seq( + '(', + $.parameter_specification_list, + ')', + ), + function_specification: $ => seq( + caseInsensitive('function'), + $.name, + $.parameter_and_result_profile, + ), + generic_declaration: $ => choice( + $.generic_subprogram_declaration, + $.generic_package_declaration, + ), + generic_formal_part: $ => seq( + caseInsensitive('generic'), + repeat($.generic_formal_parameter_declaration), + ), + generic_formal_parameter_declaration: $ => choice( +// $.formal_objet_declaration, +// $.formal_type_declaration, +// $.formal_subprogram_declaration, +// $.formal_package_declaration, + $.use_clause, + $.pragma_g, + ), + generic_subprogram_declaration: $ => seq( + $.generic_formal_part, + $.subprogram_specification, + optional($.aspect_specification), + ';', + ), + generic_package_declaration: $ => seq( + $.generic_formal_part, + $.package_specification, + ';', + ), + generic_instantiation: $ => seq( + choice( + caseInsensitive('package'), + seq( + optional($.overriding_indicator), + choice( + caseInsensitive('procedure'), + caseInsensitive('function'), + ), + ), + ), + $.name, + caseInsensitive('is'), + caseInsensitive('new'), + $.name, // includes the generic_actual_part + optional($.aspect_specification), + ';', + ), + global_aspect_definition: $ => choice( + seq( + $.global_mode, +// $.global_designator, + ), +// $.extended_global_aspect_definition, + seq( + '(', + comma_separated_list_of($.global_aspect_element), + ')', + ), + ), + global_aspect_element: $ => choice( + seq( + $.global_mode, + $.global_set, + ), +// $.extended_global_aspect_definition, + ), + global_mode: $ => choice( + $.non_empty_mode, + caseInsensitive('overriding'), + ), + global_set: $ => prec.left( + comma_separated_list_of($.name), // ??? name_list + ), + handled_sequence_of_statements: $ => seq( + $.sequence_of_statements, + optional(seq( + caseInsensitive('exception'), + $.exception_handler_list, + )), + ), + label: $ => seq( + '<<', + field('statement_identifier', $.direct_name), + '>>', + ), + mod_clause: $ => seq( + caseInsensitive('at'), + caseInsensitive('mod'), + $.expression, + ';', + ), + non_empty_mode: $ => choice( + caseInsensitive('in'), + seq( + caseInsensitive('in'), + caseInsensitive('out'), + ), + caseInsensitive('out'), + ), + null_procedure_declaration: $ => seq( + optional($.overriding_indicator), + $.procedure_specification, + caseInsensitive('is'), + caseInsensitive('null'), +// optional($.aspect_specification), + ), + null_statement: $ => seq( + caseInsensitive('null'), + ';', + ), + number_declaration: $ => seq( + $.defining_identifier_list, + ';', + caseInsensitive('constant'), +// $.assign_value, + ';', + ), + object_declaration: $ => choice( + seq( + $.defining_identifier_list, + ':', + caseInsensitive('aliased'), + caseInsensitive('constant'), + choice( + $.subtype_indication, + $.access_definition, +// $.array_type_definition, + ), +// optional($.assign_value), + optional($.aspect_specification), + ';', + ), +// $.single_task_declaration, +// $.single_protected_declaration, + ), + overriding_indicator: $ => seq( + optional(caseInsensitive('not')), + caseInsensitive('overriding'), + ), + non_empty_parameter_profile: $ => // ??? inline + $.formal_part, + parameter_and_result_profile: $ => seq( + optional($.formal_part), + $.result_profile, + ), + parameter_specification: $ => seq( + $.defining_identifier_list, + ':', + optional(caseInsensitive('aliased')), + optional($.non_empty_mode), + optional($.null_exclusion), + $.name, +// optional($.assign_value), + ), + parameter_specification_list: $ => list_of( + ';', + $.parameter_specification, + ), + pragma_g: $ => seq( + caseInsensitive('pragma'), + $.identifier, + optional(seq( + '(', + choice( +// $.pragma_argument_association_list, +// $.conditional_quantified_expression, + ), + ')', + )), + ';' + ), + procedure_specification: $ => seq( + caseInsensitive('procedure'), + $.name, + optional($.non_empty_parameter_profile), + ), + record_representation_clause: $ => prec.left(seq( + caseInsensitive('for'), + $.name, + caseInsensitive('use'), + caseInsensitive('record'), + optional($.mod_clause), + repeat($.component_clause), + caseInsensitive('end'), + caseInsensitive('record'), + optional($.name), + )), + renaming_declaration: $ => choice( +// $.object_renaming_declaration, +// $.exception_renaming_declaration, +// $.package_renaming_declaration, +// $.subprogram_renaming_declaration, +// $.generic_renaming_declaration, + ), + result_profile: $ => seq( + caseInsensitive('return'), + choice( + seq( + optional($.null_exclusion), + $.name, + ), + $.access_definition, + ), + ), + sequence_of_statements: $ => prec.left(seq( + repeat1($.statement), + repeat($.label), + )), + simple_statement: $ => choice( + $.null_statement, +// $.assignment_statement, +// $.exit_statement, +// $.goto_statement, +// $.procedure_call_statement, +// $.simple_return_statement, +// $.requeue_statement, +// $.delay_statement, +// $.abort_statement, +// $.raise_statement, + $.pragma_g, + ), + statement: $ => seq( + repeat($.label), + choice( + $.simple_statement, +// $.compound_statement, + ), + ), + subprogram_declaration: $ => seq( + optional($.overriding_indicator), + $.subprogram_specification, + optional($.aspect_specification), + ';', + ), + subprogram_specification: $ => choice( + $.procedure_specification, + $.function_specification, + ), + subtype_declaration: $ => seq( + caseInsensitive('subtype'), + $.identifier, + caseInsensitive('is'), + $.subtype_indication, + optional($.aspect_specification), + ';', + ), } }); diff --git a/package.json b/package.json index 3d9a949..04a71a5 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "generate": "tree-sitter generate", "test": "tree-sitter generate && tree-sitter test", - "example1": "tree-sitter parse example1.adb" + "update-test": "tree-sitter test --update" }, "main": "bindings/node" }