github.com/cilki/sh@v2.6.4+incompatible/interp/test_classic.go (about) 1 // Copyright (c) 2017, Daniel Martà <mvdan@mvdan.cc> 2 // See LICENSE for licensing information 3 4 package interp 5 6 import ( 7 "fmt" 8 9 "mvdan.cc/sh/syntax" 10 ) 11 12 const illegalTok = 0 13 14 type testParser struct { 15 eof bool 16 val string 17 rem []string 18 19 err func(err error) 20 } 21 22 func (p *testParser) errf(format string, a ...interface{}) { 23 p.err(fmt.Errorf(format, a...)) 24 } 25 26 func (p *testParser) next() { 27 if p.eof || len(p.rem) == 0 { 28 p.eof = true 29 p.val = "" 30 return 31 } 32 p.val = p.rem[0] 33 p.rem = p.rem[1:] 34 } 35 36 func (p *testParser) followWord(fval string) *syntax.Word { 37 if p.eof { 38 p.errf("%s must be followed by a word", fval) 39 } 40 w := &syntax.Word{Parts: []syntax.WordPart{ 41 &syntax.Lit{Value: p.val}, 42 }} 43 p.next() 44 return w 45 } 46 47 func (p *testParser) classicTest(fval string, pastAndOr bool) syntax.TestExpr { 48 var left syntax.TestExpr 49 if pastAndOr { 50 left = p.testExprBase(fval) 51 } else { 52 left = p.classicTest(fval, true) 53 } 54 if left == nil || p.eof { 55 return left 56 } 57 opStr := p.val 58 op := testBinaryOp(p.val) 59 if op == illegalTok { 60 p.errf("not a valid test operator: %s", p.val) 61 } 62 b := &syntax.BinaryTest{ 63 Op: op, 64 X: left, 65 } 66 p.next() 67 switch b.Op { 68 case syntax.AndTest, syntax.OrTest: 69 if b.Y = p.classicTest(opStr, false); b.Y == nil { 70 p.errf("%s must be followed by an expression", opStr) 71 } 72 default: 73 b.Y = p.followWord(opStr) 74 } 75 return b 76 } 77 78 func (p *testParser) testExprBase(fval string) syntax.TestExpr { 79 if p.eof { 80 return nil 81 } 82 op := testUnaryOp(p.val) 83 switch op { 84 case syntax.TsNot: 85 u := &syntax.UnaryTest{Op: op} 86 p.next() 87 u.X = p.classicTest(op.String(), false) 88 return u 89 case illegalTok: 90 return p.followWord(fval) 91 default: 92 u := &syntax.UnaryTest{Op: op} 93 p.next() 94 if p.eof { 95 // make [ -e ] fall back to [ -n -e ], i.e. use 96 // the operator as an argument 97 return &syntax.Word{Parts: []syntax.WordPart{ 98 &syntax.Lit{Value: op.String()}, 99 }} 100 } 101 u.X = p.followWord(op.String()) 102 return u 103 } 104 } 105 106 // testUnaryOp is an exact copy of syntax's. 107 func testUnaryOp(val string) syntax.UnTestOperator { 108 switch val { 109 case "!": 110 return syntax.TsNot 111 case "-e", "-a": 112 return syntax.TsExists 113 case "-f": 114 return syntax.TsRegFile 115 case "-d": 116 return syntax.TsDirect 117 case "-c": 118 return syntax.TsCharSp 119 case "-b": 120 return syntax.TsBlckSp 121 case "-p": 122 return syntax.TsNmPipe 123 case "-S": 124 return syntax.TsSocket 125 case "-L", "-h": 126 return syntax.TsSmbLink 127 case "-k": 128 return syntax.TsSticky 129 case "-g": 130 return syntax.TsGIDSet 131 case "-u": 132 return syntax.TsUIDSet 133 case "-G": 134 return syntax.TsGrpOwn 135 case "-O": 136 return syntax.TsUsrOwn 137 case "-N": 138 return syntax.TsModif 139 case "-r": 140 return syntax.TsRead 141 case "-w": 142 return syntax.TsWrite 143 case "-x": 144 return syntax.TsExec 145 case "-s": 146 return syntax.TsNoEmpty 147 case "-t": 148 return syntax.TsFdTerm 149 case "-z": 150 return syntax.TsEmpStr 151 case "-n": 152 return syntax.TsNempStr 153 case "-o": 154 return syntax.TsOptSet 155 case "-v": 156 return syntax.TsVarSet 157 case "-R": 158 return syntax.TsRefVar 159 default: 160 return illegalTok 161 } 162 } 163 164 // testBinaryOp is like syntax's, but with -a and -o, and without =~. 165 func testBinaryOp(val string) syntax.BinTestOperator { 166 switch val { 167 case "-a": 168 return syntax.AndTest 169 case "-o": 170 return syntax.OrTest 171 case "==", "=": 172 return syntax.TsMatch 173 case "!=": 174 return syntax.TsNoMatch 175 case "-nt": 176 return syntax.TsNewer 177 case "-ot": 178 return syntax.TsOlder 179 case "-ef": 180 return syntax.TsDevIno 181 case "-eq": 182 return syntax.TsEql 183 case "-ne": 184 return syntax.TsNeq 185 case "-le": 186 return syntax.TsLeq 187 case "-ge": 188 return syntax.TsGeq 189 case "-lt": 190 return syntax.TsLss 191 case "-gt": 192 return syntax.TsGtr 193 default: 194 return illegalTok 195 } 196 }