%YAML 1.2 --- # dfasm.sublime-syntax — Context-aware syntax highlighting for Sublime Text # Version: 2 (Sublime Text 4) # # Architecture: Context stacks distinguish port numbers from literal numbers # using contextual scoping. All scopes suffixed with .dfasm per design spec. # # Scope mapping: # - Port numbers (in qualified refs): constant.numeric.port.dfasm # - Literal numbers (in arguments): constant.numeric.dfasm # - Named arg keys (dest=): variable.parameter.dfasm # - Opcodes: keyword.other.opcode.dfasm # # Reference: dfasm.lark grammar, asm/opcodes.py, design plan lines 156-185 name: dfasm file_extensions: - dfasm scope: source.dfasm variables: identifier: '[a-zA-Z_][a-zA-Z0-9_]*' hex_lit: '0x[0-9a-fA-F]+' dec_lit: '[0-9]+' opcodes: 'add|sub|inc|dec|shiftl|shiftr|ashiftr|and|or|xor|not|eq|lt|lte|gt|gte|breq|brgt|brge|brof|brty|sweq|swgt|swge|swof|swty|gate|sel|merge|pass|const|free_ctx|read|write|clear|alloc|free|rd_inc|rd_dec|cmp_sw|ior|iow|iorw|load_inst|change_tag|extract_tag|exec' contexts: main: - match: ';.*$' scope: comment.line.semicolon.dfasm - match: '@system\b' scope: keyword.control.pragma.dfasm push: pragma_params # Flow operators must be matched before | and < separately # to avoid sregex matching issues with lookbehinds - match: '\|>' scope: keyword.operator.flow.out.dfasm - match: '<\|' scope: keyword.operator.flow.in.dfasm # Opcodes - match: '\b(?:{{opcodes}})\b' scope: keyword.other.opcode.dfasm # Sigils push into qualified_ref contexts - match: '@' scope: punctuation.definition.reference.node.dfasm push: qualified_ref_node_name - match: '&' scope: punctuation.definition.reference.label.dfasm push: qualified_ref_label_name - match: '\$' scope: punctuation.definition.reference.function.dfasm push: qualified_ref_func_name # Macro call: #name - match: '(#)({{identifier}})' captures: 1: punctuation.definition.macro.dfasm 2: entity.name.function.macro.dfasm # Strings with prefixes - match: 'r"' scope: storage.type.string.dfasm push: raw_string - match: 'b"' scope: storage.type.string.dfasm push: byte_string - match: '"' scope: string.quoted.double.dfasm push: string # Character literal - match: "'" scope: string.quoted.single.dfasm push: char_literal # Numbers (not in port context) - match: '{{hex_lit}}' scope: constant.numeric.dfasm - match: '{{dec_lit}}' scope: constant.numeric.dfasm # Named arguments: identifier=value (AC4.4) - match: '({{identifier}})(=)' captures: 1: variable.parameter.dfasm 2: keyword.operator.assignment.dfasm # Assignment operator - match: '=' scope: keyword.operator.assignment.dfasm # Comma - match: ',' scope: punctuation.separator.dfasm # Braces for function bodies - match: '\{' scope: punctuation.section.block.dfasm push: func_body - match: '\}' scope: punctuation.section.block.dfasm # Placement separator (must come after |>) - match: '\|(?!>)' scope: punctuation.separator.placement.dfasm # Colon separator (in port specs, but only matched if not in qualified_ref) - match: ':' scope: punctuation.separator.port.dfasm # Whitespace - match: '\s+' # === Qualified Reference Contexts === # Separate contexts per sigil to enforce scope mapping qualified_ref_node_name: - match: '{{identifier}}' scope: entity.name.tag.dfasm set: qualified_ref_suffix - match: '(?=\S)' pop: true qualified_ref_label_name: - match: '{{identifier}}' scope: entity.name.label.dfasm set: qualified_ref_suffix - match: '(?=\S)' pop: true qualified_ref_func_name: - match: '{{identifier}}' scope: entity.name.function.dfasm set: qualified_ref_suffix - match: '(?=\S)' pop: true qualified_ref_suffix: # Placement: | not followed by > - match: '\|(?!>)' scope: punctuation.separator.placement.dfasm set: placement_name # Port: : followed by number or identifier - match: ':' scope: punctuation.separator.port.dfasm set: port_spec # No suffix, pop back to main - match: '' pop: true placement_name: - match: '{{identifier}}' scope: entity.other.attribute-name.placement.dfasm set: qualified_ref_suffix_after_placement - match: '(?=\S)' pop: true qualified_ref_suffix_after_placement: # Port after placement - match: ':' scope: punctuation.separator.port.dfasm set: port_spec # No port, pop - match: '' pop: true port_spec: # Port identifier (L, R, etc.) - match: '{{identifier}}' scope: entity.other.attribute-name.port.dfasm pop: true # Hex number in port position gets constant.numeric.port.dfasm - match: '{{hex_lit}}' scope: constant.numeric.port.dfasm pop: true # Decimal number in port position gets constant.numeric.port.dfasm - match: '{{dec_lit}}' scope: constant.numeric.port.dfasm pop: true # No valid port spec, pop - match: '' pop: true # === Function Body === func_body: - meta_scope: meta.function.body.dfasm - match: '\}' scope: punctuation.section.block.dfasm pop: true # Include main context rules inside function body (AC4.5) - include: main # === Pragma Parameters === pragma_params: # param=value pairs - match: '({{identifier}})(=)({{hex_lit}}|{{dec_lit}})' captures: 1: variable.parameter.dfasm 2: keyword.operator.assignment.dfasm 3: constant.numeric.dfasm - match: ',' scope: punctuation.separator.dfasm - match: '(?=;)' pop: true - match: '$' pop: true - match: '\s+' # === String Contexts === string: - meta_scope: string.quoted.double.dfasm - match: '"' scope: string.quoted.double.dfasm pop: true - match: "\\\\[ntr0\\\\'\"]" scope: constant.character.escape.dfasm - match: '\\x[0-9a-fA-F]{2}' scope: constant.character.escape.dfasm - match: '\\' scope: constant.character.escape.dfasm raw_string: - meta_scope: string.quoted.double.raw.dfasm - match: '"' scope: string.quoted.double.raw.dfasm pop: true byte_string: - meta_scope: string.quoted.double.byte.dfasm - match: '"' scope: string.quoted.double.byte.dfasm pop: true - match: "\\\\[ntr0\\\\'\"]" scope: constant.character.escape.dfasm - match: '\\x[0-9a-fA-F]{2}' scope: constant.character.escape.dfasm - match: '\\' scope: constant.character.escape.dfasm char_literal: - meta_scope: string.quoted.single.dfasm - match: "'" scope: string.quoted.single.dfasm pop: true - match: "\\\\[ntr0\\\\'\"]" scope: constant.character.escape.dfasm - match: '\\x[0-9a-fA-F]{2}' scope: constant.character.escape.dfasm - match: '\\' scope: constant.character.escape.dfasm