Upgrade dependent version: github.com/open-policy-agent/opa (#5315)
Upgrade dependent version: github.com/open-policy-agent/opa v0.18.0 -> v0.45.0 Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io> Signed-off-by: hongzhouzi <hongzhouzi@kubesphere.io>
This commit is contained in:
425
vendor/github.com/open-policy-agent/opa/ast/parser_ext.go
generated
vendored
425
vendor/github.com/open-policy-agent/opa/ast/parser_ext.go
generated
vendored
@@ -3,26 +3,31 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file contains extra functions for parsing Rego.
|
||||
// Most of the parsing is handled by the auto-generated code in
|
||||
// parser.go, however, there are additional utilities that are
|
||||
// Most of the parsing is handled by the code in parser.go,
|
||||
// however, there are additional utilities that are
|
||||
// helpful for dealing with Rego source inputs (e.g., REPL
|
||||
// statements, source files, etc.)
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// MustParseBody returns a parsed body.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseBody(input string) Body {
|
||||
parsed, err := ParseBody(input)
|
||||
return MustParseBodyWithOpts(input, ParserOptions{})
|
||||
}
|
||||
|
||||
// MustParseBodyWithOpts returns a parsed body.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseBodyWithOpts(input string, opts ParserOptions) Body {
|
||||
parsed, err := ParseBodyWithOpts(input, opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -52,7 +57,13 @@ func MustParseImports(input string) []*Import {
|
||||
// MustParseModule returns a parsed module.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseModule(input string) *Module {
|
||||
parsed, err := ParseModule("", input)
|
||||
return MustParseModuleWithOpts(input, ParserOptions{})
|
||||
}
|
||||
|
||||
// MustParseModuleWithOpts returns a parsed module.
|
||||
// If an error occurs during parsing, panic.
|
||||
func MustParseModuleWithOpts(input string, opts ParserOptions) *Module {
|
||||
parsed, err := ParseModuleWithOpts("", input, opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -161,37 +172,15 @@ func ParseRuleFromExpr(module *Module, expr *Expr) (*Rule, error) {
|
||||
return nil, errors.New("expression cannot be used for rule head")
|
||||
}
|
||||
|
||||
if expr.IsAssignment() {
|
||||
|
||||
lhs, rhs := expr.Operand(0), expr.Operand(1)
|
||||
rule, err := ParseCompleteDocRuleFromAssignmentExpr(module, lhs, rhs)
|
||||
|
||||
if err == nil {
|
||||
return rule, nil
|
||||
} else if _, ok := lhs.Value.(Call); ok {
|
||||
return nil, errFunctionAssignOperator
|
||||
} else if _, ok := lhs.Value.(Ref); ok {
|
||||
return nil, errPartialRuleAssignOperator
|
||||
}
|
||||
|
||||
return nil, errTermAssignOperator(lhs.Value)
|
||||
}
|
||||
|
||||
if expr.IsEquality() {
|
||||
|
||||
lhs, rhs := expr.Operand(0), expr.Operand(1)
|
||||
rule, err := ParseCompleteDocRuleFromEqExpr(module, lhs, rhs)
|
||||
|
||||
if err == nil {
|
||||
return rule, nil
|
||||
return parseCompleteRuleFromEq(module, expr)
|
||||
} else if expr.IsAssignment() {
|
||||
rule, err := parseCompleteRuleFromEq(module, expr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rule, err = ParseRuleFromCallEqExpr(module, lhs, rhs)
|
||||
if err == nil {
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
return ParsePartialObjectDocRuleFromEqExpr(module, lhs, rhs)
|
||||
rule.Head.Assign = true
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
if _, ok := BuiltinMap[expr.Operator().String()]; ok {
|
||||
@@ -201,6 +190,37 @@ func ParseRuleFromExpr(module *Module, expr *Expr) (*Rule, error) {
|
||||
return ParseRuleFromCallExpr(module, expr.Terms.([]*Term))
|
||||
}
|
||||
|
||||
func parseCompleteRuleFromEq(module *Module, expr *Expr) (rule *Rule, err error) {
|
||||
|
||||
// ensure the rule location is set to the expr location
|
||||
// the helper functions called below try to set the location based
|
||||
// on the terms they've been provided but that is not as accurate.
|
||||
defer func() {
|
||||
if rule != nil {
|
||||
rule.Location = expr.Location
|
||||
rule.Head.Location = expr.Location
|
||||
}
|
||||
}()
|
||||
|
||||
lhs, rhs := expr.Operand(0), expr.Operand(1)
|
||||
if lhs == nil || rhs == nil {
|
||||
return nil, errors.New("assignment requires two operands")
|
||||
}
|
||||
|
||||
rule, err = ParseCompleteDocRuleFromEqExpr(module, lhs, rhs)
|
||||
|
||||
if err == nil {
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
rule, err = ParseRuleFromCallEqExpr(module, lhs, rhs)
|
||||
if err == nil {
|
||||
return rule, nil
|
||||
}
|
||||
|
||||
return ParsePartialObjectDocRuleFromEqExpr(module, lhs, rhs)
|
||||
}
|
||||
|
||||
// ParseCompleteDocRuleFromAssignmentExpr returns a rule if the expression can
|
||||
// be interpreted as a complete document definition declared with the assignment
|
||||
// operator.
|
||||
@@ -231,9 +251,9 @@ func ParseCompleteDocRuleFromEqExpr(module *Module, lhs, rhs *Term) (*Rule, erro
|
||||
}
|
||||
|
||||
rule := &Rule{
|
||||
Location: rhs.Location,
|
||||
Location: lhs.Location,
|
||||
Head: &Head{
|
||||
Location: rhs.Location,
|
||||
Location: lhs.Location,
|
||||
Name: name,
|
||||
Value: rhs,
|
||||
},
|
||||
@@ -252,7 +272,11 @@ func ParsePartialObjectDocRuleFromEqExpr(module *Module, lhs, rhs *Term) (*Rule,
|
||||
|
||||
ref, ok := lhs.Value.(Ref)
|
||||
if !ok || len(ref) != 2 {
|
||||
return nil, fmt.Errorf("%v cannot be used for rule name", TypeName(lhs.Value))
|
||||
return nil, fmt.Errorf("%v cannot be used as rule name", TypeName(lhs.Value))
|
||||
}
|
||||
|
||||
if _, ok := ref[0].Value.(Var); !ok {
|
||||
return nil, fmt.Errorf("%vs cannot be used as rule name", TypeName(ref[0].Value))
|
||||
}
|
||||
|
||||
name := ref[0].Value.(Var)
|
||||
@@ -288,11 +312,16 @@ func ParsePartialSetDocRuleFromTerm(module *Module, term *Term) (*Rule, error) {
|
||||
return nil, fmt.Errorf("refs cannot be used for rule")
|
||||
}
|
||||
|
||||
name, ok := ref[0].Value.(Var)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%vs cannot be used as rule name", TypeName(ref[0].Value))
|
||||
}
|
||||
|
||||
rule := &Rule{
|
||||
Location: term.Location,
|
||||
Head: &Head{
|
||||
Location: term.Location,
|
||||
Name: ref[0].Value.(Var),
|
||||
Name: name,
|
||||
Key: ref[1],
|
||||
},
|
||||
Body: NewBody(
|
||||
@@ -313,11 +342,21 @@ func ParseRuleFromCallEqExpr(module *Module, lhs, rhs *Term) (*Rule, error) {
|
||||
return nil, fmt.Errorf("must be call")
|
||||
}
|
||||
|
||||
ref, ok := call[0].Value.(Ref)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%vs cannot be used in function signature", TypeName(call[0].Value))
|
||||
}
|
||||
|
||||
name, ok := ref[0].Value.(Var)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%vs cannot be used in function signature", TypeName(ref[0].Value))
|
||||
}
|
||||
|
||||
rule := &Rule{
|
||||
Location: lhs.Location,
|
||||
Head: &Head{
|
||||
Location: lhs.Location,
|
||||
Name: call[0].Value.(Ref)[0].Value.(Var),
|
||||
Name: name,
|
||||
Args: Args(call[1:]),
|
||||
Value: rhs,
|
||||
},
|
||||
@@ -375,7 +414,14 @@ func ParseImports(input string) ([]*Import, error) {
|
||||
// For details on Module objects and their fields, see policy.go.
|
||||
// Empty input will return nil, nil.
|
||||
func ParseModule(filename, input string) (*Module, error) {
|
||||
stmts, comments, err := ParseStatements(filename, input)
|
||||
return ParseModuleWithOpts(filename, input, ParserOptions{})
|
||||
}
|
||||
|
||||
// ParseModuleWithOpts returns a parsed Module object, and has an additional input ParserOptions
|
||||
// For details on Module objects and their fields, see policy.go.
|
||||
// Empty input will return nil, nil.
|
||||
func ParseModuleWithOpts(filename, input string, popts ParserOptions) (*Module, error) {
|
||||
stmts, comments, err := ParseStatementsWithOpts(filename, input, popts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -385,7 +431,14 @@ func ParseModule(filename, input string) (*Module, error) {
|
||||
// ParseBody returns exactly one body.
|
||||
// If multiple bodies are parsed, an error is returned.
|
||||
func ParseBody(input string) (Body, error) {
|
||||
stmts, _, err := ParseStatements("", input)
|
||||
return ParseBodyWithOpts(input, ParserOptions{SkipRules: true})
|
||||
}
|
||||
|
||||
// ParseBodyWithOpts returns exactly one body. It does _not_ set SkipRules: true on its own,
|
||||
// but respects whatever ParserOptions it's been given.
|
||||
func ParseBodyWithOpts(input string, popts ParserOptions) (Body, error) {
|
||||
|
||||
stmts, _, err := ParseStatementsWithOpts("", input, popts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -395,7 +448,9 @@ func ParseBody(input string) (Body, error) {
|
||||
for _, stmt := range stmts {
|
||||
switch stmt := stmt.(type) {
|
||||
case Body:
|
||||
result = append(result, stmt...)
|
||||
for i := range stmt {
|
||||
result.Append(stmt[i])
|
||||
}
|
||||
case *Comment:
|
||||
// skip
|
||||
default:
|
||||
@@ -403,8 +458,6 @@ func ParseBody(input string) (Body, error) {
|
||||
}
|
||||
}
|
||||
|
||||
setExprIndices(result)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -413,7 +466,7 @@ func ParseBody(input string) (Body, error) {
|
||||
func ParseExpr(input string) (*Expr, error) {
|
||||
body, err := ParseBody(input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse expression")
|
||||
return nil, fmt.Errorf("failed to parse expression: %w", err)
|
||||
}
|
||||
if len(body) != 1 {
|
||||
return nil, fmt.Errorf("expected exactly one expression but got: %v", body)
|
||||
@@ -440,7 +493,7 @@ func ParsePackage(input string) (*Package, error) {
|
||||
func ParseTerm(input string) (*Term, error) {
|
||||
body, err := ParseBody(input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse term")
|
||||
return nil, fmt.Errorf("failed to parse term: %w", err)
|
||||
}
|
||||
if len(body) != 1 {
|
||||
return nil, fmt.Errorf("expected exactly one term but got: %v", body)
|
||||
@@ -456,7 +509,7 @@ func ParseTerm(input string) (*Term, error) {
|
||||
func ParseRef(input string) (Ref, error) {
|
||||
term, err := ParseTerm(input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse ref")
|
||||
return nil, fmt.Errorf("failed to parse ref: %w", err)
|
||||
}
|
||||
ref, ok := term.Value.(Ref)
|
||||
if !ok {
|
||||
@@ -497,106 +550,32 @@ func ParseStatement(input string) (Statement, error) {
|
||||
return stmts[0], nil
|
||||
}
|
||||
|
||||
// CommentsOption returns a parser option to initialize the comments store within
|
||||
// the parser.
|
||||
func CommentsOption() Option {
|
||||
return GlobalStore(commentsKey, map[commentKey]*Comment{})
|
||||
}
|
||||
|
||||
type commentKey struct {
|
||||
File string
|
||||
Row int
|
||||
Col int
|
||||
}
|
||||
|
||||
func (a commentKey) Compare(other commentKey) int {
|
||||
if a.File < other.File {
|
||||
return -1
|
||||
} else if a.File > other.File {
|
||||
return 1
|
||||
} else if a.Row < other.Row {
|
||||
return -1
|
||||
} else if a.Row > other.Row {
|
||||
return 1
|
||||
} else if a.Col < other.Col {
|
||||
return -1
|
||||
} else if a.Col > other.Col {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// ParseStatements returns a slice of parsed statements.
|
||||
// This is the default return value from the parser.
|
||||
// ParseStatements is deprecated. Use ParseStatementWithOpts instead.
|
||||
func ParseStatements(filename, input string) ([]Statement, []*Comment, error) {
|
||||
|
||||
bs := []byte(input)
|
||||
|
||||
parsed, err := Parse(filename, bs, GlobalStore(filenameKey, filename), CommentsOption())
|
||||
if err != nil {
|
||||
return nil, nil, formatParserErrors(filename, bs, err)
|
||||
}
|
||||
|
||||
var comments []*Comment
|
||||
var sl []interface{}
|
||||
if p, ok := parsed.(program); ok {
|
||||
sl = p.buf
|
||||
commentMap := p.comments.(map[commentKey]*Comment)
|
||||
commentKeys := []commentKey{}
|
||||
for k := range commentMap {
|
||||
commentKeys = append(commentKeys, k)
|
||||
}
|
||||
sort.Slice(commentKeys, func(i, j int) bool {
|
||||
return commentKeys[i].Compare(commentKeys[j]) < 0
|
||||
})
|
||||
for _, k := range commentKeys {
|
||||
comments = append(comments, commentMap[k])
|
||||
}
|
||||
} else {
|
||||
sl = parsed.([]interface{})
|
||||
}
|
||||
stmts := make([]Statement, 0, len(sl))
|
||||
|
||||
for _, x := range sl {
|
||||
if rules, ok := x.([]*Rule); ok {
|
||||
for _, rule := range rules {
|
||||
stmts = append(stmts, rule)
|
||||
}
|
||||
} else {
|
||||
// Unchecked cast should be safe. A panic indicates grammar is
|
||||
// out-of-sync.
|
||||
stmts = append(stmts, x.(Statement))
|
||||
}
|
||||
}
|
||||
|
||||
return stmts, comments, postProcess(filename, stmts)
|
||||
return ParseStatementsWithOpts(filename, input, ParserOptions{})
|
||||
}
|
||||
|
||||
func formatParserErrors(filename string, bs []byte, err error) error {
|
||||
// Errors returned by the parser are always of type errList and the errList
|
||||
// always contains *parserError.
|
||||
// https://godoc.org/github.com/mna/pigeon#hdr-Error_reporting.
|
||||
errs := err.(errList)
|
||||
r := make(Errors, len(errs))
|
||||
for i, e := range errs {
|
||||
r[i] = formatParserError(filename, bs, e.(*parserError))
|
||||
}
|
||||
return r
|
||||
}
|
||||
// ParseStatementsWithOpts returns a slice of parsed statements. This is the
|
||||
// default return value from the parser.
|
||||
func ParseStatementsWithOpts(filename, input string, popts ParserOptions) ([]Statement, []*Comment, error) {
|
||||
|
||||
func formatParserError(filename string, bs []byte, e *parserError) *Error {
|
||||
loc := NewLocation(nil, filename, e.pos.line, e.pos.col)
|
||||
inner := e.Inner.Error()
|
||||
idx := strings.Index(inner, "no match found")
|
||||
if idx >= 0 {
|
||||
// Match errors end with "no match found, expected: ...". We do not want to
|
||||
// include ", expected: ..." as it does not provide any value, so truncate the
|
||||
// string here.
|
||||
inner = inner[:idx+14]
|
||||
parser := NewParser().
|
||||
WithFilename(filename).
|
||||
WithReader(bytes.NewBufferString(input)).
|
||||
WithProcessAnnotation(popts.ProcessAnnotation).
|
||||
WithFutureKeywords(popts.FutureKeywords...).
|
||||
WithAllFutureKeywords(popts.AllFutureKeywords).
|
||||
WithCapabilities(popts.Capabilities).
|
||||
WithSkipRules(popts.SkipRules).
|
||||
withUnreleasedKeywords(popts.unreleasedKeywords)
|
||||
|
||||
stmts, comments, errs := parser.Parse()
|
||||
|
||||
if len(errs) > 0 {
|
||||
return nil, nil, errs
|
||||
}
|
||||
err := NewError(ParseErr, loc, inner)
|
||||
err.Details = newParserErrorDetail(bs, e.pos)
|
||||
return err
|
||||
|
||||
return stmts, comments, nil
|
||||
}
|
||||
|
||||
func parseModule(filename string, stmts []Statement, comments []*Comment) (*Module, error) {
|
||||
@@ -607,20 +586,21 @@ func parseModule(filename string, stmts []Statement, comments []*Comment) (*Modu
|
||||
|
||||
var errs Errors
|
||||
|
||||
_package, ok := stmts[0].(*Package)
|
||||
pkg, ok := stmts[0].(*Package)
|
||||
if !ok {
|
||||
loc := stmts[0].(Statement).Loc()
|
||||
loc := stmts[0].Loc()
|
||||
errs = append(errs, NewError(ParseErr, loc, "package expected"))
|
||||
}
|
||||
|
||||
mod := &Module{
|
||||
Package: _package,
|
||||
Package: pkg,
|
||||
stmts: stmts,
|
||||
}
|
||||
|
||||
// The comments slice only holds comments that were not their own statements.
|
||||
mod.Comments = append(mod.Comments, comments...)
|
||||
|
||||
for _, stmt := range stmts[1:] {
|
||||
for i, stmt := range stmts[1:] {
|
||||
switch stmt := stmt.(type) {
|
||||
case *Import:
|
||||
mod.Imports = append(mod.Imports, stmt)
|
||||
@@ -633,98 +613,42 @@ func parseModule(filename string, stmts []Statement, comments []*Comment) (*Modu
|
||||
errs = append(errs, NewError(ParseErr, stmt[0].Location, err.Error()))
|
||||
} else {
|
||||
mod.Rules = append(mod.Rules, rule)
|
||||
|
||||
// NOTE(tsandall): the statement should now be interpreted as a
|
||||
// rule so update the statement list. This is important for the
|
||||
// logic below that associates annotations with statements.
|
||||
stmts[i+1] = rule
|
||||
}
|
||||
case *Package:
|
||||
errs = append(errs, NewError(ParseErr, stmt.Loc(), "unexpected package"))
|
||||
case *Comment: // Ignore comments, they're handled above.
|
||||
case *Annotations:
|
||||
mod.Annotations = append(mod.Annotations, stmt)
|
||||
case *Comment:
|
||||
// Ignore comments, they're handled above.
|
||||
default:
|
||||
panic("illegal value") // Indicates grammar is out-of-sync with code.
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) == 0 {
|
||||
return mod, nil
|
||||
if len(errs) > 0 {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
return nil, errs
|
||||
}
|
||||
errs = append(errs, attachAnnotationsNodes(mod)...)
|
||||
|
||||
func postProcess(filename string, stmts []Statement) error {
|
||||
|
||||
if err := mangleDataVars(stmts); err != nil {
|
||||
return err
|
||||
if len(errs) > 0 {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
if err := mangleInputVars(stmts); err != nil {
|
||||
return err
|
||||
return mod, nil
|
||||
}
|
||||
|
||||
func newScopeAttachmentErr(a *Annotations, want string) *Error {
|
||||
var have string
|
||||
if a.node != nil {
|
||||
have = fmt.Sprintf(" (have %v)", TypeName(a.node))
|
||||
}
|
||||
|
||||
mangleWildcards(stmts)
|
||||
mangleExprIndices(stmts)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mangleDataVars(stmts []Statement) error {
|
||||
for i := range stmts {
|
||||
vt := newVarToRefTransformer(DefaultRootDocument.Value.(Var), DefaultRootRef.Copy())
|
||||
stmt, err := Transform(vt, stmts[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stmts[i] = stmt.(Statement)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mangleInputVars(stmts []Statement) error {
|
||||
for i := range stmts {
|
||||
vt := newVarToRefTransformer(InputRootDocument.Value.(Var), InputRootRef.Copy())
|
||||
stmt, err := Transform(vt, stmts[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stmts[i] = stmt.(Statement)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mangleExprIndices(stmts []Statement) {
|
||||
for _, stmt := range stmts {
|
||||
setExprIndices(stmt)
|
||||
}
|
||||
}
|
||||
|
||||
func setExprIndices(x interface{}) {
|
||||
WalkBodies(x, func(b Body) bool {
|
||||
for i, expr := range b {
|
||||
expr.Index = i
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
func mangleWildcards(stmts []Statement) {
|
||||
m := &wildcardMangler{}
|
||||
for i := range stmts {
|
||||
stmt, _ := Transform(m, stmts[i])
|
||||
stmts[i] = stmt.(Statement)
|
||||
}
|
||||
}
|
||||
|
||||
type wildcardMangler struct {
|
||||
c int
|
||||
}
|
||||
|
||||
func (m *wildcardMangler) Transform(x interface{}) (interface{}, error) {
|
||||
if term, ok := x.(Var); ok {
|
||||
if term.Equal(Wildcard.Value) {
|
||||
name := fmt.Sprintf("%s%d", WildcardPrefix, m.c)
|
||||
m.c++
|
||||
return Var(name), nil
|
||||
}
|
||||
}
|
||||
return x, nil
|
||||
return NewError(ParseErr, a.Loc(), "annotation scope '%v' must be applied to %v%v", a.Scope, want, have)
|
||||
}
|
||||
|
||||
func setRuleModule(rule *Rule, module *Module) {
|
||||
@@ -734,54 +658,13 @@ func setRuleModule(rule *Rule, module *Module) {
|
||||
}
|
||||
}
|
||||
|
||||
type varToRefTransformer struct {
|
||||
orig Var
|
||||
target Ref
|
||||
// skip set to true to avoid recursively processing the result of
|
||||
// transformation.
|
||||
skip bool
|
||||
}
|
||||
|
||||
func newVarToRefTransformer(orig Var, target Ref) *varToRefTransformer {
|
||||
return &varToRefTransformer{
|
||||
orig: orig,
|
||||
target: target,
|
||||
skip: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (vt *varToRefTransformer) Transform(x interface{}) (interface{}, error) {
|
||||
if vt.skip {
|
||||
vt.skip = false
|
||||
return x, nil
|
||||
}
|
||||
switch x := x.(type) {
|
||||
case *Head:
|
||||
// The next AST node will be the rule name (which should not be
|
||||
// transformed).
|
||||
vt.skip = true
|
||||
case Ref:
|
||||
// The next AST node will be the ref head (which should not be
|
||||
// transformed).
|
||||
vt.skip = true
|
||||
case Var:
|
||||
if x.Equal(vt.orig) {
|
||||
vt.skip = true
|
||||
return vt.target, nil
|
||||
}
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// ParserErrorDetail holds additional details for parser errors.
|
||||
type ParserErrorDetail struct {
|
||||
Line string `json:"line"`
|
||||
Idx int `json:"idx"`
|
||||
}
|
||||
|
||||
func newParserErrorDetail(bs []byte, pos position) *ParserErrorDetail {
|
||||
|
||||
offset := pos.offset
|
||||
func newParserErrorDetail(bs []byte, offset int) *ParserErrorDetail {
|
||||
|
||||
// Find first non-space character at or before offset position.
|
||||
if offset >= len(bs) {
|
||||
@@ -830,7 +713,11 @@ func newParserErrorDetail(bs []byte, pos position) *ParserErrorDetail {
|
||||
func (d ParserErrorDetail) Lines() []string {
|
||||
line := strings.TrimLeft(d.Line, "\t") // remove leading tabs
|
||||
tabCount := len(d.Line) - len(line)
|
||||
return []string{line, strings.Repeat(" ", d.Idx-tabCount) + "^"}
|
||||
indent := d.Idx - tabCount
|
||||
if indent < 0 {
|
||||
indent = 0
|
||||
}
|
||||
return []string{line, strings.Repeat(" ", indent) + "^"}
|
||||
}
|
||||
|
||||
func isNewLineChar(b byte) bool {
|
||||
|
||||
Reference in New Issue
Block a user