From 00394a80501960ad26787b5c44435ed5ed67ad84 Mon Sep 17 00:00:00 2001 From: Alexander Neonxp Kiryukhin Date: Mon, 9 Mar 2026 23:05:42 +0300 Subject: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BD=D0=BE=D1=81=D1=82=D1=8C=D1=8E?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=B1=D0=B8=D0=B1=D0=BB=D0=B8=D0=BE=D1=82=D0=B5=D0=BA=D1=83.?= =?UTF-8?q?=20=D0=9F=D0=B5=D1=80=D0=B5=D0=B2=D1=91=D0=BB=20=D1=81=20EBNF?= =?UTF-8?q?=20=D0=BD=D0=B0=20PEG.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/body.go | 28 ------------------ model/directive.go | 9 ------ model/lookup.go | 56 ----------------------------------- model/model.go | 44 ++++++++++++++++++++++++++++ model/setting.go | 6 ---- model/value.go | 85 ------------------------------------------------------ model/visitor.go | 6 ---- 7 files changed, 44 insertions(+), 190 deletions(-) delete mode 100644 model/body.go delete mode 100644 model/directive.go delete mode 100644 model/lookup.go create mode 100644 model/model.go delete mode 100644 model/setting.go delete mode 100644 model/value.go delete mode 100644 model/visitor.go (limited to 'model') diff --git a/model/body.go b/model/body.go deleted file mode 100644 index b7b4a0c..0000000 --- a/model/body.go +++ /dev/null @@ -1,28 +0,0 @@ -package model - -import ( - "errors" - "fmt" -) - -type Body []any - -var ErrInvalidType = errors.New("invalid type") - -func (d Body) Execute(v Visitor) error { - for _, it := range d { - switch it := it.(type) { - case *Setting: - if err := v.VisitSetting(it.Key, it.Value); err != nil { - return err - } - case *Directive: - if err := v.VisitDirective(it.Name, it.Arguments, it.Body); err != nil { - return err - } - default: - return fmt.Errorf("%w: %t", ErrInvalidType, it) - } - } - return nil -} diff --git a/model/directive.go b/model/directive.go deleted file mode 100644 index 3852e72..0000000 --- a/model/directive.go +++ /dev/null @@ -1,9 +0,0 @@ -package model - -type Directive struct { - Name string - Arguments Values - Body Body -} - -type Directives []*Directive diff --git a/model/lookup.go b/model/lookup.go deleted file mode 100644 index 880a1f8..0000000 --- a/model/lookup.go +++ /dev/null @@ -1,56 +0,0 @@ -package model - -import ( - "os" - "strings" -) - -// WordLookup тип определяющий функцию поиска замены слов при -// стрингификации Values. -type WordLookup func(word Word) string - -// chainLookup утилитарная функция для последовательных применений функций -// поиска до первого нахождения подстановки. Если returnOrigin == true, -// то в случае неудачи вернёт имя слова. -func chainLookup(lookups ...WordLookup) WordLookup { - return func(word Word) string { - for _, lookup := range lookups { - if v := lookup(word); v != "" { - return v - } - } - return "" - } -} - -// LookupEnv функция типа WordLookup которая пытается подставить вместо word -// соответствующую ему переменную окружения ОС. При этом он срабатывает только -// если слово начинается со знака `$`. -func LookupEnv(word Word) string { - if !strings.HasPrefix(string(word), "$") { - return "" - } - varName := strings.TrimPrefix(string(word), "$") - if result, ok := os.LookupEnv(varName); ok { - return result - } - return "" -} - -// LookupSubst функция типа WordLookup которая пытается подставить вместо word -// значение из словаря подстановок по соответствующему ключу. -func LookupSubst(subst map[Word]string) WordLookup { - return func(word Word) string { - if result, ok := subst[word]; ok { - return result - } - return "" - } -} - -// Origin возвращает просто строковое представления слова. Если поставить в -// конце цепочки - то вместо пустоты (если предыдущие фильтры не сработали) -// вернётся оригинальное имя слова. -func Origin(word Word) string { - return string(word) -} diff --git a/model/model.go b/model/model.go new file mode 100644 index 0000000..2bc6dfb --- /dev/null +++ b/model/model.go @@ -0,0 +1,44 @@ +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/model/setting.go b/model/setting.go deleted file mode 100644 index 363a8a9..0000000 --- a/model/setting.go +++ /dev/null @@ -1,6 +0,0 @@ -package model - -type Setting struct { - Key string - Value Values -} diff --git a/model/value.go b/model/value.go deleted file mode 100644 index 9fa8e9b..0000000 --- a/model/value.go +++ /dev/null @@ -1,85 +0,0 @@ -package model - -import ( - "fmt" - "strconv" - "strings" -) - -type Value any - -type Values []Value - -// BuildString собирает из значений Value цельную строку, при этом приводя все -// значения к типу string. Так же принимает функции типа WordLookup, которые -// последовательно будут пытаться привести значения типа Word к -// контекстозависимым значениям. Например, пытаться находить по имени переменную -// окружения ОС. -func (v Values) BuildString(lookups ...WordLookup) string { - sw := strings.Builder{} - - for _, v := range v { - switch v := v.(type) { - case string: - sw.WriteString(v) - case float64: - sw.WriteString(strconv.FormatFloat(v, 'f', 5, 64)) - case int: - sw.WriteString(strconv.Itoa(v)) - case bool: - if v { - sw.WriteString("true") - continue - } - sw.WriteString("false") - case Word: - sw.WriteString(chainLookup(lookups...)(v)) - } - } - - return sw.String() -} - -func (v Values) String() string { - result := make([]string, 0, len(v)) - - for _, v := range v { - switch v := v.(type) { - case string: - result = append(result, v) - case float64: - result = append(result, strconv.FormatFloat(v, 'f', 5, 64)) - case int: - result = append(result, strconv.Itoa(v)) - case bool: - if v { - result = append(result, "true") - continue - } - result = append(result, "false") - case Word: - result = append(result, string(v)) - } - } - - return strings.Join(result, " ") -} - -func (v Values) Int() (int, error) { - if len(v) != 1 { - return 0, fmt.Errorf("AsInt can return only single value (there is %d values)", len(v)) - } - val := v[0] - switch val := val.(type) { - case int: - return val, nil - case string: - return strconv.Atoi(val) - case float64: - return int(val), nil - default: - return 0, fmt.Errorf("invalid type for convert to int: %t", val) - } -} - -type Word string diff --git a/model/visitor.go b/model/visitor.go deleted file mode 100644 index 3f290d3..0000000 --- a/model/visitor.go +++ /dev/null @@ -1,6 +0,0 @@ -package model - -type Visitor interface { - VisitDirective(ident string, args Values, body Body) error - VisitSetting(key string, values Values) error -} -- cgit v1.2.3