src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/parse/cmpd/cmpd.go (about)

     1  // Package cmpd contains utilities for working with compound nodes.
     2  package cmpd
     3  
     4  import (
     5  	"fmt"
     6  
     7  	"src.elv.sh/pkg/parse"
     8  )
     9  
    10  // Primary returns a primary node and true if that's the only child of the
    11  // compound node. Otherwise it returns nil and false.
    12  func Primary(n *parse.Compound) (*parse.Primary, bool) {
    13  	if n != nil && len(n.Indexings) == 1 && len(n.Indexings[0].Indices) == 0 {
    14  		return n.Indexings[0].Head, true
    15  	}
    16  	return nil, false
    17  }
    18  
    19  // StringLiteral returns the value of a string literal and true if that's the
    20  // only child of the compound node. Otherwise it returns "" and false.
    21  func StringLiteral(n *parse.Compound) (string, bool) {
    22  	if pn, ok := Primary(n); ok {
    23  		switch pn.Type {
    24  		case parse.Bareword, parse.SingleQuoted, parse.DoubleQuoted:
    25  			return pn.Value, true
    26  		}
    27  	}
    28  	return "", false
    29  }
    30  
    31  // Lambda returns a lambda primary node and true if that's the only child of the
    32  // compound node. Otherwise it returns nil and false.
    33  func Lambda(n *parse.Compound) (*parse.Primary, bool) {
    34  	if pn, ok := Primary(n); ok {
    35  		if pn.Type == parse.Lambda {
    36  			return pn, true
    37  		}
    38  	}
    39  	return nil, false
    40  }
    41  
    42  // StringLiteralOrError is like StringLiteral, but returns an error suitable as
    43  // a compiler error when StringLiteral would return false.
    44  func StringLiteralOrError(n *parse.Compound, what string) (string, error) {
    45  	s, ok := StringLiteral(n)
    46  	if !ok {
    47  		return "", fmt.Errorf("%s must be string literal, found %s", what, Shape(n))
    48  	}
    49  	return s, nil
    50  }
    51  
    52  // Shape describes the shape of the compound node.
    53  func Shape(n *parse.Compound) string {
    54  	if len(n.Indexings) == 0 {
    55  		return "empty expression"
    56  	}
    57  	if len(n.Indexings) > 1 {
    58  		return "compound expression"
    59  	}
    60  	in := n.Indexings[0]
    61  	if len(in.Indices) > 0 {
    62  		return "indexing expression"
    63  	}
    64  	pn := in.Head
    65  	return "primary expression of type " + pn.Type.String()
    66  }