refactor(fstab): Adapt fstab to new style; Adapting the parser

This commit is contained in:
Myzel394 2024-10-08 12:11:02 +02:00
parent f6b825ebed
commit 1f4717deba
No known key found for this signature in database
GPG Key ID: ED20A1D1D423AF3F
3 changed files with 279 additions and 0 deletions

View File

@ -0,0 +1,45 @@
package ast
import (
"config-lsp/common"
commonparser "config-lsp/common/parser"
"github.com/emirpasic/gods/maps/treemap"
)
type FstabFieldName string
const (
FstabFieldSpec FstabFieldName = "spec"
FstabFieldMountPoint FstabFieldName = "mountpoint"
FstabFieldFileSystemType FstabFieldName = "filesystemtype"
FstabFieldOptions FstabFieldName = "options"
FstabFieldFreq FstabFieldName = "freq"
FstabFieldPass FstabFieldName = "pass"
)
type FstabField struct {
common.LocationRange
Value commonparser.ParsedString
}
type FstabFields struct {
common.LocationRange
Spec *FstabField
MountPoint *FstabField
FilesystemType *FstabField
Options *FstabField
Freq *FstabField
Pass *FstabField
}
type FstabEntry struct {
Fields FstabFields
}
type FstabConfig struct {
// [uint32]FstabEntry - line number to line mapping
Entries *treemap.Map
// [uint32]{} - line number to empty struct for comments
CommentLines map[uint32]struct{}
}

View File

@ -0,0 +1,159 @@
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])
fallthrough
case 4:
options = parseField(line, input, fields[3])
fallthrough
case 3:
filesystemType = parseField(line, input, fields[2])
fallthrough
case 2:
mountPoint = parseField(line, input, fields[1])
fallthrough
case 1:
spec = parseField(line, input, fields[0])
}
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`: " ",
},
}),
}
}

View File

@ -0,0 +1,75 @@
package ast
import (
"config-lsp/utils"
"testing"
)
func TestExample1(
t *testing.T,
) {
input := utils.Dedent(`
LABEL=test /mnt/test ext4 defaults 0 0
`)
c := NewFstabConfig()
errors := c.Parse(input)
if len(errors) > 0 {
t.Fatalf("Expected no errors, got %v", errors)
}
if c.Entries.Size() != 1 {
t.Fatalf("Expected 1 entry, got %d", c.Entries.Size())
}
rawFirstEntry, _ := c.Entries.Get(uint32(0))
firstEntry := rawFirstEntry.(FstabEntry)
if !(firstEntry.Fields.Spec.Value.Value == "LABEL=test" && firstEntry.Fields.MountPoint.Value.Value == "/mnt/test" && firstEntry.Fields.FilesystemType.Value.Value == "ext4" && firstEntry.Fields.Options.Value.Value == "defaults" && firstEntry.Fields.Freq.Value.Value == "0" && firstEntry.Fields.Pass.Value.Value == "0") {
t.Fatalf("Expected entry to be LABEL=test /mnt/test ext4 defaults 0 0, got %v", firstEntry)
}
if !(firstEntry.Fields.Spec.LocationRange.Start.Line == 0 && firstEntry.Fields.Spec.LocationRange.Start.Character == 0) {
t.Errorf("Expected spec start to be 0:0, got %v", firstEntry.Fields.Spec.LocationRange.Start)
}
if !(firstEntry.Fields.Spec.LocationRange.End.Line == 0 && firstEntry.Fields.Spec.LocationRange.End.Character == 10) {
t.Errorf("Expected spec end to be 0:10, got %v", firstEntry.Fields.Spec.LocationRange.End)
}
if !(firstEntry.Fields.MountPoint.LocationRange.Start.Line == 0 && firstEntry.Fields.MountPoint.LocationRange.Start.Character == 11) {
t.Errorf("Expected mountpoint start to be 0:11, got %v", firstEntry.Fields.MountPoint.LocationRange.Start)
}
if !(firstEntry.Fields.MountPoint.LocationRange.End.Line == 0 && firstEntry.Fields.MountPoint.LocationRange.End.Character == 20) {
t.Errorf("Expected mountpoint end to be 0:20, got %v", firstEntry.Fields.MountPoint.LocationRange.End)
}
if !(firstEntry.Fields.FilesystemType.LocationRange.Start.Line == 0 && firstEntry.Fields.FilesystemType.LocationRange.Start.Character == 21) {
t.Errorf("Expected filesystemtype start to be 0:21, got %v", firstEntry.Fields.FilesystemType.LocationRange.Start)
}
if !(firstEntry.Fields.FilesystemType.LocationRange.End.Line == 0 && firstEntry.Fields.FilesystemType.LocationRange.End.Character == 25) {
t.Errorf("Expected filesystemtype end to be 0:25, got %v", firstEntry.Fields.FilesystemType.LocationRange.End)
}
if !(firstEntry.Fields.Options.LocationRange.Start.Line == 0 && firstEntry.Fields.Options.LocationRange.Start.Character == 26) {
t.Errorf("Expected options start to be 0:26, got %v", firstEntry.Fields.Options.LocationRange.Start)
}
if !(firstEntry.Fields.Options.LocationRange.End.Line == 0 && firstEntry.Fields.Options.LocationRange.End.Character == 34) {
t.Errorf("Expected options end to be 0:34, got %v", firstEntry.Fields.Options.LocationRange.End)
}
if !(firstEntry.Fields.Freq.LocationRange.Start.Line == 0 && firstEntry.Fields.Freq.LocationRange.Start.Character == 35) {
t.Errorf("Expected freq start to be 0:35, got %v", firstEntry.Fields.Freq.LocationRange.Start)
}
if !(firstEntry.Fields.Freq.LocationRange.End.Line == 0 && firstEntry.Fields.Freq.LocationRange.End.Character == 36) {
t.Errorf("Expected freq end to be 0:36, got %v", firstEntry.Fields.Freq.LocationRange.End)
}
if !(firstEntry.Fields.Pass.LocationRange.Start.Line == 0 && firstEntry.Fields.Pass.LocationRange.Start.Character == 37) {
t.Errorf("Expected pass start to be 0:37, got %v", firstEntry.Fields.Pass.LocationRange.Start)
}
}