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 }