...

Source file src/github.com/drone/envsubst/v2/parse/parse.go

Documentation: github.com/drone/envsubst/v2/parse

     1  package parse
     2  
     3  import (
     4  	"errors"
     5  )
     6  
     7  var (
     8  	// ErrBadSubstitution represents a substitution parsing error.
     9  	ErrBadSubstitution = errors.New("bad substitution")
    10  
    11  	// ErrMissingClosingBrace represents a missing closing brace "}" error.
    12  	ErrMissingClosingBrace = errors.New("missing closing brace")
    13  
    14  	// ErrParseVariableName represents the error when unable to parse a
    15  	// variable name within a substitution.
    16  	ErrParseVariableName = errors.New("unable to parse variable name")
    17  
    18  	// ErrParseFuncSubstitution represents the error when unable to parse the
    19  	// substitution within a function parameter.
    20  	ErrParseFuncSubstitution = errors.New("unable to parse substitution within function")
    21  
    22  	// ErrParseDefaultFunction represent the error when unable to parse a
    23  	// default function.
    24  	ErrParseDefaultFunction = errors.New("unable to parse default function")
    25  )
    26  
    27  // Tree is the representation of a single parsed SQL statement.
    28  type Tree struct {
    29  	Root Node
    30  
    31  	// Parsing only; cleared after parse.
    32  	scanner *scanner
    33  }
    34  
    35  // Parse parses the string and returns a Tree.
    36  func Parse(buf string) (*Tree, error) {
    37  	t := new(Tree)
    38  	t.scanner = new(scanner)
    39  	return t.Parse(buf)
    40  }
    41  
    42  // Parse parses the string buffer to construct an ast
    43  // representation for expansion.
    44  func (t *Tree) Parse(buf string) (tree *Tree, err error) {
    45  	t.scanner.init(buf)
    46  	t.Root, err = t.parseAny()
    47  	return t, err
    48  }
    49  
    50  func (t *Tree) parseAny() (Node, error) {
    51  	t.scanner.accept = acceptRune
    52  	t.scanner.mode = scanIdent | scanLbrack | scanEscape
    53  	t.scanner.escapeChars = dollar
    54  
    55  	switch t.scanner.scan() {
    56  	case tokenIdent:
    57  		left := newTextNode(
    58  			t.scanner.string(),
    59  		)
    60  		right, err := t.parseAny()
    61  		switch {
    62  		case err != nil:
    63  			return nil, err
    64  		case right == empty:
    65  			return left, nil
    66  		}
    67  		return newListNode(left, right), nil
    68  	case tokenEOF:
    69  		return empty, nil
    70  	case tokenLbrack:
    71  		left, err := t.parseFunc()
    72  		if err != nil {
    73  			return nil, err
    74  		}
    75  
    76  		right, err := t.parseAny()
    77  		switch {
    78  		case err != nil:
    79  			return nil, err
    80  		case right == empty:
    81  			return left, nil
    82  		}
    83  		return newListNode(left, right), nil
    84  	}
    85  
    86  	return nil, ErrBadSubstitution
    87  }
    88  
    89  func (t *Tree) parseFunc() (Node, error) {
    90  	// Turn on all escape characters
    91  	t.scanner.escapeChars = escapeAll
    92  	switch t.scanner.peek() {
    93  	case '#':
    94  		return t.parseLenFunc()
    95  	}
    96  
    97  	var name string
    98  	t.scanner.accept = acceptIdent
    99  	t.scanner.mode = scanIdent
   100  
   101  	switch t.scanner.scan() {
   102  	case tokenIdent:
   103  		name = t.scanner.string()
   104  	default:
   105  		return nil, ErrParseVariableName
   106  	}
   107  
   108  	switch t.scanner.peek() {
   109  	case ':':
   110  		return t.parseDefaultOrSubstr(name)
   111  	case '=':
   112  		return t.parseDefaultFunc(name)
   113  	case ',', '^':
   114  		return t.parseCasingFunc(name)
   115  	case '/':
   116  		return t.parseReplaceFunc(name)
   117  	case '#':
   118  		return t.parseRemoveFunc(name, acceptHashFunc)
   119  	case '%':
   120  		return t.parseRemoveFunc(name, acceptPercentFunc)
   121  	}
   122  
   123  	t.scanner.accept = acceptIdent
   124  	t.scanner.mode = scanRbrack
   125  	switch t.scanner.scan() {
   126  	case tokenRbrack:
   127  		return newFuncNode(name), nil
   128  	default:
   129  		return nil, ErrMissingClosingBrace
   130  	}
   131  }
   132  
   133  // parse a substitution function parameter.
   134  func (t *Tree) parseParam(accept acceptFunc, mode byte) (Node, error) {
   135  	t.scanner.accept = accept
   136  	t.scanner.mode = mode | scanLbrack
   137  	switch t.scanner.scan() {
   138  	case tokenLbrack:
   139  		return t.parseFunc()
   140  	case tokenIdent:
   141  		return newTextNode(
   142  			t.scanner.string(),
   143  		), nil
   144  	case tokenRbrack:
   145  		return newTextNode(
   146  			t.scanner.string(),
   147  		), nil
   148  	default:
   149  		return nil, ErrParseFuncSubstitution
   150  	}
   151  }
   152  
   153  // parse either a default or substring substitution function.
   154  func (t *Tree) parseDefaultOrSubstr(name string) (Node, error) {
   155  	t.scanner.read()
   156  	r := t.scanner.peek()
   157  	t.scanner.unread()
   158  	switch r {
   159  	case '=', '-', '?', '+':
   160  		return t.parseDefaultFunc(name)
   161  	default:
   162  		return t.parseSubstrFunc(name)
   163  	}
   164  }
   165  
   166  // parses the ${param:offset} string function
   167  // parses the ${param:offset:length} string function
   168  func (t *Tree) parseSubstrFunc(name string) (Node, error) {
   169  	node := new(FuncNode)
   170  	node.Param = name
   171  
   172  	t.scanner.accept = acceptOneColon
   173  	t.scanner.mode = scanIdent
   174  	switch t.scanner.scan() {
   175  	case tokenIdent:
   176  		node.Name = t.scanner.string()
   177  	default:
   178  		return nil, ErrBadSubstitution
   179  	}
   180  
   181  	// scan arg[1]
   182  	{
   183  		param, err := t.parseParam(rejectColonClose, scanIdent)
   184  		if err != nil {
   185  			return nil, err
   186  		}
   187  
   188  		// param.Value = t.scanner.string()
   189  		node.Args = append(node.Args, param)
   190  	}
   191  
   192  	// expect delimiter or close
   193  	t.scanner.accept = acceptColon
   194  	t.scanner.mode = scanIdent | scanRbrack
   195  	switch t.scanner.scan() {
   196  	case tokenRbrack:
   197  		return node, nil
   198  	case tokenIdent:
   199  		// no-op
   200  	default:
   201  		return nil, ErrBadSubstitution
   202  	}
   203  
   204  	// scan arg[2]
   205  	{
   206  		param, err := t.parseParam(acceptNotClosing, scanIdent)
   207  		if err != nil {
   208  			return nil, err
   209  		}
   210  		node.Args = append(node.Args, param)
   211  	}
   212  
   213  	return node, t.consumeRbrack()
   214  }
   215  
   216  // parses the ${param%word} string function
   217  // parses the ${param%%word} string function
   218  // parses the ${param#word} string function
   219  // parses the ${param##word} string function
   220  func (t *Tree) parseRemoveFunc(name string, accept acceptFunc) (Node, error) {
   221  	node := new(FuncNode)
   222  	node.Param = name
   223  
   224  	t.scanner.accept = accept
   225  	t.scanner.mode = scanIdent
   226  	switch t.scanner.scan() {
   227  	case tokenIdent:
   228  		node.Name = t.scanner.string()
   229  	default:
   230  		return nil, ErrBadSubstitution
   231  	}
   232  
   233  	// scan arg[1]
   234  	{
   235  		param, err := t.parseParam(acceptNotClosing, scanIdent)
   236  		if err != nil {
   237  			return nil, err
   238  		}
   239  
   240  		// param.Value = t.scanner.string()
   241  		node.Args = append(node.Args, param)
   242  	}
   243  
   244  	return node, t.consumeRbrack()
   245  }
   246  
   247  // parses the ${param/pattern/string} string function
   248  // parses the ${param//pattern/string} string function
   249  // parses the ${param/#pattern/string} string function
   250  // parses the ${param/%pattern/string} string function
   251  func (t *Tree) parseReplaceFunc(name string) (Node, error) {
   252  	node := new(FuncNode)
   253  	node.Param = name
   254  
   255  	t.scanner.accept = acceptReplaceFunc
   256  	t.scanner.mode = scanIdent
   257  	switch t.scanner.scan() {
   258  	case tokenIdent:
   259  		node.Name = t.scanner.string()
   260  	default:
   261  		return nil, ErrBadSubstitution
   262  	}
   263  
   264  	// scan arg[1]
   265  	{
   266  		param, err := t.parseParam(acceptNotSlash, scanIdent|scanEscape)
   267  		if err != nil {
   268  			return nil, err
   269  		}
   270  		node.Args = append(node.Args, param)
   271  	}
   272  
   273  	// expect delimiter
   274  	t.scanner.accept = acceptSlash
   275  	t.scanner.mode = scanIdent
   276  	switch t.scanner.scan() {
   277  	case tokenIdent:
   278  		// no-op
   279  	default:
   280  		return nil, ErrBadSubstitution
   281  	}
   282  
   283  	// check for blank string
   284  	switch t.scanner.peek() {
   285  	case '}':
   286  		return node, t.consumeRbrack()
   287  	}
   288  
   289  	// scan arg[2]
   290  	{
   291  		param, err := t.parseParam(acceptNotClosing, scanIdent|scanEscape)
   292  		if err != nil {
   293  			return nil, err
   294  		}
   295  		node.Args = append(node.Args, param)
   296  	}
   297  
   298  	return node, t.consumeRbrack()
   299  }
   300  
   301  // parses the ${parameter=word} string function
   302  // parses the ${parameter:=word} string function
   303  // parses the ${parameter:-word} string function
   304  // parses the ${parameter:?word} string function
   305  // parses the ${parameter:+word} string function
   306  func (t *Tree) parseDefaultFunc(name string) (Node, error) {
   307  	node := new(FuncNode)
   308  	node.Param = name
   309  
   310  	t.scanner.accept = acceptDefaultFunc
   311  	if t.scanner.peek() == '=' {
   312  		t.scanner.accept = acceptOneEqual
   313  	}
   314  	t.scanner.mode = scanIdent
   315  	switch t.scanner.scan() {
   316  	case tokenIdent:
   317  		node.Name = t.scanner.string()
   318  	default:
   319  		return nil, ErrParseDefaultFunction
   320  	}
   321  
   322  	// loop through all possible runes in default param
   323  	for {
   324  		// this acts as the break condition. Peek to see if we reached the end
   325  		switch t.scanner.peek() {
   326  		case '}':
   327  			return node, t.consumeRbrack()
   328  		}
   329  		param, err := t.parseParam(acceptNotClosing, scanIdent)
   330  		if err != nil {
   331  			return nil, err
   332  		}
   333  
   334  		node.Args = append(node.Args, param)
   335  	}
   336  }
   337  
   338  // parses the ${param,} string function
   339  // parses the ${param,,} string function
   340  // parses the ${param^} string function
   341  // parses the ${param^^} string function
   342  func (t *Tree) parseCasingFunc(name string) (Node, error) {
   343  	node := new(FuncNode)
   344  	node.Param = name
   345  
   346  	t.scanner.accept = acceptCasingFunc
   347  	t.scanner.mode = scanIdent
   348  	switch t.scanner.scan() {
   349  	case tokenIdent:
   350  		node.Name = t.scanner.string()
   351  	default:
   352  		return nil, ErrBadSubstitution
   353  	}
   354  
   355  	return node, t.consumeRbrack()
   356  }
   357  
   358  // parses the ${#param} string function
   359  func (t *Tree) parseLenFunc() (Node, error) {
   360  	node := new(FuncNode)
   361  
   362  	t.scanner.accept = acceptOneHash
   363  	t.scanner.mode = scanIdent
   364  	switch t.scanner.scan() {
   365  	case tokenIdent:
   366  		node.Name = t.scanner.string()
   367  	default:
   368  		return nil, ErrBadSubstitution
   369  	}
   370  
   371  	t.scanner.accept = acceptIdent
   372  	t.scanner.mode = scanIdent
   373  	switch t.scanner.scan() {
   374  	case tokenIdent:
   375  		node.Param = t.scanner.string()
   376  	default:
   377  		return nil, ErrBadSubstitution
   378  	}
   379  
   380  	return node, t.consumeRbrack()
   381  }
   382  
   383  // consumeRbrack consumes a right closing bracket. If a closing
   384  // bracket token is not consumed an ErrBadSubstitution is returned.
   385  func (t *Tree) consumeRbrack() error {
   386  	t.scanner.mode = scanRbrack
   387  	if t.scanner.scan() != tokenRbrack {
   388  		return ErrBadSubstitution
   389  	}
   390  	return nil
   391  }
   392  
   393  // consumeDelimiter consumes a function argument delimiter. If a
   394  // delimiter is not consumed an ErrBadSubstitution is returned.
   395  // func (t *Tree) consumeDelimiter(accept acceptFunc, mode uint) error {
   396  // 	t.scanner.accept = accept
   397  // 	t.scanner.mode = mode
   398  // 	if t.scanner.scan() != tokenRbrack {
   399  // 		return ErrBadSubstitution
   400  // 	}
   401  // 	return nil
   402  // }
   403  

View as plain text