Skip to content

Commit 736bbe4

Browse files
Steve Ramageclaude
andcommitted
refactor: wrap only the raw-hex hardware-address forms in the literal label (#501)
HARDWARE_ADDRESS wrapped its whole alternation in Labeled(Role.LITERAL), but two branches — IPV4_ADDR and IPV6_ADDR — are already Labeled (IPv6 also carries SemanticTag.IPV6). So an IP literal got a redundant second literal region over the same span. Move the wrapper down onto just the raw-hex forms (RAW_HARDWARE_ADDRESS) and let the already-labeled IP forms sit beside it, so every accepted value now colours as exactly one region. No matching change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 92c10bd commit 736bbe4

2 files changed

Lines changed: 27 additions & 11 deletions

File tree

  • src
    • main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar
    • test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar

src/main/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/Combinators.kt

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,18 +128,26 @@ val MAC_ADDRESS = Labeled(Role.LITERAL, AlternativeCombinator(
128128
hwAddrGroups(HW_ADDR_WORD, DOT, 3),
129129
))
130130

131-
// A hardware address as accepted by parse_hw_addr_full with expected_len == 0 (Match=, Link=,
132-
// Neighbor.LinkLayerAddress=). Besides 6-byte MACs this also accepts 4-, 16- and 20-byte (Infiniband)
133-
// hardware addresses, and — because the parser first tries in_addr_from_string — plain IPv4 and IPv6
134-
// address literals. colon/hyphen use 1-byte fields (4/6/16/20 groups); dot uses 2-byte fields
135-
// (2/3/8/10 groups). Longest group counts come first so the classic (first-full-match) matcher never
136-
// stops on a shorter prefix.
137-
val HARDWARE_ADDRESS = Labeled(Role.LITERAL, AlternativeCombinator(
138-
IPV6_ADDR,
139-
IPV4_ADDR,
131+
// The raw hex forms of a hardware address (colon/hyphen use 1-byte fields → 4/6/16/20 groups; dot uses
132+
// 2-byte fields → 2/3/8/10 groups). Longest group counts come first so the classic (first-full-match)
133+
// matcher never stops on a shorter prefix. Wrapped once so the whole address reads as a single literal
134+
// span rather than per-field.
135+
private val RAW_HARDWARE_ADDRESS = Labeled(Role.LITERAL, AlternativeCombinator(
140136
hwAddrGroups(HW_ADDR_BYTE, COLON, 20), hwAddrGroups(HW_ADDR_BYTE, COLON, 16), hwAddrGroups(HW_ADDR_BYTE, COLON, 6), hwAddrGroups(HW_ADDR_BYTE, COLON, 4),
141137
hwAddrGroups(HW_ADDR_BYTE, HYPHEN, 20), hwAddrGroups(HW_ADDR_BYTE, HYPHEN, 16), hwAddrGroups(HW_ADDR_BYTE, HYPHEN, 6), hwAddrGroups(HW_ADDR_BYTE, HYPHEN, 4),
142138
hwAddrGroups(HW_ADDR_WORD, DOT, 10), hwAddrGroups(HW_ADDR_WORD, DOT, 8), hwAddrGroups(HW_ADDR_WORD, DOT, 3), hwAddrGroups(HW_ADDR_WORD, DOT, 2),
143139
))
144140

141+
// A hardware address as accepted by parse_hw_addr_full with expected_len == 0 (Match=, Link=,
142+
// Neighbor.LinkLayerAddress=). Besides 6-byte MACs it accepts 4-, 16- and 20-byte (Infiniband)
143+
// hardware addresses, and — because the parser first tries in_addr_from_string — plain IPv4 and IPv6
144+
// address literals. IPV4_ADDR / IPV6_ADDR are already Labeled (IPv6 also carries SemanticTag.IPV6), so
145+
// they sit alongside the wrapped raw forms rather than inside a second wrapper — a whole-alternation
146+
// Labeled would emit a redundant second literal region over an IP literal's span.
147+
val HARDWARE_ADDRESS = AlternativeCombinator(
148+
IPV6_ADDR,
149+
IPV4_ADDR,
150+
RAW_HARDWARE_ADDRESS,
151+
)
152+
145153

src/test/kotlin/net/sjrx/intellij/plugins/systemdunitfiles/semanticdata/optionvalues/grammar/MacAddressGrammarTest.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,17 @@ class MacAddressGrammarTest {
7878

7979
@Test
8080
fun testAddressColorsAsOneLiteralSpan() {
81-
// Both combinators are wrapped in Labeled(Role.LITERAL): the whole address is a single literal
82-
// span (not coloured per octet / with the separators as operators).
81+
// Both combinators wrap the raw hex forms in Labeled(Role.LITERAL): the whole address is a single
82+
// literal span (not coloured per octet / with the separators as operators).
8383
assertEquals(listOf(Region(0, 17, Role.LITERAL)), mac.colorize("00:11:22:33:44:55"))
8484
assertEquals(listOf(Region(0, 17, Role.LITERAL)), hwAddr.colorize("00-11-22-33-44-55"))
8585
}
86+
87+
@Test
88+
fun testIpLiteralInHardwareAddressColorsAsOneRegion() {
89+
// The raw-hex wrapper is not layered over IPV4_ADDR / IPV6_ADDR (they are already Labeled), so an
90+
// IP literal yields exactly one region — its own — carrying the IPv6 tag, not a doubled span.
91+
assertEquals(listOf(Region(0, 11, Role.LITERAL, SemanticTag.IPV6)), hwAddr.colorize("2001:db8::1"))
92+
assertEquals(listOf(Region(0, 11, Role.LITERAL)), hwAddr.colorize("192.168.1.1"))
93+
}
8694
}

0 commit comments

Comments
 (0)