const PREC = { CONSTANT_INTERFACE: 3, VARIABLE_INTERFACE: 2, SIGNAL_INTERFACE: 1, ILLEGAL_INTERFACE: -3, }; // 15.2 Character set const RANGE_ATTRIBUTE_DESIGNATOR = [ 'range', 'reverse_range' ]; const PREDEFINED_ATTRIBUTE_DESIGNATOR = [ 'base', 'left', 'right', 'high', 'low', 'image', 'pos', 'val', 'succ', 'pred', 'leftof', 'rightof', 'subtype', 'length', 'ascending', 'descending', 'element', 'delayed', 'stable', 'quiet', 'transaction', 'event', 'active', 'last_event', 'last_active', 'last_value', 'driving', 'driving_value', 'simple_name', 'instance_name', 'path_name', ]; const PREDEFINED_ATTRIBUTE_DESIGNATOR_WITH_EXPRESSION = [ 'image', 'value', 'pos', 'val', 'succ', 'pred', 'leftof', 'rightof', 'left', 'right', 'high', 'low', 'length', 'ascending', 'delayed', 'stable', 'quiet' ]; const EXPONENT = seq( choice('e','E'), optional(choice('+','-')), repeat(/[0-9_]/), ); module.exports = grammar({ name: 'vhdl', word: $ => $.basic_identifier, extras: $ => [ // {{{ $.comment, $.tool_directive, /\s/, ], // }}} inline: $ => [ // {{{ $._entity_name, // 3.2 $._generate_specification, // 3.4 $._configuration_item, // 3.4.2 $._block_specification, // 3.4.2 $._designator, // 4.2.1 $._subprogram_declaration, // 4.2.1 $._subprogram_kind, // 4.3 $._subprogram_body, // 4.3 $._subprogram_instantiation_declaration, // 4.4 $._uninstantiated_name, // 4.4 $._package_name, // 4.8 $._scalar_type_definition, // 5.2.1 $._range, // 5.2.1 $._range_attribute_name, // 5.2.1 $._numeric_type_definition, // 5.2.1 $._unit, // 5.2.4 $._discrete_range, // 5.3.2 $._object_declaration, // 6 $._constraint, // 6.3 $._element_constraint, // 6.3 $._resolution_indication, // 6.3 $._generic_interface_declaration, // 6.5 $._port_interface_declaration, // 6.5 $._procedure_interface_declaration, // 6.5 $._function_interface_declaration, // 6.5 $._alias_denotator, // 6.6 $._illegal_interface_declaration, // 6.5.2 $._subprogram_interface_declaration, // 6.5.4 $._formal_part, // 6.5.7 $._actual_part, // 6.5.7 $._generic_interface_list, // 6.5.6.1 $._port_interface_list, // 6.5.6.1 $._procedure_parameter_list, // 6.5.6.1 $._function_parameter_list, // 6.5.6.1 $._clause, // HEADER $._group_template, // 6.10 $._group_constituent, // 6.10 $._component_name, // 7.3 $._name, // 8 $._range_attribute_designator, // 8.6 $._external_object_name, // 8.7 $._name_or_label, // 8.7 $._external_pathname, // 8.7 $._expression, // 9.1 $._condition, // 9.1 $._simple_expression, // 9.1 $._string_expression, // 9.1 $._severity_expression, // 9.1 $._file_open_kind, // 9.1 $._time_expression, // 9.1 $._literal, // 9.3.2 $._numeric_literal, // 9.3.2 $._element_association, // 9.3.3 $._value, // 9.3.3 $._choice, // 9.3.3 $._function_name, // 9.3.4 $._signal_name, // 10.2 $._sensitivity_clause, // 10.2 $._condition_clause, // 10.2 $._timeout_clause, // 10.2 $._signal_assignment_statement, // 10.5 $._simple_signal_assignment, // 10.5.2 $._conditional_signal_assignment, // 10.5.3 $._selected_signal_assignment, // 10.5.4 $._variable_assignment_statement, // 10.6 $._iteration_scheme, // 10.10 $._concurrent_signal_assignment, // 11.6 $._generate_statement, // 11.8 $._library_unit, // 13.1 $._digit, // 15.5.2 $._digit_immed, // 15.5.2 $._identifier, // 14.4 $._abstract_literal, // 15.5 // PSL $._PSL_Identifier, // PSL $._PSL_Boolean, // PSL 5 $._PSL_Any_Type, // PSL 5 $._PSL_Clock_Expression, // PSL 5.3 $._PSL_Value, // PSL 5 $._PSL_FL_Property, // PSL 6.2 $._PSL_Property, // PSL 6.2 $._PSL_HDL_Module_NAME, // PSL 7.2 ], // }}} conflicts: $ => [ // {{{ // 'procedure' _identifier • 'is' … // // procedure_declaration: // procedure foo is begin end procedure; // procedure_declaration: // procedure foo is new bar; [$._procedure_specification, $.procedure_instantiation_declaration], [$._function_specification , $.function_instantiation_declaration ], // NOTE: This conflict can be solved inlining the rules, but there // is a large penalty on the generated parser size (that is already // quite large) // function_call (positional_association_element) // ambiguous_name (expression_list) // // _name '(' _expression ')' // // `foo ('+')` -> function_call (see _actual_part) // `foo ("str")` -> function_call (see _actual_part) [$.positional_association_element, $.expression_list], [$.positional_association_element, $.group_constituent_list, $._primary], // `(id (discrete_range))` // slice name: // `assert (arr (id'range))` // subtype indication // `assert new rec (elem (id'range));` [$.index_constraint, $.slice_name], // '(' _simple_name '(' _simple_name • ')' … // resolution_function: // assert new subtype_st (resolve_fun type_t); // ^^^^^^^^^^^ // type_mark: // assert new subtype_st (type_t object'range); // ^^^^^^ // Unsure when _expression is used [$.resolution_function, $.type_mark, $._primary], // type_mark is ambiguos with simple_name in many contexts [$.type_mark, $._primary], [$.type_mark, $._primary, $.entity_instantiation], [$.type_mark, $._primary, $.PSL_Hierarchical_HDL_Name], [$.type_mark, $.function_call], [$.type_mark, $.ambiguous_name, $.function_call], [$.type_mark, $.ambiguous_name, $.function_call, $.slice_name], [$.type_mark, $.ambiguous_name, $.function_call, $.slice_name, $.record_element_resolution, $.type_mark], // _simple_name • ''' … // // attribute_name: // `assert foo'bar;` // qualified_expression: // `assert foo'(bar);` [$.attribute_name, $.type_mark], [$.attribute_name, $._primary], [$._predefined_designator, $._predefined_designator_with_expression], // '(' _simple_name • ''' … // // type_mark: // assert (foo'(bar), ...); // attribute_name: // assert (foo'bar, ...); // range_attribute_name // assert (foo'range, ...); [$.attribute_name, $.range_attribute_name, $.type_mark], // '(' _name '(' open • ')' ... // // function call: // `assert (fun (fun (open)))` // subtype indication // `assert new rec (elem (open));` // [$.positional_association_element, $.index_constraint], [$.positional_association_element, $._primary], [$.named_association_element, $._primary], // 6.2 // map clauses and map aspects shall or shall not be // followed by semicolon depending on the context [$.generic_clause], [$.port_clause], [$.procedure_parameter_clause], [$.function_parameter_clause], [$.generic_map_aspect], [$.port_map_aspect], // interfaces declarations defaults depends on context // see corpus/interface_lists/ [$.constant_interface_declaration, $.signal_interface_declaration, $.variable_interface_declaration ], [$._constant_mode, $._signal_mode, $._variable_mode], // Generate statement body // see corpus/declarations/generate.txt // If generate - Generate body - If [$.if_generate], [$.else_generate], [$.elsif_generate], [$.elsif_generate], [$.generate_statement_body], [$.case_generate_alternative], // `assert id // `restrict id;` [$.PSL_Instance, $._simple_name], [$._PSL_Property_Instance, $._PSL_Sequence_Instance, $._PSL_Ambiguous_Instance], [$._PSL_Property_Instance, $._PSL_Sequence_Instance], [$.PSL_Property_Replicator], [$.PSL_Property_Declaration], // assert '{' ... '}' [$._PSL_Compound_SERE, $._PSL_Sequence], [$.configuration_specification], ], // }}} precedences: () => [ // {{{ // Top level precedence // Used when declarations and/or statements are outside of sequential // statements, library unit or context clause. // Use case: snippets of code on web (eg. declarative part w/o body) [ 'declaration' , 'primary_unit' ], [ 'declaration' , 'secondary_unit' ], [ 'declaration' , 'context_item' ], [ 'concurrent_statement' , 'sequential_statement'], [ 'concurrent_statement' , 'declaration' ], // Component declarations vs component instantiation [ 'component_declaration', 'simple_name' ], // This following relation is ambiguos. Usually procedure_call_statement, // but component_instantiation is also legal. [ 'procedure_call', 'component_instantiation' ], // Expanded name // Subtype indication [ 'record_element_constraint' , 'type_mark' ], [ 'record_element_resolution' , 'resolution_function' ], [ 'type_mark' , 'resolution_function' ], [ 'primary' , 'resolution_function' ], // Physical literal [ 'primary' , 'physical_literal' ], [ 'attribute_name' , 'physical_literal' ], // Group constituent [ 'group_constituent_list' , 'primary' ], [ 'group_constituent_list' , 'type_mark' ], // Generate statatement element [ 'generate_statement_element', 'primary' ], // Incomplete selected assignment // Assertion // NOTE // VHDL LRM states that ambiguos VHDL/PSL assertions shall // be parsed as VHDL assertion [ 'vhdl_assertion', 'psl_assertion' ], // VHDL operands precedence [ 'range', 'exponentiation', 'factor', 'term', 'sign', 'simple_expression', 'shift_expression', 'relation', 'logical_expression', 'reduction', 'condition', ], // PSL operands precedence [ 'union', 'clocked', 'SERE_repetition', 'sequence_within', 'sequence_and', 'sequence_or', 'sequence_fusion', 'sequence_concatenation', 'termination_property', 'occurrence_property', 'bounding_property', 'sequence_implication', 'property_implication', 'invariant_property', ], [ // "next" "(" ... ")" is psl function 'psl_function_call', 'parenthesized_boolean', 'parenthesized_expression', 'occurrence_property', 'parenthesized_property', ], // Conflicts between VHDL expression and PSL expression [ 'logical_expression', 'logical_property' ], [ 'factor' , 'property_factor' ], // PSL Expression implication has the same precedence as // VHDL expressions, therefore property_implication shall // have lower precedence than implication. [ 'implication', 'property_implication' ], ], // }}} rules: { design_file: $ => repeat(choice( $._declaration, $._sequential_statement, $._concurrent_statement, $.design_unit )), // 3.2 Entity declarations {{{ entity_declaration: $ => seq( reservedWord('entity'), field('name',$._identifier), reservedWord('is'), optional(alias($._header,$.entity_header)), optional($.declarative_part), optional(seq( reservedWord('begin'), optional($.concurrent_statement_part) )), reservedWord('end'), optional(reservedWord('entity')), optional($._end_simple_name), ';' ), _entity_name: $ => field('entity', choice( $._simple_name, $.selected_name )), // }}} // 3.3 Architecture bodies {{{ architecture_body: $ => seq( reservedWord('architecture'), field('name',$._identifier), reservedWord('of'), $._entity_name, reservedWord('is'), optional($.declarative_part), reservedWord('begin'), optional($.concurrent_statement_part), reservedWord('end'), optional(reservedWord('architecture')), optional($._end_simple_name), ';' ), // }}} // 3.4 Configuration declarations {{{ configuration_declaration: $ => seq( reservedWord('configuration'), field('name',$._identifier), reservedWord('of'), $._entity_name, reservedWord('is'), // TODO // Allow any sequence of declarative_item, // verification_unit_binding_indication and block_configuration // and use highlight query to highlight the errors optional($.declarative_part), repeat($.verification_unit_binding_indication), optional($.block_configuration), reservedWord('end'), optional(reservedWord('configuration')), optional($._end_simple_name), ';' ), // }}} // 3.4.2 Block configuration {{{ block_configuration: $ => seq( reservedWord('for'), $._block_specification, repeat($.use_clause), repeat($._configuration_item), reservedWord('end'), reservedWord('for'), ';' ), _block_specification: $ => alias( $.pathname_element, $.block_specification ), generate_statement_element: $ => prec('generate_statement_element',seq( field('label', $._simple_name), '(', $._generate_specification, ')' )), _generate_specification: $ => field( 'specification', choice( $._expression, $._range, $._name_or_label ) ), _configuration_item: $ => choice( $.block_configuration, $.component_configuration ), // }}} // 3.4.3 Component configuration {{{ component_configuration: $ => seq( reservedWord('for'), $._component_specification, optional($.binding_indication), repeat($.verification_unit_binding_indication), optional($.block_configuration), reservedWord('end'), reservedWord('for'), ';' ), // }}} // 4.2.1 Subprogram declarations {{{ _subprogram_declaration: $ => choice( $.procedure_declaration, $.function_declaration, ), procedure_declaration: $ => seq( $._procedure_specification, ';' ), function_declaration: $ => seq( $._function_specification, ';' ), _procedure_specification: $ => seq( optional(choice( reservedWord('pure'), reservedWord('impure') )), reservedWord('procedure'), $._designator, optional(alias($._header,$.subprogram_header)), optional($.procedure_parameter_clause), optional($.return) ), _function_specification: $ => seq( optional(choice( reservedWord('pure'), reservedWord('impure') )), reservedWord('function'), $._designator, optional(alias($._header,$.subprogram_header)), optional($.function_parameter_clause), optional($.return) ), return: $ => seq( optional(','), // LINT: unexpected comma reservedWord('return'), $.type_mark, ), _end_designator: $ => field( 'at_end', choice( $._end_simple_name, $._operator_symbol ) ), _designator: $ => field('designator',choice( $._identifier, $._operator_symbol, )), // }}} // 4.2.2.1 Formal parameter list {{{ // ref formal_parameter_list procedure_parameter_clause: $ => seq( optional(reservedWord('parameter')), '(', optional($._procedure_parameter_list), ')', ), function_parameter_clause: $ => seq( optional(reservedWord('parameter')), '(', optional($._function_parameter_list), ')', ), // }}} // 4.3 Subprogram bodies {{{ _subprogram_body: $ => choice( $.procedure_body, $.function_body ), procedure_body: $ => seq( $._procedure_specification, reservedWord('is'), optional($.declarative_part), reservedWord('begin'), optional($.sequence_of_statements), reservedWord('end'), optional($._subprogram_kind), optional($._end_designator), ';' ), function_body: $ => seq( $._function_specification, reservedWord('is'), optional($.declarative_part), reservedWord('begin'), optional($.sequence_of_statements), reservedWord('end'), optional($._subprogram_kind), optional($._end_designator), ';' ), _subprogram_kind: $ => field('at_end',seq( optional(choice( reservedWord('pure'), reservedWord('impure') )), choice( reservedWord('procedure'), reservedWord('function') ), )), // }}} // 4.4 Subprogram instantiation declarations {{{ _subprogram_instantiation_declaration: $ => choice( $.procedure_instantiation_declaration, $.function_instantiation_declaration ), // LINT // Procedure shall not have purity procedure_instantiation_declaration: $ => seq( optional(choice( reservedWord('pure'), reservedWord('impure') )), reservedWord('procedure'), $._designator, reservedWord('is'), reservedWord('new'), $._uninstantiated_name, optional($.signature), optional(alias($._header,$.subprogram_map_aspect)), ';' ), function_instantiation_declaration: $ => seq( optional(choice( reservedWord('pure'), reservedWord('impure') )), reservedWord('function'), $._designator, reservedWord('is'), reservedWord('new'), $._uninstantiated_name, optional($.signature), optional(alias($._header,$.subprogram_map_aspect)), ';' ), _uninstantiated_name: $ => field('uninstantiated', choice( $.selected_name, $._simple_name )), // }}} // 4.5.3 Signatures {{{ signature: $ => seq( '[', sepBy(',', $.type_mark), optional($.return), ']' ), // }}} // 4.7 Package declarations {{{ package_declaration: $ => seq( reservedWord('package'), field('name',$._identifier), reservedWord('is'), optional(alias($._header,$.package_header)), optional($.declarative_part), reservedWord('end'), optional(reservedWord('package')), optional($._end_simple_name), ';' ), // }}} // 4.8 Package bodies {{{ package_body: $ => seq( reservedWord('package'), reservedWord('body'), $._package_name, reservedWord('is'), optional($.declarative_part), reservedWord('end'), optional(seq( reservedWord('package'), reservedWord('body'), )), optional($._end_simple_name), ';' ), _package_name: $ => field('package', $._simple_name), // }}} // 4.9 Package instantiation declarations {{{ package_instantiation_declaration: $ => seq( reservedWord('package'), field('name',$._identifier), reservedWord('is'), reservedWord('new'), $._uninstantiated_name, optional(alias($._header,$.package_map_aspect)), ';' ), // }}} // 5.2.1 Scalar types {{{ _scalar_type_definition: $ => choice( $.enumeration_type_definition, $._numeric_type_definition, $.physical_type_definition ), _numeric_type_definition: $ => alias( $.range_constraint, $.numeric_type_definition ), range_constraint: $ => seq( reservedWord('range'), $._range ), _range: $ => choice( $.ascending_range, $.descending_range, $._range_attribute_name, ), _range_attribute_name: $ => alias( $.range_attribute_name, $.attribute_name ), range_attribute_name: $ => seq( field('prefix', choice( $._simple_name, $.selected_name, $.ambiguous_name, $.attribute_name, $._external_object_name, )), $._range_attribute_designator, ), ascending_range: $ => prec('range',seq( field('low', $._simple_expression), reservedWord('to'), field('high', $._simple_expression), )), descending_range: $ => prec('range',seq( field('high', $._simple_expression), reservedWord('downto'), field('low', $._simple_expression), )), // }}} // 5.2.2 Enumeration types {{{ enumeration_type_definition: $ => seq( '(', sepBy1(',', $._enumeration_literal), ')' ), _enumeration_literal: $ => field('literal',choice( $.character_literal, $._identifier )), // }}} // 5.2.4 Physical types {{{ physical_type_definition: $ => seq( $.range_constraint, reservedWord('units'), optional(seq( $.primary_unit_declaration, repeat($.secondary_unit_declaration), )), reservedWord('end'), reservedWord('units'), optional($._end_simple_name) ), primary_unit_declaration: $ => seq( field('name',$._identifier), ';' ), secondary_unit_declaration: $ => seq( field('name',$._identifier), '=', choice( $.physical_literal, alias( $._physical_literal, $.physical_literal ), ), ';' ), _physical_literal: $ => seq( $._unit ), physical_literal: $ => prec('physical_literal', seq( $._abstract_literal, $._unit, )), _unit: $ => field('unit', prec('physical_literal',choice( $._simple_name, $.selected_name ))), // }}} // 5.3 Composite types {{{ _composite_type_definition: $ => choice( $._array_type_definition, $.record_type_definition ), // }}} // 5.3.2 Array types {{{ _array_type_definition: $ => choice( $.unbounded_array_definition, $.constrained_array_definition ), unbounded_array_definition: $ => seq( reservedWord('array'), '(', sepBy1(',', $.index_subtype_definition), ')', reservedWord('of'), field('element',$.subtype_indication) ), constrained_array_definition: $ => seq( reservedWord('array'), $.index_constraint, reservedWord('of'), field('element',$.subtype_indication) ), index_subtype_definition: $ => seq( $.type_mark, reservedWord('range'), $._any ), array_constraint: $ => seq( $.index_constraint, optional($._array_element_constraint) ), _array_element_constraint: $ => alias( $._element_constraint, $.array_element_constraint ), index_constraint: $ => seq( '(', choice( sepBy1(',', $._discrete_range), prec.dynamic(99, $.open) ), ')', ), _discrete_range: $ => choice( $.subtype_indication, $._range, ), open: $ => reservedWord('open'), // }}} // 5.3.3 Record types {{{ record_type_definition: $ => seq( reservedWord('record'), repeat($.element_declaration), reservedWord('end'), reservedWord('record'), optional($._end_simple_name) ), element_declaration: $ => seq( $.identifier_list, ':', $.subtype_indication, ';' ), record_constraint: $ => seq( '(', sepBy1(',', $.record_element_constraint), ')' ), record_element_constraint: $ => prec('record_element_constraint', seq( field('element', $._simple_name), $._element_constraint )), identifier_list: $ => sepBy1(',', $._identifier), // }}} // 5.4 Access types {{{ access_type_definition: $ => seq( reservedWord('access'), $.subtype_indication ), // }}} // 5.4.2 Incomplete type declaration {{{ incomplete_type_declaration: $ => seq( reservedWord('type'), field('name',$._identifier), ';' ), // }}} // 5.5 File types {{{ file_type_definition: $ => seq( reservedWord('file'), reservedWord('of'), $.type_mark ), // }}} // 5.6.2 Protected type declarations {{{ protected_type_declaration: $ => seq( reservedWord('protected'), optional($.declarative_part), reservedWord('end'), reservedWord('protected'), optional($._end_simple_name), ), // }}} // 5.6.2 Protected type bodies {{{ protected_type_body: $ => seq( reservedWord('protected'), reservedWord('body'), optional($.declarative_part), reservedWord('end'), reservedWord('protected'), reservedWord('body'), optional($._end_simple_name), ), // }}} // 6. Declarations {{{ declarative_part: $ => prec.left(repeat1( $._declaration )), _declaration: $ => prec('declaration',choice( $._subprogram_declaration, $._subprogram_body, $._subprogram_instantiation_declaration, $.package_declaration, $.package_body, $.package_instantiation_declaration, $._type_declaration, $.subtype_declaration, $._object_declaration, $.alias_declaration, $.component_declaration, $.attribute_declaration, $.attribute_specification, $.configuration_specification, $.disconnection_specification, $.use_clause, $.group_template_declaration, $.group_declaration, $._PSL_Directive, $._PSL_Declaration )), // }}} // 6.2 Type declarations {{{ _type_declaration: $ => choice( $.full_type_declaration, $.incomplete_type_declaration, ), full_type_declaration: $ => seq( reservedWord('type'), field('name',$._identifier), reservedWord('is'), $._type_definition, ';' ), _type_definition: $ => choice( $._scalar_type_definition, $._composite_type_definition, $.access_type_definition, $.file_type_definition, $.protected_type_declaration, $.protected_type_body ), // }}} // 6.3 Subtype declaration {{{ subtype_declaration: $ => seq( reservedWord('subtype'), field('name',$._identifier), reservedWord('is'), $.subtype_indication, ';' ), subtype_indication: $ => seq( optional($._resolution_indication), $.type_mark, optional($._constraint) ), _resolution_indication: $ => choice( $.resolution_function, $.record_resolution, $.parenthesized_resolution, ), resolution_function: $ => prec('resolution_function', choice( $._simple_name, $.selected_name )), parenthesized_resolution: $ => seq( '(', $._resolution_indication, ')' ), record_resolution: $ => seq( '(', sepBy1(',', $.record_element_resolution), ')' ), record_element_resolution: $ => prec('record_element_resolution', seq( field('element', $._simple_name), $._resolution_indication )), type_mark: $ => prec('type_mark',choice( $._simple_name, $.selected_name, $.attribute_name )), _constraint: $ => choice( $.range_constraint, $.array_constraint, $.record_constraint ), _element_constraint: $ => choice( $.array_constraint, $.record_constraint ), // }}} // 6.4.2 Object declarations {{{ _object_declaration: $ => choice( $.constant_declaration, $.signal_declaration, $.variable_declaration, $.shared_variable_declaration, $.file_declaration, ), // }}} // 6.4.2 Constant declarations {{{ constant_declaration: $ => seq( reservedWord('constant'), $.identifier_list, ':', $.subtype_indication, optional($.default_expression), ';' ), // }}} // 6.4.2.3 Signal declarations {{{ signal_declaration: $ => seq( reservedWord('signal'), $.identifier_list, ':', $.subtype_indication, optional($.signal_kind), optional($.default_expression), ';' ), signal_kind: $ => choice( reservedWord('register'), reservedWord('bus') ), // }}} // 6.4.2.4 Variable declarations {{{ variable_declaration: $ => seq( reservedWord('variable'), $.identifier_list, ':', $.subtype_indication, optional($.default_expression), ';' ), shared_variable_declaration: $ => seq( reservedWord('shared'), reservedWord('variable'), $.identifier_list, ':', $.subtype_indication, optional($.default_expression), ';' ), // }}} // 6.4.2.5 File declarations {{{ file_declaration: $ => seq( reservedWord('file'), $.identifier_list, ':', $.subtype_indication, optional($.file_open_information), ';' ), file_open_information: $ => seq( optional(seq( reservedWord('open'), $._file_open_kind )), reservedWord('is'), $._file_logical_name ), _file_logical_name: $ => $._string_expression, // }}} // 6.5 Interface declarations {{{ _generic_interface_declaration: $ => choice( $.constant_interface_declaration, $.type_interface_declaration, $._subprogram_interface_declaration, $.package_interface_declaration, $._illegal_interface_declaration ), _port_interface_declaration: $ => choice( $.signal_interface_declaration, $._illegal_interface_declaration ), // See 6.5.2 and 4.2.2.1 _procedure_interface_declaration: $ => choice( $.constant_interface_declaration, $.signal_interface_declaration, $.variable_interface_declaration, $.file_interface_declaration, $._illegal_interface_declaration ), _function_interface_declaration: $ => choice( $.constant_interface_declaration, $.signal_interface_declaration, $.file_interface_declaration, $._illegal_interface_declaration ), // }}} // 6.5.2 Interface object declarations {{{ constant_interface_declaration: $ => prec.dynamic( PREC.CONSTANT_INTERFACE, seq( optional(reservedWord('constant')), $.identifier_list, ':', optional(alias($._constant_mode, $.mode)), $.subtype_indication, optional($.default_expression) ) ), signal_interface_declaration: $ => prec.dynamic( PREC.SIGNAL_INTERFACE, seq( optional(reservedWord('signal')), $.identifier_list, ':', optional(alias($._signal_mode, $.mode)), $.subtype_indication, optional($.signal_kind), optional($.default_expression) ) ), variable_interface_declaration: $ => prec.dynamic( PREC.VARIABLE_INTERFACE, seq( optional(reservedWord('variable')), $.identifier_list, ':', optional(alias($._variable_mode, $.mode)), $.subtype_indication, optional($.default_expression) ) ), file_interface_declaration: $ => seq( reservedWord('file'), $.identifier_list, ':', optional(alias($._signal_mode, $.mode)), // ILLEGAL, LINT $.subtype_indication, optional($.default_expression) // ILLEGAL, LINT ), // DO NOT LINE _in: $ => reservedWord('in'), _out: $ => reservedWord('out'), _inout: $ => reservedWord('inout'), _buffer: $ => reservedWord('buffer'), _linkage: $ => reservedWord('linkage'), // DO NOT INLINE _constant_mode: $ => choice( prec.dynamic( 1, $._in), prec.dynamic(-3, $._out), prec.dynamic(-3, $._inout), prec.dynamic(-3, $._buffer), prec.dynamic(-3, $._linkage), ), // DO NOT INLINE _variable_mode: $ => choice( prec.dynamic( 1, $._in), prec.dynamic( 1, $._out), prec.dynamic( 1, $._inout), prec.dynamic(-2, $._buffer), prec.dynamic(-2, $._linkage), ), // DO NOT INLINE _signal_mode: $ => choice( prec.dynamic(1, $._in), prec.dynamic(1, $._out), prec.dynamic(1, $._inout), prec.dynamic(1, $._buffer), prec.dynamic(1, $._linkage), ), _illegal_interface_declaration: $ => prec.dynamic( PREC.ILLEGAL_INTERFACE, choice( $.constant_interface_declaration, $.signal_interface_declaration, $.variable_interface_declaration, $.file_interface_declaration, $.type_interface_declaration, $._subprogram_interface_declaration, $.package_interface_declaration ) ), // }}} // 6.5.3 Interface type declarations {{{ type_interface_declaration: $ => seq( reservedWord('type'), field('name',$._identifier), ), // }}} // 6.5.4 Interface subprogram declarations {{{ _subprogram_interface_declaration: $ => choice( $.procedure_interface_declaration, $.function_interface_declaration ), procedure_interface_declaration: $ => seq( $._procedure_specification, optional(seq( reservedWord('is'), $.interface_subprogram_default )) ), function_interface_declaration: $ => seq( $._function_specification, optional(seq( reservedWord('is'), $.interface_subprogram_default )) ), interface_subprogram_default: $ => choice( $._simple_name, $.selected_name, $._operator_symbol, alias('<>', $.same), ), // }}} // 6.5.5 Interface package declarations {{{ package_interface_declaration: $ => seq( reservedWord('package'), field('name',$._identifier), reservedWord('is'), reservedWord('new'), $._uninstantiated_name, optional(alias($._header,$.package_map_aspect)), ), // }}} // 6.5.6.1 Interface lists {{{ // LINT: Semicolon after last declaration _generic_interface_list: $ => seq( sepBy1(';', $._generic_interface_declaration), ), _port_interface_list: $ => seq( sepBy1(';', $._port_interface_declaration), ), _procedure_parameter_list: $ => seq( sepBy1(';', $._procedure_interface_declaration), ), _function_parameter_list: $ => seq( sepBy1(';', $._function_interface_declaration), ), // }}} // 6.5.6.2 Generic clauses {{{ generic_clause: $ => seq( reservedWord('generic'), '(', optional($._generic_interface_list), ')', optional($._semicolon) ), _semicolon: $ => alias(';', $.semicolon), // }}} // 6.5.6.3 Port clauses {{{ port_clause: $ => seq( reservedWord('port'), '(', optional($._port_interface_list), ')', optional($._semicolon) ), // }}} // 6.5.7 Association lists {{{ // LINT: NAMED association element shall NOT be followed by // POSITIONAL association element. // NOTE: The correct ordering is deliberatedly not enforced // by the parser. Tree-sitter does not support custom // error recovery yet. // the query. // NOTE: Having different rules for positional and named // association simplifies writing queries. association_list: $ => sepBy1(',', $._association_element), _association_element: $ => choice( $.positional_association_element, $.named_association_element ), positional_association_element: $ => seq( $._actual_part ), named_association_element: $ => seq( $._formal_part, delimiter('=>'), $._actual_part ), _formal_part: $ => field( 'formal_part', choice( $._name, $.others ), ), _actual_part: $ => field( 'actual_part', choice( $._expression, $.inertial_expression, prec.dynamic(-1, $.subtype_indication), prec.dynamic(99, $.open), // used to resolve conflicts // between ambiguous_name and function_call: // _name '(' character_literal ')' // _name '(' string_literal ')' prec.dynamic(2, $.character_literal), prec.dynamic(2, $.string_literal), ), ), // }}} // 6.5.7.2 Generic map aspects {{{ generic_map_aspect: $ => seq( reservedWord('generic'), reservedWord('map'), '(', optional(choice( $.association_list, $.default, $._any )), ')', optional($._semicolon), ), default: $ => reservedWord('default'), _any: $ => alias('<>', $.any), // }}} // 6.5.7.3 Port map aspects {{{ port_map_aspect: $ => seq( reservedWord('port'), reservedWord('map'), '(', optional($.association_list), ')', optional($._semicolon) ), // }}} // HEADER and MAP_ASPECTS {{{ _header: $ => seq( $._clause, optional($._clause), optional($._clause), optional($._clause), ), _clause: $ => choice( $.generic_clause, $.generic_map_aspect, $.port_clause, $.port_map_aspect, ), // }}} // 6.6 Alias declarations {{{ alias_declaration: $ => seq( reservedWord('alias'), $._alias_designator, optional(seq( ':', $.subtype_indication )), reservedWord('is'), $._alias_denotator, optional($.signature), ';' ), _alias_designator: $ => field( 'designator', choice( $._identifier, $.character_literal, $._operator_symbol ) ), _alias_denotator: $ => field( 'denotator', choice( $._simple_name, $.character_literal, $.selected_name, $.ambiguous_name, $.slice_name, $.attribute_name, $._external_object_name, ) ), _operator_symbol: $ => alias( $.string_literal, $.operator_symbol ), // }}} // 6.7 Attribute declarations {{{ attribute_declaration: $ => seq( reservedWord('attribute'), field('name',$._identifier), ':', $.type_mark, ';' ), // }}} // 6.8 Component declarations {{{ component_declaration: $ => prec('component_declaration',seq( reservedWord('component'), field('name',$._identifier), optional(reservedWord('is')), optional(alias($._header,$.component_header)), reservedWord('end'), reservedWord('component'), optional($._end_simple_name), ';' )), // }}} // 6.9 Group template declarations {{{ group_template_declaration: $ => seq( reservedWord('group'), field('name',$._identifier), reservedWord('is'), '(', $.entity_class_entry_list, ')', ';' ), entity_class_entry_list: $ => sepBy1(',', $.entity_class_entry), entity_class_entry: $ => seq( $.entity_class, optional($._any) ), // }}} // 6.10 Group declarations {{{ group_declaration: $ => seq( reservedWord('group'), field('name',$._identifier), ':', $._group_template, '(', $.group_constituent_list, ')', ';' ), group_constituent_list: $ => prec( 'group_constituent_list', sepBy1(',', $._group_constituent), ), _group_constituent: $ => choice( $._simple_name, $.selected_name, $.character_literal ), _group_template: $ => field( 'template', choice( $._simple_name, $.selected_name ) ), // }}} // 7.2 Specifications {{{ attribute_specification: $ => seq( reservedWord('attribute'), field('name',$._simple_name), reservedWord('of'), $.entity_specification, reservedWord('is'), $._expression, ';' ), entity_name_list: $ => choice( sepBy1(',', $.entity_designator), $.others, $.all ), entity_specification: $ => seq( $.entity_name_list, ':', $.entity_class ), entity_class: $ => choice( reservedWord('entity'), reservedWord('architecture'), reservedWord('configuration'), reservedWord('procedure'), reservedWord('function'), reservedWord('package'), reservedWord('type'), reservedWord('subtype'), reservedWord('constant'), reservedWord('signal'), reservedWord('variable'), reservedWord('component'), reservedWord('label'), reservedWord('literal'), reservedWord('units'), reservedWord('group'), reservedWord('file'), reservedWord('property'), reservedWord('sequence'), ), entity_designator: $ => seq( $._entity_tag, optional($.signature) ), _entity_tag: $ => choice( $._simple_name, $.character_literal, $._operator_symbol ), // }}} // 7.3 Configuration specification {{{ configuration_specification: $ => prec.right(seq( reservedWord('for'), // not-optional, used to improve error recovery optional(seq( $._component_specification, $.binding_indication, optional(seq( repeat($.verification_unit_binding_indication), reservedWord('end'), reservedWord('for'), ';' )) )) )), _component_specification: $ => seq( $.instantiation_list, ':', $._component_name ), instantiation_list: $ => choice( sepBy1(',', $._simple_name), $.others, $.all ), all: $ => reservedWord('all'), // TODO: Does it allow expanded name? _component_name: $ => field( 'component', $._simple_name ), // }}} // 7.3.2 Binding indication {{{ binding_indication: $ => seq( optional(seq( reservedWord('use'), $._entity_aspect, )), optional($._header), ';' ), // LINT: component_instantiation shall not be present in // binding indication _entity_aspect: $ => choice( $.entity_instantiation, $.configuration_instantiation, $.component_instantiation, $.open ), // }}} // 7.3.4 Verification unit binding indication {{{ verification_unit_binding_indication: $ => seq( reservedWord('use'), reservedWord('vunit'), $.verification_unit_list, ';' ), verification_unit_list: $ => sepBy1( ',', choice( $._simple_name, $.selected_name, ) ), // }}} // 7.4 Disconnection specification {{{ disconnection_specification: $ => seq( reservedWord('disconnect'), $.guarded_signal_specification, $._after, ';' ), guarded_signal_specification: $ => seq( $.signal_list, ':', $.type_mark, ), signal_list: $ => choice( sepBy1(',', $._signal_name), $.others, $.all ), // }}} // 8 Names {{{ _name: $ => choice( $._simple_name, $.character_literal, $.selected_name, $.ambiguous_name, $.slice_name, $.attribute_name, $._external_object_name, ), _simple_name: $ => prec('simple_name',choice( alias($.basic_identifier, $.simple_name), alias($.extended_identifier, $.extended_simple_name) )), _end_simple_name: $ => field( 'at_end', $._simple_name ), // }}} // 8.3 Selected names {{{ // LINT // Only expanded names shall have character_literal and operator_symbol // as suffix selected_name: $ => seq( field('prefix', choice( $._simple_name, $.selected_name, $.ambiguous_name, $.slice_name, $._external_object_name, )), token.immediate('.'), field('suffix', choice( $._simple_name, $.character_literal, $._operator_symbol, $.all // allowed on access value )), ), // }}} // 8.4 Indexed name (Ambiguos name) {{{ // foo (bar) // - function call // - type conversion // - slice name // - indexed name // foo (bar, baz) // - function call // - indexed name // prefix (foo) // - slice name // - indexed name ambiguous_name: $ => seq( field('prefix', choice( $._simple_name, $.selected_name, $.ambiguous_name, $.function_call )), '(', $.expression_list, ')' ), expression_list: $ => sepBy1(',', $._expression), // }}} // 8.5 Slice name {{{ slice_name: $ => seq( field('prefix', choice( $._simple_name, $.ambiguous_name, $.selected_name, $.slice_name, $.function_call, )), '(', $._range, ')' ), // }}} // 8.6 Attribute names {{{ attribute_name: $ => prec('attribute_name',seq( field('prefix', choice( $._simple_name, $.selected_name, $.ambiguous_name, // indexed_name allowed $.attribute_name, $.function_call, $._external_object_name, )), optional($.signature), choice( $._attribute_designator, $._predefined_attribute_designator, $._predefined_attribute_designator_with_expression, ), )), _attribute_designator: $ => seq( token('\''), field('designator', $._simple_name), ), _predefined_attribute_designator: $ => prec.dynamic(1, seq( token('\''), field('designator', alias($._predefined_designator, $.predefined_designator)), )), // Only predefined attributes shall have expression _predefined_attribute_designator_with_expression: $ => prec.dynamic(2, prec.right(seq( token('\''), field('designator', alias($._predefined_designator_with_expression, $.predefined_designator)), '(', $._expression, ')' ))), _range_attribute_designator: $ => seq( token('\''), field('designator', alias($._range_designator, $.predefined_designator)), optional(seq( '(', $._expression, ')', )) ), // DO NOT INLINE _predefined_designator: $ => choice( ...PREDEFINED_ATTRIBUTE_DESIGNATOR.map(attr => reservedWord(attr)) ), // DO NOT INLINE _predefined_designator_with_expression: $ => choice( ...PREDEFINED_ATTRIBUTE_DESIGNATOR_WITH_EXPRESSION.map(attr => reservedWord(attr)) ), // DO NOT INLINE _range_designator: $ => choice( ...RANGE_ATTRIBUTE_DESIGNATOR.map(attr => reservedWord(attr)) ), // }}} // 8.7 External names {{{ _external_object_name: $ => choice( $.external_constant_name, $.external_signal_name, $.external_variable_name ), external_constant_name: $ => seq( delimiter('<<'), reservedWord('constant'), $._external_pathname, ':', $.subtype_indication, delimiter('>>') ), external_signal_name: $ => seq( delimiter('<<'), reservedWord('signal'), $._external_pathname, ':', $.subtype_indication, delimiter('>>') ), external_variable_name: $ => seq( delimiter('<<'), reservedWord('variable'), $._external_pathname, ':', $.subtype_indication, delimiter('>>') ), _external_pathname: $ => choice( $.package_pathname, $.absolute_pathname, $.relative_pathname ), package_pathname: $ => seq( '@', field('library', $._simple_name), '.', sepBy1('.', field('package',$._simple_name)), '.', field('object', $._simple_name), ), absolute_pathname: $ => seq( '.', $._partial_pathname ), relative_pathname: $ => seq( repeat('^.'), $._partial_pathname ), _partial_pathname: $ => seq( repeat(seq( $.pathname_element, '.' )), field('object', $._simple_name), ), pathname_element: $ => choice( $._name_or_label, $.generate_statement_element, ), _name_or_label: $ => field( 'name_or_label', $._simple_name ), // }}} // 9. Expressions {{{ _expr: $ => choice( $._unary_expression, $._binary_expression, $._primary ), _unary_expression: $ => choice( $.condition, $.reduction, $.sign, $.factor ), _binary_expression: $ => choice( $.logical_expression, $.relation, $.shift_expression, $.simple_expression, $.concatenation, $.term, $.exponentiation, ), _primary: $ => prec('primary',choice( $._name, $._literal, $.aggregate, $.qualified_expression, $.allocator, $.parenthesized_expression, $.function_call, )), // Named expressions _expression: $ => alias( $._expr, $.expression ), _condition: $ => alias( $._expr, $.conditional_expression ), _simple_expression: $ => alias( $._expr, $.simple_expression ), _time_expression: $ => alias( $._expr, $.time_expression ), _string_expression: $ => alias( $._expr, $.string_expression ), _severity_expression: $ => alias( $._primary, $.severity_expression ), _file_open_kind: $ => alias( $._primary, $.file_open_kind ), // Special expressions default_expression: $ => seq( ':=', $._expr, ), inertial_expression: $ => seq( reservedWord('inertial'), $._expr ), parenthesized_expression: $ => prec('parenthesized_expression',seq( '(', $._expr, ')' )), // Unary expressions // LINT: condition shall not have expression as parent condition: $ => prec('condition', seq( field('operator', delimiter('??')), $._expr )), // LINT: reduction shall not have expression as parent reduction: $ => prec('reduction', seq( field('operator', choice(...['and', 'or', 'xor', 'nand', 'nor', 'xnor'].map(op => reservedWord(op)))), $._expr )), // LINT: factor shall not have SOME expression as parent factor: $ => prec.right('factor', seq( field('operator', choice(...['not', 'abs'].map(op => reservedWord(op)))), $._expr )), // LINT: sign shall not have SOME expression as parent sign: $ => prec('sign', seq( field('operator', choice(...['+', '-'].map(op => delimiter(op)))), $._expr )), // Binary expressions // LINT: nor and nand are non associative // LINT: other operators are only associative with themselves logical_expression: $ => prec.right('logical_expression',seq( $._expr, choice( // associative operators repeat1(prec.left('logical_expression',seq(field('operator', reservedWord('and' )), $._expr))), repeat1(prec.left('logical_expression',seq(field('operator', reservedWord('or' )), $._expr))), repeat1(prec.left('logical_expression',seq(field('operator', reservedWord('xor' )), $._expr))), repeat1(prec.left('logical_expression',seq(field('operator', reservedWord('xnor')), $._expr))), // non associative operators seq(prec.left('logical_expression',seq(field('operator', reservedWord('nand')), $._expr))), seq(prec.left('logical_expression',seq(field('operator', reservedWord('nor' )), $._expr))), ), )), // LINT: relations are not associative relation: $ => prec.right('relation', seq( $._expr, field('operator', choice(...['<', '>', '=', '<=', '>=', '/=', '?<', '?>', '?=', '?<=', '?>=', '?/='].map(op => delimiter(op)))), $._expr )), // LINT: shift expressions are not associative shift_expression: $ => prec.right('shift_expression', seq( $._expr, field('operator', choice(...['sll', 'srl', 'sla', 'sra', 'rol', 'ror'].map(op => reservedWord(op)))), $._expr, )), // LINT: operand shall not be sign simple_expression: $ => prec.right('simple_expression', seq( $._expr, repeat1(prec.left('simple_expression',seq( field('operator', choice( ...['+', '-'].map(op => delimiter(op)) )), $._expr ))), )), concatenation: $ => prec.right('simple_expression', seq( $._expr, repeat1(prec.left('simple_expression',seq( field('operator', delimiter('&')), $._expr ))), )), term: $ => prec.right('term', seq( $._expr, choice( repeat1(prec.left('term',seq( field('operator', choice( ...['*', '/'].map(op => delimiter(op)), ...['rem', 'mod'].map(op => reservedWord(op)), )), $._expr ))), ) )), // LINT: exponentiation are not associative exponentiation: $ => prec.left('exponentiation', seq( $._expr, field('operator', choice(...['**'].map(op => delimiter(op)))), $._expr )), // }}} // 9.3.2 Literals {{{ _literal: $ => choice( $._numeric_literal, $.string_literal, $.bit_string_literal, $.null, $.character_literal, ), _numeric_literal: $ => choice( $._abstract_literal, $.physical_literal ), null: $ => reservedWord('null'), // }}} // 9.3.3 Aggregates {{{ aggregate: $ => prec(-1, seq( '(', $._element_association_list, ')' )), _element_association_list: $ => choice( $.named_element_association, seq( $._element_association, ',', sepBy1(',', $._element_association), ), ), _element_association: $ => choice( $.positional_element_association, $.named_element_association, ), positional_element_association: $ => seq( $._value ), named_element_association: $ => prec(-1, seq( $.choices, delimiter('=>'), $._value )), _value: $ => $._expression, choices: $ => sepBy1('|', $._choice), _choice: $ => choice( $._simple_expression, $._range, $.others ), others: $ => reservedWord('others'), // }}} // 9.3.4 Function call {{{ function_call: $ => seq( $._function_name, '(', $.association_list, ')' ), _function_name: $ => field( 'function', choice( $._simple_name, $._operator_symbol, $.selected_name, $.attribute_name, ) ), // }}} // 9.3.5 Qualified expressions {{{ qualified_expression: $ => seq( $.type_mark, token('\''), choice( $.aggregate, alias($.parenthesized_expression,$.expression), ), ), // }}} // 9.3.7 Allocators {{{ allocator: $ => seq( reservedWord('new'), choice( $.subtype_indication, $.qualified_expression ) ), // }}} // 10.1 Sequential statements {{{ sequence_of_statements: $ => repeat1( $._sequential_statement ), _sequential_statement: $ => prec('sequential_statement',choice( $.process_statement, $.wait_statement, $.assertion_statement, $.report_statement, $._signal_assignment_statement, $._variable_assignment_statement, $.procedure_call_statement, $.if_statement, $.case_statement, $.loop_statement, $.next_statement, $.exit_statement, $.return_statement, $.null_statement, $._PSL_Directive, $._PSL_Declaration, )), // }}} // 10.2 Wait statement {{{ wait_statement: $ => seq( optional($.label), reservedWord('wait'), optional($._sensitivity_clause), optional($._condition_clause), optional($._timeout_clause), ';' ), _sensitivity_clause: $ => seq( reservedWord('on'), $.sensitivity_list ), _condition_clause: $ => seq( reservedWord('until'), $._condition ), _timeout_clause: $ => seq( reservedWord('for'), $._time_expression ), // LINT // all is not allowed on sensitivy clause sensitivity_list: $ => choice( $.all, sepBy1(',', $._signal_name), ), _signal_name: $ => $._name, // }}} // 10.3 Assertion statement {{{ assertion_statement: $ => prec('vhdl_assertion',seq( optional($.label), optional(reservedWord('postponed')), reservedWord('assert'), $._condition, optional($._report), optional($._severity), ';' )), // }}} // 10.4 Report statement {{{ report_statement: $ => seq( optional($.label), $._report, optional($._severity), ';' ), _report: $ => seq( reservedWord('report'), $._string_expression ), _severity: $ => seq( reservedWord('severity'), $._severity_expression ), // }}} // 10.5 Signal assignments {{{ _signal_assignment_statement: $ => choice( $._simple_signal_assignment, $._conditional_signal_assignment, $._selected_signal_assignment, ), // }}} // 10.5.2 Simple signal assignments {{{ _simple_signal_assignment: $ => choice( $.simple_waveform_assignment, $.simple_force_assignment, $.simple_release_assignment ), simple_waveform_assignment: $ => seq( optional($.label), $._target, '<=', optional(reservedWord('guarded')), optional($.delay_mechanism), $.waveforms, ';' ), simple_force_assignment: $ => seq( optional($.label), $._target, '<=', optional(reservedWord('guarded')), reservedWord('force'), optional($.force_mode), optional($._value), ';' ), simple_release_assignment: $ => seq( optional($.label), $._target, '<=', optional(reservedWord('guarded')), reservedWord('release'), optional($.force_mode), ';' ), force_mode: $ => choice( $._in, $._out ), delay_mechanism: $ => choice( $.transport, $.inertial, ), transport: $ => reservedWord('transport'), inertial: $ => seq( optional($._reject), reservedWord('inertial') ), _reject: $ => seq( reservedWord('reject'), field('reject', $._time_expression), ), _target: $ => field( 'target', choice( $._name, $.aggregate ), ), waveforms: $ => choice( $.unaffected, sepBy1(',', $.waveform_element) ), unaffected: $ => reservedWord('unaffected'), waveform_element: $ => seq( $._value, optional($._after) ), _after: $ => seq( reservedWord('after'), $._time_expression ), // }}} // 10.5.3 Conditional signal assignments {{{ _conditional_signal_assignment: $ => choice( $.conditional_waveform_assignment, $.conditional_force_assignment ), conditional_waveform_assignment: $ => prec(1,seq( optional($.label), $._target, '<=', optional(reservedWord('guarded')), optional($.delay_mechanism), $.conditional_waveforms, ';' )), _when_clause: $ => seq( reservedWord('when'), $._condition ), conditional_waveforms: $ => seq( $.waveforms, $._when_clause, repeat($.alternative_conditional_waveforms), ), alternative_conditional_waveforms: $ => seq( reservedWord('else'), $.waveforms, optional($._when_clause) ), conditional_force_assignment: $ => seq( $._target, '<=', reservedWord('force'), optional($.force_mode), $.conditional_expressions, ';' ), conditional_expressions: $ => seq( $._value, $._when_clause, repeat($.alternative_conditional_expressions), ), alternative_conditional_expressions: $ => seq( reservedWord('else'), $._value, optional($._when_clause) ), // }}} // 10.5.4 Selected signal assignments {{{ _selected_signal_assignment: $ => choice( $.selected_waveform_assignment, $.selected_force_assignment ), selected_waveform_assignment: $ => seq( optional($.label), reservedWord('with'), $._expression, reservedWord('select'), optional(delimiter('?')), $._target, '<=', optional(reservedWord('guarded')), optional($.delay_mechanism), $.selected_waveforms, ';' ), selected_force_assignment: $ => seq( optional($.label), reservedWord('with'), $._expression, reservedWord('select'), optional(delimiter('?')), $._target, '<=', reservedWord('force'), optional($.force_mode), $.selected_expressions, ';' ), selected_waveforms: $ => seq( $.waveforms, reservedWord('when'), $.choices, repeat($.alternative_selected_waveforms) ), alternative_selected_waveforms: $ => seq( ',', $.waveforms, reservedWord('when'), $.choices, ), selected_expressions: $ => seq( $._value, reservedWord('when'), $.choices, repeat($.alternative_selected_expressions) ), alternative_selected_expressions: $ => seq( ',', $._value, reservedWord('when'), $.choices, ), // }}} // 10.6 Variable assignments {{{ _variable_assignment_statement: $ => choice( $.simple_variable_assignment, $.conditional_variable_assignment, $.selected_variable_assignment, ), // }}} // 10.6.2 Simple variable assignments {{{ simple_variable_assignment: $ => prec(1,seq( optional($.label), $._target, ':=', $._value, ';' )), // }}} // 10.6.3 Conditional variable assignments {{{ conditional_variable_assignment: $ => seq( optional($.label), $._target, ':=', $.conditional_expressions, ';' ), // }}} // 10.6.4 Selected variable assignments {{{ selected_variable_assignment: $ => seq( optional($.label), reservedWord('with'), $._expression, reservedWord('select'), optional(delimiter('?')), $._target, ':=', $.selected_expressions, ';' ), // }}} // 10.7 Procedure call statement {{{ procedure_call_statement: $ => prec('procedure_call', seq( optional($.label), optional(reservedWord('postponed')), field('procedure', choice( $._simple_name, $.selected_name )), optional(seq( '(', $.association_list, ')', )), ';' )), // }}} // 10.8 If statement {{{ if_statement: $ => seq( optional($.label), $.if, repeat($.elsif), optional($.else), reservedWord('end'), reservedWord('if'), optional($._end_simple_name), ';' ), if: $ => seq( reservedWord('if'), $._condition, reservedWord('then'), optional($.sequence_of_statements), ), elsif: $ => seq( reservedWord('elsif'), $._condition, reservedWord('then'), optional($.sequence_of_statements) ), else: $ => seq( reservedWord('else'), optional($.sequence_of_statements) ), // }}} // 10.9 Case statement {{{ case_statement: $ => seq( optional($.label), reservedWord('case'), optional(delimiter('?')), $._expression, reservedWord('is'), repeat($.case_statement_alternative), reservedWord('end'), reservedWord('case'), optional(delimiter('?')), optional($._end_simple_name), ';' ), case_statement_alternative: $ => seq( reservedWord('when'), $.choices, delimiter('=>'), optional($.sequence_of_statements) ), // }}} // 10.10 Loop statement {{{ loop_statement: $ => seq( optional($.label), optional($._iteration_scheme), reservedWord('loop'), optional($.sequence_of_statements), reservedWord('end'), reservedWord('loop'), optional($._end_simple_name), ';' ), _iteration_scheme: $ => choice( $.while_loop, $.for_loop ), while_loop: $ => seq( reservedWord('while'), $._condition, ), for_loop: $ => seq( reservedWord('for'), $.parameter_specification ), parameter_specification: $ => seq( field('name',$._identifier), reservedWord('in'), $._discrete_range ), // }}} // 10.11 Next statement {{{ next_statement: $ => seq( optional($.label), reservedWord('next'), optional($._loop_label), optional($._when_clause), ';' ), _loop_label: $ => field( 'loop_label', $._simple_name ), // }}} // 10.12 Exit statement {{{ exit_statement: $ => seq( optional($.label), reservedWord('exit'), optional($._loop_label), optional($._when_clause), ';' ), // }}} // 10.13 Return statement {{{ return_statement: $ => seq( optional($.label), reservedWord('return'), optional($._expression), ';' ), // }}} // 10.14 Null statement {{{ null_statement: $ => seq( optional($.label), reservedWord('null'), ';' ), // }}} // 11 Concurrent statements {{{ concurrent_statement_part: $ => repeat1( $._concurrent_statement ), _concurrent_statement: $ => prec('concurrent_statement', choice( $.block_statement, $.process_statement, $.component_instantiation_statement, $.procedure_call_statement, $.assertion_statement, $._concurrent_signal_assignment, $._generate_statement, $._PSL_Directive, $._PSL_Declaration )), // }}} // 11.2 Block statement {{{ block_statement: $ => seq( optional($.label), reservedWord('block'), optional(seq( '(', $._guard, ')' )), optional(reservedWord('is')), optional(alias($._header,$.block_header)), optional($.declarative_part), reservedWord('begin'), optional($.concurrent_statement_part), reservedWord('end'), reservedWord('block'), optional($._end_simple_name), ';' ), _guard: $ => field( 'guard', $._condition ), // }}} // 11.3 Process statement {{{ process_statement: $ => seq( optional($.label), optional(reservedWord('postponed')), reservedWord('process'), optional(seq( '(', $.sensitivity_list, ')' )), optional(reservedWord('is')), optional($.declarative_part), reservedWord('begin'), optional($.sequence_of_statements), reservedWord('end'), optional(reservedWord('postponed')), reservedWord('process'), optional($._end_simple_name), ';' ), // }}} // 11.6 Concurrent signal assignments {{{ _concurrent_signal_assignment: $ => choice( alias( $.simple_waveform_assignment, $.simple_concurrent_signal_assignment ), alias( $.conditional_waveform_assignment, $.conditional_concurrent_signal_assignment ), alias( $.selected_waveform_assignment, $.selected_concurrent_signal_assignment ) ), // }}} // 11.7 Component instantiation statements {{{ // LINT entity aspect shall not be open component_instantiation_statement: $ => seq( optional($.label), $._entity_aspect, optional(alias($._header,$.component_map_aspect)), ';' ), entity_instantiation: $ => seq( reservedWord('entity'), field('entity', choice( $._simple_name, $.selected_name, )), optional(seq( '(', field('architecture',$._simple_name), ')' )) ), configuration_instantiation: $ => seq( reservedWord('configuration'), field('configuration', choice( $._simple_name, $.selected_name, )) ), component_instantiation: $ => prec('component_instantiation',seq( optional(reservedWord('component')), field('component', choice( $._simple_name, $.selected_name, )), )), // }}} // 11.8 Generate statements {{{ _generate_statement: $ => choice( $.for_generate_statement, $.if_generate_statement, $.case_generate_statement, ), for_generate_statement: $ => seq( optional($.label), reservedWord('for'), $.parameter_specification, reservedWord('generate'), optional($.generate_statement_body), reservedWord('end'), reservedWord('generate'), optional($._end_simple_name), ';' ), if_generate_statement: $ => seq( optional($.label), $.if_generate, repeat($.elsif_generate), optional($.else_generate), reservedWord('end'), reservedWord('generate'), optional($._end_simple_name), ';' ), if_generate: $ => seq( reservedWord('if'), optional($.label), $._condition, reservedWord('generate'), optional($.generate_statement_body), ), elsif_generate: $ => seq( reservedWord('elsif'), optional($.label), $._condition, reservedWord('generate'), optional($.generate_statement_body) ), else_generate: $ => seq( reservedWord('else'), optional($.label), reservedWord('generate'), optional($.generate_statement_body) ), case_generate_statement: $ => seq( optional($.label), reservedWord('case'), $._expression, reservedWord('generate'), repeat($.case_generate_alternative), reservedWord('end'), reservedWord('generate'), optional($._end_simple_name), ';' ), case_generate_alternative: $ => seq( reservedWord('when'), optional($.label), $.choices, delimiter('=>'), optional($.generate_statement_body) ), generate_statement_body: $ => choice( // with begin seq( optional($.declarative_part), reservedWord('begin'), repeat($._concurrent_statement), optional(seq( reservedWord('end'), optional($._end_simple_name), ';' )), ), // with end seq( optional(seq( optional($.declarative_part), reservedWord('begin'), )), repeat($._concurrent_statement), reservedWord('end'), optional($._end_simple_name), ';' ), // without both repeat1($._concurrent_statement), ), label: $ => seq( $._identifier, ':' ), // }}} // 12.4 Use clauses {{{ use_clause: $ => seq( reservedWord('use'), sepBy1(',', $.selected_name), ';' ), // }}} // 13.1 Design units {{{ design_unit: $ => prec.right(choice( $.context_clause, seq( optional($.context_clause), $._library_unit ), )), _library_unit: $ => choice( $._primary_unit, $._secondary_unit ), _primary_unit: $ => prec('primary_unit',choice( $.entity_declaration, $.configuration_declaration, $.package_declaration, $.package_instantiation_declaration, $.context_declaration, $._PSL_Verification_Unit, )), _secondary_unit: $ => prec('secondary_unit',choice( $.architecture_body, $.package_body )), // }}} // 13.2 Design libraries {{{ library_clause: $ => seq( reservedWord('library'), $.logical_name_list, ';' ), logical_name_list: $ => sepBy1(',', field('library',$._simple_name)), // }}} // 13.3 Context declarations {{{ context_declaration: $ => seq( reservedWord('context'), field('name',$._identifier), reservedWord('is'), optional($.context_clause), reservedWord('end'), optional(reservedWord('context')), optional($._end_simple_name), ';' ), // }}} // 13.4 Context clauses {{{ context_clause: $ => prec.right(repeat1( $._context_item )), _context_item: $ => prec('context_item',choice( $.library_clause, $.use_clause, $.context_reference )), context_reference: $ => seq( reservedWord('context'), $.context_list, ';' ), context_list: $ => sepBy1(',', $.selected_name), // }}} // 15.3 Separators {{{ // }}} // 15.4 Identifiers {{{ _identifier: $ => choice( alias($.basic_identifier, $.identifier), $.extended_identifier ), basic_identifier: $ => token(seq( /[a-zA-Z]/, repeat(seq( optional('_'), /[a-zA-Z0-9]/ )) )), extended_identifier: $ => token(seq( '\\', /(\\\\|[^\r\n\\])*/, '\\', )), // }}} // 15.5 Abstract literals _abstract_literal: $ => choice( $.integer_decimal, $.real_decimal, $.based_integer, $.based_real ), // 15.5.2 Decimal literals integer_decimal: $ => token(seq( repeat1(/[0-9_]/), optional(EXPONENT) )), real_decimal: $ => token(seq( repeat1(/[0-9_]/), '.', // not optional. // optional used here to highlight incomplete code optional(seq( repeat1(/[0-9_]/), optional(EXPONENT) )) )), // 15.5.3 Based literals // TODO: Write another grammar to parse the values based_integer: $ => token(seq( repeat('0'), choice(/[0-9]/,/1[0-6]/), '#', /[0-9a-fA-F_]*/, '#', optional(EXPONENT) )), based_real: $ => token(seq( repeat('0'), choice(/[0-9]/,/1[0-6]/), '#', /[0-9a-fA-F_]*/, '.', /[0-9a-fA-F_]*/, '#', optional(EXPONENT) )), // 15.6 Character literal character_literal: $ => choice( // Longest token has higher precedence // the second alternative can't be matched. // But, when the code is incomplete, tree-sitter will know // there is only a "'" missing and will recovery from the // error. seq(/'.'/), seq(/'[^;,)\r\n]/,"'"), // error recovery ), // 15.7 String literal string_literal: $ => choice( // same trick used on character_literal seq(/"(""|[^"\r\n])*"/), seq(/"(""|[^";,)\r\n])*/,'"'), ), // 15.8 Bit string literals bit_string_literal: $ => choice( seq(/[0-9]*[uUsS]?[bBoOxX]"[^" \r\n]*"/), seq(/[0-9]*[uUsS]?[bBoOxX]"[^" ;,)\r\n]*/,'"'), seq(/[0-9]*[dD]"[^" \r\n]*"/), seq(/[0-9]*[dD]"[^" ;,)\r\n]*/,'"'), ), // 15.9 Comments comment: $ => token(choice( prec(2,/--.*/), prec(2,seq( // from tree-sitter-c '/*', /[^*]*\*+([^/*][^*]*\*+)*/, '/' )) )), // 15.11 Tool directives tool_directive: $ => token(/`.*/), // PSL // PSL 5. Boolean layer {{{ _PSL_Identifier: $ => alias( $._identifier, $.PSL_Identifier ), _PSL_Any_Type: $ => prec(1,choice( alias($._expr, $.PSL_Any_Type), $.PSL_Expression, $.PSL_Built_In_Function_Call, $.PSL_Union_Expression, )), _PSL_Boolean: $ => choice( alias($._expr, $.PSL_Boolean), $.PSL_Expression, $.PSL_Built_In_Function_Call ), PSL_Parenthesized_Boolean: $ => seq( '(', $._PSL_Boolean, ')' ), _PSL_Number: $ => choice( alias($._expr, $.PSL_Number), $.PSL_Built_In_Function_Call ), _PSL_Value: $ => $._PSL_Any_Type, PSL_Expression: $ => prec.right('implication', seq( $._PSL_Boolean, field('operator', choice(...['->', '<->'].map(op => delimiter(op)))), $._PSL_Boolean, )), // }}} // PSL 5.2.3 Built-in functions {{{ PSL_Built_In_Function_Call: $ => prec('psl_function_call', choice( seq( choice( reservedWord('prev'), reservedWord('next'), reservedWord('stable'), reservedWord('rose'), reservedWord('fell'), reservedWord('isunknown'), reservedWord('countones'), reservedWord('onehot'), reservedWord('onehot0'), reservedWord('nondet'), reservedWord('nondet_vector'), ), '(', sepBy1(',', choice($._PSL_Any_Type, $.PSL_Value_Set)), ')', ), seq( reservedWord('ended'), '(', $._PSL_Sequence, ')', ) )), // }}} // PSL 5.3 Clock expressions {{{ _PSL_Clock_Expression: $ => choice( $._condition, $.PSL_Built_In_Function_Call ), // }}} // PSL 5.3 Union expressions {{{ PSL_Union_Expression: $ => prec.left('union', seq( $._PSL_Any_Type, field('operator', reservedWord('union')), $._PSL_Any_Type, )), // }}} // PSL 5.4 Default clock declaration {{{ _PSL_Declaration: $ => choice( $.PSL_Property_Declaration, $.PSL_Sequence_Declaration, $.PSL_Clock_Declaration ), PSL_Clock_Declaration: $ => seq( reservedWord('default'), reservedWord('clock'), reservedWord('is'), $._PSL_Clock_Expression, ';' ), // }}} // PSL 6.1.1 Sequential Extended Regular Expressions (SEREs) {{{ _PSL_SERE: $ => choice( $._PSL_Boolean, $._PSL_Sequence, $.PSL_Simple_SERE, $._PSL_Compound_SERE, ), PSL_Simple_SERE: $ => choice( $._PSL_Fusion_SERE, $._PSL_Concat_SERE, ), _PSL_Fusion_SERE: $ => prec.right('sequence_fusion', seq( $._PSL_SERE, repeat1(prec.left(seq( field('operator', delimiter(':')), $._PSL_SERE, ))), )), _PSL_Concat_SERE: $ => prec.right('sequence_concatenation', seq( $._PSL_SERE, repeat1(prec.left(seq( field('operator', delimiter(';')), $._PSL_SERE, ))), )), // }}} // PSL 6.1.1.2 Compound SEREs {{{ _PSL_Compound_SERE: $ => prec.dynamic(1, choice( $.PSL_Repeated_SERE, $.PSL_Braced_SERE, $.PSL_Clocked_SERE, alias( choice( $.PSL_Compound_SERE_And, $.PSL_Compound_SERE_Within ), $.PSL_Compound_SERE, ), $.PSL_Parameterized_SERE, )), PSL_Compound_SERE_Or: $ => prec.right('sequence_or', seq( $._PSL_Compound_SERE, repeat1(prec.left(seq( field('operator', delimiter('|')), $._PSL_Compound_SERE, ))) )), PSL_Compound_SERE_And: $ => prec.right('sequence_and', seq( $._PSL_Compound_SERE, repeat1(prec.left(seq( field('operator', choice(...['&', '&&'].map(op => delimiter(op)))), $._PSL_Compound_SERE, ))) )), PSL_Compound_SERE_Within: $ => prec.right('sequence_within', seq( $._PSL_Compound_SERE, repeat1(prec.left(seq( field('operator', reservedWord('within')), $._PSL_Compound_SERE, ))) )), PSL_Parameterized_SERE: $ => seq( reservedWord('for'), $.PSL_Parameters_Definition, ':', field('operator', choice(...['|', '&', '&&'].map(op => delimiter(op)))), '{', field('SERE', $._PSL_SERE), '}' ), PSL_Parameters_Definition: $ => sepBy1(',', $.PSL_Parameter_Specification), PSL_Parameter_Specification: $ => seq( $._PSL_Identifier, optional($.PSL_Index_Range), reservedWord('in'), $.PSL_Value_Set ), // }}} // PSL 6.1.2 Sequences {{{ _PSL_Sequence: $ => choice( $._PSL_Sequence_Instance, $.PSL_Repeated_SERE, $.PSL_Braced_SERE, $.PSL_Clocked_SERE ), PSL_Repeated_SERE: $ => prec.left( 'SERE_repetition', seq( optional(choice( $._PSL_Boolean, $._PSL_Sequence, )), $.PSL_Count, ), ), PSL_Count: $ => seq( '[', optional(field('operator', choice(...['+', '*', '=', '->'].map(op => token.immediate(prec(3, (op))))) )), optional(choice( $._PSL_Number, $._PSL_Range )), ']', ), _PSL_Range: $ => $._range, PSL_Braced_SERE: $ => prec.right(seq( '{', $._PSL_SERE, '}' )), PSL_Clocked_SERE: $ => prec.left( 'clocked', seq( '{', $._PSL_SERE, '}', '@', $._PSL_Clock_Expression, ) ), // }}} // PSL 6.2 Properties {{{ _PSL_Property: $ => choice( $.PSL_Property_Replicator, $._PSL_FL_Property, $._PSL_Ambiguous_Instance, ), _PSL_FL_Property: $ => choice( $._PSL_Property_Instance, $.PSL_Parenthesized_FL_Property, $.PSL_Sequential_FL_Property, $.PSL_Clocked_FL_Property, $.PSL_Invariant_FL_Property, $.PSL_Ocurrence_FL_Property, $.PSL_Extended_Ocurrence_FL_Property, $.PSL_Termination_FL_Property, $.PSL_Bounding_FL_Property, $.PSL_Suffix_Implication_FL_Property, $.PSL_Parameterized_Property, $.PSL_Implication_FL_Property, $.PSL_Logical_FL_Property, $.PSL_Factor_FL_Property, $._PSL_Boolean ), PSL_Parenthesized_FL_Property: $ => prec('parenthesized_property',seq( '(', $._PSL_FL_Property, ')', )), PSL_Sequential_FL_Property: $ => prec.left(-1, seq( $._PSL_Sequence, optional('!') )), PSL_Clocked_FL_Property: $ => prec.right('clocked', seq( $._PSL_FL_Property, repeat1(prec.left('clocked',seq( field('operator', delimiter('@')), $._PSL_Clock_Expression ))), )), PSL_Invariant_FL_Property: $ => prec.right('invariant_property', seq( field('operator', choice(...['always', 'never'].map(op => reservedWord(op)))), $._PSL_FL_Property )), PSL_Ocurrence_FL_Property: $ => prec.right('occurrence_property', seq( field('operator', seq( choice(...['next', 'eventually'].map(op => reservedWord(op))), optional(token.immediate('!')) )), $._PSL_FL_Property )), PSL_Implication_FL_Property: $ => prec.right('property_implication', seq( $._PSL_FL_Property, repeat1(prec.left('property_implication',seq( field('operator', choice(...['->', '<->'].map(op => delimiter(op)))), $._PSL_FL_Property, ))), )), PSL_Logical_FL_Property: $ => prec.right('logical_property', seq( $._PSL_FL_Property, repeat1(prec.left('logical_property',seq( field('operator', choice(...['and', 'or'].map(op => reservedWord(op)))), $._PSL_FL_Property, ))), )), PSL_Factor_FL_Property: $ => prec.left('property_factor', seq( field('operator', reservedWord('not')), $._PSL_FL_Property, )), PSL_Extended_Ocurrence_FL_Property: $ => prec.right('occurrence_property', seq( field('operator', seq( choice(...[ 'eventually', 'next', 'next_a', 'next_e', 'next_event', 'next_event_a', 'next_event_e' ].map(op => reservedWord(op))), optional(token.immediate('!')) )), $._PSL_Extended_Ocurrence_argument, )), _PSL_Extended_Ocurrence_argument: $ => seq( choice( $._PSL_Extended_Ocurrence_FL_Property_Count_Specification, $._PSL_Extended_Ocurrence_FL_Property_Until_Specification, ), '(', field('Property', $._PSL_FL_Property), ')', ), _PSL_Extended_Ocurrence_FL_Property_Count_Specification: $ => seq( $.PSL_Count, ), _PSL_Extended_Ocurrence_FL_Property_Until_Specification: $ => prec('parenthesized_boolean',seq( '(', field('Boolean', $._PSL_Boolean), ')', optional($.PSL_Count), )), PSL_Termination_FL_Property: $ => prec.left('termination_property', seq( $._PSL_FL_Property, field('operator', choice(...['async_abort', 'sync_abort', 'abort'].map(op => reservedWord(op)))), $._PSL_Boolean )), PSL_Bounding_FL_Property: $ => prec.right('bounding_property', seq( $._PSL_FL_Property, field('operator', seq( choice(...['until', 'before'].map(op => reservedWord(op))), optional(token.immediate('!')), optional(token.immediate('_')) )), $._PSL_FL_Property, )), PSL_Suffix_Implication_FL_Property: $ => choice( prec.right(seq( '{', field('SERE', $._PSL_SERE), '}', '(', field('Property', $._PSL_FL_Property), ')', )), prec.right('sequence_implication', choice( ...['|=>', '|->'].map(op => { return seq( field('Sequence', $._PSL_Sequence), field('operator', delimiter(op)), field('Property', $._PSL_FL_Property), ) }) )), ), PSL_Parameterized_Property: $ => seq( reservedWord('for'), $.PSL_Parameters_Definition, ':', field('operator', choice(...['and', 'or'].map(op => reservedWord(op)))), '(', $._PSL_FL_Property, ')', ), // }}} // PSL 6.2.3 Replicated properties {{{ PSL_Property_Replicator: $ => seq( reservedWord('forall'), $.PSL_Parameter_Specification, ':', field('Property', choice( prec.dynamic(3,$._PSL_Property_Instance), $._PSL_Property ) ) ), PSL_Index_Range: $ => seq( '(', $._PSL_Range, ')' ), PSL_Value_Set: $ => choice( $.boolean, seq( '{', $._PSL_Value_Range, repeat(seq( ',', $._PSL_Value_Range )), '}', ), ), boolean: $ => reservedWord('boolean'), _PSL_Value_Range: $ => choice( $._PSL_Value, $._PSL_Range ), // }}} // PSL 6.3 Property and sequence declarations {{{ PSL_Property_Declaration: $ => seq( reservedWord('property'), $._PSL_Identifier, optional(seq( '(', $.PSL_Formal_Parameter_List, ')', )), reservedWord('is'), choice( prec.dynamic(3, $._PSL_Property_Instance), $._PSL_Property, ), ';' ), PSL_Sequence_Declaration: $ => seq( reservedWord('sequence'), $._PSL_Identifier, optional(seq( '(', $.PSL_Formal_Parameter_List, ')', )), reservedWord('is'), $._PSL_Sequence, ';' ), PSL_Formal_Parameter_List: $ => sepBy1(';', $.PSL_Formal_Parameter), PSL_Formal_Parameter: $ => seq( $._PSL_Parameter_Specification, sepBy1(',', $._PSL_Identifier) ), _PSL_Parameter_Specification: $ => choice( $.PSL_Constant_Parameter_Specification, $.PSL_Temporal_Parameter_Specification, ), PSL_Constant_Parameter_Specification: $ => choice( reservedWord('const'), seq( optional(reservedWord('const')), choice( $.PSL_HDL_Type, $.PSL_Type_Class ) ), ), PSL_Temporal_Parameter_Specification: $ => choice( reservedWord('sequence'), reservedWord('property'), ), PSL_HDL_Type: $ => seq( reservedWord('hdltype'), $.subtype_indication ), PSL_Type_Class: $ => choice( reservedWord('boolean'), reservedWord('bit'), reservedWord('bit_vector'), reservedWord('numeric'), reservedWord('string'), ), // }}} // PSL 6.3.3 Instantiation {{{ PSL_Instance: $ => seq( $._PSL_Identifier, optional(seq( '(', $.PSL_Actual_Parameter_List, ')' )) ), _PSL_Ambiguous_Instance: $ => prec.dynamic(-1,seq( alias($.PSL_Instance, $.PSL_Ambiguous_Instance) )), _PSL_Sequence_Instance: $ => prec.dynamic(-2, alias($.PSL_Instance, $.PSL_Sequence_Instance) ), _PSL_Property_Instance: $ => prec.dynamic(-2, alias($.PSL_Instance, $.PSL_Property_Instance) ), PSL_Actual_Parameter_List: $ => sepBy1(',', $.PSL_Actual_Parameter), PSL_Actual_Parameter: $ => choice( $._PSL_Any_Type, $._PSL_Sequence, $._PSL_Property ), // }}} // PSL 7.1 Verification directives {{{ _PSL_Directive: $ => choice( $.PSL_Assert_Directive, $.PSL_Assume_Directive, $.PSL_Assume_Guarantee_Directive, $.PSL_Restrict_Directive, $.PSL_Restrict_Guarantee_Directive, $.PSL_Cover_Directive, $.PSL_Fairness_Directive, $.PSL_Strong_Fairness_Directive, ), PSL_Assert_Directive: $ => prec('psl_assertion',seq( optional($.label), reservedWord('assert'), $._PSL_Property, optional($._report), ';' )), PSL_Assume_Directive: $ => seq( optional($.label), reservedWord('assume'), $._PSL_Property, ';' ), PSL_Assume_Guarantee_Directive: $ => seq( optional($.label), reservedWord('assume_guarantee'), $._PSL_Property, optional($._report), ';' ), PSL_Restrict_Directive: $ => seq( optional($.label), reservedWord('restrict'), $._PSL_Sequence, ';' ), PSL_Restrict_Guarantee_Directive: $ => seq( optional($.label), reservedWord('restrict_guarantee'), $._PSL_Sequence, optional($._report), ';' ), PSL_Cover_Directive: $ => seq( optional($.label), reservedWord('cover'), $._PSL_Sequence, optional($._report), ';' ), PSL_Fairness_Directive: $ => seq( optional($.label), reservedWord('fairness'), $._PSL_Boolean, ';' ), PSL_Strong_Fairness_Directive: $ => seq( optional($.label), reservedWord('strong'), reservedWord('fairness'), $._PSL_Boolean, ',', $._PSL_Boolean, ';' ), // }}} // PSL 7.2 Verification units {{{ _PSL_Verification_Unit: $ => choice( $.PSL_VUnit, $.PSL_VProp, $.PSL_VMode ), PSL_VUnit: $ => seq( reservedWord('vunit'), $._PSL_Identifier, $.PSL_Verification_Unit_Body ), PSL_VProp: $ => seq( reservedWord('vprop'), $._PSL_Identifier, $.PSL_Verification_Unit_Body ), PSL_VMode: $ => seq( reservedWord('vmode'), $._PSL_Identifier, $.PSL_Verification_Unit_Body ), PSL_Verification_Unit_Body: $ => seq( optional(seq( '(', $.PSL_Hierarchical_HDL_Name, ')' )), '{', repeat($.PSL_Inherit_Spec), repeat($._PSL_VUnit_Item), '}' ), PSL_Hierarchical_HDL_Name: $ => seq( $._PSL_HDL_Module_NAME, repeat(seq( choice( token.immediate('.'), token.immediate('/'), ), field('instance', $._simple_name) )) ), _PSL_HDL_Module_NAME: $ => seq( field('entity', $._simple_name), optional(seq( '(', field('architecture', $._simple_name), ')' )) ), PSL_Inherit_Spec: $ => seq( reservedWord('inherit'), sepBy1(',', $._name), ';' ), _PSL_VUnit_Item: $ => choice( $._declaration, $._concurrent_statement ), // }}} }, supertype: $ => [ $._primary_unit, $._secondary_unit, $._context_item, $._sequential_statement, $._concurrent_statement, $._PSL_Verification_Unit, $._PSL_Declaration, $._PSL_Directive ] }) // Helper functions {{{ function binary_expression(prec, operands, optable) { return choice(...optable.map(([operator, precedence, tokenize]) => { return prec(precedence, seq( field('left', operands), field('operator', tokenize(operator)), field('right', operands) )) })) } function unary_expression(prec, operand, optable) { return choice(...optable.map(([operator, precedence, tokenize]) => { return prec(precedence, seq( field('operator', tokenize(operator)), field('argument', operand) )) })) } function delimiter(delim, precedence = 2) { return token(prec(precedence, delim)) } function reservedWord(word) { //return word return alias(reserved(caseInsensitive(word)), word) } function reserved(regex) { return token(prec(2, new RegExp(regex))) } function caseInsensitive(word) { return word.split('') .map(letter => `[${letter}${letter.toUpperCase()}]`) .join('') } function sepBy1(sep, rule) { return seq(rule, repeat(seq(sep, rule))) } function sepBy(sep, rule) { return optional(sepBy1(sep, rule)) } // }}}