mirror of
https://github.com/Myzel394/config-lsp.git
synced 2025-06-18 23:15:26 +02:00
feat(hosts): Add hosts parser
This commit is contained in:
parent
a2b5f1ea93
commit
4fe2f46b1b
14
common/errors.go
Normal file
14
common/errors.go
Normal file
@ -0,0 +1,14 @@
|
||||
package common
|
||||
|
||||
type LSPError struct {
|
||||
Range LocationRange
|
||||
Err error
|
||||
}
|
||||
|
||||
type SyntaxError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (s SyntaxError) Error() string {
|
||||
return s.Message
|
||||
}
|
29
common/location.go
Normal file
29
common/location.go
Normal file
@ -0,0 +1,29 @@
|
||||
package common
|
||||
|
||||
type Location struct {
|
||||
Line uint32
|
||||
Character uint32
|
||||
}
|
||||
|
||||
type LocationRange struct {
|
||||
Start Location
|
||||
End Location
|
||||
}
|
||||
|
||||
func (l *LocationRange) ChangeBothLines(newLine uint32) {
|
||||
l.Start.Line = newLine
|
||||
l.End.Line = newLine
|
||||
}
|
||||
|
||||
func CreateSingleCharRange(line uint32, character uint32) LocationRange {
|
||||
return LocationRange{
|
||||
Start: Location{
|
||||
Line: line,
|
||||
Character: character,
|
||||
},
|
||||
End: Location{
|
||||
Line: line,
|
||||
Character: character,
|
||||
},
|
||||
}
|
||||
}
|
1
go.mod
1
go.mod
@ -8,6 +8,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
||||
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||
github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
|
126
handlers/hosts/Hosts.g4
Normal file
126
handlers/hosts/Hosts.g4
Normal file
@ -0,0 +1,126 @@
|
||||
grammar Hosts;
|
||||
|
||||
lineStatement
|
||||
: SEPARATOR? entry SEPARATOR? leadingComment? EOF
|
||||
;
|
||||
|
||||
entry
|
||||
: ipAddress SEPARATOR hostname (SEPARATOR aliases)?
|
||||
;
|
||||
|
||||
aliases
|
||||
: (alias SEPARATOR?)+
|
||||
;
|
||||
|
||||
alias
|
||||
: DOMAIN
|
||||
;
|
||||
|
||||
hostname
|
||||
: domain
|
||||
;
|
||||
|
||||
domain
|
||||
: DOMAIN
|
||||
;
|
||||
|
||||
ipAddress
|
||||
: (ipv4Address | ipv6Address)
|
||||
;
|
||||
|
||||
ipv4Address
|
||||
: singleIPv4Address
|
||||
// Allow optional range to tell user ranges are not allowed
|
||||
ipRange?
|
||||
;
|
||||
|
||||
singleIPv4Address
|
||||
: ipv4Digit DOT ipv4Digit DOT ipv4Digit DOT ipv4Digit
|
||||
;
|
||||
|
||||
// This is not correct but fits for now
|
||||
ipv6Address
|
||||
: singleIPv6Address
|
||||
// Allow optional range to tell user ranges are not allowed
|
||||
ipRange?
|
||||
;
|
||||
|
||||
singleIPv6Address
|
||||
: (ipv6Octet COLON)+ ipv6Octet
|
||||
;
|
||||
|
||||
ipv4Digit
|
||||
: DIGITS
|
||||
;
|
||||
|
||||
ipv6Octet
|
||||
: OCTETS
|
||||
;
|
||||
|
||||
ipRange
|
||||
: SLASH ipRangeBits
|
||||
;
|
||||
|
||||
ipRangeBits
|
||||
: DIGITS
|
||||
;
|
||||
|
||||
comment
|
||||
: COMMENTLINE
|
||||
;
|
||||
|
||||
leadingComment
|
||||
: COMMENTLINE
|
||||
;
|
||||
|
||||
COMMENTLINE
|
||||
: HASHTAG ~[\r\n]+
|
||||
;
|
||||
|
||||
SLASH
|
||||
: '/'
|
||||
;
|
||||
|
||||
DOT
|
||||
: '.'
|
||||
;
|
||||
|
||||
COLON
|
||||
: ':'
|
||||
;
|
||||
|
||||
HASHTAG
|
||||
: '#'
|
||||
;
|
||||
|
||||
SEPARATOR
|
||||
: [ \t]+
|
||||
;
|
||||
|
||||
NEWLINE
|
||||
: [\r]? [\n]
|
||||
;
|
||||
|
||||
DIGITS
|
||||
: DIGIT+
|
||||
;
|
||||
|
||||
fragment DIGIT
|
||||
: [0-9]
|
||||
;
|
||||
|
||||
OCTETS
|
||||
: OCTET+
|
||||
;
|
||||
|
||||
fragment OCTET
|
||||
: [0-9a-fA-F]
|
||||
;
|
||||
|
||||
DOMAIN
|
||||
: ((STRING)+ (DOT [a-zA-Z]+)*)
|
||||
;
|
||||
|
||||
fragment STRING
|
||||
: ~(' ' | '\t' | '\n' | '\r' | '#' | '.')
|
||||
;
|
48
handlers/hosts/parser/Hosts.interp
Normal file
48
handlers/hosts/parser/Hosts.interp
Normal file
@ -0,0 +1,48 @@
|
||||
token literal names:
|
||||
null
|
||||
null
|
||||
'/'
|
||||
'.'
|
||||
':'
|
||||
'#'
|
||||
null
|
||||
null
|
||||
null
|
||||
null
|
||||
null
|
||||
|
||||
token symbolic names:
|
||||
null
|
||||
COMMENTLINE
|
||||
SLASH
|
||||
DOT
|
||||
COLON
|
||||
HASHTAG
|
||||
SEPARATOR
|
||||
NEWLINE
|
||||
DIGITS
|
||||
OCTETS
|
||||
DOMAIN
|
||||
|
||||
rule names:
|
||||
lineStatement
|
||||
entry
|
||||
aliases
|
||||
alias
|
||||
hostname
|
||||
domain
|
||||
ipAddress
|
||||
ipv4Address
|
||||
singleIPv4Address
|
||||
ipv6Address
|
||||
singleIPv6Address
|
||||
ipv4Digit
|
||||
ipv6Octet
|
||||
ipRange
|
||||
ipRangeBits
|
||||
comment
|
||||
leadingComment
|
||||
|
||||
|
||||
atn:
|
||||
[4, 1, 10, 110, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 1, 0, 3, 0, 36, 8, 0, 1, 0, 1, 0, 3, 0, 40, 8, 0, 1, 0, 3, 0, 43, 8, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 52, 8, 1, 1, 2, 1, 2, 3, 2, 56, 8, 2, 4, 2, 58, 8, 2, 11, 2, 12, 2, 59, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 3, 6, 70, 8, 6, 1, 7, 1, 7, 3, 7, 74, 8, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 3, 9, 86, 8, 9, 1, 10, 1, 10, 1, 10, 4, 10, 91, 8, 10, 11, 10, 12, 10, 92, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 0, 0, 17, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 0, 0, 102, 0, 35, 1, 0, 0, 0, 2, 46, 1, 0, 0, 0, 4, 57, 1, 0, 0, 0, 6, 61, 1, 0, 0, 0, 8, 63, 1, 0, 0, 0, 10, 65, 1, 0, 0, 0, 12, 69, 1, 0, 0, 0, 14, 71, 1, 0, 0, 0, 16, 75, 1, 0, 0, 0, 18, 83, 1, 0, 0, 0, 20, 90, 1, 0, 0, 0, 22, 96, 1, 0, 0, 0, 24, 98, 1, 0, 0, 0, 26, 100, 1, 0, 0, 0, 28, 103, 1, 0, 0, 0, 30, 105, 1, 0, 0, 0, 32, 107, 1, 0, 0, 0, 34, 36, 5, 6, 0, 0, 35, 34, 1, 0, 0, 0, 35, 36, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 39, 3, 2, 1, 0, 38, 40, 5, 6, 0, 0, 39, 38, 1, 0, 0, 0, 39, 40, 1, 0, 0, 0, 40, 42, 1, 0, 0, 0, 41, 43, 3, 32, 16, 0, 42, 41, 1, 0, 0, 0, 42, 43, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 45, 5, 0, 0, 1, 45, 1, 1, 0, 0, 0, 46, 47, 3, 12, 6, 0, 47, 48, 5, 6, 0, 0, 48, 51, 3, 8, 4, 0, 49, 50, 5, 6, 0, 0, 50, 52, 3, 4, 2, 0, 51, 49, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 3, 1, 0, 0, 0, 53, 55, 3, 6, 3, 0, 54, 56, 5, 6, 0, 0, 55, 54, 1, 0, 0, 0, 55, 56, 1, 0, 0, 0, 56, 58, 1, 0, 0, 0, 57, 53, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 57, 1, 0, 0, 0, 59, 60, 1, 0, 0, 0, 60, 5, 1, 0, 0, 0, 61, 62, 5, 10, 0, 0, 62, 7, 1, 0, 0, 0, 63, 64, 3, 10, 5, 0, 64, 9, 1, 0, 0, 0, 65, 66, 5, 10, 0, 0, 66, 11, 1, 0, 0, 0, 67, 70, 3, 14, 7, 0, 68, 70, 3, 18, 9, 0, 69, 67, 1, 0, 0, 0, 69, 68, 1, 0, 0, 0, 70, 13, 1, 0, 0, 0, 71, 73, 3, 16, 8, 0, 72, 74, 3, 26, 13, 0, 73, 72, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 15, 1, 0, 0, 0, 75, 76, 3, 22, 11, 0, 76, 77, 5, 3, 0, 0, 77, 78, 3, 22, 11, 0, 78, 79, 5, 3, 0, 0, 79, 80, 3, 22, 11, 0, 80, 81, 5, 3, 0, 0, 81, 82, 3, 22, 11, 0, 82, 17, 1, 0, 0, 0, 83, 85, 3, 20, 10, 0, 84, 86, 3, 26, 13, 0, 85, 84, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, 19, 1, 0, 0, 0, 87, 88, 3, 24, 12, 0, 88, 89, 5, 4, 0, 0, 89, 91, 1, 0, 0, 0, 90, 87, 1, 0, 0, 0, 91, 92, 1, 0, 0, 0, 92, 90, 1, 0, 0, 0, 92, 93, 1, 0, 0, 0, 93, 94, 1, 0, 0, 0, 94, 95, 3, 24, 12, 0, 95, 21, 1, 0, 0, 0, 96, 97, 5, 8, 0, 0, 97, 23, 1, 0, 0, 0, 98, 99, 5, 9, 0, 0, 99, 25, 1, 0, 0, 0, 100, 101, 5, 2, 0, 0, 101, 102, 3, 28, 14, 0, 102, 27, 1, 0, 0, 0, 103, 104, 5, 8, 0, 0, 104, 29, 1, 0, 0, 0, 105, 106, 5, 1, 0, 0, 106, 31, 1, 0, 0, 0, 107, 108, 5, 1, 0, 0, 108, 33, 1, 0, 0, 0, 10, 35, 39, 42, 51, 55, 59, 69, 73, 85, 92]
|
14
handlers/hosts/parser/Hosts.tokens
Normal file
14
handlers/hosts/parser/Hosts.tokens
Normal file
@ -0,0 +1,14 @@
|
||||
COMMENTLINE=1
|
||||
SLASH=2
|
||||
DOT=3
|
||||
COLON=4
|
||||
HASHTAG=5
|
||||
SEPARATOR=6
|
||||
NEWLINE=7
|
||||
DIGITS=8
|
||||
OCTETS=9
|
||||
DOMAIN=10
|
||||
'/'=2
|
||||
'.'=3
|
||||
':'=4
|
||||
'#'=5
|
50
handlers/hosts/parser/HostsLexer.interp
Normal file
50
handlers/hosts/parser/HostsLexer.interp
Normal file
@ -0,0 +1,50 @@
|
||||
token literal names:
|
||||
null
|
||||
null
|
||||
'/'
|
||||
'.'
|
||||
':'
|
||||
'#'
|
||||
null
|
||||
null
|
||||
null
|
||||
null
|
||||
null
|
||||
|
||||
token symbolic names:
|
||||
null
|
||||
COMMENTLINE
|
||||
SLASH
|
||||
DOT
|
||||
COLON
|
||||
HASHTAG
|
||||
SEPARATOR
|
||||
NEWLINE
|
||||
DIGITS
|
||||
OCTETS
|
||||
DOMAIN
|
||||
|
||||
rule names:
|
||||
COMMENTLINE
|
||||
SLASH
|
||||
DOT
|
||||
COLON
|
||||
HASHTAG
|
||||
SEPARATOR
|
||||
NEWLINE
|
||||
DIGITS
|
||||
DIGIT
|
||||
OCTETS
|
||||
OCTET
|
||||
DOMAIN
|
||||
STRING
|
||||
|
||||
channel names:
|
||||
DEFAULT_TOKEN_CHANNEL
|
||||
HIDDEN
|
||||
|
||||
mode names:
|
||||
DEFAULT_MODE
|
||||
|
||||
atn:
|
||||
[4, 0, 10, 83, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 1, 0, 1, 0, 4, 0, 30, 8, 0, 11, 0, 12, 0, 31, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 4, 5, 43, 8, 5, 11, 5, 12, 5, 44, 1, 6, 3, 6, 48, 8, 6, 1, 6, 1, 6, 1, 7, 4, 7, 53, 8, 7, 11, 7, 12, 7, 54, 1, 8, 1, 8, 1, 9, 4, 9, 60, 8, 9, 11, 9, 12, 9, 61, 1, 10, 1, 10, 1, 11, 4, 11, 67, 8, 11, 11, 11, 12, 11, 68, 1, 11, 1, 11, 4, 11, 73, 8, 11, 11, 11, 12, 11, 74, 5, 11, 77, 8, 11, 10, 11, 12, 11, 80, 9, 11, 1, 12, 1, 12, 0, 0, 13, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 0, 19, 9, 21, 0, 23, 10, 25, 0, 1, 0, 8, 2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, 32, 1, 0, 13, 13, 1, 0, 10, 10, 1, 0, 48, 57, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 65, 90, 97, 122, 5, 0, 9, 10, 13, 13, 32, 32, 35, 35, 46, 46, 87, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 1, 27, 1, 0, 0, 0, 3, 33, 1, 0, 0, 0, 5, 35, 1, 0, 0, 0, 7, 37, 1, 0, 0, 0, 9, 39, 1, 0, 0, 0, 11, 42, 1, 0, 0, 0, 13, 47, 1, 0, 0, 0, 15, 52, 1, 0, 0, 0, 17, 56, 1, 0, 0, 0, 19, 59, 1, 0, 0, 0, 21, 63, 1, 0, 0, 0, 23, 66, 1, 0, 0, 0, 25, 81, 1, 0, 0, 0, 27, 29, 3, 9, 4, 0, 28, 30, 8, 0, 0, 0, 29, 28, 1, 0, 0, 0, 30, 31, 1, 0, 0, 0, 31, 29, 1, 0, 0, 0, 31, 32, 1, 0, 0, 0, 32, 2, 1, 0, 0, 0, 33, 34, 5, 47, 0, 0, 34, 4, 1, 0, 0, 0, 35, 36, 5, 46, 0, 0, 36, 6, 1, 0, 0, 0, 37, 38, 5, 58, 0, 0, 38, 8, 1, 0, 0, 0, 39, 40, 5, 35, 0, 0, 40, 10, 1, 0, 0, 0, 41, 43, 7, 1, 0, 0, 42, 41, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 42, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 12, 1, 0, 0, 0, 46, 48, 7, 2, 0, 0, 47, 46, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 49, 1, 0, 0, 0, 49, 50, 7, 3, 0, 0, 50, 14, 1, 0, 0, 0, 51, 53, 3, 17, 8, 0, 52, 51, 1, 0, 0, 0, 53, 54, 1, 0, 0, 0, 54, 52, 1, 0, 0, 0, 54, 55, 1, 0, 0, 0, 55, 16, 1, 0, 0, 0, 56, 57, 7, 4, 0, 0, 57, 18, 1, 0, 0, 0, 58, 60, 3, 21, 10, 0, 59, 58, 1, 0, 0, 0, 60, 61, 1, 0, 0, 0, 61, 59, 1, 0, 0, 0, 61, 62, 1, 0, 0, 0, 62, 20, 1, 0, 0, 0, 63, 64, 7, 5, 0, 0, 64, 22, 1, 0, 0, 0, 65, 67, 3, 25, 12, 0, 66, 65, 1, 0, 0, 0, 67, 68, 1, 0, 0, 0, 68, 66, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69, 78, 1, 0, 0, 0, 70, 72, 3, 5, 2, 0, 71, 73, 7, 6, 0, 0, 72, 71, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 72, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 77, 1, 0, 0, 0, 76, 70, 1, 0, 0, 0, 77, 80, 1, 0, 0, 0, 78, 76, 1, 0, 0, 0, 78, 79, 1, 0, 0, 0, 79, 24, 1, 0, 0, 0, 80, 78, 1, 0, 0, 0, 81, 82, 8, 7, 0, 0, 82, 26, 1, 0, 0, 0, 9, 0, 31, 44, 47, 54, 61, 68, 74, 78, 0]
|
14
handlers/hosts/parser/HostsLexer.tokens
Normal file
14
handlers/hosts/parser/HostsLexer.tokens
Normal file
@ -0,0 +1,14 @@
|
||||
COMMENTLINE=1
|
||||
SLASH=2
|
||||
DOT=3
|
||||
COLON=4
|
||||
HASHTAG=5
|
||||
SEPARATOR=6
|
||||
NEWLINE=7
|
||||
DIGITS=8
|
||||
OCTETS=9
|
||||
DOMAIN=10
|
||||
'/'=2
|
||||
'.'=3
|
||||
':'=4
|
||||
'#'=5
|
124
handlers/hosts/parser/hosts_base_listener.go
Normal file
124
handlers/hosts/parser/hosts_base_listener.go
Normal file
@ -0,0 +1,124 @@
|
||||
// Code generated from Hosts.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package parser // Hosts
|
||||
|
||||
import "github.com/antlr4-go/antlr/v4"
|
||||
|
||||
// BaseHostsListener is a complete listener for a parse tree produced by HostsParser.
|
||||
type BaseHostsListener struct{}
|
||||
|
||||
var _ HostsListener = &BaseHostsListener{}
|
||||
|
||||
// VisitTerminal is called when a terminal node is visited.
|
||||
func (s *BaseHostsListener) VisitTerminal(node antlr.TerminalNode) {}
|
||||
|
||||
// VisitErrorNode is called when an error node is visited.
|
||||
func (s *BaseHostsListener) VisitErrorNode(node antlr.ErrorNode) {}
|
||||
|
||||
// EnterEveryRule is called when any rule is entered.
|
||||
func (s *BaseHostsListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}
|
||||
|
||||
// ExitEveryRule is called when any rule is exited.
|
||||
func (s *BaseHostsListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}
|
||||
|
||||
// EnterLineStatement is called when production lineStatement is entered.
|
||||
func (s *BaseHostsListener) EnterLineStatement(ctx *LineStatementContext) {}
|
||||
|
||||
// ExitLineStatement is called when production lineStatement is exited.
|
||||
func (s *BaseHostsListener) ExitLineStatement(ctx *LineStatementContext) {}
|
||||
|
||||
// EnterEntry is called when production entry is entered.
|
||||
func (s *BaseHostsListener) EnterEntry(ctx *EntryContext) {}
|
||||
|
||||
// ExitEntry is called when production entry is exited.
|
||||
func (s *BaseHostsListener) ExitEntry(ctx *EntryContext) {}
|
||||
|
||||
// EnterAliases is called when production aliases is entered.
|
||||
func (s *BaseHostsListener) EnterAliases(ctx *AliasesContext) {}
|
||||
|
||||
// ExitAliases is called when production aliases is exited.
|
||||
func (s *BaseHostsListener) ExitAliases(ctx *AliasesContext) {}
|
||||
|
||||
// EnterAlias is called when production alias is entered.
|
||||
func (s *BaseHostsListener) EnterAlias(ctx *AliasContext) {}
|
||||
|
||||
// ExitAlias is called when production alias is exited.
|
||||
func (s *BaseHostsListener) ExitAlias(ctx *AliasContext) {}
|
||||
|
||||
// EnterHostname is called when production hostname is entered.
|
||||
func (s *BaseHostsListener) EnterHostname(ctx *HostnameContext) {}
|
||||
|
||||
// ExitHostname is called when production hostname is exited.
|
||||
func (s *BaseHostsListener) ExitHostname(ctx *HostnameContext) {}
|
||||
|
||||
// EnterDomain is called when production domain is entered.
|
||||
func (s *BaseHostsListener) EnterDomain(ctx *DomainContext) {}
|
||||
|
||||
// ExitDomain is called when production domain is exited.
|
||||
func (s *BaseHostsListener) ExitDomain(ctx *DomainContext) {}
|
||||
|
||||
// EnterIpAddress is called when production ipAddress is entered.
|
||||
func (s *BaseHostsListener) EnterIpAddress(ctx *IpAddressContext) {}
|
||||
|
||||
// ExitIpAddress is called when production ipAddress is exited.
|
||||
func (s *BaseHostsListener) ExitIpAddress(ctx *IpAddressContext) {}
|
||||
|
||||
// EnterIpv4Address is called when production ipv4Address is entered.
|
||||
func (s *BaseHostsListener) EnterIpv4Address(ctx *Ipv4AddressContext) {}
|
||||
|
||||
// ExitIpv4Address is called when production ipv4Address is exited.
|
||||
func (s *BaseHostsListener) ExitIpv4Address(ctx *Ipv4AddressContext) {}
|
||||
|
||||
// EnterSingleIPv4Address is called when production singleIPv4Address is entered.
|
||||
func (s *BaseHostsListener) EnterSingleIPv4Address(ctx *SingleIPv4AddressContext) {}
|
||||
|
||||
// ExitSingleIPv4Address is called when production singleIPv4Address is exited.
|
||||
func (s *BaseHostsListener) ExitSingleIPv4Address(ctx *SingleIPv4AddressContext) {}
|
||||
|
||||
// EnterIpv6Address is called when production ipv6Address is entered.
|
||||
func (s *BaseHostsListener) EnterIpv6Address(ctx *Ipv6AddressContext) {}
|
||||
|
||||
// ExitIpv6Address is called when production ipv6Address is exited.
|
||||
func (s *BaseHostsListener) ExitIpv6Address(ctx *Ipv6AddressContext) {}
|
||||
|
||||
// EnterSingleIPv6Address is called when production singleIPv6Address is entered.
|
||||
func (s *BaseHostsListener) EnterSingleIPv6Address(ctx *SingleIPv6AddressContext) {}
|
||||
|
||||
// ExitSingleIPv6Address is called when production singleIPv6Address is exited.
|
||||
func (s *BaseHostsListener) ExitSingleIPv6Address(ctx *SingleIPv6AddressContext) {}
|
||||
|
||||
// EnterIpv4Digit is called when production ipv4Digit is entered.
|
||||
func (s *BaseHostsListener) EnterIpv4Digit(ctx *Ipv4DigitContext) {}
|
||||
|
||||
// ExitIpv4Digit is called when production ipv4Digit is exited.
|
||||
func (s *BaseHostsListener) ExitIpv4Digit(ctx *Ipv4DigitContext) {}
|
||||
|
||||
// EnterIpv6Octet is called when production ipv6Octet is entered.
|
||||
func (s *BaseHostsListener) EnterIpv6Octet(ctx *Ipv6OctetContext) {}
|
||||
|
||||
// ExitIpv6Octet is called when production ipv6Octet is exited.
|
||||
func (s *BaseHostsListener) ExitIpv6Octet(ctx *Ipv6OctetContext) {}
|
||||
|
||||
// EnterIpRange is called when production ipRange is entered.
|
||||
func (s *BaseHostsListener) EnterIpRange(ctx *IpRangeContext) {}
|
||||
|
||||
// ExitIpRange is called when production ipRange is exited.
|
||||
func (s *BaseHostsListener) ExitIpRange(ctx *IpRangeContext) {}
|
||||
|
||||
// EnterIpRangeBits is called when production ipRangeBits is entered.
|
||||
func (s *BaseHostsListener) EnterIpRangeBits(ctx *IpRangeBitsContext) {}
|
||||
|
||||
// ExitIpRangeBits is called when production ipRangeBits is exited.
|
||||
func (s *BaseHostsListener) ExitIpRangeBits(ctx *IpRangeBitsContext) {}
|
||||
|
||||
// EnterComment is called when production comment is entered.
|
||||
func (s *BaseHostsListener) EnterComment(ctx *CommentContext) {}
|
||||
|
||||
// ExitComment is called when production comment is exited.
|
||||
func (s *BaseHostsListener) ExitComment(ctx *CommentContext) {}
|
||||
|
||||
// EnterLeadingComment is called when production leadingComment is entered.
|
||||
func (s *BaseHostsListener) EnterLeadingComment(ctx *LeadingCommentContext) {}
|
||||
|
||||
// ExitLeadingComment is called when production leadingComment is exited.
|
||||
func (s *BaseHostsListener) ExitLeadingComment(ctx *LeadingCommentContext) {}
|
145
handlers/hosts/parser/hosts_lexer.go
Normal file
145
handlers/hosts/parser/hosts_lexer.go
Normal file
@ -0,0 +1,145 @@
|
||||
// Code generated from Hosts.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
"sync"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Suppress unused import error
|
||||
var _ = fmt.Printf
|
||||
var _ = sync.Once{}
|
||||
var _ = unicode.IsLetter
|
||||
|
||||
type HostsLexer struct {
|
||||
*antlr.BaseLexer
|
||||
channelNames []string
|
||||
modeNames []string
|
||||
// TODO: EOF string
|
||||
}
|
||||
|
||||
var HostsLexerLexerStaticData struct {
|
||||
once sync.Once
|
||||
serializedATN []int32
|
||||
ChannelNames []string
|
||||
ModeNames []string
|
||||
LiteralNames []string
|
||||
SymbolicNames []string
|
||||
RuleNames []string
|
||||
PredictionContextCache *antlr.PredictionContextCache
|
||||
atn *antlr.ATN
|
||||
decisionToDFA []*antlr.DFA
|
||||
}
|
||||
|
||||
func hostslexerLexerInit() {
|
||||
staticData := &HostsLexerLexerStaticData
|
||||
staticData.ChannelNames = []string{
|
||||
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
|
||||
}
|
||||
staticData.ModeNames = []string{
|
||||
"DEFAULT_MODE",
|
||||
}
|
||||
staticData.LiteralNames = []string{
|
||||
"", "", "'/'", "'.'", "':'", "'#'",
|
||||
}
|
||||
staticData.SymbolicNames = []string{
|
||||
"", "COMMENTLINE", "SLASH", "DOT", "COLON", "HASHTAG", "SEPARATOR",
|
||||
"NEWLINE", "DIGITS", "OCTETS", "DOMAIN",
|
||||
}
|
||||
staticData.RuleNames = []string{
|
||||
"COMMENTLINE", "SLASH", "DOT", "COLON", "HASHTAG", "SEPARATOR", "NEWLINE",
|
||||
"DIGITS", "DIGIT", "OCTETS", "OCTET", "DOMAIN", "STRING",
|
||||
}
|
||||
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
|
||||
staticData.serializedATN = []int32{
|
||||
4, 0, 10, 83, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2,
|
||||
4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2,
|
||||
10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 1, 0, 1, 0, 4, 0, 30, 8, 0, 11,
|
||||
0, 12, 0, 31, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 4,
|
||||
5, 43, 8, 5, 11, 5, 12, 5, 44, 1, 6, 3, 6, 48, 8, 6, 1, 6, 1, 6, 1, 7,
|
||||
4, 7, 53, 8, 7, 11, 7, 12, 7, 54, 1, 8, 1, 8, 1, 9, 4, 9, 60, 8, 9, 11,
|
||||
9, 12, 9, 61, 1, 10, 1, 10, 1, 11, 4, 11, 67, 8, 11, 11, 11, 12, 11, 68,
|
||||
1, 11, 1, 11, 4, 11, 73, 8, 11, 11, 11, 12, 11, 74, 5, 11, 77, 8, 11, 10,
|
||||
11, 12, 11, 80, 9, 11, 1, 12, 1, 12, 0, 0, 13, 1, 1, 3, 2, 5, 3, 7, 4,
|
||||
9, 5, 11, 6, 13, 7, 15, 8, 17, 0, 19, 9, 21, 0, 23, 10, 25, 0, 1, 0, 8,
|
||||
2, 0, 10, 10, 13, 13, 2, 0, 9, 9, 32, 32, 1, 0, 13, 13, 1, 0, 10, 10, 1,
|
||||
0, 48, 57, 3, 0, 48, 57, 65, 70, 97, 102, 2, 0, 65, 90, 97, 122, 5, 0,
|
||||
9, 10, 13, 13, 32, 32, 35, 35, 46, 46, 87, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0,
|
||||
0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0,
|
||||
0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 23, 1,
|
||||
0, 0, 0, 1, 27, 1, 0, 0, 0, 3, 33, 1, 0, 0, 0, 5, 35, 1, 0, 0, 0, 7, 37,
|
||||
1, 0, 0, 0, 9, 39, 1, 0, 0, 0, 11, 42, 1, 0, 0, 0, 13, 47, 1, 0, 0, 0,
|
||||
15, 52, 1, 0, 0, 0, 17, 56, 1, 0, 0, 0, 19, 59, 1, 0, 0, 0, 21, 63, 1,
|
||||
0, 0, 0, 23, 66, 1, 0, 0, 0, 25, 81, 1, 0, 0, 0, 27, 29, 3, 9, 4, 0, 28,
|
||||
30, 8, 0, 0, 0, 29, 28, 1, 0, 0, 0, 30, 31, 1, 0, 0, 0, 31, 29, 1, 0, 0,
|
||||
0, 31, 32, 1, 0, 0, 0, 32, 2, 1, 0, 0, 0, 33, 34, 5, 47, 0, 0, 34, 4, 1,
|
||||
0, 0, 0, 35, 36, 5, 46, 0, 0, 36, 6, 1, 0, 0, 0, 37, 38, 5, 58, 0, 0, 38,
|
||||
8, 1, 0, 0, 0, 39, 40, 5, 35, 0, 0, 40, 10, 1, 0, 0, 0, 41, 43, 7, 1, 0,
|
||||
0, 42, 41, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 42, 1, 0, 0, 0, 44, 45,
|
||||
1, 0, 0, 0, 45, 12, 1, 0, 0, 0, 46, 48, 7, 2, 0, 0, 47, 46, 1, 0, 0, 0,
|
||||
47, 48, 1, 0, 0, 0, 48, 49, 1, 0, 0, 0, 49, 50, 7, 3, 0, 0, 50, 14, 1,
|
||||
0, 0, 0, 51, 53, 3, 17, 8, 0, 52, 51, 1, 0, 0, 0, 53, 54, 1, 0, 0, 0, 54,
|
||||
52, 1, 0, 0, 0, 54, 55, 1, 0, 0, 0, 55, 16, 1, 0, 0, 0, 56, 57, 7, 4, 0,
|
||||
0, 57, 18, 1, 0, 0, 0, 58, 60, 3, 21, 10, 0, 59, 58, 1, 0, 0, 0, 60, 61,
|
||||
1, 0, 0, 0, 61, 59, 1, 0, 0, 0, 61, 62, 1, 0, 0, 0, 62, 20, 1, 0, 0, 0,
|
||||
63, 64, 7, 5, 0, 0, 64, 22, 1, 0, 0, 0, 65, 67, 3, 25, 12, 0, 66, 65, 1,
|
||||
0, 0, 0, 67, 68, 1, 0, 0, 0, 68, 66, 1, 0, 0, 0, 68, 69, 1, 0, 0, 0, 69,
|
||||
78, 1, 0, 0, 0, 70, 72, 3, 5, 2, 0, 71, 73, 7, 6, 0, 0, 72, 71, 1, 0, 0,
|
||||
0, 73, 74, 1, 0, 0, 0, 74, 72, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 77,
|
||||
1, 0, 0, 0, 76, 70, 1, 0, 0, 0, 77, 80, 1, 0, 0, 0, 78, 76, 1, 0, 0, 0,
|
||||
78, 79, 1, 0, 0, 0, 79, 24, 1, 0, 0, 0, 80, 78, 1, 0, 0, 0, 81, 82, 8,
|
||||
7, 0, 0, 82, 26, 1, 0, 0, 0, 9, 0, 31, 44, 47, 54, 61, 68, 74, 78, 0,
|
||||
}
|
||||
deserializer := antlr.NewATNDeserializer(nil)
|
||||
staticData.atn = deserializer.Deserialize(staticData.serializedATN)
|
||||
atn := staticData.atn
|
||||
staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState))
|
||||
decisionToDFA := staticData.decisionToDFA
|
||||
for index, state := range atn.DecisionToState {
|
||||
decisionToDFA[index] = antlr.NewDFA(state, index)
|
||||
}
|
||||
}
|
||||
|
||||
// HostsLexerInit initializes any static state used to implement HostsLexer. By default the
|
||||
// static state used to implement the lexer is lazily initialized during the first call to
|
||||
// NewHostsLexer(). You can call this function if you wish to initialize the static state ahead
|
||||
// of time.
|
||||
func HostsLexerInit() {
|
||||
staticData := &HostsLexerLexerStaticData
|
||||
staticData.once.Do(hostslexerLexerInit)
|
||||
}
|
||||
|
||||
// NewHostsLexer produces a new lexer instance for the optional input antlr.CharStream.
|
||||
func NewHostsLexer(input antlr.CharStream) *HostsLexer {
|
||||
HostsLexerInit()
|
||||
l := new(HostsLexer)
|
||||
l.BaseLexer = antlr.NewBaseLexer(input)
|
||||
staticData := &HostsLexerLexerStaticData
|
||||
l.Interpreter = antlr.NewLexerATNSimulator(l, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache)
|
||||
l.channelNames = staticData.ChannelNames
|
||||
l.modeNames = staticData.ModeNames
|
||||
l.RuleNames = staticData.RuleNames
|
||||
l.LiteralNames = staticData.LiteralNames
|
||||
l.SymbolicNames = staticData.SymbolicNames
|
||||
l.GrammarFileName = "Hosts.g4"
|
||||
// TODO: l.EOF = antlr.TokenEOF
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// HostsLexer tokens.
|
||||
const (
|
||||
HostsLexerCOMMENTLINE = 1
|
||||
HostsLexerSLASH = 2
|
||||
HostsLexerDOT = 3
|
||||
HostsLexerCOLON = 4
|
||||
HostsLexerHASHTAG = 5
|
||||
HostsLexerSEPARATOR = 6
|
||||
HostsLexerNEWLINE = 7
|
||||
HostsLexerDIGITS = 8
|
||||
HostsLexerOCTETS = 9
|
||||
HostsLexerDOMAIN = 10
|
||||
)
|
112
handlers/hosts/parser/hosts_listener.go
Normal file
112
handlers/hosts/parser/hosts_listener.go
Normal file
@ -0,0 +1,112 @@
|
||||
// Code generated from Hosts.g4 by ANTLR 4.13.0. DO NOT EDIT.
|
||||
|
||||
package parser // Hosts
|
||||
|
||||
import "github.com/antlr4-go/antlr/v4"
|
||||
|
||||
// HostsListener is a complete listener for a parse tree produced by HostsParser.
|
||||
type HostsListener interface {
|
||||
antlr.ParseTreeListener
|
||||
|
||||
// EnterLineStatement is called when entering the lineStatement production.
|
||||
EnterLineStatement(c *LineStatementContext)
|
||||
|
||||
// EnterEntry is called when entering the entry production.
|
||||
EnterEntry(c *EntryContext)
|
||||
|
||||
// EnterAliases is called when entering the aliases production.
|
||||
EnterAliases(c *AliasesContext)
|
||||
|
||||
// EnterAlias is called when entering the alias production.
|
||||
EnterAlias(c *AliasContext)
|
||||
|
||||
// EnterHostname is called when entering the hostname production.
|
||||
EnterHostname(c *HostnameContext)
|
||||
|
||||
// EnterDomain is called when entering the domain production.
|
||||
EnterDomain(c *DomainContext)
|
||||
|
||||
// EnterIpAddress is called when entering the ipAddress production.
|
||||
EnterIpAddress(c *IpAddressContext)
|
||||
|
||||
// EnterIpv4Address is called when entering the ipv4Address production.
|
||||
EnterIpv4Address(c *Ipv4AddressContext)
|
||||
|
||||
// EnterSingleIPv4Address is called when entering the singleIPv4Address production.
|
||||
EnterSingleIPv4Address(c *SingleIPv4AddressContext)
|
||||
|
||||
// EnterIpv6Address is called when entering the ipv6Address production.
|
||||
EnterIpv6Address(c *Ipv6AddressContext)
|
||||
|
||||
// EnterSingleIPv6Address is called when entering the singleIPv6Address production.
|
||||
EnterSingleIPv6Address(c *SingleIPv6AddressContext)
|
||||
|
||||
// EnterIpv4Digit is called when entering the ipv4Digit production.
|
||||
EnterIpv4Digit(c *Ipv4DigitContext)
|
||||
|
||||
// EnterIpv6Octet is called when entering the ipv6Octet production.
|
||||
EnterIpv6Octet(c *Ipv6OctetContext)
|
||||
|
||||
// EnterIpRange is called when entering the ipRange production.
|
||||
EnterIpRange(c *IpRangeContext)
|
||||
|
||||
// EnterIpRangeBits is called when entering the ipRangeBits production.
|
||||
EnterIpRangeBits(c *IpRangeBitsContext)
|
||||
|
||||
// EnterComment is called when entering the comment production.
|
||||
EnterComment(c *CommentContext)
|
||||
|
||||
// EnterLeadingComment is called when entering the leadingComment production.
|
||||
EnterLeadingComment(c *LeadingCommentContext)
|
||||
|
||||
// ExitLineStatement is called when exiting the lineStatement production.
|
||||
ExitLineStatement(c *LineStatementContext)
|
||||
|
||||
// ExitEntry is called when exiting the entry production.
|
||||
ExitEntry(c *EntryContext)
|
||||
|
||||
// ExitAliases is called when exiting the aliases production.
|
||||
ExitAliases(c *AliasesContext)
|
||||
|
||||
// ExitAlias is called when exiting the alias production.
|
||||
ExitAlias(c *AliasContext)
|
||||
|
||||
// ExitHostname is called when exiting the hostname production.
|
||||
ExitHostname(c *HostnameContext)
|
||||
|
||||
// ExitDomain is called when exiting the domain production.
|
||||
ExitDomain(c *DomainContext)
|
||||
|
||||
// ExitIpAddress is called when exiting the ipAddress production.
|
||||
ExitIpAddress(c *IpAddressContext)
|
||||
|
||||
// ExitIpv4Address is called when exiting the ipv4Address production.
|
||||
ExitIpv4Address(c *Ipv4AddressContext)
|
||||
|
||||
// ExitSingleIPv4Address is called when exiting the singleIPv4Address production.
|
||||
ExitSingleIPv4Address(c *SingleIPv4AddressContext)
|
||||
|
||||
// ExitIpv6Address is called when exiting the ipv6Address production.
|
||||
ExitIpv6Address(c *Ipv6AddressContext)
|
||||
|
||||
// ExitSingleIPv6Address is called when exiting the singleIPv6Address production.
|
||||
ExitSingleIPv6Address(c *SingleIPv6AddressContext)
|
||||
|
||||
// ExitIpv4Digit is called when exiting the ipv4Digit production.
|
||||
ExitIpv4Digit(c *Ipv4DigitContext)
|
||||
|
||||
// ExitIpv6Octet is called when exiting the ipv6Octet production.
|
||||
ExitIpv6Octet(c *Ipv6OctetContext)
|
||||
|
||||
// ExitIpRange is called when exiting the ipRange production.
|
||||
ExitIpRange(c *IpRangeContext)
|
||||
|
||||
// ExitIpRangeBits is called when exiting the ipRangeBits production.
|
||||
ExitIpRangeBits(c *IpRangeBitsContext)
|
||||
|
||||
// ExitComment is called when exiting the comment production.
|
||||
ExitComment(c *CommentContext)
|
||||
|
||||
// ExitLeadingComment is called when exiting the leadingComment production.
|
||||
ExitLeadingComment(c *LeadingCommentContext)
|
||||
}
|
2369
handlers/hosts/parser/hosts_parser.go
Normal file
2369
handlers/hosts/parser/hosts_parser.go
Normal file
File diff suppressed because it is too large
Load Diff
82
handlers/hosts/tree/handler.go
Normal file
82
handlers/hosts/tree/handler.go
Normal file
@ -0,0 +1,82 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/handlers/hosts/parser"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
)
|
||||
|
||||
func (p *HostsParser) Clear() {
|
||||
p.Tree = HostsTree{
|
||||
Entries: make(map[uint32]*HostsEntry),
|
||||
}
|
||||
p.CommentLines = make(map[uint32]struct{})
|
||||
}
|
||||
|
||||
var commentPattern = regexp.MustCompile(`^\s*#.*$`)
|
||||
var emptyPattern = regexp.MustCompile(`^\s*$`)
|
||||
|
||||
func (p *HostsParser) parseStatement(
|
||||
line uint32,
|
||||
input string,
|
||||
) []common.LSPError {
|
||||
stream := antlr.NewInputStream(input)
|
||||
|
||||
errorListener := createErrorListener(line)
|
||||
lexer := parser.NewHostsLexer(stream)
|
||||
lexer.RemoveErrorListeners()
|
||||
lexer.AddErrorListener(&errorListener)
|
||||
|
||||
errors := errorListener.Errors
|
||||
|
||||
errorListener = createErrorListener(line)
|
||||
tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
|
||||
antlrParser := parser.NewHostsParser(tokenStream)
|
||||
antlrParser.RemoveErrorListeners()
|
||||
antlrParser.AddErrorListener(&errorListener)
|
||||
|
||||
listener := createHostsFileListener(p, line)
|
||||
antlr.ParseTreeWalkerDefault.Walk(
|
||||
&listener,
|
||||
antlrParser.LineStatement(),
|
||||
)
|
||||
|
||||
errors = append(errors, errorListener.Errors...)
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
func (p *HostsParser) Parse(input string) []common.LSPError {
|
||||
errors := make([]common.LSPError, 0)
|
||||
lines := strings.Split(input, "\n")
|
||||
|
||||
for rawLineNumber, line := range lines {
|
||||
lineNumber := uint32(rawLineNumber + 1)
|
||||
|
||||
if commentPattern.MatchString(line) {
|
||||
p.CommentLines[lineNumber] = struct{}{}
|
||||
continue
|
||||
}
|
||||
|
||||
if emptyPattern.MatchString(line) {
|
||||
continue
|
||||
}
|
||||
|
||||
errors = append(
|
||||
errors,
|
||||
p.parseStatement(lineNumber, line)...,
|
||||
)
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
func CreateNewHostsParser() HostsParser {
|
||||
p := HostsParser{}
|
||||
p.Clear()
|
||||
|
||||
return p
|
||||
}
|
143
handlers/hosts/tree/handler_test.go
Normal file
143
handlers/hosts/tree/handler_test.go
Normal file
@ -0,0 +1,143 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"config-lsp/utils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidSimpleExampleWorks(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := utils.Dedent(`
|
||||
1.2.3.4 hello.com
|
||||
`)
|
||||
|
||||
parser := CreateNewHostsParser()
|
||||
errors := parser.Parse(input)
|
||||
|
||||
if len(errors) != 0 {
|
||||
t.Errorf("Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
if !(len(parser.Tree.Entries) == 1) {
|
||||
t.Errorf("Expected 1 entry, but got %v", len(parser.Tree.Entries))
|
||||
}
|
||||
|
||||
if parser.Tree.Entries[1].IPAddress == nil {
|
||||
t.Errorf("Expected IP address to be present, but got nil")
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].IPAddress.Value == "1.2.3.4") {
|
||||
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[1].IPAddress.Value)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].Hostname.Value == "hello.com") {
|
||||
t.Errorf("Expected hostname to be hello.com, but got %v", parser.Tree.Entries[1].Hostname.Value)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].Aliases == nil) {
|
||||
t.Errorf("Expected no aliases, but got %v", parser.Tree.Entries[1].Aliases)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].Location.Start.Line == 1) {
|
||||
t.Errorf("Expected line to be 1, but got %v", parser.Tree.Entries[1].Location.Start.Line)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].Location.Start.Character == 0) {
|
||||
t.Errorf("Expected start to be 0, but got %v", parser.Tree.Entries[1].Location.Start)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].Location.End.Character == 16) {
|
||||
t.Errorf("Expected end to be 16, but got %v", parser.Tree.Entries[1].Location.End.Character)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].IPAddress.Location.Start.Line == 1) {
|
||||
t.Errorf("Expected IP address line to be 1, but got %v", parser.Tree.Entries[1].IPAddress.Location.Start.Line)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].IPAddress.Location.Start.Character == 0) {
|
||||
t.Errorf("Expected IP address start to be 0, but got %v", parser.Tree.Entries[1].IPAddress.Location.Start.Character)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].IPAddress.Location.End.Character == 6) {
|
||||
t.Errorf("Expected IP address end to be 6, but got %v", parser.Tree.Entries[1].IPAddress.Location.End.Character)
|
||||
}
|
||||
|
||||
if !(len(parser.CommentLines) == 0) {
|
||||
t.Errorf("Expected no comment lines, but got %v", len(parser.CommentLines))
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidComplexExampleWorks(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := utils.Dedent(`
|
||||
|
||||
# This is a comment
|
||||
1.2.3.4 hello.com test.com # This is another comment
|
||||
5.5.5.5 test.com
|
||||
1.2.3.4 example.com check.com
|
||||
`)
|
||||
|
||||
parser := CreateNewHostsParser()
|
||||
errors := parser.Parse(input)
|
||||
|
||||
if len(errors) != 0 {
|
||||
t.Errorf("Expected no errors, but got %v", errors)
|
||||
}
|
||||
|
||||
if !(len(parser.Tree.Entries) == 3) {
|
||||
t.Errorf("Expected 3 entries, but got %v", len(parser.Tree.Entries))
|
||||
}
|
||||
|
||||
if parser.Tree.Entries[3].IPAddress == nil {
|
||||
t.Errorf("Expected IP address to be present, but got nil")
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[3].IPAddress.Value == "1.2.3.4") {
|
||||
t.Errorf("Expected IP address to be 1.2.3.4, but got %v", parser.Tree.Entries[2].IPAddress.Value)
|
||||
}
|
||||
|
||||
if !(len(parser.CommentLines) == 1) {
|
||||
t.Errorf("Expected 1 comment line, but got %v", len(parser.CommentLines))
|
||||
}
|
||||
|
||||
if !(utils.KeyExists(parser.CommentLines, 2)) {
|
||||
t.Errorf("Expected comment line 2 to exist, but it does not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidExampleWorks(
|
||||
t *testing.T,
|
||||
) {
|
||||
input := utils.Dedent(`
|
||||
1.2.3.4
|
||||
`)
|
||||
|
||||
parser := CreateNewHostsParser()
|
||||
errors := parser.Parse(input)
|
||||
|
||||
if len(errors) == 0 {
|
||||
t.Errorf("Expected errors, but got none")
|
||||
}
|
||||
|
||||
if !(len(parser.Tree.Entries) == 1) {
|
||||
t.Errorf("Expected 1 entries, but got %v", len(parser.Tree.Entries))
|
||||
}
|
||||
|
||||
if !(len(parser.CommentLines) == 0) {
|
||||
t.Errorf("Expected no comment lines, but got %v", len(parser.CommentLines))
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].IPAddress.Value == "1.2.3.4") {
|
||||
t.Errorf("Expected IP address to be nil, but got %v", parser.Tree.Entries[1].IPAddress)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].Hostname == nil) {
|
||||
t.Errorf("Expected hostname to be nil, but got %v", parser.Tree.Entries[1].Hostname)
|
||||
}
|
||||
|
||||
if !(parser.Tree.Entries[1].Aliases == nil) {
|
||||
t.Errorf("Expected aliases to be nil, but got %v", parser.Tree.Entries[1].Aliases)
|
||||
}
|
||||
}
|
73
handlers/hosts/tree/hosts.go
Normal file
73
handlers/hosts/tree/hosts.go
Normal file
@ -0,0 +1,73 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"fmt"
|
||||
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
)
|
||||
|
||||
func characterRangeFromCtx(
|
||||
ctx antlr.BaseParserRuleContext,
|
||||
) common.LocationRange {
|
||||
line := uint32(ctx.GetStart().GetLine())
|
||||
start := uint32(ctx.GetStart().GetStart())
|
||||
end := uint32(ctx.GetStop().GetStop())
|
||||
|
||||
return common.LocationRange{
|
||||
Start: common.Location{
|
||||
Line: line,
|
||||
Character: start,
|
||||
},
|
||||
End: common.Location{
|
||||
Line: line,
|
||||
Character: end,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type HostsParser struct {
|
||||
Tree HostsTree
|
||||
CommentLines map[uint32]struct{}
|
||||
}
|
||||
|
||||
type HostsTree struct {
|
||||
// [line]entry
|
||||
Entries map[uint32]*HostsEntry
|
||||
}
|
||||
|
||||
type HostsEntry struct {
|
||||
Location common.LocationRange
|
||||
|
||||
IPAddress *HostsIPAddress
|
||||
Hostname *HostsHostname
|
||||
Aliases []*HostsHostname
|
||||
}
|
||||
|
||||
func (p HostsEntry) String() string {
|
||||
str := fmt.Sprintf("HostsEntry(%v)", p.Location)
|
||||
|
||||
if p.IPAddress != nil {
|
||||
str += " " + p.IPAddress.Value
|
||||
}
|
||||
|
||||
if p.Hostname != nil {
|
||||
str += " " + p.Hostname.Value
|
||||
}
|
||||
|
||||
if p.Aliases != nil {
|
||||
str += " " + fmt.Sprintf("%v", p.Aliases)
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
type HostsIPAddress struct {
|
||||
Location common.LocationRange
|
||||
Value string
|
||||
}
|
||||
|
||||
type HostsHostname struct {
|
||||
Location common.LocationRange
|
||||
Value string
|
||||
}
|
129
handlers/hosts/tree/listener.go
Normal file
129
handlers/hosts/tree/listener.go
Normal file
@ -0,0 +1,129 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"config-lsp/common"
|
||||
"config-lsp/handlers/hosts/parser"
|
||||
|
||||
"github.com/antlr4-go/antlr/v4"
|
||||
)
|
||||
|
||||
type hostsListenerContext struct {
|
||||
line uint32
|
||||
}
|
||||
|
||||
type hostsParserListener struct {
|
||||
*parser.BaseHostsListener
|
||||
Parser *HostsParser
|
||||
hostsContext hostsListenerContext
|
||||
}
|
||||
|
||||
func (s *hostsParserListener) EnterComment(ctx *parser.CommentContext) {
|
||||
line := uint32(s.hostsContext.line)
|
||||
s.Parser.CommentLines[line] = struct{}{}
|
||||
}
|
||||
|
||||
func (s *hostsParserListener) EnterEntry(ctx *parser.EntryContext) {
|
||||
location := characterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location.ChangeBothLines(s.hostsContext.line)
|
||||
|
||||
s.Parser.Tree.Entries[location.Start.Line] = &HostsEntry{
|
||||
Location: location,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *hostsParserListener) EnterIpAddress(ctx *parser.IpAddressContext) {
|
||||
location := characterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location.ChangeBothLines(s.hostsContext.line)
|
||||
|
||||
entry := s.Parser.Tree.Entries[location.Start.Line]
|
||||
|
||||
entry.IPAddress = &HostsIPAddress{
|
||||
Location: location,
|
||||
Value: ctx.GetText(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *hostsParserListener) EnterHostname(ctx *parser.HostnameContext) {
|
||||
location := characterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location.ChangeBothLines(s.hostsContext.line)
|
||||
|
||||
entry := s.Parser.Tree.Entries[location.Start.Line]
|
||||
|
||||
entry.Hostname = &HostsHostname{
|
||||
Location: location,
|
||||
Value: ctx.GetText(),
|
||||
}
|
||||
|
||||
s.Parser.Tree.Entries[location.Start.Line] = entry
|
||||
}
|
||||
|
||||
func (s *hostsParserListener) EnterAliases(ctx *parser.AliasesContext) {
|
||||
location := characterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location.ChangeBothLines(s.hostsContext.line)
|
||||
|
||||
entry := s.Parser.Tree.Entries[location.Start.Line]
|
||||
|
||||
aliases := make([]*HostsHostname, 0)
|
||||
|
||||
entry.Aliases = aliases
|
||||
}
|
||||
|
||||
func (s *hostsParserListener) EnterAlias(ctx *parser.AliasContext) {
|
||||
location := characterRangeFromCtx(ctx.BaseParserRuleContext)
|
||||
location.ChangeBothLines(s.hostsContext.line)
|
||||
|
||||
entry := s.Parser.Tree.Entries[location.Start.Line]
|
||||
|
||||
alias := HostsHostname{
|
||||
Location: location,
|
||||
Value: ctx.GetText(),
|
||||
}
|
||||
|
||||
entry.Aliases = append(entry.Aliases, &alias)
|
||||
}
|
||||
|
||||
func createHostsFileListener(
|
||||
parser *HostsParser,
|
||||
line uint32,
|
||||
) hostsParserListener {
|
||||
return hostsParserListener{
|
||||
Parser: parser,
|
||||
hostsContext: hostsListenerContext{
|
||||
line: line,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type errorListener struct {
|
||||
*antlr.DefaultErrorListener
|
||||
Errors []common.LSPError
|
||||
hostsContext hostsListenerContext
|
||||
}
|
||||
|
||||
func createErrorListener(
|
||||
line uint32,
|
||||
) errorListener {
|
||||
return errorListener{
|
||||
Errors: make([]common.LSPError, 0),
|
||||
hostsContext: hostsListenerContext{
|
||||
line: line,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (d *errorListener) SyntaxError(
|
||||
recognizer antlr.Recognizer,
|
||||
offendingSymbol interface{},
|
||||
_ int,
|
||||
character int,
|
||||
message string,
|
||||
error antlr.RecognitionException,
|
||||
) {
|
||||
line := d.hostsContext.line
|
||||
d.Errors = append(d.Errors, common.LSPError{
|
||||
Range: common.CreateSingleCharRange(uint32(line), uint32(character)),
|
||||
Err: common.SyntaxError{
|
||||
Message: message,
|
||||
},
|
||||
})
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
package utils
|
||||
|
||||
import "strings"
|
||||
|
||||
func Dedent(s string) string {
|
||||
return strings.TrimLeft(s, "\n")
|
||||
return s[len("\n"):]
|
||||
}
|
||||
|
||||
func KeyExists[T comparable, V any](keys map[T]V, key T) bool {
|
||||
|
Loading…
x
Reference in New Issue
Block a user