diff options
Diffstat (limited to '')
| -rw-r--r-- | README.md | 236 | ||||
| -rw-r--r-- | example.conf | 12 | ||||
| -rw-r--r-- | loader.go | 18 | ||||
| -rw-r--r-- | loader_test.go | 90 | ||||
| -rw-r--r-- | model/directive.go | 137 | ||||
| -rw-r--r-- | model/group.go | 48 | ||||
| -rw-r--r-- | model/model.go | 58 | ||||
| -rw-r--r-- | parser/errors.go | 34 | ||||
| -rw-r--r-- | parser/grammar.peg | 111 | ||||
| -rw-r--r-- | parser/parser.go | 776 |
10 files changed, 793 insertions, 727 deletions
@@ -1,5 +1,8 @@ # conf +[](https://oc.neonxp.ru) +[](https://pkg.go.dev/go.neonxp.ru/conf) + Go библиотека для парсинга конфигурационных файлов `.conf` похожем на классические UNIX конфиги, как у nginx или bind9. @@ -13,8 +16,8 @@ go get go.neonxp.ru/conf ## Особенности формата -- **Команды**: `directive arg1 arg2;` -- **Команды с телом**: `directive arg1 arg2 { ... }` +- **Директивы**: `directive arg1 arg2;` +- **Директивы с телом**: `directive arg1 arg2 { ... }` - **Типы аргументов**: строки (двойные/одинарные кавычки/backticks для многострочных строк), числа (целые/дробные), булевы значения - **Вложенные блоки**: произвольная глубина вложенности - **Комментарии**: `#` до конца строки @@ -37,13 +40,13 @@ func main() { panic(err) } - // Получение команды и её значения + // Получение директивы и её значения if hostCmd := cfg.Get("server"); hostCmd != nil { fmt.Printf("Server: %v\n", hostCmd.Value()) } // Навигация по вложенной структуре - sslEnabled := cfg.Get("server").Group.Get("ssl").Group.Get("enabled") + sslEnabled := cfg.Get("server").Group().Get("ssl").Group().Get("enabled") fmt.Printf("SSL enabled: %v\n", sslEnabled.Value()) } ``` @@ -51,12 +54,12 @@ func main() { ## Пример конфигурационного файла ```conf -# Простые команды без тела +# Простые директивы без тела listen 8080; host "127.0.0.1"; debug false; -# Команды с аргументами и телом +# Директивы с аргументами и телом server "web" { host "localhost"; port 8080; @@ -73,7 +76,7 @@ server "web" { } } -# Несколько команд с одинаковым именем +# Несколько директив с одинаковым именем cache "redis" { host "redis.local"; port 6379; @@ -93,108 +96,6 @@ template ` `; ``` -## API - -### Загрузка конфигурации - -```go -// Из файла -cfg, err := conf.LoadFile("path/to/config.conf") - -// Из памяти -cfg, err := conf.Load("inline", []byte("listen 8080;")) -``` - -### Типы данных - -```go -// model.Ident — идентификатор команды (псевдоним для string) -ident := model.Ident("server") - -// model.Command — команда с именем, аргументами и вложенной группой -type Command struct { - Name Ident // Имя команды - Args []any // Аргументы команды - Group Group // Вложенные команды (тело команды) -} - -// model.Group — срез команд -type Group []Command -``` - -### Методы Command - -| Метод | Описание | -| ------------- | -------------------------------------------- | -| `Value() any` | Возвращает первый аргумент команды или `nil` | - -### Методы Group - -| Метод | Описание | -| ---------------------------------------------------------- | ---------------------------------------------------------- | -| `Get(name Ident) *Command` | Возвращает первую команду с указанным именем или `nil` | -| `Filter(predicate func(*Command) bool) iter.Seq[*Command]` | Возвращает итератор по командам, удовлетворяющим предикату | - -## Навигация по конфигурации - -```go -// Простой доступ -listenCmd := cfg.Get("listen") -fmt.Println(listenCmd.Value()) // 8080 - -// Цепочка вложенной навигации -port := cfg.Get("server").Group.Get("http").Group.Get("port") -fmt.Println(port.Value()) // 8080 - -// Использование Filter -for cmd := range cfg.Filter(func(c *model.Command) bool { - return c.Name == "cache" -}) { - fmt.Printf("Cache: %v\n", cmd.Value()) -} -``` - -## Работа с аргументами - -Аргументы сохраняются в срез `Args` типа `[]any`. Возможные типы: - -```go -// Строка в двойных кавычках: "value" -// Строка в одинарных кавычках: 'value' -// Строка в backticks: `value` -// Число целое: 42 -// Число дробное: 3.14 -// Булево значение: true, false - -// Пример доступа к аргументам: -cmd := cfg.Get("test") -if cmd != nil && len(cmd.Args) > 0 { - val1 := cmd.Args[0] // Первый аргумент - val2 := cmd.Args[1] // Второй аргумент - - // Приведение типа для строк - if str, ok := val1.(string); ok { - fmt.Println("String:", str) - } - - // Приведение типа для чисел - if num, ok := val2.(int); ok { - fmt.Println("Int:", num) - } -} -``` - -## Грамматика (PEG) - -Формат использует PEG (Parsing Expression Grammar). Грамматика описана в файле `parser/grammar.peg`. - -Основные правила: - -- Все команды без тела заканчиваются точкой с запятой `;` -- Тело команды заключается в фигурные скобки `{ }` -- Аргументы разделяются пробелами -- Комментарии начинаются с `#` - ## Требования - Go 1.23+ (для использования `iter.Seq`) @@ -223,6 +124,9 @@ if cmd != nil && len(cmd.Args) > 0 { # conf (English) +[](https://oc.neonxp.ru) +[](https://pkg.go.dev/go.neonxp.ru/conf) + Go library for parsing `.conf` configuration files (like many classic UNIX programms like nginx or bind9). ## Installation @@ -233,8 +137,8 @@ go get go.neonxp.ru/conf ## Format Features -- **Commands**: `directive arg1 arg2;` -- **Commands with body**: `directive arg1 arg2 { ... }` +- **Directives**: `directive arg1 arg2;` +- **Directives with body**: `directive arg1 arg2 { ... }` - **Argument types**: strings (double/single quotes, backticks for multiline strings), numbers (integer/float), boolean values - **Nested blocks**: arbitrary nesting depth - **Comments**: `#` until end of line @@ -257,7 +161,7 @@ func main() { panic(err) } - // Get command and its value + // Get directive and its value if hostCmd := cfg.Get("server"); hostCmd != nil { fmt.Printf("Server: %v\n", hostCmd.Value()) } @@ -271,12 +175,12 @@ func main() { ## Example Configuration File ```conf -# Simple commands without body +# Simple directives without body listen 8080; host "127.0.0.1"; debug false; -# Commands with arguments and body +# Directives with arguments and body server "web" { host "localhost"; port 8080; @@ -293,7 +197,7 @@ server "web" { } } -# Multiple commands with same name +# Multiple directives with same name cache "redis" { host "redis.local"; port 6379; @@ -313,108 +217,6 @@ template ` `; ``` -## API - -### Loading Configuration - -```go -// From file -cfg, err := conf.LoadFile("path/to/config.conf") - -// From memory -cfg, err := conf.Load("inline", []byte("listen 8080;")) -``` - -### Data Types - -```go -// model.Ident — command identifier (alias for string) -ident := model.Ident("server") - -// model.Command — command with name, arguments and nested group -type Command struct { - Name Ident // Command name - Args []any // Command arguments - Group Group // Nested commands (command body) -} - -// model.Group — slice of commands -type Group []Command -``` - -### Command Methods - -| Method | Description | -| ------------- | ------------------------------------------ | -| `Value() any` | Returns first argument of command or `nil` | - -### Group Methods - -| Method | Description | -| ---------------------------------------------------------- | -------------------------------------------------- | -| `Get(name Ident) *Command` | Returns first command with specified name or `nil` | -| `Filter(predicate func(*Command) bool) iter.Seq[*Command]` | Returns iterator over commands matching predicate | - -## Configuration Navigation - -```go -// Simple access -listenCmd := cfg.Get("listen") -fmt.Println(listenCmd.Value()) // 8080 - -// Nested navigation chain -port := cfg.Get("server").Group.Get("http").Group.Get("port") -fmt.Println(port.Value()) // 8080 - -// Using Filter -for cmd := range cfg.Filter(func(c *model.Command) bool { - return c.Name == "cache" -}) { - fmt.Printf("Cache: %v\n", cmd.Value()) -} -``` - -## Working with Arguments - -Arguments are stored in `Args` slice of type `[]any`. Possible types: - -```go -// Double-quoted string: "value" -// Single-quoted string: 'value' -// Backtick string: `value` -// Integer number: 42 -// Float number: 3.14 -// Boolean value: true, false - -// Example accessing arguments: -cmd := cfg.Get("test") -if cmd != nil && len(cmd.Args) > 0 { - val1 := cmd.Args[0] // First argument - val2 := cmd.Args[1] // Second argument - - // Type assertion for strings - if str, ok := val1.(string); ok { - fmt.Println("String:", str) - } - - // Type assertion for numbers - if num, ok := val2.(int); ok { - fmt.Println("Int:", num) - } -} -``` - -## Grammar (PEG) - -The format uses PEG (Parsing Expression Grammar). Grammar is described in file `parser/grammar.peg`. - -Basic rules: - -- All commands without body end with semicolon `;` -- Command body is enclosed in curly braces `{ }` -- Arguments are separated by spaces -- Comments start with `#` - ## Requirements - Go 1.23+ (for `iter.Seq`) diff --git a/example.conf b/example.conf new file mode 100644 index 0000000..ba01b60 --- /dev/null +++ b/example.conf @@ -0,0 +1,12 @@ +some directive; +group1 param1 { + group2 param2 { + group3 param3 { + key "value"; + int_key 123; + float_key 123.321; + bool_key true; + } + external_vars "Concatenate with" EXTERNAL_VAR "and integer" 123; + } +}
\ No newline at end of file @@ -1,3 +1,20 @@ +// Package conf library for parsing `.conf` configuration files. +// +// This file is part of conf library. +// Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. package conf import ( @@ -18,7 +35,6 @@ func LoadFile(filename string) (model.Group, error) { } func Load(name string, input []byte) (model.Group, error) { - res, err := parser.Parse(name, input) if err != nil { return nil, parser.CaretErrors(err, string(input)) diff --git a/loader_test.go b/loader_test.go index 3c9a84a..e2d7e48 100644 --- a/loader_test.go +++ b/loader_test.go @@ -1,41 +1,85 @@ +// Package conf_test tests. +// +// This file is part of conf library. +// Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. package conf_test import ( "fmt" - "log" "go.neonxp.ru/conf" ) -func ExampleLoad() { - test := ` - some directive; - group1 param1 { - group2 param2 { - group3 param3 { - key value; - } - } - } - ` - result, err := conf.Load("test", []byte(test)) +func ExampleLoadFile() { + result, err := conf.LoadFile("./example.conf") if err != nil { - log.Fatal(err) + panic("\n" + err.Error()) } - fmt.Println( + out( result.Get("group1"). - Group.Get("group2"). - Group.Get("group3"). - Group.Get("key").Value(), + Group().Get("group2"). + Group().Get("group3"). + Group().Get("key").Value(), ) // → value + out( + result.Get("group1"). + Group().Get("group2"). + Group().Get("group3"). + Group().Get("int_key").Value(), + ) // → 123 + out( + result.Get("group1"). + Group().Get("group2"). + Group().Get("group3"). + Group().Get("float_key").Value(), + ) // → 123.321 + out( + result.Get("group1"). + Group().Get("group2"). + Group().Get("group3"). + Group().Get("bool_key").Value(), + ) // → true - fmt.Println( + out( result.Get("group1"). - Group.Get("group2"). - Group.Get("group3").Value(), + Group().Get("group2"). + Group().Get("group3").Value(), ) // → param3 - // Output: value - // param3 + out( + result.Get("group1"). + Group().Get("group2"). + Group().Get("external_vars"). + StringExt(" ", func(key string) (string, bool) { + if key == "EXTERNAL_VAR" { + return "external variable", true + } + return "unknnown var", false + }), + ) // → Concatenate with external variable and integer 123 + + // Output: value (string) + // 123 (int) + // 123.321 (float64) + // true (bool) + // param3 (model.Ident) + // Concatenate with external variable and integer 123 (string) +} + +func out(a any) { + fmt.Printf("%v (%T)\n", a, a) } diff --git a/model/directive.go b/model/directive.go new file mode 100644 index 0000000..a4ab032 --- /dev/null +++ b/model/directive.go @@ -0,0 +1,137 @@ +// Package model implements custom types and methods used in conf parser. +// +// This file is part of conf library. +// Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. +package model + +import ( + "strconv" + "strings" +) + +type Directive struct { + Name Ident + RawValues []any +} + +// Group returns group of directive. +func (c *Directive) Group() Group { + if c == nil { + return Group{} + } + if len(c.RawValues) > 0 { + last := c.RawValues[len(c.RawValues)-1] + if g, ok := last.(Group); ok { + return g + } + } + return Group{} +} + +// Value returns first argument of directive. +func (c *Directive) Value() any { + args := c.Values() + if len(args) > 0 { + return args[0] + } + return nil +} + +// String returns first argument of directive as string. +func (c *Directive) String() string { + args := c.Values() + if len(args) > 0 { + if s, ok := args[0].(string); ok { + return s + } + } + return "" +} + +// Int returns first argument of directive as int. +func (c *Directive) Int() int { + args := c.Values() + if len(args) > 0 { + if s, ok := args[0].(int); ok { + return s + } + } + return 0 +} + +// Float returns first argument of directive as int. +func (c *Directive) Float() float64 { + args := c.Values() + if len(args) > 0 { + if s, ok := args[0].(float64); ok { + return s + } + } + return 0 +} + +// Bool returns first argument of directive as boolean. +func (c *Directive) Bool() bool { + args := c.Values() + if len(args) > 0 { + if s, ok := args[0].(bool); ok { + return s + } + } + return false +} + +// Values returns directive values without group. +func (c *Directive) Values() []any { + if c == nil { + return []any{} + } + result := make([]any, 0, len(c.RawValues)) + for _, rv := range c.RawValues { + if _, ok := rv.(Group); ok { + continue + } + result = append(result, rv) + } + return result +} + +type Lookup func(key string) (string, bool) + +// StringExt joins all values of directive in single string. +// Idents passes to identLookup func, e.g.`os.LookupEnv`. +func (c *Directive) StringExt(sep string, identLookup Lookup) string { + args := c.Values() + stringSl := make([]string, len(args)) + for i, it := range args { + switch it := it.(type) { + case string: + stringSl[i] = it + case float64: + stringSl[i] = strconv.FormatFloat(it, 'g', 5, 64) + case int: + stringSl[i] = strconv.Itoa(it) + case bool: + stringSl[i] = strconv.FormatBool(it) + case Ident: + if newVal, isset := identLookup(string(it)); isset { + stringSl[i] = newVal + } + } + } + + return strings.Join(stringSl, sep) +} diff --git a/model/group.go b/model/group.go new file mode 100644 index 0000000..a06c2ef --- /dev/null +++ b/model/group.go @@ -0,0 +1,48 @@ +// Package model implements custom types and methods used in conf parser. +// +// This file is part of conf library. +// Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. +package model + +import "iter" + +type Group []Directive + +// Get returns first directive with given name. +func (g Group) Get(name Ident) *Directive { + for _, c := range g { + if c.Name == name { + return &c + } + } + return nil +} + +// Filter directives by predicate and returns iterator over filtered items. +func (g Group) Filter(predicate func(c *Directive) bool) iter.Seq[*Directive] { + return func(yield func(*Directive) bool) { + for _, c := range g { + if predicate(&c) && !yield(&c) { + return + } + } + } +} + +// Directives returns iterator over Directives by ident. +func (g Group) Directives(ident Ident) iter.Seq[*Directive] { + return g.Filter(func(c *Directive) bool { return c.Name == ident }) +} diff --git a/model/model.go b/model/model.go index 2bc6dfb..6f18f6f 100644 --- a/model/model.go +++ b/model/model.go @@ -1,44 +1,20 @@ +// Package model implements custom types and methods used in conf parser. +// +// This file is part of conf library. +// Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. package model -import ( - "iter" -) - type Ident string - -type Command struct { - Name Ident - Args []any - Group Group -} - -// Value returns first argument of command. -func (c *Command) Value() any { - if len(c.Args) > 0 { - return c.Args[0] - } - return nil -} - -type Group []Command - -// Get returns first command with given name. -func (g Group) Get(name Ident) *Command { - for _, c := range g { - if c.Name == name { - return &c - } - } - return nil -} - -// Filter commands by predicate and returns iterator over filtered commands. -func (g Group) Filter(predicate func(c *Command) bool) iter.Seq[*Command] { - return func(yield func(*Command) bool) { - for _, c := range g { - if predicate(&c) && !yield(&c) { - return - } - } - } -} diff --git a/parser/errors.go b/parser/errors.go index c2ed049..b1f839e 100644 --- a/parser/errors.go +++ b/parser/errors.go @@ -1,3 +1,20 @@ +// Package parser parses conf language. +// +// This file is part of conf library. +// Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. package parser import ( @@ -39,9 +56,8 @@ func CaretErrors(err error, input string) error { if el, ok := err.(ErrorLister); ok { var buffer bytes.Buffer for _, e := range el.Errors() { - err1, shouldReturn := caretError(e, input, buffer, err) - if shouldReturn { - return err1 + if err := caretError(e, input); err != nil { + buffer.WriteString(err.Error()) } } return errors.New(buffer.String()) @@ -49,8 +65,8 @@ func CaretErrors(err error, input string) error { return err } -func caretError(e error, input string, buffer bytes.Buffer, err error) (error, bool) { - if parserErr, ok := e.(ParserError); ok { +func caretError(err error, input string) error { + if parserErr, ok := err.(ParserError); ok { _, col, off := parserErr.Pos() line := extractLine(input, off) if col >= len(line) { @@ -69,13 +85,9 @@ func caretError(e error, input string, buffer bytes.Buffer, err error) (error, b pos += 7 } } - fmt.Fprintf(&buffer, "%s\n%s\n%s\n", line, strings.Repeat(" ", pos)+"^", err.Error()) - - return err, true - } else { - return err, true + return fmt.Errorf("%s\n%s\n%w", line, strings.Repeat(" ", pos)+"^", err) } - return nil, false + return err } func extractLine(input string, initPos int) string { diff --git a/parser/grammar.peg b/parser/grammar.peg index 38b6dc8..760257f 100644 --- a/parser/grammar.peg +++ b/parser/grammar.peg @@ -1,5 +1,21 @@ { // Package parser parses conf language. + // + // This file is part of conf library. + // Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> + // + // This program is free software: you can redistribute it and/or modify + // it under the terms of the GNU General Public License as published by + // the Free Software Foundation, either version 3 of the License, or + // (at your option) any later version. + // + // This program is distributed in the hope that it will be useful, + // but WITHOUT ANY WARRANTY; without even the implied warranty of + // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + // GNU General Public License for more details. + // + // You should have received a copy of the GNU General Public License + // along with this program. If not, see <https://www.gnu.org/licenses/>. package parser import ( @@ -13,7 +29,7 @@ if v == nil { return nil } - if v := v.([]any); len(v) == 0 { + if v, ok := v.([]any); ok && len(v) == 0 { return nil } @@ -21,32 +37,31 @@ } } -Config ← _ stmts:( Command* ) EOF { - if stmts == nil { +Config ← _ directives:( Directive* ) EOF { + if directives == nil { return model.Group{}, nil } - groupAny := toAnySlice(stmts) + groupAny := toAnySlice(directives) groupSl := make(model.Group, len(groupAny)) for i, e := range groupAny { - groupSl[i] = e.(model.Command) + groupSl[i] = e.(model.Directive) } return groupSl, nil } -Group ← '{' _ stmts:( Command* ) _ '}' { - if stmts == nil { +Group ← '{' _ directives:( Directive* ) _ '}' { + if directives == nil { return model.Group{}, nil } - groupAny := toAnySlice(stmts) + groupAny := toAnySlice(directives) groupSl := make(model.Group, len(groupAny)) for i, e := range groupAny { - groupSl[i] = e.(model.Command) + groupSl[i] = e.(model.Directive) } return groupSl, nil } -Command ← name:Ident _ args:Args _ { - var group model.Group +Directive ← name:Ident _ args:Args _ { rawArgs := args.([]any) argsSlice := make([]any, 0, len(rawArgs)) if len(rawArgs) > 0 { @@ -54,73 +69,79 @@ Command ← name:Ident _ args:Args _ { if s == nil { continue } - if g, ok := s.(model.Group); ok { - group = g - continue - } if l, ok := s.([]any); ok { l = slices.DeleteFunc(l, func(x any) bool { return x == nil }) argsSlice = append(argsSlice, l...) } } } - return model.Command{Name: name.(model.Ident), Args: argsSlice, Group: group}, nil + return model.Directive{Name: name.(model.Ident), RawValues: argsSlice}, nil } Args ← Values? (Group / EOS) Values ← vals:Value* { return toAnySlice(vals), nil } -Value ← val:( Ident / String / Number / Boolean ) __ { return val, nil } -String ← ( '"' DoubleStringChar* '"' / "'" SingleStringChar "'" / '`' RawStringChar* '`' ) { - return string(c.text), nil -} - -// Сервисные литералы +Value ← val:( Ident / String / Number ) __ { return val, nil } // {{{ Строки +String ← ( '"' DoubleStringChar* '"' / "'" SingleStringChar "'" / '`' RawStringChar* '`' ) { + return strconv.Unquote(string(c.text)) +} DoubleStringChar ← !( '"' / "\\" / EOL ) SourceChar / "\\" DoubleStringEscape SingleStringChar ← !( "'" / "\\" / EOL ) SourceChar / "\\" SingleStringEscape -RawStringChar ← !'`' SourceChar +RawStringChar ← !'`' SourceChar DoubleStringEscape ← '"' / CommonEscapeSequence SingleStringEscape ← "'" / CommonEscapeSequence CommonEscapeSequence ← SingleCharEscape / OctalEscape / HexEscape / LongUnicodeEscape / ShortUnicodeEscape -SingleCharEscape ← 'a' / 'b' / 'n' / 'f' / 'r' / 't' / 'v' / '\\' -OctalEscape ← OctalDigit OctalDigit OctalDigit -HexEscape ← 'x' HexDigit HexDigit -LongUnicodeEscape ← 'U' HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit -ShortUnicodeEscape ← 'u' HexDigit HexDigit HexDigit HexDigit +SingleCharEscape ← 'a' / 'b' / 'n' / 'f' / 'r' / 't' / 'v' / '\\' +OctalEscape ← OctalDigit OctalDigit OctalDigit +HexEscape ← 'x' HexDigit HexDigit +LongUnicodeEscape ← 'U' HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit HexDigit +ShortUnicodeEscape ← 'u' HexDigit HexDigit HexDigit HexDigit OctalDigit ← [0-7] -DecimalDigit ← [0-9] HexDigit ← [0-9a-f]i SourceChar ← . // }}} // {{{ Числа -Number ← '-'? Integer ( '.' DecimalDigit+ )? Exponent? { return strconv.ParseFloat(string(c.text), 64) } -Integer ← '0' / NonZeroDecimalDigit DecimalDigit* -Exponent ← 'e'i [+-]? DecimalDigit+ -DecimalDigit ← [0-9] +Number ← '-'? UInteger ('.' DecimalDigit+)? Exponent? { + if i, err := strconv.Atoi(string(c.text)); err == nil { + return i, nil + } + return strconv.ParseFloat(string(c.text), 64) +} + +UInteger ← '0' / NonZeroDecimalDigit DecimalDigit* +Exponent ← 'e'i [+-]? DecimalDigit+ +DecimalDigit ← [0-9] NonZeroDecimalDigit ← [1-9] // }}} // {{{ Идентификатор -Ident ← (Alpha / AllowedSpec) (Alpha / AllowedSpec / Number)* { return model.Ident(c.text), nil } -Alpha ← [a-zA-Z] +Ident ← (Alpha / AllowedSpec) (Alpha / AllowedSpec / Number)* { + switch string(c.text) { + case "true": + return true, nil + case "false": + return false, nil + default: + return model.Ident(c.text), nil + } +} +Alpha ← [a-zA-Z] AllowedSpec ← '$' / '@' / '%' / '_' / '-' / '+' // }}} -Boolean ← "true" { return true, nil } / "false" { return false, nil } - -Comment ← '#' ( ![\r\n] . )* -__ ← ( Whitespace / EOL / Comment )* -_ ← ( [ \t\r\n] / Comment )* - +// {{{ Оставшиеся спец моменты +Comment ← '#' ( ![\r\n] . )* +__ ← ( Whitespace / EOL / Comment )* +_ ← ( [ \t\r\n] / Comment )* Whitespace ← [ \t\r] -EOL ← '\n' -EOS ← __ ';' { return nil, nil } / _ Comment? EOL { return nil, nil } / __ EOF { return nil, nil } - -EOF ← !.
\ No newline at end of file +EOL ← '\n' +EOS ← __ ';' { return nil, nil } / _ Comment? EOL { return nil, nil } / __ EOF { return nil, nil } +EOF ← !. +// }}}
\ No newline at end of file diff --git a/parser/parser.go b/parser/parser.go index e6abdaf..0cf8f2c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -1,6 +1,22 @@ // Code generated by pigeon; DO NOT EDIT. // Package parser parses conf language. +// +// This file is part of conf library. +// Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. package parser import ( @@ -24,7 +40,7 @@ func toAnySlice(v any) []any { if v == nil { return nil } - if v := v.([]any); len(v) == 0 { + if v, ok := v.([]any); ok && len(v) == 0 { return nil } @@ -35,43 +51,43 @@ var g = &grammar{ rules: []*rule{ { name: "Config", - pos: position{line: 24, col: 1, offset: 355}, + pos: position{line: 40, col: 1, offset: 1184}, expr: &actionExpr{ - pos: position{line: 24, col: 10, offset: 366}, + pos: position{line: 40, col: 10, offset: 1195}, run: (*parser).callonConfig1, expr: &seqExpr{ - pos: position{line: 24, col: 10, offset: 366}, + pos: position{line: 40, col: 10, offset: 1195}, exprs: []any{ &zeroOrMoreExpr{ - pos: position{line: 120, col: 5, offset: 3403}, + pos: position{line: 142, col: 14, offset: 4397}, expr: &choiceExpr{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -79,7 +95,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -90,20 +106,20 @@ var g = &grammar{ }, }, &labeledExpr{ - pos: position{line: 24, col: 12, offset: 368}, - label: "stmts", + pos: position{line: 40, col: 12, offset: 1197}, + label: "directives", expr: &zeroOrMoreExpr{ - pos: position{line: 24, col: 20, offset: 376}, + pos: position{line: 40, col: 25, offset: 1210}, expr: &ruleRefExpr{ - pos: position{line: 24, col: 20, offset: 376}, - name: "Command", + pos: position{line: 40, col: 25, offset: 1210}, + name: "Directive", }, }, }, ¬Expr{ - pos: position{line: 126, col: 7, offset: 3575}, + pos: position{line: 146, col: 14, offset: 4588}, expr: &anyMatcher{ - line: 126, col: 8, offset: 3576, + line: 146, col: 15, offset: 4589, }, }, }, @@ -112,49 +128,49 @@ var g = &grammar{ }, { name: "Group", - pos: position{line: 36, col: 1, offset: 642}, + pos: position{line: 52, col: 1, offset: 1490}, expr: &actionExpr{ - pos: position{line: 36, col: 9, offset: 652}, + pos: position{line: 52, col: 9, offset: 1500}, run: (*parser).callonGroup1, expr: &seqExpr{ - pos: position{line: 36, col: 9, offset: 652}, + pos: position{line: 52, col: 9, offset: 1500}, exprs: []any{ &litMatcher{ - pos: position{line: 36, col: 9, offset: 652}, + pos: position{line: 52, col: 9, offset: 1500}, val: "{", ignoreCase: false, want: "\"{\"", }, &zeroOrMoreExpr{ - pos: position{line: 120, col: 5, offset: 3403}, + pos: position{line: 142, col: 14, offset: 4397}, expr: &choiceExpr{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -162,7 +178,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -173,46 +189,46 @@ var g = &grammar{ }, }, &labeledExpr{ - pos: position{line: 36, col: 15, offset: 658}, - label: "stmts", + pos: position{line: 52, col: 15, offset: 1506}, + label: "directives", expr: &zeroOrMoreExpr{ - pos: position{line: 36, col: 23, offset: 666}, + pos: position{line: 52, col: 28, offset: 1519}, expr: &ruleRefExpr{ - pos: position{line: 36, col: 23, offset: 666}, - name: "Command", + pos: position{line: 52, col: 28, offset: 1519}, + name: "Directive", }, }, }, &zeroOrMoreExpr{ - pos: position{line: 120, col: 5, offset: 3403}, + pos: position{line: 142, col: 14, offset: 4397}, expr: &choiceExpr{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -220,7 +236,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -231,7 +247,7 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 36, col: 36, offset: 679}, + pos: position{line: 52, col: 43, offset: 1534}, val: "}", ignoreCase: false, want: "\"}\"", @@ -241,25 +257,25 @@ var g = &grammar{ }, }, { - name: "Command", - pos: position{line: 48, col: 1, offset: 934}, + name: "Directive", + pos: position{line: 64, col: 1, offset: 1801}, expr: &actionExpr{ - pos: position{line: 48, col: 11, offset: 946}, - run: (*parser).callonCommand1, + pos: position{line: 64, col: 13, offset: 1815}, + run: (*parser).callonDirective1, expr: &seqExpr{ - pos: position{line: 48, col: 11, offset: 946}, + pos: position{line: 64, col: 13, offset: 1815}, exprs: []any{ &labeledExpr{ - pos: position{line: 48, col: 11, offset: 946}, + pos: position{line: 64, col: 13, offset: 1815}, label: "name", expr: &actionExpr{ - pos: position{line: 111, col: 9, offset: 3087}, - run: (*parser).callonCommand4, + pos: position{line: 125, col: 15, offset: 3911}, + run: (*parser).callonDirective4, expr: &seqExpr{ - pos: position{line: 111, col: 9, offset: 3087}, + pos: position{line: 125, col: 15, offset: 3911}, exprs: []any{ &charClassMatcher{ - pos: position{line: 112, col: 9, offset: 3187}, + pos: position{line: 135, col: 15, offset: 4182}, val: "[$@%_-+a-zA-Z]", chars: []rune{'$', '@', '%', '_', '-', '+'}, ranges: []rune{'a', 'z', 'A', 'Z'}, @@ -267,12 +283,12 @@ var g = &grammar{ inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 111, col: 31, offset: 3109}, + pos: position{line: 125, col: 37, offset: 3933}, expr: &choiceExpr{ - pos: position{line: 111, col: 32, offset: 3110}, + pos: position{line: 125, col: 38, offset: 3934}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 112, col: 9, offset: 3187}, + pos: position{line: 135, col: 15, offset: 4182}, val: "[$@%_-+a-zA-Z]", chars: []rune{'$', '@', '%', '_', '-', '+'}, ranges: []rune{'a', 'z', 'A', 'Z'}, @@ -280,43 +296,43 @@ var g = &grammar{ inverted: false, }, &actionExpr{ - pos: position{line: 103, col: 10, offset: 2796}, - run: (*parser).callonCommand10, + pos: position{line: 111, col: 10, offset: 3492}, + run: (*parser).callonDirective10, expr: &seqExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, expr: &litMatcher{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &choiceExpr{ - pos: position{line: 104, col: 11, offset: 2904}, + pos: position{line: 118, col: 23, offset: 3704}, alternatives: []any{ &litMatcher{ - pos: position{line: 104, col: 11, offset: 2904}, + pos: position{line: 118, col: 23, offset: 3704}, val: "0", ignoreCase: false, want: "\"0\"", }, &seqExpr{ - pos: position{line: 104, col: 17, offset: 2910}, + pos: position{line: 118, col: 29, offset: 3710}, exprs: []any{ &charClassMatcher{ - pos: position{line: 107, col: 23, offset: 3029}, + pos: position{line: 121, col: 23, offset: 3847}, val: "[1-9]", ranges: []rune{'1', '9'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 104, col: 37, offset: 2930}, + pos: position{line: 118, col: 49, offset: 3730}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -328,20 +344,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 103, col: 23, offset: 2809}, + pos: position{line: 111, col: 24, offset: 3506}, expr: &seqExpr{ - pos: position{line: 103, col: 25, offset: 2811}, + pos: position{line: 111, col: 25, offset: 3507}, exprs: []any{ &litMatcher{ - pos: position{line: 103, col: 25, offset: 2811}, + pos: position{line: 111, col: 25, offset: 3507}, val: ".", ignoreCase: false, want: "\".\"", }, &oneOrMoreExpr{ - pos: position{line: 103, col: 29, offset: 2815}, + pos: position{line: 111, col: 29, offset: 3511}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -352,20 +368,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 103, col: 46, offset: 2832}, + pos: position{line: 111, col: 45, offset: 3527}, expr: &seqExpr{ - pos: position{line: 105, col: 12, offset: 2957}, + pos: position{line: 119, col: 23, offset: 3768}, exprs: []any{ &litMatcher{ - pos: position{line: 105, col: 12, offset: 2957}, + pos: position{line: 119, col: 23, offset: 3768}, val: "e", ignoreCase: true, want: "\"e\"i", }, &zeroOrOneExpr{ - pos: position{line: 105, col: 17, offset: 2962}, + pos: position{line: 119, col: 28, offset: 3773}, expr: &charClassMatcher{ - pos: position{line: 105, col: 17, offset: 2962}, + pos: position{line: 119, col: 28, offset: 3773}, val: "[+-]", chars: []rune{'+', '-'}, ignoreCase: false, @@ -373,9 +389,9 @@ var g = &grammar{ }, }, &oneOrMoreExpr{ - pos: position{line: 105, col: 23, offset: 2968}, + pos: position{line: 119, col: 34, offset: 3779}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -396,35 +412,35 @@ var g = &grammar{ }, }, &zeroOrMoreExpr{ - pos: position{line: 120, col: 5, offset: 3403}, + pos: position{line: 142, col: 14, offset: 4397}, expr: &choiceExpr{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -432,7 +448,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -443,43 +459,43 @@ var g = &grammar{ }, }, &labeledExpr{ - pos: position{line: 48, col: 24, offset: 959}, + pos: position{line: 64, col: 26, offset: 1828}, label: "args", expr: &ruleRefExpr{ - pos: position{line: 48, col: 29, offset: 964}, + pos: position{line: 64, col: 31, offset: 1833}, name: "Args", }, }, &zeroOrMoreExpr{ - pos: position{line: 120, col: 5, offset: 3403}, + pos: position{line: 142, col: 14, offset: 4397}, expr: &choiceExpr{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -487,7 +503,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -503,40 +519,40 @@ var g = &grammar{ }, { name: "Args", - pos: position{line: 70, col: 1, offset: 1602}, + pos: position{line: 81, col: 1, offset: 2327}, expr: &seqExpr{ - pos: position{line: 70, col: 8, offset: 1611}, + pos: position{line: 81, col: 8, offset: 2336}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 70, col: 8, offset: 1611}, + pos: position{line: 81, col: 8, offset: 2336}, expr: &actionExpr{ - pos: position{line: 72, col: 10, offset: 1645}, + pos: position{line: 83, col: 10, offset: 2370}, run: (*parser).callonArgs3, expr: &labeledExpr{ - pos: position{line: 72, col: 10, offset: 1645}, + pos: position{line: 83, col: 10, offset: 2370}, label: "vals", expr: &zeroOrMoreExpr{ - pos: position{line: 72, col: 15, offset: 1650}, + pos: position{line: 83, col: 15, offset: 2375}, expr: &actionExpr{ - pos: position{line: 74, col: 9, offset: 1701}, + pos: position{line: 85, col: 9, offset: 2426}, run: (*parser).callonArgs6, expr: &seqExpr{ - pos: position{line: 74, col: 9, offset: 1701}, + pos: position{line: 85, col: 9, offset: 2426}, exprs: []any{ &labeledExpr{ - pos: position{line: 74, col: 9, offset: 1701}, + pos: position{line: 85, col: 9, offset: 2426}, label: "val", expr: &choiceExpr{ - pos: position{line: 74, col: 15, offset: 1707}, + pos: position{line: 85, col: 15, offset: 2432}, alternatives: []any{ &actionExpr{ - pos: position{line: 111, col: 9, offset: 3087}, + pos: position{line: 125, col: 15, offset: 3911}, run: (*parser).callonArgs10, expr: &seqExpr{ - pos: position{line: 111, col: 9, offset: 3087}, + pos: position{line: 125, col: 15, offset: 3911}, exprs: []any{ &charClassMatcher{ - pos: position{line: 112, col: 9, offset: 3187}, + pos: position{line: 135, col: 15, offset: 4182}, val: "[$@%_-+a-zA-Z]", chars: []rune{'$', '@', '%', '_', '-', '+'}, ranges: []rune{'a', 'z', 'A', 'Z'}, @@ -544,12 +560,12 @@ var g = &grammar{ inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 111, col: 31, offset: 3109}, + pos: position{line: 125, col: 37, offset: 3933}, expr: &choiceExpr{ - pos: position{line: 111, col: 32, offset: 3110}, + pos: position{line: 125, col: 38, offset: 3934}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 112, col: 9, offset: 3187}, + pos: position{line: 135, col: 15, offset: 4182}, val: "[$@%_-+a-zA-Z]", chars: []rune{'$', '@', '%', '_', '-', '+'}, ranges: []rune{'a', 'z', 'A', 'Z'}, @@ -557,43 +573,43 @@ var g = &grammar{ inverted: false, }, &actionExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, run: (*parser).callonArgs16, expr: &seqExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, expr: &litMatcher{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &choiceExpr{ - pos: position{line: 104, col: 11, offset: 2904}, + pos: position{line: 118, col: 23, offset: 3704}, alternatives: []any{ &litMatcher{ - pos: position{line: 104, col: 11, offset: 2904}, + pos: position{line: 118, col: 23, offset: 3704}, val: "0", ignoreCase: false, want: "\"0\"", }, &seqExpr{ - pos: position{line: 104, col: 17, offset: 2910}, + pos: position{line: 118, col: 29, offset: 3710}, exprs: []any{ &charClassMatcher{ - pos: position{line: 107, col: 23, offset: 3029}, + pos: position{line: 121, col: 23, offset: 3847}, val: "[1-9]", ranges: []rune{'1', '9'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 104, col: 37, offset: 2930}, + pos: position{line: 118, col: 49, offset: 3730}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -605,20 +621,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 103, col: 23, offset: 2809}, + pos: position{line: 111, col: 24, offset: 3506}, expr: &seqExpr{ - pos: position{line: 103, col: 25, offset: 2811}, + pos: position{line: 111, col: 25, offset: 3507}, exprs: []any{ &litMatcher{ - pos: position{line: 103, col: 25, offset: 2811}, + pos: position{line: 111, col: 25, offset: 3507}, val: ".", ignoreCase: false, want: "\".\"", }, &oneOrMoreExpr{ - pos: position{line: 103, col: 29, offset: 2815}, + pos: position{line: 111, col: 29, offset: 3511}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -629,20 +645,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 103, col: 46, offset: 2832}, + pos: position{line: 111, col: 45, offset: 3527}, expr: &seqExpr{ - pos: position{line: 105, col: 12, offset: 2957}, + pos: position{line: 119, col: 23, offset: 3768}, exprs: []any{ &litMatcher{ - pos: position{line: 105, col: 12, offset: 2957}, + pos: position{line: 119, col: 23, offset: 3768}, val: "e", ignoreCase: true, want: "\"e\"i", }, &zeroOrOneExpr{ - pos: position{line: 105, col: 17, offset: 2962}, + pos: position{line: 119, col: 28, offset: 3773}, expr: &charClassMatcher{ - pos: position{line: 105, col: 17, offset: 2962}, + pos: position{line: 119, col: 28, offset: 3773}, val: "[+-]", chars: []rune{'+', '-'}, ignoreCase: false, @@ -650,9 +666,9 @@ var g = &grammar{ }, }, &oneOrMoreExpr{ - pos: position{line: 105, col: 23, offset: 2968}, + pos: position{line: 119, col: 34, offset: 3779}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -672,32 +688,32 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 75, col: 10, offset: 1777}, + pos: position{line: 88, col: 10, offset: 2513}, run: (*parser).callonArgs38, expr: &choiceExpr{ - pos: position{line: 75, col: 12, offset: 1779}, + pos: position{line: 88, col: 12, offset: 2515}, alternatives: []any{ &seqExpr{ - pos: position{line: 75, col: 12, offset: 1779}, + pos: position{line: 88, col: 12, offset: 2515}, exprs: []any{ &litMatcher{ - pos: position{line: 75, col: 12, offset: 1779}, + pos: position{line: 88, col: 12, offset: 2515}, val: "\"", ignoreCase: false, want: "\"\\\"\"", }, &zeroOrMoreExpr{ - pos: position{line: 75, col: 16, offset: 1783}, + pos: position{line: 88, col: 16, offset: 2519}, expr: &choiceExpr{ - pos: position{line: 82, col: 20, offset: 1976}, + pos: position{line: 91, col: 20, offset: 2663}, alternatives: []any{ &seqExpr{ - pos: position{line: 82, col: 20, offset: 1976}, + pos: position{line: 91, col: 20, offset: 2663}, exprs: []any{ ¬Expr{ - pos: position{line: 82, col: 20, offset: 1976}, + pos: position{line: 91, col: 20, offset: 2663}, expr: &charClassMatcher{ - pos: position{line: 82, col: 23, offset: 1979}, + pos: position{line: 91, col: 23, offset: 2666}, val: "[\"\\\\\\n]", chars: []rune{'"', '\\', '\n'}, ignoreCase: false, @@ -705,48 +721,48 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 99, col: 14, offset: 2757, + line: 107, col: 14, offset: 3453, }, }, }, &seqExpr{ - pos: position{line: 82, col: 55, offset: 2011}, + pos: position{line: 91, col: 55, offset: 2698}, exprs: []any{ &litMatcher{ - pos: position{line: 82, col: 55, offset: 2011}, + pos: position{line: 91, col: 55, offset: 2698}, val: "\\", ignoreCase: false, want: "\"\\\\\"", }, &choiceExpr{ - pos: position{line: 86, col: 22, offset: 2173}, + pos: position{line: 95, col: 22, offset: 2863}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 90, col: 20, offset: 2381}, + pos: position{line: 99, col: 24, offset: 3075}, val: "[abnf\"rtv\\\\]", chars: []rune{'a', 'b', 'n', 'f', '"', 'r', 't', 'v', '\\'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 91, col: 15, offset: 2444}, + pos: position{line: 100, col: 24, offset: 3147}, exprs: []any{ &charClassMatcher{ - pos: position{line: 96, col: 14, offset: 2690}, + pos: position{line: 105, col: 14, offset: 3409}, val: "[0-7]", ranges: []rune{'0', '7'}, ignoreCase: false, inverted: false, }, &charClassMatcher{ - pos: position{line: 96, col: 14, offset: 2690}, + pos: position{line: 105, col: 14, offset: 3409}, val: "[0-7]", ranges: []rune{'0', '7'}, ignoreCase: false, inverted: false, }, &charClassMatcher{ - pos: position{line: 96, col: 14, offset: 2690}, + pos: position{line: 105, col: 14, offset: 3409}, val: "[0-7]", ranges: []rune{'0', '7'}, ignoreCase: false, @@ -755,23 +771,23 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 92, col: 13, offset: 2491}, + pos: position{line: 101, col: 24, offset: 3205}, exprs: []any{ &litMatcher{ - pos: position{line: 92, col: 13, offset: 2491}, + pos: position{line: 101, col: 24, offset: 3205}, val: "x", ignoreCase: false, want: "\"x\"", }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, @@ -780,65 +796,65 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 93, col: 21, offset: 2535}, + pos: position{line: 102, col: 24, offset: 3252}, exprs: []any{ &litMatcher{ - pos: position{line: 93, col: 21, offset: 2535}, + pos: position{line: 102, col: 24, offset: 3252}, val: "U", ignoreCase: false, want: "\"U\"", }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, @@ -847,37 +863,37 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 94, col: 22, offset: 2634}, + pos: position{line: 103, col: 24, offset: 3353}, exprs: []any{ &litMatcher{ - pos: position{line: 94, col: 22, offset: 2634}, + pos: position{line: 103, col: 24, offset: 3353}, val: "u", ignoreCase: false, want: "\"u\"", }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, @@ -893,7 +909,7 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 75, col: 34, offset: 1801}, + pos: position{line: 88, col: 34, offset: 2537}, val: "\"", ignoreCase: false, want: "\"\\\"\"", @@ -901,24 +917,24 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 75, col: 40, offset: 1807}, + pos: position{line: 88, col: 40, offset: 2543}, exprs: []any{ &litMatcher{ - pos: position{line: 75, col: 40, offset: 1807}, + pos: position{line: 88, col: 40, offset: 2543}, val: "'", ignoreCase: false, want: "\"'\"", }, &choiceExpr{ - pos: position{line: 83, col: 20, offset: 2056}, + pos: position{line: 92, col: 20, offset: 2743}, alternatives: []any{ &seqExpr{ - pos: position{line: 83, col: 20, offset: 2056}, + pos: position{line: 92, col: 20, offset: 2743}, exprs: []any{ ¬Expr{ - pos: position{line: 83, col: 20, offset: 2056}, + pos: position{line: 92, col: 20, offset: 2743}, expr: &charClassMatcher{ - pos: position{line: 83, col: 23, offset: 2059}, + pos: position{line: 92, col: 23, offset: 2746}, val: "[\\\\\\\\n]", chars: []rune{'\'', '\\', '\n'}, ignoreCase: false, @@ -926,48 +942,48 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 99, col: 14, offset: 2757, + line: 107, col: 14, offset: 3453, }, }, }, &seqExpr{ - pos: position{line: 83, col: 55, offset: 2091}, + pos: position{line: 92, col: 55, offset: 2778}, exprs: []any{ &litMatcher{ - pos: position{line: 83, col: 55, offset: 2091}, + pos: position{line: 92, col: 55, offset: 2778}, val: "\\", ignoreCase: false, want: "\"\\\\\"", }, &choiceExpr{ - pos: position{line: 87, col: 22, offset: 2223}, + pos: position{line: 96, col: 22, offset: 2913}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 90, col: 20, offset: 2381}, + pos: position{line: 99, col: 24, offset: 3075}, val: "[abnf\\rtv\\\\]", chars: []rune{'a', 'b', 'n', 'f', '\'', 'r', 't', 'v', '\\'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 91, col: 15, offset: 2444}, + pos: position{line: 100, col: 24, offset: 3147}, exprs: []any{ &charClassMatcher{ - pos: position{line: 96, col: 14, offset: 2690}, + pos: position{line: 105, col: 14, offset: 3409}, val: "[0-7]", ranges: []rune{'0', '7'}, ignoreCase: false, inverted: false, }, &charClassMatcher{ - pos: position{line: 96, col: 14, offset: 2690}, + pos: position{line: 105, col: 14, offset: 3409}, val: "[0-7]", ranges: []rune{'0', '7'}, ignoreCase: false, inverted: false, }, &charClassMatcher{ - pos: position{line: 96, col: 14, offset: 2690}, + pos: position{line: 105, col: 14, offset: 3409}, val: "[0-7]", ranges: []rune{'0', '7'}, ignoreCase: false, @@ -976,23 +992,23 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 92, col: 13, offset: 2491}, + pos: position{line: 101, col: 24, offset: 3205}, exprs: []any{ &litMatcher{ - pos: position{line: 92, col: 13, offset: 2491}, + pos: position{line: 101, col: 24, offset: 3205}, val: "x", ignoreCase: false, want: "\"x\"", }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, @@ -1001,65 +1017,65 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 93, col: 21, offset: 2535}, + pos: position{line: 102, col: 24, offset: 3252}, exprs: []any{ &litMatcher{ - pos: position{line: 93, col: 21, offset: 2535}, + pos: position{line: 102, col: 24, offset: 3252}, val: "U", ignoreCase: false, want: "\"U\"", }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, @@ -1068,37 +1084,37 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 94, col: 22, offset: 2634}, + pos: position{line: 103, col: 24, offset: 3353}, exprs: []any{ &litMatcher{ - pos: position{line: 94, col: 22, offset: 2634}, + pos: position{line: 103, col: 24, offset: 3353}, val: "u", ignoreCase: false, want: "\"u\"", }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, inverted: false, }, &charClassMatcher{ - pos: position{line: 98, col: 12, offset: 2732}, + pos: position{line: 106, col: 12, offset: 3428}, val: "[0-9a-f]i", ranges: []rune{'0', '9', 'a', 'f'}, ignoreCase: true, @@ -1113,7 +1129,7 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 75, col: 61, offset: 1828}, + pos: position{line: 88, col: 61, offset: 2564}, val: "'", ignoreCase: false, want: "\"'\"", @@ -1121,36 +1137,36 @@ var g = &grammar{ }, }, &seqExpr{ - pos: position{line: 75, col: 67, offset: 1834}, + pos: position{line: 88, col: 67, offset: 2570}, exprs: []any{ &litMatcher{ - pos: position{line: 75, col: 67, offset: 1834}, + pos: position{line: 88, col: 67, offset: 2570}, val: "`", ignoreCase: false, want: "\"`\"", }, &zeroOrMoreExpr{ - pos: position{line: 75, col: 71, offset: 1838}, + pos: position{line: 88, col: 71, offset: 2574}, expr: &seqExpr{ - pos: position{line: 84, col: 17, offset: 2133}, + pos: position{line: 93, col: 20, offset: 2823}, exprs: []any{ ¬Expr{ - pos: position{line: 84, col: 17, offset: 2133}, + pos: position{line: 93, col: 20, offset: 2823}, expr: &litMatcher{ - pos: position{line: 84, col: 18, offset: 2134}, + pos: position{line: 93, col: 21, offset: 2824}, val: "`", ignoreCase: false, want: "\"`\"", }, }, &anyMatcher{ - line: 99, col: 14, offset: 2757, + line: 107, col: 14, offset: 3453, }, }, }, }, &litMatcher{ - pos: position{line: 75, col: 86, offset: 1853}, + pos: position{line: 88, col: 86, offset: 2589}, val: "`", ignoreCase: false, want: "\"`\"", @@ -1161,43 +1177,43 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, run: (*parser).callonArgs121, expr: &seqExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, exprs: []any{ &zeroOrOneExpr{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, expr: &litMatcher{ - pos: position{line: 103, col: 10, offset: 2796}, + pos: position{line: 111, col: 10, offset: 3492}, val: "-", ignoreCase: false, want: "\"-\"", }, }, &choiceExpr{ - pos: position{line: 104, col: 11, offset: 2904}, + pos: position{line: 118, col: 23, offset: 3704}, alternatives: []any{ &litMatcher{ - pos: position{line: 104, col: 11, offset: 2904}, + pos: position{line: 118, col: 23, offset: 3704}, val: "0", ignoreCase: false, want: "\"0\"", }, &seqExpr{ - pos: position{line: 104, col: 17, offset: 2910}, + pos: position{line: 118, col: 29, offset: 3710}, exprs: []any{ &charClassMatcher{ - pos: position{line: 107, col: 23, offset: 3029}, + pos: position{line: 121, col: 23, offset: 3847}, val: "[1-9]", ranges: []rune{'1', '9'}, ignoreCase: false, inverted: false, }, &zeroOrMoreExpr{ - pos: position{line: 104, col: 37, offset: 2930}, + pos: position{line: 118, col: 49, offset: 3730}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1209,20 +1225,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 103, col: 23, offset: 2809}, + pos: position{line: 111, col: 24, offset: 3506}, expr: &seqExpr{ - pos: position{line: 103, col: 25, offset: 2811}, + pos: position{line: 111, col: 25, offset: 3507}, exprs: []any{ &litMatcher{ - pos: position{line: 103, col: 25, offset: 2811}, + pos: position{line: 111, col: 25, offset: 3507}, val: ".", ignoreCase: false, want: "\".\"", }, &oneOrMoreExpr{ - pos: position{line: 103, col: 29, offset: 2815}, + pos: position{line: 111, col: 29, offset: 3511}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1233,20 +1249,20 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 103, col: 46, offset: 2832}, + pos: position{line: 111, col: 45, offset: 3527}, expr: &seqExpr{ - pos: position{line: 105, col: 12, offset: 2957}, + pos: position{line: 119, col: 23, offset: 3768}, exprs: []any{ &litMatcher{ - pos: position{line: 105, col: 12, offset: 2957}, + pos: position{line: 119, col: 23, offset: 3768}, val: "e", ignoreCase: true, want: "\"e\"i", }, &zeroOrOneExpr{ - pos: position{line: 105, col: 17, offset: 2962}, + pos: position{line: 119, col: 28, offset: 3773}, expr: &charClassMatcher{ - pos: position{line: 105, col: 17, offset: 2962}, + pos: position{line: 119, col: 28, offset: 3773}, val: "[+-]", chars: []rune{'+', '-'}, ignoreCase: false, @@ -1254,9 +1270,9 @@ var g = &grammar{ }, }, &oneOrMoreExpr{ - pos: position{line: 105, col: 23, offset: 2968}, + pos: position{line: 119, col: 34, offset: 3779}, expr: &charClassMatcher{ - pos: position{line: 106, col: 16, offset: 2999}, + pos: position{line: 120, col: 23, offset: 3817}, val: "[0-9]", ranges: []rune{'0', '9'}, ignoreCase: false, @@ -1269,59 +1285,39 @@ var g = &grammar{ }, }, }, - &actionExpr{ - pos: position{line: 116, col: 11, offset: 3266}, - run: (*parser).callonArgs143, - expr: &litMatcher{ - pos: position{line: 116, col: 11, offset: 3266}, - val: "true", - ignoreCase: false, - want: "\"true\"", - }, - }, - &actionExpr{ - pos: position{line: 116, col: 41, offset: 3296}, - run: (*parser).callonArgs145, - expr: &litMatcher{ - pos: position{line: 116, col: 41, offset: 3296}, - val: "false", - ignoreCase: false, - want: "\"false\"", - }, - }, }, }, }, &zeroOrMoreExpr{ - pos: position{line: 119, col: 6, offset: 3365}, + pos: position{line: 141, col: 14, offset: 4350}, expr: &choiceExpr{ - pos: position{line: 119, col: 8, offset: 3367}, + pos: position{line: 141, col: 16, offset: 4352}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 122, col: 14, offset: 3444}, + pos: position{line: 143, col: 14, offset: 4437}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -1329,7 +1325,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -1347,48 +1343,48 @@ var g = &grammar{ }, }, &choiceExpr{ - pos: position{line: 70, col: 17, offset: 1620}, + pos: position{line: 81, col: 17, offset: 2345}, alternatives: []any{ &ruleRefExpr{ - pos: position{line: 70, col: 17, offset: 1620}, + pos: position{line: 81, col: 17, offset: 2345}, name: "Group", }, &actionExpr{ - pos: position{line: 124, col: 7, offset: 3473}, - run: (*parser).callonArgs159, + pos: position{line: 145, col: 14, offset: 4480}, + run: (*parser).callonArgs155, expr: &seqExpr{ - pos: position{line: 124, col: 7, offset: 3473}, + pos: position{line: 145, col: 14, offset: 4480}, exprs: []any{ &zeroOrMoreExpr{ - pos: position{line: 119, col: 6, offset: 3365}, + pos: position{line: 141, col: 14, offset: 4350}, expr: &choiceExpr{ - pos: position{line: 119, col: 8, offset: 3367}, + pos: position{line: 141, col: 16, offset: 4352}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 122, col: 14, offset: 3444}, + pos: position{line: 143, col: 14, offset: 4437}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -1396,7 +1392,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -1407,7 +1403,7 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 124, col: 10, offset: 3476}, + pos: position{line: 145, col: 17, offset: 4483}, val: ";", ignoreCase: false, want: "\";\"", @@ -1416,41 +1412,41 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 124, col: 36, offset: 3502}, - run: (*parser).callonArgs172, + pos: position{line: 145, col: 43, offset: 4509}, + run: (*parser).callonArgs168, expr: &seqExpr{ - pos: position{line: 124, col: 36, offset: 3502}, + pos: position{line: 145, col: 43, offset: 4509}, exprs: []any{ &zeroOrMoreExpr{ - pos: position{line: 120, col: 5, offset: 3403}, + pos: position{line: 142, col: 14, offset: 4397}, expr: &choiceExpr{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 120, col: 7, offset: 3405}, + pos: position{line: 142, col: 16, offset: 4399}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -1458,7 +1454,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -1469,25 +1465,25 @@ var g = &grammar{ }, }, &zeroOrOneExpr{ - pos: position{line: 124, col: 38, offset: 3504}, + pos: position{line: 145, col: 45, offset: 4511}, expr: &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -1495,7 +1491,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -1504,7 +1500,7 @@ var g = &grammar{ }, }, &litMatcher{ - pos: position{line: 123, col: 7, offset: 3460}, + pos: position{line: 144, col: 14, offset: 4460}, val: "\n", ignoreCase: false, want: "\"\\n\"", @@ -1513,41 +1509,41 @@ var g = &grammar{ }, }, &actionExpr{ - pos: position{line: 124, col: 73, offset: 3539}, - run: (*parser).callonArgs193, + pos: position{line: 145, col: 80, offset: 4546}, + run: (*parser).callonArgs189, expr: &seqExpr{ - pos: position{line: 124, col: 73, offset: 3539}, + pos: position{line: 145, col: 80, offset: 4546}, exprs: []any{ &zeroOrMoreExpr{ - pos: position{line: 119, col: 6, offset: 3365}, + pos: position{line: 141, col: 14, offset: 4350}, expr: &choiceExpr{ - pos: position{line: 119, col: 8, offset: 3367}, + pos: position{line: 141, col: 16, offset: 4352}, alternatives: []any{ &charClassMatcher{ - pos: position{line: 122, col: 14, offset: 3444}, + pos: position{line: 143, col: 14, offset: 4437}, val: "[ \\t\\r\\n]", chars: []rune{' ', '\t', '\r', '\n'}, ignoreCase: false, inverted: false, }, &seqExpr{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, exprs: []any{ &litMatcher{ - pos: position{line: 118, col: 11, offset: 3339}, + pos: position{line: 140, col: 14, offset: 4316}, val: "#", ignoreCase: false, want: "\"#\"", }, &zeroOrMoreExpr{ - pos: position{line: 118, col: 15, offset: 3343}, + pos: position{line: 140, col: 18, offset: 4320}, expr: &seqExpr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, exprs: []any{ ¬Expr{ - pos: position{line: 118, col: 17, offset: 3345}, + pos: position{line: 140, col: 20, offset: 4322}, expr: &charClassMatcher{ - pos: position{line: 118, col: 18, offset: 3346}, + pos: position{line: 140, col: 21, offset: 4323}, val: "[\\r\\n]", chars: []rune{'\r', '\n'}, ignoreCase: false, @@ -1555,7 +1551,7 @@ var g = &grammar{ }, }, &anyMatcher{ - line: 118, col: 25, offset: 3353, + line: 140, col: 28, offset: 4330, }, }, }, @@ -1566,9 +1562,9 @@ var g = &grammar{ }, }, ¬Expr{ - pos: position{line: 126, col: 7, offset: 3575}, + pos: position{line: 146, col: 14, offset: 4588}, expr: &anyMatcher{ - line: 126, col: 8, offset: 3576, + line: 146, col: 15, offset: 4589, }, }, }, @@ -1582,14 +1578,14 @@ var g = &grammar{ }, } -func (c *current) onConfig1(stmts any) (any, error) { - if stmts == nil { +func (c *current) onConfig1(directives any) (any, error) { + if directives == nil { return model.Group{}, nil } - groupAny := toAnySlice(stmts) + groupAny := toAnySlice(directives) groupSl := make(model.Group, len(groupAny)) for i, e := range groupAny { - groupSl[i] = e.(model.Command) + groupSl[i] = e.(model.Directive) } return groupSl, nil } @@ -1597,17 +1593,17 @@ func (c *current) onConfig1(stmts any) (any, error) { func (p *parser) callonConfig1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onConfig1(stack["stmts"]) + return p.cur.onConfig1(stack["directives"]) } -func (c *current) onGroup1(stmts any) (any, error) { - if stmts == nil { +func (c *current) onGroup1(directives any) (any, error) { + if directives == nil { return model.Group{}, nil } - groupAny := toAnySlice(stmts) + groupAny := toAnySlice(directives) groupSl := make(model.Group, len(groupAny)) for i, e := range groupAny { - groupSl[i] = e.(model.Command) + groupSl[i] = e.(model.Directive) } return groupSl, nil } @@ -1615,31 +1611,40 @@ func (c *current) onGroup1(stmts any) (any, error) { func (p *parser) callonGroup1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onGroup1(stack["stmts"]) + return p.cur.onGroup1(stack["directives"]) } -func (c *current) onCommand10() (any, error) { +func (c *current) onDirective10() (any, error) { + if i, err := strconv.Atoi(string(c.text)); err == nil { + return i, nil + } return strconv.ParseFloat(string(c.text), 64) } -func (p *parser) callonCommand10() (any, error) { +func (p *parser) callonDirective10() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onCommand10() + return p.cur.onDirective10() } -func (c *current) onCommand4() (any, error) { - return model.Ident(c.text), nil +func (c *current) onDirective4() (any, error) { + switch string(c.text) { + case "true": + return true, nil + case "false": + return false, nil + default: + return model.Ident(c.text), nil + } } -func (p *parser) callonCommand4() (any, error) { +func (p *parser) callonDirective4() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onCommand4() + return p.cur.onDirective4() } -func (c *current) onCommand1(name, args any) (any, error) { - var group model.Group +func (c *current) onDirective1(name, args any) (any, error) { rawArgs := args.([]any) argsSlice := make([]any, 0, len(rawArgs)) if len(rawArgs) > 0 { @@ -1648,7 +1653,7 @@ func (c *current) onCommand1(name, args any) (any, error) { continue } if g, ok := s.(model.Group); ok { - group = g + argsSlice = append(argsSlice, g) continue } if l, ok := s.([]any); ok { @@ -1657,16 +1662,19 @@ func (c *current) onCommand1(name, args any) (any, error) { } } } - return model.Command{Name: name.(model.Ident), Args: argsSlice, Group: group}, nil + return model.Directive{Name: name.(model.Ident), RawValues: argsSlice}, nil } -func (p *parser) callonCommand1() (any, error) { +func (p *parser) callonDirective1() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onCommand1(stack["name"], stack["args"]) + return p.cur.onDirective1(stack["name"], stack["args"]) } func (c *current) onArgs16() (any, error) { + if i, err := strconv.Atoi(string(c.text)); err == nil { + return i, nil + } return strconv.ParseFloat(string(c.text), 64) } @@ -1677,7 +1685,14 @@ func (p *parser) callonArgs16() (any, error) { } func (c *current) onArgs10() (any, error) { - return model.Ident(c.text), nil + switch string(c.text) { + case "true": + return true, nil + case "false": + return false, nil + default: + return model.Ident(c.text), nil + } } func (p *parser) callonArgs10() (any, error) { @@ -1687,7 +1702,7 @@ func (p *parser) callonArgs10() (any, error) { } func (c *current) onArgs38() (any, error) { - return string(c.text), nil + return strconv.Unquote(string(c.text)) } func (p *parser) callonArgs38() (any, error) { @@ -1697,6 +1712,9 @@ func (p *parser) callonArgs38() (any, error) { } func (c *current) onArgs121() (any, error) { + if i, err := strconv.Atoi(string(c.text)); err == nil { + return i, nil + } return strconv.ParseFloat(string(c.text), 64) } @@ -1706,26 +1724,6 @@ func (p *parser) callonArgs121() (any, error) { return p.cur.onArgs121() } -func (c *current) onArgs143() (any, error) { - return true, nil -} - -func (p *parser) callonArgs143() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onArgs143() -} - -func (c *current) onArgs145() (any, error) { - return false, nil -} - -func (p *parser) callonArgs145() (any, error) { - stack := p.vstack[len(p.vstack)-1] - _ = stack - return p.cur.onArgs145() -} - func (c *current) onArgs6(val any) (any, error) { return val, nil } @@ -1746,34 +1744,34 @@ func (p *parser) callonArgs3() (any, error) { return p.cur.onArgs3(stack["vals"]) } -func (c *current) onArgs159() (any, error) { +func (c *current) onArgs155() (any, error) { return nil, nil } -func (p *parser) callonArgs159() (any, error) { +func (p *parser) callonArgs155() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onArgs159() + return p.cur.onArgs155() } -func (c *current) onArgs172() (any, error) { +func (c *current) onArgs168() (any, error) { return nil, nil } -func (p *parser) callonArgs172() (any, error) { +func (p *parser) callonArgs168() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onArgs172() + return p.cur.onArgs168() } -func (c *current) onArgs193() (any, error) { +func (c *current) onArgs189() (any, error) { return nil, nil } -func (p *parser) callonArgs193() (any, error) { +func (p *parser) callonArgs189() (any, error) { stack := p.vstack[len(p.vstack)-1] _ = stack - return p.cur.onArgs193() + return p.cur.onArgs189() } var ( |
