feat(aliases): Add first aliases

This commit is contained in:
Myzel394 2024-08-29 21:54:17 +02:00
parent 6c3e0d9d23
commit a5f834a38b
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
18 changed files with 3526 additions and 38 deletions

View File

@ -1,6 +1,9 @@
package common package common
import protocol "github.com/tliron/glsp/protocol_3_16" import (
"github.com/antlr4-go/antlr/v4"
protocol "github.com/tliron/glsp/protocol_3_16"
)
type Location struct { type Location struct {
Line uint32 Line uint32
@ -63,3 +66,22 @@ func CreateSingleCharRange(line uint32, character uint32) LocationRange {
}, },
} }
} }
func CharacterRangeFromCtx(
ctx antlr.BaseParserRuleContext,
) LocationRange {
line := uint32(ctx.GetStart().GetLine())
start := uint32(ctx.GetStart().GetStart())
end := uint32(ctx.GetStop().GetStop())
return LocationRange{
Start: Location{
Line: line,
Character: start,
},
End: Location{
Line: line,
Character: end + 1,
},
}
}

102
handlers/aliases/Aliases.g4 Normal file
View File

@ -0,0 +1,102 @@
grammar Aliases;
lineStatement
: entry SEPARATOR? comment? EOF
;
entry
: SEPARATOR? key SEPARATOR? separator SEPARATOR? values
;
separator
: COLON
;
key
: STRING
;
// // Values // //
values
: (value COMMA SEPARATOR)* value
;
value
: (user | file | command | include | email)
;
user
: STRING
;
file
: (SLASH STRING)+ SLASH?
;
command
: VERTLINE STRING
;
include
: COLON INCLUDE COLON file
;
comment
: NUMBER_SIGN (SEPARATOR? STRING)+ SEPARATOR?
;
email
: STRING AT STRING
;
error
: errorStatus COLON errorCode SEPARATOR errorMessage
;
errorStatus
: STRING
;
errorCode
: STRING
;
errorMessage
: STRING
;
SEPARATOR
: [ \t]+
;
AT
: '@'
;
INCLUDE
: 'i' 'n' 'c' 'l' 'u' 'd' 'e'
;
VERTLINE
: '|'
;
COLON
: ':'
;
COMMA
: ','
;
NUMBER_SIGN
: '#'
;
SLASH
: '/'
;
STRING
: ~(' ' | '\t' | '\n' | '\r' | ':' | ',' | '#' | '@' | '|' | '/')+
;

View File

@ -0,0 +1,45 @@
token literal names:
null
null
'@'
null
'|'
':'
','
'#'
'/'
null
token symbolic names:
null
SEPARATOR
AT
INCLUDE
VERTLINE
COLON
COMMA
NUMBER_SIGN
SLASH
STRING
rule names:
lineStatement
entry
separator
key
values
value
user
file
command
include
comment
email
error
errorStatus
errorCode
errorMessage
atn:
[4, 1, 9, 124, 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, 1, 0, 1, 0, 3, 0, 35, 8, 0, 1, 0, 3, 0, 38, 8, 0, 1, 0, 1, 0, 1, 1, 3, 1, 43, 8, 1, 1, 1, 1, 1, 3, 1, 47, 8, 1, 1, 1, 1, 1, 3, 1, 51, 8, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 5, 4, 63, 8, 4, 10, 4, 12, 4, 66, 9, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 75, 8, 5, 1, 6, 1, 6, 1, 7, 1, 7, 4, 7, 81, 8, 7, 11, 7, 12, 7, 82, 1, 7, 3, 7, 86, 8, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 3, 10, 98, 8, 10, 1, 10, 4, 10, 101, 8, 10, 11, 10, 12, 10, 102, 1, 10, 3, 10, 106, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 0, 0, 16, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 0, 0, 122, 0, 32, 1, 0, 0, 0, 2, 42, 1, 0, 0, 0, 4, 54, 1, 0, 0, 0, 6, 56, 1, 0, 0, 0, 8, 64, 1, 0, 0, 0, 10, 74, 1, 0, 0, 0, 12, 76, 1, 0, 0, 0, 14, 80, 1, 0, 0, 0, 16, 87, 1, 0, 0, 0, 18, 90, 1, 0, 0, 0, 20, 95, 1, 0, 0, 0, 22, 107, 1, 0, 0, 0, 24, 111, 1, 0, 0, 0, 26, 117, 1, 0, 0, 0, 28, 119, 1, 0, 0, 0, 30, 121, 1, 0, 0, 0, 32, 34, 3, 2, 1, 0, 33, 35, 5, 1, 0, 0, 34, 33, 1, 0, 0, 0, 34, 35, 1, 0, 0, 0, 35, 37, 1, 0, 0, 0, 36, 38, 3, 20, 10, 0, 37, 36, 1, 0, 0, 0, 37, 38, 1, 0, 0, 0, 38, 39, 1, 0, 0, 0, 39, 40, 5, 0, 0, 1, 40, 1, 1, 0, 0, 0, 41, 43, 5, 1, 0, 0, 42, 41, 1, 0, 0, 0, 42, 43, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 46, 3, 6, 3, 0, 45, 47, 5, 1, 0, 0, 46, 45, 1, 0, 0, 0, 46, 47, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 50, 3, 4, 2, 0, 49, 51, 5, 1, 0, 0, 50, 49, 1, 0, 0, 0, 50, 51, 1, 0, 0, 0, 51, 52, 1, 0, 0, 0, 52, 53, 3, 8, 4, 0, 53, 3, 1, 0, 0, 0, 54, 55, 5, 5, 0, 0, 55, 5, 1, 0, 0, 0, 56, 57, 5, 9, 0, 0, 57, 7, 1, 0, 0, 0, 58, 59, 3, 10, 5, 0, 59, 60, 5, 6, 0, 0, 60, 61, 5, 1, 0, 0, 61, 63, 1, 0, 0, 0, 62, 58, 1, 0, 0, 0, 63, 66, 1, 0, 0, 0, 64, 62, 1, 0, 0, 0, 64, 65, 1, 0, 0, 0, 65, 67, 1, 0, 0, 0, 66, 64, 1, 0, 0, 0, 67, 68, 3, 10, 5, 0, 68, 9, 1, 0, 0, 0, 69, 75, 3, 12, 6, 0, 70, 75, 3, 14, 7, 0, 71, 75, 3, 16, 8, 0, 72, 75, 3, 18, 9, 0, 73, 75, 3, 22, 11, 0, 74, 69, 1, 0, 0, 0, 74, 70, 1, 0, 0, 0, 74, 71, 1, 0, 0, 0, 74, 72, 1, 0, 0, 0, 74, 73, 1, 0, 0, 0, 75, 11, 1, 0, 0, 0, 76, 77, 5, 9, 0, 0, 77, 13, 1, 0, 0, 0, 78, 79, 5, 8, 0, 0, 79, 81, 5, 9, 0, 0, 80, 78, 1, 0, 0, 0, 81, 82, 1, 0, 0, 0, 82, 80, 1, 0, 0, 0, 82, 83, 1, 0, 0, 0, 83, 85, 1, 0, 0, 0, 84, 86, 5, 8, 0, 0, 85, 84, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, 15, 1, 0, 0, 0, 87, 88, 5, 4, 0, 0, 88, 89, 5, 9, 0, 0, 89, 17, 1, 0, 0, 0, 90, 91, 5, 5, 0, 0, 91, 92, 5, 3, 0, 0, 92, 93, 5, 5, 0, 0, 93, 94, 3, 14, 7, 0, 94, 19, 1, 0, 0, 0, 95, 100, 5, 7, 0, 0, 96, 98, 5, 1, 0, 0, 97, 96, 1, 0, 0, 0, 97, 98, 1, 0, 0, 0, 98, 99, 1, 0, 0, 0, 99, 101, 5, 9, 0, 0, 100, 97, 1, 0, 0, 0, 101, 102, 1, 0, 0, 0, 102, 100, 1, 0, 0, 0, 102, 103, 1, 0, 0, 0, 103, 105, 1, 0, 0, 0, 104, 106, 5, 1, 0, 0, 105, 104, 1, 0, 0, 0, 105, 106, 1, 0, 0, 0, 106, 21, 1, 0, 0, 0, 107, 108, 5, 9, 0, 0, 108, 109, 5, 2, 0, 0, 109, 110, 5, 9, 0, 0, 110, 23, 1, 0, 0, 0, 111, 112, 3, 26, 13, 0, 112, 113, 5, 5, 0, 0, 113, 114, 3, 28, 14, 0, 114, 115, 5, 1, 0, 0, 115, 116, 3, 30, 15, 0, 116, 25, 1, 0, 0, 0, 117, 118, 5, 9, 0, 0, 118, 27, 1, 0, 0, 0, 119, 120, 5, 9, 0, 0, 120, 29, 1, 0, 0, 0, 121, 122, 5, 9, 0, 0, 122, 31, 1, 0, 0, 0, 12, 34, 37, 42, 46, 50, 64, 74, 82, 85, 97, 102, 105]

View File

@ -0,0 +1,15 @@
SEPARATOR=1
AT=2
INCLUDE=3
VERTLINE=4
COLON=5
COMMA=6
NUMBER_SIGN=7
SLASH=8
STRING=9
'@'=2
'|'=4
':'=5
','=6
'#'=7
'/'=8

View File

@ -0,0 +1,44 @@
token literal names:
null
null
'@'
null
'|'
':'
','
'#'
'/'
null
token symbolic names:
null
SEPARATOR
AT
INCLUDE
VERTLINE
COLON
COMMA
NUMBER_SIGN
SLASH
STRING
rule names:
SEPARATOR
AT
INCLUDE
VERTLINE
COLON
COMMA
NUMBER_SIGN
SLASH
STRING
channel names:
DEFAULT_TOKEN_CHANNEL
HIDDEN
mode names:
DEFAULT_MODE
atn:
[4, 0, 9, 49, 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, 1, 0, 4, 0, 21, 8, 0, 11, 0, 12, 0, 22, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 4, 8, 46, 8, 8, 11, 8, 12, 8, 47, 0, 0, 9, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 1, 0, 2, 2, 0, 9, 9, 32, 32, 9, 0, 9, 10, 13, 13, 32, 32, 35, 35, 44, 44, 47, 47, 58, 58, 64, 64, 124, 124, 50, 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, 17, 1, 0, 0, 0, 1, 20, 1, 0, 0, 0, 3, 24, 1, 0, 0, 0, 5, 26, 1, 0, 0, 0, 7, 34, 1, 0, 0, 0, 9, 36, 1, 0, 0, 0, 11, 38, 1, 0, 0, 0, 13, 40, 1, 0, 0, 0, 15, 42, 1, 0, 0, 0, 17, 45, 1, 0, 0, 0, 19, 21, 7, 0, 0, 0, 20, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 20, 1, 0, 0, 0, 22, 23, 1, 0, 0, 0, 23, 2, 1, 0, 0, 0, 24, 25, 5, 64, 0, 0, 25, 4, 1, 0, 0, 0, 26, 27, 5, 105, 0, 0, 27, 28, 5, 110, 0, 0, 28, 29, 5, 99, 0, 0, 29, 30, 5, 108, 0, 0, 30, 31, 5, 117, 0, 0, 31, 32, 5, 100, 0, 0, 32, 33, 5, 101, 0, 0, 33, 6, 1, 0, 0, 0, 34, 35, 5, 124, 0, 0, 35, 8, 1, 0, 0, 0, 36, 37, 5, 58, 0, 0, 37, 10, 1, 0, 0, 0, 38, 39, 5, 44, 0, 0, 39, 12, 1, 0, 0, 0, 40, 41, 5, 35, 0, 0, 41, 14, 1, 0, 0, 0, 42, 43, 5, 47, 0, 0, 43, 16, 1, 0, 0, 0, 44, 46, 8, 1, 0, 0, 45, 44, 1, 0, 0, 0, 46, 47, 1, 0, 0, 0, 47, 45, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 18, 1, 0, 0, 0, 3, 0, 22, 47, 0]

View File

@ -0,0 +1,15 @@
SEPARATOR=1
AT=2
INCLUDE=3
VERTLINE=4
COLON=5
COMMA=6
NUMBER_SIGN=7
SLASH=8
STRING=9
'@'=2
'|'=4
':'=5
','=6
'#'=7
'/'=8

View File

@ -0,0 +1,118 @@
// Code generated from Aliases.g4 by ANTLR 4.13.0. DO NOT EDIT.
package parser // Aliases
import "github.com/antlr4-go/antlr/v4"
// BaseAliasesListener is a complete listener for a parse tree produced by AliasesParser.
type BaseAliasesListener struct{}
var _ AliasesListener = &BaseAliasesListener{}
// VisitTerminal is called when a terminal node is visited.
func (s *BaseAliasesListener) VisitTerminal(node antlr.TerminalNode) {}
// VisitErrorNode is called when an error node is visited.
func (s *BaseAliasesListener) VisitErrorNode(node antlr.ErrorNode) {}
// EnterEveryRule is called when any rule is entered.
func (s *BaseAliasesListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}
// ExitEveryRule is called when any rule is exited.
func (s *BaseAliasesListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}
// EnterLineStatement is called when production lineStatement is entered.
func (s *BaseAliasesListener) EnterLineStatement(ctx *LineStatementContext) {}
// ExitLineStatement is called when production lineStatement is exited.
func (s *BaseAliasesListener) ExitLineStatement(ctx *LineStatementContext) {}
// EnterEntry is called when production entry is entered.
func (s *BaseAliasesListener) EnterEntry(ctx *EntryContext) {}
// ExitEntry is called when production entry is exited.
func (s *BaseAliasesListener) ExitEntry(ctx *EntryContext) {}
// EnterSeparator is called when production separator is entered.
func (s *BaseAliasesListener) EnterSeparator(ctx *SeparatorContext) {}
// ExitSeparator is called when production separator is exited.
func (s *BaseAliasesListener) ExitSeparator(ctx *SeparatorContext) {}
// EnterKey is called when production key is entered.
func (s *BaseAliasesListener) EnterKey(ctx *KeyContext) {}
// ExitKey is called when production key is exited.
func (s *BaseAliasesListener) ExitKey(ctx *KeyContext) {}
// EnterValues is called when production values is entered.
func (s *BaseAliasesListener) EnterValues(ctx *ValuesContext) {}
// ExitValues is called when production values is exited.
func (s *BaseAliasesListener) ExitValues(ctx *ValuesContext) {}
// EnterValue is called when production value is entered.
func (s *BaseAliasesListener) EnterValue(ctx *ValueContext) {}
// ExitValue is called when production value is exited.
func (s *BaseAliasesListener) ExitValue(ctx *ValueContext) {}
// EnterUser is called when production user is entered.
func (s *BaseAliasesListener) EnterUser(ctx *UserContext) {}
// ExitUser is called when production user is exited.
func (s *BaseAliasesListener) ExitUser(ctx *UserContext) {}
// EnterFile is called when production file is entered.
func (s *BaseAliasesListener) EnterFile(ctx *FileContext) {}
// ExitFile is called when production file is exited.
func (s *BaseAliasesListener) ExitFile(ctx *FileContext) {}
// EnterCommand is called when production command is entered.
func (s *BaseAliasesListener) EnterCommand(ctx *CommandContext) {}
// ExitCommand is called when production command is exited.
func (s *BaseAliasesListener) ExitCommand(ctx *CommandContext) {}
// EnterInclude is called when production include is entered.
func (s *BaseAliasesListener) EnterInclude(ctx *IncludeContext) {}
// ExitInclude is called when production include is exited.
func (s *BaseAliasesListener) ExitInclude(ctx *IncludeContext) {}
// EnterComment is called when production comment is entered.
func (s *BaseAliasesListener) EnterComment(ctx *CommentContext) {}
// ExitComment is called when production comment is exited.
func (s *BaseAliasesListener) ExitComment(ctx *CommentContext) {}
// EnterEmail is called when production email is entered.
func (s *BaseAliasesListener) EnterEmail(ctx *EmailContext) {}
// ExitEmail is called when production email is exited.
func (s *BaseAliasesListener) ExitEmail(ctx *EmailContext) {}
// EnterError is called when production error is entered.
func (s *BaseAliasesListener) EnterError(ctx *ErrorContext) {}
// ExitError is called when production error is exited.
func (s *BaseAliasesListener) ExitError(ctx *ErrorContext) {}
// EnterErrorStatus is called when production errorStatus is entered.
func (s *BaseAliasesListener) EnterErrorStatus(ctx *ErrorStatusContext) {}
// ExitErrorStatus is called when production errorStatus is exited.
func (s *BaseAliasesListener) ExitErrorStatus(ctx *ErrorStatusContext) {}
// EnterErrorCode is called when production errorCode is entered.
func (s *BaseAliasesListener) EnterErrorCode(ctx *ErrorCodeContext) {}
// ExitErrorCode is called when production errorCode is exited.
func (s *BaseAliasesListener) ExitErrorCode(ctx *ErrorCodeContext) {}
// EnterErrorMessage is called when production errorMessage is entered.
func (s *BaseAliasesListener) EnterErrorMessage(ctx *ErrorMessageContext) {}
// ExitErrorMessage is called when production errorMessage is exited.
func (s *BaseAliasesListener) ExitErrorMessage(ctx *ErrorMessageContext) {}

View File

@ -0,0 +1,129 @@
// Code generated from Aliases.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 AliasesLexer struct {
*antlr.BaseLexer
channelNames []string
modeNames []string
// TODO: EOF string
}
var AliasesLexerLexerStaticData 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 aliaseslexerLexerInit() {
staticData := &AliasesLexerLexerStaticData
staticData.ChannelNames = []string{
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
}
staticData.ModeNames = []string{
"DEFAULT_MODE",
}
staticData.LiteralNames = []string{
"", "", "'@'", "", "'|'", "':'", "','", "'#'", "'/'",
}
staticData.SymbolicNames = []string{
"", "SEPARATOR", "AT", "INCLUDE", "VERTLINE", "COLON", "COMMA", "NUMBER_SIGN",
"SLASH", "STRING",
}
staticData.RuleNames = []string{
"SEPARATOR", "AT", "INCLUDE", "VERTLINE", "COLON", "COMMA", "NUMBER_SIGN",
"SLASH", "STRING",
}
staticData.PredictionContextCache = antlr.NewPredictionContextCache()
staticData.serializedATN = []int32{
4, 0, 9, 49, 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, 1, 0, 4, 0, 21,
8, 0, 11, 0, 12, 0, 22, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7,
1, 8, 4, 8, 46, 8, 8, 11, 8, 12, 8, 47, 0, 0, 9, 1, 1, 3, 2, 5, 3, 7, 4,
9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 1, 0, 2, 2, 0, 9, 9, 32, 32, 9, 0, 9,
10, 13, 13, 32, 32, 35, 35, 44, 44, 47, 47, 58, 58, 64, 64, 124, 124, 50,
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, 17, 1, 0, 0, 0, 1, 20, 1, 0, 0, 0, 3, 24, 1, 0, 0, 0, 5, 26, 1, 0,
0, 0, 7, 34, 1, 0, 0, 0, 9, 36, 1, 0, 0, 0, 11, 38, 1, 0, 0, 0, 13, 40,
1, 0, 0, 0, 15, 42, 1, 0, 0, 0, 17, 45, 1, 0, 0, 0, 19, 21, 7, 0, 0, 0,
20, 19, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 20, 1, 0, 0, 0, 22, 23, 1,
0, 0, 0, 23, 2, 1, 0, 0, 0, 24, 25, 5, 64, 0, 0, 25, 4, 1, 0, 0, 0, 26,
27, 5, 105, 0, 0, 27, 28, 5, 110, 0, 0, 28, 29, 5, 99, 0, 0, 29, 30, 5,
108, 0, 0, 30, 31, 5, 117, 0, 0, 31, 32, 5, 100, 0, 0, 32, 33, 5, 101,
0, 0, 33, 6, 1, 0, 0, 0, 34, 35, 5, 124, 0, 0, 35, 8, 1, 0, 0, 0, 36, 37,
5, 58, 0, 0, 37, 10, 1, 0, 0, 0, 38, 39, 5, 44, 0, 0, 39, 12, 1, 0, 0,
0, 40, 41, 5, 35, 0, 0, 41, 14, 1, 0, 0, 0, 42, 43, 5, 47, 0, 0, 43, 16,
1, 0, 0, 0, 44, 46, 8, 1, 0, 0, 45, 44, 1, 0, 0, 0, 46, 47, 1, 0, 0, 0,
47, 45, 1, 0, 0, 0, 47, 48, 1, 0, 0, 0, 48, 18, 1, 0, 0, 0, 3, 0, 22, 47,
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)
}
}
// AliasesLexerInit initializes any static state used to implement AliasesLexer. By default the
// static state used to implement the lexer is lazily initialized during the first call to
// NewAliasesLexer(). You can call this function if you wish to initialize the static state ahead
// of time.
func AliasesLexerInit() {
staticData := &AliasesLexerLexerStaticData
staticData.once.Do(aliaseslexerLexerInit)
}
// NewAliasesLexer produces a new lexer instance for the optional input antlr.CharStream.
func NewAliasesLexer(input antlr.CharStream) *AliasesLexer {
AliasesLexerInit()
l := new(AliasesLexer)
l.BaseLexer = antlr.NewBaseLexer(input)
staticData := &AliasesLexerLexerStaticData
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 = "Aliases.g4"
// TODO: l.EOF = antlr.TokenEOF
return l
}
// AliasesLexer tokens.
const (
AliasesLexerSEPARATOR = 1
AliasesLexerAT = 2
AliasesLexerINCLUDE = 3
AliasesLexerVERTLINE = 4
AliasesLexerCOLON = 5
AliasesLexerCOMMA = 6
AliasesLexerNUMBER_SIGN = 7
AliasesLexerSLASH = 8
AliasesLexerSTRING = 9
)

View File

@ -0,0 +1,106 @@
// Code generated from Aliases.g4 by ANTLR 4.13.0. DO NOT EDIT.
package parser // Aliases
import "github.com/antlr4-go/antlr/v4"
// AliasesListener is a complete listener for a parse tree produced by AliasesParser.
type AliasesListener 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)
// EnterSeparator is called when entering the separator production.
EnterSeparator(c *SeparatorContext)
// EnterKey is called when entering the key production.
EnterKey(c *KeyContext)
// EnterValues is called when entering the values production.
EnterValues(c *ValuesContext)
// EnterValue is called when entering the value production.
EnterValue(c *ValueContext)
// EnterUser is called when entering the user production.
EnterUser(c *UserContext)
// EnterFile is called when entering the file production.
EnterFile(c *FileContext)
// EnterCommand is called when entering the command production.
EnterCommand(c *CommandContext)
// EnterInclude is called when entering the include production.
EnterInclude(c *IncludeContext)
// EnterComment is called when entering the comment production.
EnterComment(c *CommentContext)
// EnterEmail is called when entering the email production.
EnterEmail(c *EmailContext)
// EnterError is called when entering the error production.
EnterError(c *ErrorContext)
// EnterErrorStatus is called when entering the errorStatus production.
EnterErrorStatus(c *ErrorStatusContext)
// EnterErrorCode is called when entering the errorCode production.
EnterErrorCode(c *ErrorCodeContext)
// EnterErrorMessage is called when entering the errorMessage production.
EnterErrorMessage(c *ErrorMessageContext)
// ExitLineStatement is called when exiting the lineStatement production.
ExitLineStatement(c *LineStatementContext)
// ExitEntry is called when exiting the entry production.
ExitEntry(c *EntryContext)
// ExitSeparator is called when exiting the separator production.
ExitSeparator(c *SeparatorContext)
// ExitKey is called when exiting the key production.
ExitKey(c *KeyContext)
// ExitValues is called when exiting the values production.
ExitValues(c *ValuesContext)
// ExitValue is called when exiting the value production.
ExitValue(c *ValueContext)
// ExitUser is called when exiting the user production.
ExitUser(c *UserContext)
// ExitFile is called when exiting the file production.
ExitFile(c *FileContext)
// ExitCommand is called when exiting the command production.
ExitCommand(c *CommandContext)
// ExitInclude is called when exiting the include production.
ExitInclude(c *IncludeContext)
// ExitComment is called when exiting the comment production.
ExitComment(c *CommentContext)
// ExitEmail is called when exiting the email production.
ExitEmail(c *EmailContext)
// ExitError is called when exiting the error production.
ExitError(c *ErrorContext)
// ExitErrorStatus is called when exiting the errorStatus production.
ExitErrorStatus(c *ErrorStatusContext)
// ExitErrorCode is called when exiting the errorCode production.
ExitErrorCode(c *ErrorCodeContext)
// ExitErrorMessage is called when exiting the errorMessage production.
ExitErrorMessage(c *ErrorMessageContext)
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
package tree
import (
"config-lsp/common"
)
// Procedure
// Save options in fields
// Each type, such as Include, User etc is own type
// Each type inherits interface
// This interface has methods such as:
// - CheckIsUser()
// For user, this checks if the user is listed in passwd
// For include, this includes the file and parses it and validates it
//
// Parse content manually as the /etc/aliases file is so simple
type AliasKey struct {
Location common.LocationRange
Value string
}
type AliasValues struct {
Location common.LocationRange
Values []AliasValueInterface
}
type AliasEntry struct {
Location common.LocationRange
Key *AliasKey
Separator *common.LocationRange
Values *AliasValues
}
type AliasesParser struct {
Aliases map[uint32]*AliasEntry
CommentLines map[uint32]struct{}
}

View File

@ -0,0 +1 @@
package tree

View File

@ -0,0 +1,208 @@
package tree
import (
"config-lsp/common"
"config-lsp/handlers/aliases/parser"
"github.com/antlr4-go/antlr/v4"
)
type aliasesListenerContext struct {
line uint32
currentIncludeIndex *uint32
}
type aliasesParserListener struct {
*parser.BaseAliasesListener
Parser *AliasesParser
Errors []common.LSPError
aliasContext aliasesListenerContext
}
func (s *aliasesParserListener) EnterEntry(ctx *parser.EntryContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
s.Parser.Aliases[location.Start.Line] = &AliasEntry{
Location: location,
}
}
func (s *aliasesParserListener) EnterSeparator(ctx *parser.SeparatorContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
entry := s.Parser.Aliases[location.Start.Line]
entry.Separator = &location
}
func (s *aliasesParserListener) EnterKey(ctx *parser.KeyContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
entry := s.Parser.Aliases[location.Start.Line]
entry.Key = &AliasKey{
Location: location,
Value: ctx.GetText(),
}
}
func (s *aliasesParserListener) EnterValues(ctx *parser.ValuesContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
entry := s.Parser.Aliases[location.Start.Line]
entry.Values = &AliasValues{
Location: location,
Values: make([]AliasValueInterface, 0, 5),
}
}
// === Value === //
func (s *aliasesParserListener) EnterUser(ctx *parser.UserContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
user := AliasValueUser{
AliasValue: AliasValue{
Location: location,
Value: ctx.GetText(),
},
}
entry := s.Parser.Aliases[location.Start.Line]
entry.Values.Values = append(entry.Values.Values, user)
}
func (s *aliasesParserListener) EnterFile(ctx *parser.FileContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
if s.aliasContext.currentIncludeIndex != nil {
// This `file` is inside an `include`, so we need to set the path on the include
values := s.Parser.Aliases[location.Start.Line].Values
rawValue := values.Values[*s.aliasContext.currentIncludeIndex]
// Set the path
include := rawValue.(AliasValueInclude)
include.Path = AliasValueIncludePath{
Location: location,
Path: path(ctx.GetText()),
}
values.Values[*s.aliasContext.currentIncludeIndex] = include
// Clean up
s.aliasContext.currentIncludeIndex = nil
return
}
// Raw file, process it
file := AliasValueFile{
AliasValue: AliasValue{
Location: location,
Value: ctx.GetText(),
},
Path: path(ctx.GetText()),
}
entry := s.Parser.Aliases[location.Start.Line]
entry.Values.Values = append(entry.Values.Values, file)
}
func (s *aliasesParserListener) EnterCommand(ctx *parser.CommandContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
command := AliasValueCommand{
AliasValue: AliasValue{
Location: location,
Value: ctx.GetText(),
},
Command: ctx.GetText()[1:],
}
entry := s.Parser.Aliases[location.Start.Line]
entry.Values.Values = append(entry.Values.Values, command)
}
func (s *aliasesParserListener) EnterInclude(ctx *parser.IncludeContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
include := AliasValueInclude{
AliasValue: AliasValue{
Location: location,
Value: ctx.GetText(),
},
}
entry := s.Parser.Aliases[location.Start.Line]
entry.Values.Values = append(entry.Values.Values, include)
index := uint32(len(entry.Values.Values) - 1)
s.aliasContext.currentIncludeIndex = &index
}
func (s *aliasesParserListener) EnterEmail(ctx *parser.EmailContext) {
location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.aliasContext.line)
email := AliasValueEmail{
AliasValue: AliasValue{
Location: location,
Value: ctx.GetText(),
},
}
entry := s.Parser.Aliases[location.Start.Line]
entry.Values.Values = append(entry.Values.Values, email)
}
func createListener(
parser *AliasesParser,
line uint32,
) aliasesParserListener {
return aliasesParserListener{
Parser: parser,
aliasContext: aliasesListenerContext{
line: line,
},
Errors: make([]common.LSPError, 0),
}
}
type errorListener struct {
*antlr.DefaultErrorListener
Errors []common.LSPError
context aliasesListenerContext
}
func (d *errorListener) SyntaxError(
recognizer antlr.Recognizer,
offendingSymbol interface{},
_ int,
character int,
message string,
error antlr.RecognitionException,
) {
line := d.context.line
d.Errors = append(d.Errors, common.LSPError{
Range: common.CreateSingleCharRange(uint32(line), uint32(character)),
Err: common.SyntaxError{
Message: message,
},
})
}
func createErrorListener(
line uint32,
) errorListener {
return errorListener{
Errors: make([]common.LSPError, 0),
context: aliasesListenerContext{
line: line,
},
}
}

View File

@ -0,0 +1,79 @@
package tree
import (
"config-lsp/common"
"config-lsp/handlers/aliases/parser"
"config-lsp/utils"
"github.com/antlr4-go/antlr/v4"
"regexp"
)
func NewAliasesParser() AliasesParser {
p := AliasesParser{}
p.Clear()
return p
}
func (p *AliasesParser) Clear() {
p.CommentLines = make(map[uint32]struct{})
p.Aliases = make(map[uint32]*AliasEntry)
}
var commentPattern = regexp.MustCompile(`^\s*#.*$`)
var emptyPattern = regexp.MustCompile(`^\s*$`)
func (p *AliasesParser) Parse(input string) []common.LSPError {
errors := make([]common.LSPError, 0)
lines := utils.SplitIntoLines(input)
for rawLineNumber, line := range lines {
lineNumber := uint32(rawLineNumber)
if commentPattern.MatchString(line) {
p.CommentLines[lineNumber] = struct{}{}
continue
}
if emptyPattern.MatchString(line) {
continue
}
errors = append(
errors,
p.parseStatement(lineNumber, line)...,
)
}
return errors
}
func (p *AliasesParser) parseStatement(
line uint32,
input string,
) []common.LSPError {
stream := antlr.NewInputStream(input)
lexerErrorListener := createErrorListener(line)
lexer := parser.NewAliasesLexer(stream)
lexer.RemoveErrorListeners()
lexer.AddErrorListener(&lexerErrorListener)
tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
parserErrorListener := createErrorListener(line)
antlrParser := parser.NewAliasesParser(tokenStream)
antlrParser.RemoveErrorListeners()
antlrParser.AddErrorListener(&parserErrorListener)
listener := createListener(p, line)
antlr.ParseTreeWalkerDefault.Walk(
&listener,
antlrParser.LineStatement(),
)
errors := lexerErrorListener.Errors
errors = append(errors, parserErrorListener.Errors...)
return errors
}

View File

@ -0,0 +1,107 @@
package tree
import (
"config-lsp/utils"
"testing"
)
func TestSimpleExampleWorks(
t *testing.T,
) {
input := utils.Dedent(`
postmaster: root
`)
parser := NewAliasesParser()
errors := parser.Parse(input)
if len(errors) != 0 {
t.Fatalf("Expected no errors, got %v", errors)
}
if !(len(parser.Aliases) == 1) {
t.Fatalf("Expected 1 alias, got %v", len(parser.Aliases))
}
if !(parser.Aliases[0].Key.Value == "postmaster") {
t.Fatalf("Expected key to be 'postmaster', got %v", parser.Aliases[1].Key.Value)
}
userValue := parser.Aliases[0].Values.Values[0].(AliasValueUser)
if !(userValue.Value == "root") {
t.Fatalf("Expected value to be 'root', got %v", userValue.Value)
}
if !(userValue.Location.Start.Line == 0) {
t.Fatalf("Expected start line to be 0, got %v", userValue.Location.Start.Line)
}
}
func TestMultipleValuesWorks(
t *testing.T,
) {
input := utils.Dedent(`
heinz: root, goli
michel: raiks@example.com
`)
parser := NewAliasesParser()
errors := parser.Parse(input)
if len(errors) != 0 {
t.Fatalf("Expected no errors, got %v", errors)
}
if !(len(parser.Aliases) == 2) {
t.Fatalf("Expected 2 aliases, got %v", len(parser.Aliases))
}
if !(parser.Aliases[0].Key.Value == "heinz") {
t.Fatalf("Expected key to be 'heinz', got %v", parser.Aliases[1].Key.Value)
}
if !(parser.Aliases[1].Key.Value == "michel") {
t.Fatalf("Expected key to be 'michel', got %v", parser.Aliases[1].Key.Value)
}
emailValue := parser.Aliases[1].Values.Values[0].(AliasValueEmail)
if !(emailValue.Value == "raiks@example.com") {
t.Fatalf("Expected value to be 'raiks@example.com', got %v", emailValue.Value)
}
}
func TestIncludeWorks(
t *testing.T,
) {
input := utils.Dedent(`
luke: :include:/etc/other_aliases
`)
parser := NewAliasesParser()
errors := parser.Parse(input)
if len(errors) != 0 {
t.Fatalf("Expected no errors, got %v", errors)
}
if !(len(parser.Aliases) == 1) {
t.Fatalf("Expected 1 alias, got %v", len(parser.Aliases))
}
if !(parser.Aliases[0].Key.Value == "luke") {
t.Fatalf("Expected key to be 'luke', got %v", parser.Aliases[1].Key.Value)
}
includeValue := parser.Aliases[0].Values.Values[0].(AliasValueInclude)
if !(includeValue.Path.Path == "/etc/other_aliases") {
t.Fatalf("Expected path to be '/etc/other_aliases', got %v", includeValue.Path.Path)
}
if !(includeValue.Location.Start.Character == 6 && includeValue.Location.End.Character == 33) {
t.Fatalf("Expected location to be 6-33, got %v-%v", includeValue.Location.Start.Character, includeValue.Location.End.Character)
}
if !(includeValue.Path.Location.Start.Character == 15 && includeValue.Path.Location.End.Character == 33) {
t.Fatalf("Expected path location to be 15-33, got %v-%v", includeValue.Path.Location.Start.Character, includeValue.Path.Location.End.Character)
}
}

View File

@ -0,0 +1,55 @@
package tree
import (
"config-lsp/common"
docvalues "config-lsp/doc-values"
protocol "github.com/tliron/glsp/protocol_3_16"
)
type AliasValueInterface interface {
FetchCompletions(line string, cursor uint32) []protocol.CompletionItem
CheckIsValid() []*docvalues.InvalidValue
}
func (a AliasValue) FetchCompletions(line string, cursor uint32) []protocol.CompletionItem {
return nil
}
func (a AliasValue) CheckIsValid() []*docvalues.InvalidValue {
return nil
}
type AliasValue struct {
Location common.LocationRange
Value string
}
type AliasValueUser struct {
AliasValue
}
type path string
type AliasValueFile struct {
AliasValue
Path path
}
type AliasValueCommand struct {
AliasValue
Command string
}
type AliasValueIncludePath struct {
Location common.LocationRange
Path path
}
type AliasValueInclude struct {
AliasValue
Path AliasValueIncludePath
}
type AliasValueEmail struct {
AliasValue
}

View File

@ -4,29 +4,8 @@ import (
"config-lsp/common" "config-lsp/common"
"fmt" "fmt"
"net" "net"
"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 + 1,
},
}
}
type HostsParser struct { type HostsParser struct {
Tree HostsTree Tree HostsTree
CommentLines map[uint32]struct{} CommentLines map[uint32]struct{}

View File

@ -26,7 +26,7 @@ func (s *hostsParserListener) EnterComment(ctx *parser.CommentContext) {
} }
func (s *hostsParserListener) EnterEntry(ctx *parser.EntryContext) { func (s *hostsParserListener) EnterEntry(ctx *parser.EntryContext) {
location := characterRangeFromCtx(ctx.BaseParserRuleContext) location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.hostsContext.line) location.ChangeBothLines(s.hostsContext.line)
s.Parser.Tree.Entries[location.Start.Line] = &HostsEntry{ s.Parser.Tree.Entries[location.Start.Line] = &HostsEntry{
@ -35,7 +35,7 @@ func (s *hostsParserListener) EnterEntry(ctx *parser.EntryContext) {
} }
func (s *hostsParserListener) EnterIpAddress(ctx *parser.IpAddressContext) { func (s *hostsParserListener) EnterIpAddress(ctx *parser.IpAddressContext) {
location := characterRangeFromCtx(ctx.BaseParserRuleContext) location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.hostsContext.line) location.ChangeBothLines(s.hostsContext.line)
ip := net.ParseIP(ctx.GetText()) ip := net.ParseIP(ctx.GetText())
@ -66,7 +66,7 @@ func (s *hostsParserListener) EnterIpAddress(ctx *parser.IpAddressContext) {
} }
func (s *hostsParserListener) EnterHostname(ctx *parser.HostnameContext) { func (s *hostsParserListener) EnterHostname(ctx *parser.HostnameContext) {
location := characterRangeFromCtx(ctx.BaseParserRuleContext) location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.hostsContext.line) location.ChangeBothLines(s.hostsContext.line)
entry := s.Parser.Tree.Entries[location.Start.Line] entry := s.Parser.Tree.Entries[location.Start.Line]
@ -80,7 +80,7 @@ func (s *hostsParserListener) EnterHostname(ctx *parser.HostnameContext) {
} }
func (s *hostsParserListener) EnterAliases(ctx *parser.AliasesContext) { func (s *hostsParserListener) EnterAliases(ctx *parser.AliasesContext) {
location := characterRangeFromCtx(ctx.BaseParserRuleContext) location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.hostsContext.line) location.ChangeBothLines(s.hostsContext.line)
entry := s.Parser.Tree.Entries[location.Start.Line] entry := s.Parser.Tree.Entries[location.Start.Line]
@ -91,7 +91,7 @@ func (s *hostsParserListener) EnterAliases(ctx *parser.AliasesContext) {
} }
func (s *hostsParserListener) EnterAlias(ctx *parser.AliasContext) { func (s *hostsParserListener) EnterAlias(ctx *parser.AliasContext) {
location := characterRangeFromCtx(ctx.BaseParserRuleContext) location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext)
location.ChangeBothLines(s.hostsContext.line) location.ChangeBothLines(s.hostsContext.line)
entry := s.Parser.Tree.Entries[location.Start.Line] entry := s.Parser.Tree.Entries[location.Start.Line]
@ -123,17 +123,6 @@ type errorListener struct {
hostsContext hostsListenerContext hostsContext hostsListenerContext
} }
func createErrorListener(
line uint32,
) errorListener {
return errorListener{
Errors: make([]common.LSPError, 0),
hostsContext: hostsListenerContext{
line: line,
},
}
}
func (d *errorListener) SyntaxError( func (d *errorListener) SyntaxError(
recognizer antlr.Recognizer, recognizer antlr.Recognizer,
offendingSymbol interface{}, offendingSymbol interface{},
@ -150,3 +139,14 @@ func (d *errorListener) SyntaxError(
}, },
}) })
} }
func createErrorListener(
line uint32,
) errorListener {
return errorListener{
Errors: make([]common.LSPError, 0),
hostsContext: hostsListenerContext{
line: line,
},
}
}