195 lines
4.2 KiB
Go

package ast
import (
"config-lsp/common"
commonparser "config-lsp/common/parser"
"config-lsp/handlers/fstab/ast/parser"
"config-lsp/utils"
"regexp"
"github.com/antlr4-go/antlr/v4"
"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*$`)
func (c *FstabConfig) Parse(input string) []common.LSPError {
errors := make([]common.LSPError, 0)
lines := utils.SplitIntoLines(input)
context := createListenerContext()
for rawLineNumber, line := range lines {
lineNumber := uint32(rawLineNumber)
context.line = lineNumber
if emptyPattern.MatchString(line) {
continue
}
if commentPattern.MatchString(line) {
c.CommentLines[lineNumber] = struct{}{}
continue
}
errors = append(
errors,
c.parseStatement(context, line)...,
)
}
return errors
}
// TODO: Handle leading comments
func (c *FstabConfig) parseStatement(
context *fstabListenerContext,
input string,
) []common.LSPError {
stream := antlr.NewInputStream(input)
lexerErrorListener := createErrorListener(context.line)
lexer := parser.NewFstabLexer(stream)
lexer.RemoveErrorListeners()
lexer.AddErrorListener(&lexerErrorListener)
tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
parserErrorListener := createErrorListener(context.line)
antlrParser := parser.NewFstabParser(tokenStream)
antlrParser.RemoveErrorListeners()
antlrParser.AddErrorListener(&parserErrorListener)
listener := createListener(c, context)
antlr.ParseTreeWalkerDefault.Walk(
&listener,
antlrParser.Entry(),
)
errors := lexerErrorListener.Errors
errors = append(errors, parserErrorListener.Errors...)
errors = append(errors, listener.Errors...)
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`: " ",
},
}),
}
}