github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/builtins/core/structs/if.go (about) 1 package structs 2 3 import ( 4 "errors" 5 6 "github.com/lmorg/murex/lang" 7 "github.com/lmorg/murex/lang/types" 8 ) 9 10 func init() { 11 lang.DefineMethod("if", cmdIf, types.Any, types.Generic) 12 lang.DefineMethod("!if", cmdIf, types.Any, types.Generic) 13 } 14 15 const ( 16 fIf = iota 17 fThen 18 fElse 19 fDone 20 ) 21 22 func cmdIf(p *lang.Process) error { 23 p.Stdout.SetDataType(types.Generic) 24 25 if p.Parameters.Len() == 0 { 26 return errors.New("no arguments made. `if` requires parameters") 27 } 28 29 var ( 30 blocks [3][]rune 31 flag int 32 ) 33 34 if p.IsMethod { 35 // We derive the conditional state from stdin 36 flag++ 37 } 38 39 for i := 0; i < p.Parameters.Len(); i++ { 40 switch { 41 case i == 0 && !p.IsMethod: 42 r, err := p.Parameters.Block(0) 43 if err != nil { 44 return err 45 } 46 47 blocks[0] = r 48 flag++ 49 50 default: 51 if flag == fDone { 52 return errors.New("parameters past end of `then` block") 53 } 54 55 s, err := p.Parameters.String(i) 56 if err != nil { 57 return err 58 } 59 60 matched, err := setFlag(&s, &flag) 61 if err != nil { 62 return err 63 } 64 65 if matched { 66 continue 67 } 68 69 r, err := p.Parameters.Block(i) 70 if err != nil { 71 return err 72 } 73 74 blocks[flag] = r 75 flag++ 76 } 77 } 78 79 var conditional bool 80 81 if len(blocks[fIf]) > 0 { 82 // --- IF --- (function) 83 fork := p.Fork(lang.F_PARENT_VARTABLE | lang.F_NO_STDIN | lang.F_CREATE_STDOUT | lang.F_NO_STDERR) 84 i, err := fork.Execute(blocks[fIf]) 85 if err != nil { 86 return err 87 } 88 89 b, err := fork.Stdout.ReadAll() 90 if err != nil { 91 return err 92 } 93 conditional = types.IsTrue(b, i) 94 95 } else { 96 // --- IF --- (method) 97 b, err := p.Stdin.ReadAll() 98 if err != nil { 99 return err 100 } 101 conditional = types.IsTrue(b, p.Previous.ExitNum) 102 } 103 104 if (conditional && !p.IsNot) || (!conditional && p.IsNot) { 105 // --- THEN --- 106 if len(blocks[fThen]) > 0 { 107 _, err := p.Fork(lang.F_PARENT_VARTABLE | lang.F_NO_STDIN).Execute(blocks[fThen]) 108 if err != nil { 109 return err 110 } 111 } 112 113 } else { 114 // --- ELSE --- 115 if len(blocks[fElse]) > 0 { 116 _, err := p.Fork(lang.F_PARENT_VARTABLE | lang.F_NO_STDIN).Execute(blocks[fElse]) 117 if err != nil { 118 return err 119 } 120 } 121 } 122 123 return nil 124 } 125 126 func setFlag(s *string, flag *int) (bool, error) { 127 switch *s { 128 case "then": 129 if *flag > fThen { 130 return false, errors.New("`then` appears too late in parameters") 131 } 132 *flag = fThen 133 return true, nil 134 135 case "else": 136 if *flag > fElse { 137 return false, errors.New("`else` appears too late in parameters") 138 } 139 *flag = fElse 140 return true, nil 141 142 default: 143 return false, nil 144 145 } 146 }