github.com/rajeev159/opa@v0.45.0/topdown/regex_template.go (about) 1 package topdown 2 3 // Copyright 2012 The Gorilla Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license as follows: 6 7 // Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 8 // 9 // Redistribution and use in source and binary forms, with or without 10 // modification, are permitted provided that the following conditions are 11 // met: 12 // 13 // * Redistributions of source code must retain the above copyright 14 // notice, this list of conditions and the following disclaimer. 15 // * Redistributions in binary form must reproduce the above 16 // copyright notice, this list of conditions and the following disclaimer 17 // in the documentation and/or other materials provided with the 18 // distribution. 19 // * Neither the name of Google Inc. nor the names of its 20 // contributors may be used to endorse or promote products derived from 21 // this software without specific prior written permission. 22 // 23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 35 // This file was forked from https://github.com/gorilla/mux/commit/eac83ba2c004bb75 36 37 import ( 38 "bytes" 39 "fmt" 40 "regexp" 41 ) 42 43 // delimiterIndices returns the first level delimiter indices from a string. 44 // It returns an error in case of unbalanced delimiters. 45 func delimiterIndices(s string, delimiterStart, delimiterEnd byte) ([]int, error) { 46 var level, idx int 47 idxs := make([]int, 0) 48 for i := 0; i < len(s); i++ { 49 switch s[i] { 50 case delimiterStart: 51 if level++; level == 1 { 52 idx = i 53 } 54 case delimiterEnd: 55 if level--; level == 0 { 56 idxs = append(idxs, idx, i+1) 57 } else if level < 0 { 58 return nil, fmt.Errorf(`unbalanced braces in %q`, s) 59 } 60 } 61 } 62 63 if level != 0 { 64 return nil, fmt.Errorf(`unbalanced braces in %q`, s) 65 } 66 67 return idxs, nil 68 } 69 70 // compileRegexTemplate parses a template and returns a Regexp. 71 // 72 // You can define your own delimiters. It is e.g. common to use curly braces {} but I recommend using characters 73 // which have no special meaning in Regex, e.g.: <, > 74 // 75 // reg, err := compiler.CompileRegex("foo:bar.baz:<[0-9]{2,10}>", '<', '>') 76 // // if err != nil ... 77 // reg.MatchString("foo:bar.baz:123") 78 func compileRegexTemplate(tpl string, delimiterStart, delimiterEnd byte) (*regexp.Regexp, error) { 79 // Check if it is well-formed. 80 idxs, errBraces := delimiterIndices(tpl, delimiterStart, delimiterEnd) 81 if errBraces != nil { 82 return nil, errBraces 83 } 84 varsR := make([]*regexp.Regexp, len(idxs)/2) 85 pattern := bytes.NewBufferString("") 86 87 // WriteByte's error value is always nil for bytes.Buffer, no need to check it. 88 pattern.WriteByte('^') 89 90 var end int 91 var err error 92 for i := 0; i < len(idxs); i += 2 { 93 // Set all values we are interested in. 94 raw := tpl[end:idxs[i]] 95 end = idxs[i+1] 96 patt := tpl[idxs[i]+1 : end-1] 97 // Build the regexp pattern. 98 varIdx := i / 2 99 fmt.Fprintf(pattern, "%s(%s)", regexp.QuoteMeta(raw), patt) 100 varsR[varIdx], err = regexp.Compile(fmt.Sprintf("^%s$", patt)) 101 if err != nil { 102 return nil, err 103 } 104 } 105 106 // Add the remaining. 107 raw := tpl[end:] 108 109 // WriteString's error value is always nil for bytes.Buffer, no need to check it. 110 pattern.WriteString(regexp.QuoteMeta(raw)) 111 112 // WriteByte's error value is always nil for bytes.Buffer, no need to check it. 113 pattern.WriteByte('$') 114 115 // Compile full regexp. 116 reg, errCompile := regexp.Compile(pattern.String()) 117 if errCompile != nil { 118 return nil, errCompile 119 } 120 121 return reg, nil 122 }