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

     1  package structs
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/lmorg/murex/config/defaults"
    10  	"github.com/lmorg/murex/lang"
    11  	"github.com/lmorg/murex/lang/types"
    12  	"github.com/lmorg/murex/utils"
    13  	"github.com/lmorg/murex/utils/json"
    14  )
    15  
    16  func init() {
    17  	lang.DefineFunction("alias", cmdAlias, types.Null)
    18  	lang.DefineFunction("!alias", cmdUnalias, types.Null)
    19  	lang.DefineFunction("function", cmdFunc, types.Null)
    20  	lang.DefineFunction("!function", cmdUnfunc, types.Null)
    21  	lang.DefineFunction("private", cmdPrivate, types.Null)
    22  	//lang.DefineFunction("!private", cmdUnprivate, types.Null)
    23  	lang.DefineFunction("method", cmdMethod, types.Null)
    24  
    25  	defaults.AppendProfile(`
    26  	autocomplete set method { [
    27  		{
    28  			"FlagsDesc": {
    29  				"define": "Define method"
    30  			}
    31  		}
    32  	] }
    33  `)
    34  }
    35  
    36  var rxAlias = regexp.MustCompile(`^([-_.a-zA-Z0-9]+)=(.*?)$`)
    37  
    38  func cmdAlias(p *lang.Process) error {
    39  	if p.Parameters.Len() == 0 {
    40  		p.Stdout.SetDataType(types.Json)
    41  		b, err := json.Marshal(lang.GlobalAliases.Dump(), p.Stdout.IsTTY())
    42  		if err != nil {
    43  			return err
    44  		}
    45  		_, err = p.Stdout.Writeln(b)
    46  		return err
    47  
    48  	}
    49  
    50  	p.Stdout.SetDataType(types.Null)
    51  
    52  	s, _ := p.Parameters.String(0)
    53  	eq, _ := p.Parameters.String(1)
    54  
    55  	if !rxAlias.MatchString(s) && len(eq) > 0 && eq[0] != '=' {
    56  		return errors.New("invalid syntax. Expecting `alias new_name=original_name parameter1 parameter2 ...`")
    57  	}
    58  
    59  	var (
    60  		split  = rxAlias.FindStringSubmatch(s)
    61  		name   string
    62  		params []string
    63  	)
    64  
    65  	if len(split) == 0 {
    66  		name = s
    67  		params = p.Parameters.StringArray()[1:]
    68  		switch {
    69  		case len(params) == 0:
    70  			return fmt.Errorf("no command supplied")
    71  		case len(params[0]) == 1 && params[0] == "=":
    72  			params = params[1:]
    73  		case len(params[0]) > 0 && params[0][0] == '=':
    74  			params[0] = params[0][1:]
    75  		default:
    76  			return fmt.Errorf("unknown error. Please check syntax follows `alias new_name=original_name parameter1 parameter2 ...`")
    77  		}
    78  
    79  	} else {
    80  		name = split[1]
    81  		params = append([]string{split[2]}, p.Parameters.StringArray()[1:]...)
    82  	}
    83  
    84  	if len(params) == 0 {
    85  		return fmt.Errorf("no command supplied")
    86  	}
    87  
    88  	if params[0] == "" && len(params) > 0 {
    89  		params = params[1:]
    90  	}
    91  
    92  	if len(params) == 0 || params[0] == "" {
    93  		return fmt.Errorf("no command supplied")
    94  	}
    95  
    96  	lang.GlobalAliases.Add(name, params, p.FileRef)
    97  	return nil
    98  }
    99  
   100  func cmdUnalias(p *lang.Process) error {
   101  	p.Stdout.SetDataType(types.Null)
   102  
   103  	for _, name := range p.Parameters.StringArray() {
   104  		err := lang.GlobalAliases.Delete(name)
   105  		if err != nil {
   106  			return err
   107  		}
   108  	}
   109  	return nil
   110  }
   111  
   112  func cmdFunc(p *lang.Process) error {
   113  	var dtParamsT []lang.MxFunctionParams
   114  
   115  	name, err := p.Parameters.String(0)
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	blockId := 1
   121  	if p.Parameters.Len() == 3 {
   122  		blockId++
   123  
   124  		dtParamsS, err := p.Parameters.String(1)
   125  		if err != nil {
   126  			return err
   127  		}
   128  
   129  		dtParamsT, err = lang.ParseMxFunctionParameters(dtParamsS)
   130  		if err != nil {
   131  			return fmt.Errorf("cannot parse function parameter block: %s:%scode: (%s)",
   132  				//err.Error(), lang.EscapedColon, lang.EscapeColonInErr(dtParamsS))
   133  				err.Error(), utils.NewLineString, dtParamsS)
   134  		}
   135  	}
   136  
   137  	block, err := p.Parameters.Block(blockId)
   138  	if err != nil {
   139  		return err
   140  	}
   141  
   142  	switch {
   143  	case len(name) == 0:
   144  		return errors.New("function name is an empty (zero length) string")
   145  
   146  	case strings.Contains(name, "$"):
   147  		return errors.New("function name cannot contain a dollar, '$', character")
   148  
   149  	default:
   150  		lang.MxFunctions.Define(name, dtParamsT, block, p.FileRef)
   151  		return nil
   152  	}
   153  }
   154  
   155  func cmdUnfunc(p *lang.Process) error {
   156  	name, err := p.Parameters.String(0)
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	return lang.MxFunctions.Undefine(name)
   162  }
   163  
   164  func cmdPrivate(p *lang.Process) error {
   165  	name, err := p.Parameters.String(0)
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	block, err := p.Parameters.Block(1)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	switch {
   176  	case len(name) == 0:
   177  		return errors.New("private name is an empty (zero length) string")
   178  
   179  	case strings.Contains(name, "$"):
   180  		return errors.New("private name cannot contain a dollar, '$', character")
   181  
   182  	default:
   183  		lang.PrivateFunctions.Define(name, nil, block, p.FileRef)
   184  		return nil
   185  	}
   186  }
   187  
   188  /*func cmdUnprivate(p *lang.Process) error {
   189  	name, err := p.Parameters.String(0)
   190  	if err != nil {
   191  		return err
   192  	}
   193  
   194  	return lang.PrivateFunctions.Undefine(name)
   195  }*/
   196  
   197  func cmdMethod(p *lang.Process) error {
   198  	fn, err := p.Parameters.String(0)
   199  	if err != nil {
   200  		return err
   201  	}
   202  
   203  	switch fn {
   204  	case "define":
   205  		return cmdMethodDefine(p)
   206  	default:
   207  		return fmt.Errorf("invalid parameter `%s`", fn)
   208  	}
   209  }
   210  
   211  type methodDefineT struct {
   212  	Stdin  string
   213  	Stdout string
   214  }
   215  
   216  func cmdMethodDefine(p *lang.Process) error {
   217  	name, err := p.Parameters.String(1)
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	j, err := p.Parameters.String(2)
   223  	if err != nil {
   224  		return err
   225  	}
   226  
   227  	var mdt methodDefineT
   228  	err = json.UnmarshalMurex([]byte(j), &mdt)
   229  	if err != nil {
   230  		return err
   231  	}
   232  
   233  	if mdt.Stdin != "" {
   234  		lang.MethodStdin.Define(name, mdt.Stdin)
   235  		err = lang.MethodStdin.Degroup()
   236  		if err != nil {
   237  			return err
   238  		}
   239  	}
   240  
   241  	if mdt.Stdout != "" {
   242  		lang.MethodStdout.Define(name, mdt.Stdout)
   243  		err = lang.MethodStdout.Degroup()
   244  		if err != nil {
   245  			return err
   246  		}
   247  	}
   248  
   249  	return nil
   250  }