github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/builtins/core/structs/while.go (about) 1 package structs 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/lmorg/murex/builtins/pipes/streams" 8 "github.com/lmorg/murex/lang" 9 "github.com/lmorg/murex/lang/stdio" 10 "github.com/lmorg/murex/lang/types" 11 ) 12 13 func init() { 14 lang.DefineFunction("while", cmdWhile, types.Null) 15 lang.DefineFunction("!while", cmdWhile, types.Null) 16 } 17 18 const ( 19 whileConditional int = iota + 1 20 whileCheckStdout 21 ) 22 23 func cmdWhile(p *lang.Process) error { 24 p.Stdout.SetDataType(types.Generic) 25 26 var state, iteration int 27 28 switch p.Parameters.Len() { 29 case 2: 30 state = whileConditional 31 32 case 1: 33 state = whileCheckStdout 34 35 default: 36 return fmt.Errorf("invalid usage. Please check docs at https://murex.rocks or `murex-docs %s`", p.Name.String()) 37 } 38 39 switch state { 40 case whileCheckStdout: 41 // Condition is taken from the while loop. 42 block, err := p.Parameters.Block(0) 43 if err != nil { 44 return err 45 } 46 47 for { 48 if p.HasCancelled() { 49 return errors.New(errCancelled) 50 } 51 52 iteration++ 53 if !setMetaValues(p, iteration) { 54 return fmt.Errorf("cancelled") 55 } 56 57 fork := p.Fork(lang.F_PARENT_VARTABLE | lang.F_NO_STDIN) 58 var stdout stdio.Io 59 fork.Stdout, stdout = streams.NewTee(p.Stdout) 60 61 i, err := fork.Execute(block) 62 if err != nil { 63 return err 64 } 65 b, err := stdout.ReadAll() 66 if err != nil { 67 return err 68 } 69 70 conditional := types.IsTrue(b, i) 71 72 if (!p.IsNot && !conditional) || 73 (p.IsNot && conditional) { 74 return nil 75 } 76 77 } 78 79 case whileConditional: 80 // Condition is first parameter, while loop is second. 81 ifBlock, err := p.Parameters.Block(0) 82 if err != nil { 83 return err 84 } 85 86 whileBlock, err := p.Parameters.Block(1) 87 if err != nil { 88 return err 89 } 90 91 for { 92 if p.HasTerminated() { 93 return nil 94 } 95 96 iteration++ 97 if !setMetaValues(p, iteration) { 98 return fmt.Errorf("cancelled") 99 } 100 101 fork := p.Fork(lang.F_NO_STDIN | lang.F_CREATE_STDOUT | lang.F_NO_STDERR) 102 i, err := fork.Execute(ifBlock) 103 if err != nil { 104 return err 105 } 106 b, err := fork.Stdout.ReadAll() 107 if err != nil { 108 return err 109 } 110 conditional := types.IsTrue(b, i) 111 112 if (!p.IsNot && !conditional) || 113 (p.IsNot && conditional) { 114 return nil 115 } 116 117 fork = p.Fork(lang.F_NO_STDIN) 118 _, err = fork.Execute(whileBlock) 119 if err != nil { 120 return err 121 } 122 } 123 124 default: 125 return errors.New("this condition should never be reached. Please file a bug at https://github.com/lmorg/murex/issues") 126 127 } 128 }