github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/lang/expressions/ast.go (about) 1 package expressions 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "github.com/lmorg/murex/lang" 8 "github.com/lmorg/murex/lang/expressions/primitives" 9 "github.com/lmorg/murex/lang/expressions/symbols" 10 "github.com/lmorg/murex/lang/types" 11 "github.com/lmorg/murex/utils/consts" 12 ) 13 14 type astNodeT struct { 15 key symbols.Exp 16 value []rune 17 pos int 18 offset int 19 dt *primitives.DataType 20 } 21 22 func (node *astNodeT) Value() string { 23 return string(node.value) 24 } 25 26 type ParserT struct { 27 ast []*astNodeT 28 statement *StatementT 29 charPos int 30 charOffset int 31 astPos int 32 startRow int 33 endRow int 34 startCol int 35 endCol int 36 expression []rune 37 subExp bool 38 p *lang.Process 39 _strictTypes interface{} 40 _strictArrays interface{} 41 _expandGlob interface{} 42 } 43 44 func (tree *ParserT) nextChar() rune { 45 if tree.charPos+1 >= len(tree.expression) { 46 return 0 47 } 48 return tree.expression[tree.charPos+1] 49 } 50 51 func (tree *ParserT) prevChar() rune { 52 if tree.charPos < 1 { 53 return 0 54 } 55 return tree.expression[tree.charPos-1] 56 } 57 58 func (tree *ParserT) crLf() { 59 tree.endRow++ 60 tree.endCol = tree.charPos 61 } 62 63 func (tree *ParserT) GetColumnN() int { return tree.charOffset - tree.startCol + 2 } 64 func (tree *ParserT) GetLineN() int { return tree.startRow } 65 66 func (tree *ParserT) appendAst(key symbols.Exp, value ...rune) { 67 tree.ast = append(tree.ast, &astNodeT{ 68 key: key, 69 value: value, 70 pos: tree.charPos - len(value), 71 offset: tree.charOffset, 72 }) 73 } 74 75 func (tree *ParserT) appendAstWithPrimitive(key symbols.Exp, dt *primitives.DataType, value ...rune) { 76 tree.ast = append(tree.ast, &astNodeT{ 77 key: key, 78 value: value, 79 pos: tree.charPos - len(value), 80 offset: tree.charOffset, 81 dt: dt, 82 }) 83 } 84 85 func (tree *ParserT) foldAst(new *astNodeT) error { 86 switch { 87 case tree.astPos <= 0: 88 return fmt.Errorf("cannot fold when tree.astPos<%d> <= 0<%d> (%s)", 89 tree.astPos, len(tree.ast), consts.IssueTrackerURL) 90 91 case tree.astPos >= len(tree.ast)-1: 92 return fmt.Errorf("cannot fold when tree.astPos<%d> >= len(tree.ast)-1<%d> (%s)", 93 tree.astPos, len(tree.ast), consts.IssueTrackerURL) 94 95 case len(tree.ast) == 3: 96 tree.ast = []*astNodeT{new} 97 98 case tree.astPos == 1: 99 tree.ast = append([]*astNodeT{new}, tree.ast[3:]...) 100 101 case tree.astPos == len(tree.ast)-2: 102 tree.ast = append(tree.ast[:len(tree.ast)-3], new) 103 104 default: 105 start := append(tree.ast[:tree.astPos-1], new) 106 end := tree.ast[tree.astPos+2:] 107 tree.ast = append(start, end...) 108 } 109 110 return nil 111 } 112 113 // memory safe 114 func (tree *ParserT) prevSymbol() *astNodeT { 115 if tree.astPos-1 < 0 { 116 return nil 117 } 118 119 return tree.ast[tree.astPos-1] 120 } 121 122 // memory safe 123 func (tree *ParserT) currentSymbol() *astNodeT { 124 if tree.astPos < 0 || tree.astPos >= len(tree.ast) { 125 return nil 126 } 127 128 return tree.ast[tree.astPos] 129 } 130 131 // memory safe 132 func (tree *ParserT) nextSymbol() *astNodeT { 133 if tree.astPos+1 >= len(tree.ast) { 134 return nil 135 } 136 137 return tree.ast[tree.astPos+1] 138 } 139 140 func (tree *ParserT) getLeftAndRightSymbols() (*astNodeT, *astNodeT, error) { 141 left := tree.prevSymbol() 142 right := tree.nextSymbol() 143 144 if left == nil { 145 return nil, nil, raiseError(tree.expression, tree.ast[tree.astPos], 0, "missing value left of operation") 146 } 147 148 if right == nil { 149 return nil, nil, raiseError(tree.expression, tree.ast[tree.astPos], 0, "missing value right of operation") 150 } 151 152 return left, right, nil 153 } 154 155 func node2primitive(node *astNodeT) (*primitives.DataType, error) { 156 switch node.key { 157 case symbols.Number: 158 f, err := strconv.ParseFloat(node.Value(), 64) 159 if err != nil { 160 return nil, raiseError(nil, node, 0, err.Error()) 161 } 162 return primitives.NewPrimitive(primitives.Number, f), nil 163 164 case symbols.QuoteSingle, symbols.QuoteDouble, symbols.QuoteParenthesis: 165 return primitives.NewPrimitive(primitives.String, node.Value()), nil 166 167 case symbols.Boolean: 168 return primitives.NewPrimitive( 169 primitives.Boolean, 170 types.IsTrueString(string(node.value), 0), 171 ), nil 172 173 case symbols.Bareword: 174 return primitives.NewPrimitive(primitives.Bareword, nil), nil 175 176 case symbols.Calculated, symbols.Scalar, symbols.SubExpressionBegin: 177 return primitives.NewPrimitive(primitives.Null, nil), nil 178 179 case symbols.Null: 180 return primitives.NewPrimitive(primitives.Null, nil), nil 181 182 } 183 184 return nil, raiseError(nil, node, 0, fmt.Sprintf("unexpected error converting node to primitive (%s)", consts.IssueTrackerURL)) 185 } 186 187 func (tree *ParserT) StrictTypes() bool { 188 if tree._strictTypes != nil { 189 return tree._strictTypes.(bool) 190 } 191 192 var err error 193 tree._strictTypes, err = tree.p.Config.Get("proc", "strict-types", types.Boolean) 194 if err != nil { 195 panic(err) 196 } 197 198 return tree._strictTypes.(bool) 199 } 200 201 func (tree *ParserT) StrictArrays() bool { 202 if tree._strictArrays != nil { 203 return tree._strictArrays.(bool) 204 } 205 206 var err error 207 tree._strictArrays, err = tree.p.Config.Get("proc", "strict-arrays", types.Boolean) 208 if err != nil { 209 panic(err) 210 } 211 212 return tree._strictArrays.(bool) 213 } 214 215 func (tree *ParserT) ExpandGlob() bool { 216 if tree._expandGlob != nil { 217 return tree._expandGlob.(bool) 218 } 219 220 var err error 221 tree._expandGlob, err = tree.p.Config.Get("shell", "expand-globs", types.Boolean) 222 if err != nil { 223 panic(err) 224 } 225 226 tree._expandGlob = tree._expandGlob.(bool) && tree.p.Scope.Id == lang.ShellProcess.Id && 227 tree.p.Parent.Id == lang.ShellProcess.Id && !tree.p.Background.Get() && lang.Interactive 228 229 return tree._expandGlob.(bool) 230 }