129 lines
2.9 KiB
Go
129 lines
2.9 KiB
Go
// Copyright (c) 2020 Denis Tingajkin
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at:
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package goheader
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
type Calculable interface {
|
|
Calculate(map[string]Value) error
|
|
Get() string
|
|
}
|
|
|
|
type Value interface {
|
|
Calculable
|
|
Read(*Reader) Issue
|
|
}
|
|
|
|
func calculateValue(calculable Calculable, values map[string]Value) (string, error) {
|
|
sb := strings.Builder{}
|
|
r := calculable.Get()
|
|
var endIndex int
|
|
var startIndex int
|
|
for startIndex = strings.Index(r, "{{"); startIndex >= 0; startIndex = strings.Index(r, "{{") {
|
|
_, _ = sb.WriteString(r[:startIndex])
|
|
endIndex = strings.Index(r, "}}")
|
|
if endIndex < 0 {
|
|
return "", errors.New("missed value ending")
|
|
}
|
|
subVal := strings.ToLower(strings.TrimSpace(r[startIndex+2 : endIndex]))
|
|
if val := values[subVal]; val != nil {
|
|
if err := val.Calculate(values); err != nil {
|
|
return "", err
|
|
}
|
|
sb.WriteString(val.Get())
|
|
} else {
|
|
return "", fmt.Errorf("unknown value name %v", subVal)
|
|
}
|
|
endIndex += 2
|
|
r = r[endIndex:]
|
|
}
|
|
_, _ = sb.WriteString(r)
|
|
return sb.String(), nil
|
|
}
|
|
|
|
type ConstValue struct {
|
|
RawValue string
|
|
}
|
|
|
|
func (c *ConstValue) Calculate(values map[string]Value) error {
|
|
v, err := calculateValue(c, values)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.RawValue = v
|
|
return nil
|
|
}
|
|
|
|
func (c *ConstValue) Get() string {
|
|
return c.RawValue
|
|
}
|
|
|
|
func (c *ConstValue) Read(s *Reader) Issue {
|
|
l := s.Location()
|
|
p := s.Position()
|
|
for _, ch := range c.Get() {
|
|
if ch != s.Peek() {
|
|
s.SetPosition(p)
|
|
f := s.ReadWhile(func(r rune) bool {
|
|
return r != '\n'
|
|
})
|
|
return NewIssueWithLocation(fmt.Sprintf("Expected:%v, Actual: %v", c.Get(), f), l)
|
|
}
|
|
s.Next()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type RegexpValue struct {
|
|
RawValue string
|
|
}
|
|
|
|
func (r *RegexpValue) Calculate(values map[string]Value) error {
|
|
v, err := calculateValue(r, values)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r.RawValue = v
|
|
return nil
|
|
}
|
|
|
|
func (r *RegexpValue) Get() string {
|
|
return r.RawValue
|
|
}
|
|
|
|
func (r *RegexpValue) Read(s *Reader) Issue {
|
|
l := s.Location()
|
|
p := regexp.MustCompile(r.Get())
|
|
pos := s.Position()
|
|
str := s.Finish()
|
|
s.SetPosition(pos)
|
|
indexes := p.FindAllIndex([]byte(str), -1)
|
|
if len(indexes) == 0 {
|
|
return NewIssueWithLocation(fmt.Sprintf("Pattern %v doesn't match.", p.String()), l)
|
|
}
|
|
s.SetPosition(pos + indexes[0][1])
|
|
return nil
|
|
}
|
|
|
|
var _ Value = &ConstValue{}
|
|
var _ Value = &RegexpValue{}
|