210 lines
4.2 KiB
Go

package ast
import (
"config-lsp/common"
commonparser "config-lsp/common/parser"
"config-lsp/utils"
"regexp"
"github.com/emirpasic/gods/maps/treemap"
gods "github.com/emirpasic/gods/utils"
)
func NewFstabConfig() *FstabConfig {
config := &FstabConfig{}
config.Clear()
return config
}
func (c *FstabConfig) Clear() {
c.Entries = treemap.NewWith(gods.UInt32Comparator)
c.CommentLines = map[uint32]struct{}{}
}
var commentPattern = regexp.MustCompile(`^\s*#`)
var emptyPattern = regexp.MustCompile(`^\s*$`)
var whitespacePattern = regexp.MustCompile(`\S+`)
func (c *FstabConfig) Parse(input string) []common.LSPError {
errors := make([]common.LSPError, 0)
lines := utils.SplitIntoLines(input)
for rawLineNumber, line := range lines {
lineNumber := uint32(rawLineNumber)
if emptyPattern.MatchString(line) {
continue
}
if commentPattern.MatchString(line) {
c.CommentLines[lineNumber] = struct{}{}
continue
}
errors = append(
errors,
c.parseStatement(lineNumber, line)...,
)
}
return errors
}
func (c *FstabConfig) parseStatement(
line uint32,
input string,
) []common.LSPError {
fields := whitespacePattern.FindAllStringIndex(input, -1)
if len(fields) == 0 {
return []common.LSPError{
{
Range: common.LocationRange{
Start: common.Location{
Line: line,
Character: 0,
},
End: common.Location{
Line: line,
Character: 0,
},
},
},
}
}
var spec *FstabField
var mountPoint *FstabField
var filesystemType *FstabField
var options *FstabField
var freq *FstabField
var pass *FstabField
switch len(fields) {
case 6:
pass = parseField(line, input, fields[5])
fallthrough
case 5:
freq = parseField(line, input, fields[4])
if pass == nil && fields[4][1] < len(input) {
pass = createPartialField(line, input, fields[4][1], len(input))
}
fallthrough
case 4:
options = parseField(line, input, fields[3])
if freq == nil && fields[3][1] < len(input) {
freq = createPartialField(line, input, fields[3][1], len(input))
}
fallthrough
case 3:
filesystemType = parseField(line, input, fields[2])
if options == nil && fields[2][1] < len(input) {
options = createPartialField(line, input, fields[2][1], len(input))
}
fallthrough
case 2:
mountPoint = parseField(line, input, fields[1])
if filesystemType == nil && fields[1][1] < len(input) {
filesystemType = createPartialField(line, input, fields[1][1], len(input))
}
fallthrough
case 1:
spec = parseField(line, input, fields[0])
if mountPoint == nil && fields[0][1] < len(input) {
mountPoint = createPartialField(line, input, fields[0][1], len(input))
}
}
fstabLine := &FstabEntry{
Fields: FstabFields{
LocationRange: common.LocationRange{
Start: common.Location{
Line: line,
Character: 0,
},
End: common.Location{
Line: line,
Character: uint32(len(input)),
},
},
Spec: spec,
MountPoint: mountPoint,
FilesystemType: filesystemType,
Options: options,
Freq: freq,
Pass: pass,
},
}
c.Entries.Put(line, fstabLine)
return nil
}
func parseField(
line uint32,
input string,
field []int,
) *FstabField {
start := uint32(field[0])
end := uint32(field[1])
value := input[start:end]
return &FstabField{
LocationRange: common.LocationRange{
Start: common.Location{
Line: line,
Character: start,
},
End: common.Location{
Line: line,
Character: end,
},
},
Value: commonparser.ParseRawString(value, commonparser.ParseFeatures{
ParseEscapedCharacters: true,
ParseDoubleQuotes: true,
Replacements: &map[string]string{
`\\040`: " ",
},
}),
}
}
func createPartialField(
line uint32,
input string,
start int,
end int,
) *FstabField {
return nil
return &FstabField{
LocationRange: common.LocationRange{
Start: common.Location{
Line: line,
Character: uint32(start),
},
End: common.Location{
Line: line,
Character: uint32(end),
},
},
Value: commonparser.ParseRawString(input[end:end], commonparser.ParseFeatures{
ParseEscapedCharacters: true,
ParseDoubleQuotes: true,
Replacements: &map[string]string{},
}),
}
}