github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/builtins/core/ranges/ranges.go (about)

     1  package ranges
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/lmorg/murex/debug"
    10  	"github.com/lmorg/murex/lang"
    11  	"github.com/lmorg/murex/lang/types"
    12  )
    13  
    14  func init() {
    15  	lang.DefineMethod("@[", CmdRange, types.ReadArray, types.WriteArray)
    16  }
    17  
    18  const usage = "\nUsage: [start..end] / [start..end]se\n(start or end can be omitted)"
    19  
    20  // if additional ranges are added here, they will also need to be added to
    21  // /home/lau/dev/go/src/github.com/lmorg/murex/lang/parameters.go
    22  var RxSplitRange = regexp.MustCompile(`^\s*(.*?)\s*\.\.\s*(.*?)\s*\]([bt8ernsiu]*)\s*$`)
    23  
    24  func CmdRange(p *lang.Process) (err error) {
    25  	dt := p.Stdin.GetDataType()
    26  	p.Stdout.SetDataType(dt)
    27  
    28  	if err := p.ErrIfNotAMethod(); err != nil {
    29  		return err
    30  	}
    31  
    32  	s := p.Parameters.StringAll()
    33  
    34  	split := RxSplitRange.FindStringSubmatch(s)
    35  	if len(split) != 4 {
    36  		err = indexAndExpand(p, dt)
    37  		if err != nil {
    38  			return fmt.Errorf("not a valid range: %v.%s\nnor a valid index: %v", split, usage, err)
    39  		}
    40  		return nil
    41  	}
    42  
    43  	r := &rangeParameters{
    44  		Start: split[1],
    45  		End:   split[2],
    46  	}
    47  
    48  	if strings.Contains(split[3], "e") {
    49  		r.Exclude = true
    50  		split[3] = strings.Replace(split[3], "e", "", -1)
    51  	}
    52  
    53  	if strings.Contains(split[3], "8") {
    54  		r.RmBS = true
    55  		split[3] = strings.Replace(split[3], "8", "", -1)
    56  	}
    57  
    58  	if strings.Contains(split[3], "b") {
    59  		r.StripBlank = true
    60  		split[3] = strings.Replace(split[3], "b", "", -1)
    61  	}
    62  
    63  	if strings.Contains(split[3], "t") {
    64  		r.TrimSpace = true
    65  		split[3] = strings.Replace(split[3], "t", "", -1)
    66  	}
    67  
    68  	if len(split[3]) > 1 {
    69  		return fmt.Errorf("invalid syntax: you cannot combine the following flags: %s.%s", split[3], usage)
    70  	}
    71  
    72  	switch split[3] {
    73  	case "r":
    74  		err = newRegexp(r)
    75  
    76  	case "s":
    77  		err = newString(r)
    78  
    79  	case "n":
    80  		err = newNumber(r)
    81  
    82  	case "i":
    83  		err = newIndex(r)
    84  
    85  	default:
    86  		if p.Name.String() == "@[" {
    87  			err = newNumber(r)
    88  		} else {
    89  			err = newIndex(r)
    90  		}
    91  	}
    92  
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	return readArray(p, r, dt)
    98  }
    99  
   100  func indexAndExpand(p *lang.Process, dt string) (err error) {
   101  	if !debug.Enabled {
   102  		defer func() {
   103  			if r := recover(); r != nil {
   104  				err = fmt.Errorf("panic caught, please report this to https://github.com/lmorg/murex/issues : %s", r)
   105  			}
   106  		}()
   107  	}
   108  
   109  	// We will set data type from the index function but fallback to this just
   110  	// in case it's forgotten about in the index function. This is safe because
   111  	// SetDataType() cannot overwrite the data type once set.
   112  	defer p.Stdout.SetDataType(dt)
   113  
   114  	params := p.Parameters.StringArray()
   115  	l := len(params) - 1
   116  	if l < 0 {
   117  		return errors.New("missing parameters. Please select 1 or more indexes")
   118  	}
   119  
   120  	switch {
   121  	case params[l] == "]":
   122  		params = params[:l]
   123  	case strings.HasSuffix(params[l], "]"):
   124  		params[l] = params[l][:len(params[l])-1]
   125  	default:
   126  		return errors.New("missing closing bracket, ` ]`")
   127  	}
   128  
   129  	f := lang.ReadIndexes[dt]
   130  	if f == nil {
   131  		return errors.New("i don't know how to get an index from this data type: `" + dt + "`")
   132  	}
   133  
   134  	silent, err := p.Config.Get("index", "silent", types.Boolean)
   135  	if err != nil {
   136  		silent = false
   137  	}
   138  
   139  	err = f(p, params)
   140  	if silent.(bool) {
   141  		return nil
   142  	}
   143  
   144  	return err
   145  }