mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-10 07:34:04 -08:00
cb6eb30182
This fixes a bug that has been annoying me minorly for some time now: sometimes, after parse errors, a subsequent parser run would fail. The reason is that yylex() modifies some global variables (yytext, yydata) during its run to keep state. To make subsequent parser runs correct, these have to be reset before each run. Also, close files after reading them.
65 lines
1.6 KiB
Go
65 lines
1.6 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// NOTE: This parser is non-reentrant due to its dependence on global state.
|
|
|
|
// GoLex sadly needs these global variables for storing temporary token/parsing information.
|
|
var yylval *yySymType // For storing extra token information, like the contents of a string.
|
|
var yyline int // Line number within the current file or buffer.
|
|
var yypos int // Character position within the current line.
|
|
var parsedConfig = New() // Temporary variable for storing the parsed configuration.
|
|
|
|
type ConfigLexer struct {
|
|
errors []string
|
|
}
|
|
|
|
func (lexer *ConfigLexer) Lex(lval *yySymType) int {
|
|
yylval = lval
|
|
token_type := yylex()
|
|
return token_type
|
|
}
|
|
|
|
func (lexer *ConfigLexer) Error(errorStr string) {
|
|
err := fmt.Sprintf("Error reading config at line %v, char %v: %v", yyline, yypos, errorStr)
|
|
lexer.errors = append(lexer.errors, err)
|
|
}
|
|
|
|
func LoadFromReader(configReader io.Reader) (*Config, error) {
|
|
yyin = configReader
|
|
yypos = 1
|
|
yyline = 1
|
|
yydata = ""
|
|
yytext = ""
|
|
|
|
lexer := &ConfigLexer{}
|
|
yyParse(lexer)
|
|
|
|
if len(lexer.errors) > 0 {
|
|
err := errors.New(strings.Join(lexer.errors, "\n"))
|
|
return &Config{}, err
|
|
}
|
|
|
|
return parsedConfig, nil
|
|
}
|
|
|
|
func LoadFromString(configString string) (*Config, error) {
|
|
configReader := strings.NewReader(configString)
|
|
return LoadFromReader(configReader)
|
|
}
|
|
|
|
func LoadFromFile(fileName string) (*Config, error) {
|
|
configReader, err := os.Open(fileName)
|
|
defer configReader.Close()
|
|
if err != nil {
|
|
return &Config{}, err
|
|
}
|
|
return LoadFromReader(configReader)
|
|
}
|