github.com/benhoyt/goawk@v1.8.1/internal/ast/ast.go (about) 1 // GoAWK parser - abstract syntax tree structs 2 3 package ast 4 5 import ( 6 "fmt" 7 "strconv" 8 "strings" 9 10 . "github.com/benhoyt/goawk/lexer" 11 ) 12 13 // Stmts is a block containing multiple statements. 14 type Stmts []Stmt 15 16 func (ss Stmts) String() string { 17 lines := []string{} 18 for _, s := range ss { 19 subLines := strings.Split(s.String(), "\n") 20 for _, sl := range subLines { 21 lines = append(lines, " "+sl+"\n") 22 } 23 } 24 return strings.Join(lines, "") 25 } 26 27 // Action is pattern-action section of a program. 28 type Action struct { 29 Pattern []Expr 30 Stmts Stmts 31 } 32 33 func (a *Action) String() string { 34 patterns := make([]string, len(a.Pattern)) 35 for i, p := range a.Pattern { 36 patterns[i] = p.String() 37 } 38 sep := "" 39 if len(patterns) > 0 && a.Stmts != nil { 40 sep = " " 41 } 42 stmtsStr := "" 43 if a.Stmts != nil { 44 stmtsStr = "{\n" + a.Stmts.String() + "}" 45 } 46 return strings.Join(patterns, ", ") + sep + stmtsStr 47 } 48 49 // Expr is the abstract syntax tree for any AWK expression. 50 type Expr interface { 51 expr() 52 String() string 53 } 54 55 // All these types implement the Expr interface. 56 func (e *FieldExpr) expr() {} 57 func (e *UnaryExpr) expr() {} 58 func (e *BinaryExpr) expr() {} 59 func (e *ArrayExpr) expr() {} 60 func (e *InExpr) expr() {} 61 func (e *CondExpr) expr() {} 62 func (e *NumExpr) expr() {} 63 func (e *StrExpr) expr() {} 64 func (e *RegExpr) expr() {} 65 func (e *VarExpr) expr() {} 66 func (e *IndexExpr) expr() {} 67 func (e *AssignExpr) expr() {} 68 func (e *AugAssignExpr) expr() {} 69 func (e *IncrExpr) expr() {} 70 func (e *CallExpr) expr() {} 71 func (e *UserCallExpr) expr() {} 72 func (e *MultiExpr) expr() {} 73 func (e *GetlineExpr) expr() {} 74 75 // Field expression like $0. 76 type FieldExpr struct { 77 Index Expr 78 } 79 80 func (e *FieldExpr) String() string { 81 return "$" + e.Index.String() 82 } 83 84 // Unary expression like -1234. 85 type UnaryExpr struct { 86 Op Token 87 Value Expr 88 } 89 90 func (e *UnaryExpr) String() string { 91 return e.Op.String() + e.Value.String() 92 } 93 94 // Binary expression like 1 + 2. 95 type BinaryExpr struct { 96 Left Expr 97 Op Token 98 Right Expr 99 } 100 101 func (e *BinaryExpr) String() string { 102 var opStr string 103 if e.Op == CONCAT { 104 opStr = " " 105 } else { 106 opStr = " " + e.Op.String() + " " 107 } 108 return "(" + e.Left.String() + opStr + e.Right.String() + ")" 109 } 110 111 // Array reference. Not really a stand-alone expression, except as 112 // an argument to split() or a user function call. 113 type ArrayExpr struct { 114 Scope VarScope 115 Index int 116 Name string 117 } 118 119 func (e *ArrayExpr) String() string { 120 return e.Name 121 } 122 123 // In expression like (index in array). 124 type InExpr struct { 125 Index []Expr 126 Array *ArrayExpr 127 } 128 129 func (e *InExpr) String() string { 130 if len(e.Index) == 1 { 131 return "(" + e.Index[0].String() + " in " + e.Array.String() + ")" 132 } 133 indices := make([]string, len(e.Index)) 134 for i, index := range e.Index { 135 indices[i] = index.String() 136 } 137 return "((" + strings.Join(indices, ", ") + ") in " + e.Array.String() + ")" 138 } 139 140 // Conditional expression like cond ? 1 : 0. 141 type CondExpr struct { 142 Cond Expr 143 True Expr 144 False Expr 145 } 146 147 func (e *CondExpr) String() string { 148 return "(" + e.Cond.String() + " ? " + e.True.String() + " : " + e.False.String() + ")" 149 } 150 151 // Literal number like 1234. 152 type NumExpr struct { 153 Value float64 154 } 155 156 func (e *NumExpr) String() string { 157 return fmt.Sprintf("%.6g", e.Value) 158 } 159 160 // Literal string like "foo". 161 type StrExpr struct { 162 Value string 163 } 164 165 func (e *StrExpr) String() string { 166 return strconv.Quote(e.Value) 167 } 168 169 // Stand-alone regex expression, equivalent to: $0 ~ /regex/. 170 type RegExpr struct { 171 Regex string 172 } 173 174 func (e *RegExpr) String() string { 175 escaped := strings.Replace(e.Regex, "/", `\/`, -1) 176 return "/" + escaped + "/" 177 } 178 179 type VarScope int 180 181 const ( 182 ScopeSpecial VarScope = iota 183 ScopeGlobal 184 ScopeLocal 185 ) 186 187 // Variable reference (special var, global, or local). Index is the 188 // resolved variable index used by the interpreter; Name is the 189 // original name used by String(). 190 type VarExpr struct { 191 Scope VarScope 192 Index int 193 Name string 194 } 195 196 func (e *VarExpr) String() string { 197 return e.Name 198 } 199 200 // Index expression like a[k] (rvalue or lvalue). 201 type IndexExpr struct { 202 Array *ArrayExpr 203 Index []Expr 204 } 205 206 func (e *IndexExpr) String() string { 207 indices := make([]string, len(e.Index)) 208 for i, index := range e.Index { 209 indices[i] = index.String() 210 } 211 return e.Array.String() + "[" + strings.Join(indices, ", ") + "]" 212 } 213 214 // Assignment expression like x = 1234. 215 type AssignExpr struct { 216 Left Expr // can be one of: var, array[x], $n 217 Right Expr 218 } 219 220 func (e *AssignExpr) String() string { 221 return e.Left.String() + " = " + e.Right.String() 222 } 223 224 // Augmented assignment expression like x += 5. 225 type AugAssignExpr struct { 226 Left Expr // can be one of: var, array[x], $n 227 Op Token 228 Right Expr 229 } 230 231 func (e *AugAssignExpr) String() string { 232 return e.Left.String() + " " + e.Op.String() + "= " + e.Right.String() 233 } 234 235 // Increment or decrement expression like x++ or --y. 236 type IncrExpr struct { 237 Expr Expr 238 Op Token 239 Pre bool 240 } 241 242 func (e *IncrExpr) String() string { 243 if e.Pre { 244 return e.Op.String() + e.Expr.String() 245 } else { 246 return e.Expr.String() + e.Op.String() 247 } 248 } 249 250 // Builtin function call like length($1). 251 type CallExpr struct { 252 Func Token 253 Args []Expr 254 } 255 256 func (e *CallExpr) String() string { 257 args := make([]string, len(e.Args)) 258 for i, a := range e.Args { 259 args[i] = a.String() 260 } 261 return e.Func.String() + "(" + strings.Join(args, ", ") + ")" 262 } 263 264 // User-defined function call like my_func(1, 2, 3). Index is the 265 // resolved function index used by the interpreter; Name is the 266 // original name used by String(). 267 type UserCallExpr struct { 268 Native bool // false = AWK-defined function, true = native Go func 269 Index int 270 Name string 271 Args []Expr 272 } 273 274 func (e *UserCallExpr) String() string { 275 args := make([]string, len(e.Args)) 276 for i, a := range e.Args { 277 args[i] = a.String() 278 } 279 return e.Name + "(" + strings.Join(args, ", ") + ")" 280 } 281 282 // MultiExpr isn't an interpretable expression, but it's used as a 283 // pseudo-expression for print[f] parsing. 284 type MultiExpr struct { 285 Exprs []Expr 286 } 287 288 func (e *MultiExpr) String() string { 289 exprs := make([]string, len(e.Exprs)) 290 for i, e := range e.Exprs { 291 exprs[i] = e.String() 292 } 293 return "(" + strings.Join(exprs, ", ") + ")" 294 } 295 296 // Getline expression (read from file or pipe input). 297 type GetlineExpr struct { 298 Command Expr 299 Var *VarExpr 300 File Expr 301 } 302 303 func (e *GetlineExpr) String() string { 304 s := "" 305 if e.Command != nil { 306 s += e.Command.String() + " |" 307 } 308 s += "getline" 309 if e.Var != nil { 310 s += " " + e.Var.String() 311 } 312 if e.File != nil { 313 s += " <" + e.File.String() 314 } 315 return s 316 } 317 318 // IsLValue returns true if the given expression can be used as an 319 // lvalue (on the left-hand side of an assignment, in a ++ or -- 320 // operation, or as the third argument to sub or gsub). 321 func IsLValue(expr Expr) bool { 322 switch expr.(type) { 323 case *VarExpr, *IndexExpr, *FieldExpr: 324 return true 325 default: 326 return false 327 } 328 } 329 330 // Stmt is the abstract syntax tree for any AWK statement. 331 type Stmt interface { 332 stmt() 333 String() string 334 } 335 336 // All these types implement the Stmt interface. 337 func (s *PrintStmt) stmt() {} 338 func (s *PrintfStmt) stmt() {} 339 func (s *ExprStmt) stmt() {} 340 func (s *IfStmt) stmt() {} 341 func (s *ForStmt) stmt() {} 342 func (s *ForInStmt) stmt() {} 343 func (s *WhileStmt) stmt() {} 344 func (s *DoWhileStmt) stmt() {} 345 func (s *BreakStmt) stmt() {} 346 func (s *ContinueStmt) stmt() {} 347 func (s *NextStmt) stmt() {} 348 func (s *ExitStmt) stmt() {} 349 func (s *DeleteStmt) stmt() {} 350 func (s *ReturnStmt) stmt() {} 351 func (s *BlockStmt) stmt() {} 352 353 // Print statement like print $1, $3. 354 type PrintStmt struct { 355 Args []Expr 356 Redirect Token 357 Dest Expr 358 } 359 360 func (s *PrintStmt) String() string { 361 return printString("print", s.Args, s.Redirect, s.Dest) 362 } 363 364 func printString(f string, args []Expr, redirect Token, dest Expr) string { 365 parts := make([]string, len(args)) 366 for i, a := range args { 367 parts[i] = a.String() 368 } 369 str := f + " " + strings.Join(parts, ", ") 370 if dest != nil { 371 str += " " + redirect.String() + dest.String() 372 } 373 return str 374 } 375 376 // Printf statement like printf "%3d", 1234. 377 type PrintfStmt struct { 378 Args []Expr 379 Redirect Token 380 Dest Expr 381 } 382 383 func (s *PrintfStmt) String() string { 384 return printString("printf", s.Args, s.Redirect, s.Dest) 385 } 386 387 // Expression statement like a bare function call: my_func(x). 388 type ExprStmt struct { 389 Expr Expr 390 } 391 392 func (s *ExprStmt) String() string { 393 return s.Expr.String() 394 } 395 396 // If or if-else statement. 397 type IfStmt struct { 398 Cond Expr 399 Body Stmts 400 Else Stmts 401 } 402 403 func (s *IfStmt) String() string { 404 str := "if (" + trimParens(s.Cond.String()) + ") {\n" + s.Body.String() + "}" 405 if len(s.Else) > 0 { 406 str += " else {\n" + s.Else.String() + "}" 407 } 408 return str 409 } 410 411 // C-like for loop: for (i=0; i<10; i++) print i. 412 type ForStmt struct { 413 Pre Stmt 414 Cond Expr 415 Post Stmt 416 Body Stmts 417 } 418 419 func (s *ForStmt) String() string { 420 preStr := "" 421 if s.Pre != nil { 422 preStr = s.Pre.String() 423 } 424 condStr := "" 425 if s.Cond != nil { 426 condStr = " " + trimParens(s.Cond.String()) 427 } 428 postStr := "" 429 if s.Post != nil { 430 postStr = " " + s.Post.String() 431 } 432 return "for (" + preStr + ";" + condStr + ";" + postStr + ") {\n" + s.Body.String() + "}" 433 } 434 435 // For-in loop: for (k in a) print k, a[k]. 436 type ForInStmt struct { 437 Var *VarExpr 438 Array *ArrayExpr 439 Body Stmts 440 } 441 442 func (s *ForInStmt) String() string { 443 return "for (" + s.Var.String() + " in " + s.Array.String() + ") {\n" + s.Body.String() + "}" 444 } 445 446 // While loop. 447 type WhileStmt struct { 448 Cond Expr 449 Body Stmts 450 } 451 452 func (s *WhileStmt) String() string { 453 return "while (" + trimParens(s.Cond.String()) + ") {\n" + s.Body.String() + "}" 454 } 455 456 // Do-while loop. 457 type DoWhileStmt struct { 458 Body Stmts 459 Cond Expr 460 } 461 462 func (s *DoWhileStmt) String() string { 463 return "do {\n" + s.Body.String() + "} while (" + trimParens(s.Cond.String()) + ")" 464 } 465 466 // Break statement. 467 type BreakStmt struct{} 468 469 func (s *BreakStmt) String() string { 470 return "break" 471 } 472 473 // Continue statement. 474 type ContinueStmt struct{} 475 476 func (s *ContinueStmt) String() string { 477 return "continue" 478 } 479 480 // Next statement. 481 type NextStmt struct{} 482 483 func (s *NextStmt) String() string { 484 return "next" 485 } 486 487 // Exit statement. 488 type ExitStmt struct { 489 Status Expr 490 } 491 492 func (s *ExitStmt) String() string { 493 var statusStr string 494 if s.Status != nil { 495 statusStr = " " + s.Status.String() 496 } 497 return "exit" + statusStr 498 } 499 500 // Delete statement like delete a[k]. 501 type DeleteStmt struct { 502 Array *ArrayExpr 503 Index []Expr 504 } 505 506 func (s *DeleteStmt) String() string { 507 indices := make([]string, len(s.Index)) 508 for i, index := range s.Index { 509 indices[i] = index.String() 510 } 511 return "delete " + s.Array.String() + "[" + strings.Join(indices, ", ") + "]" 512 } 513 514 // Return statement. 515 type ReturnStmt struct { 516 Value Expr 517 } 518 519 func (s *ReturnStmt) String() string { 520 var valueStr string 521 if s.Value != nil { 522 valueStr = " " + s.Value.String() 523 } 524 return "return" + valueStr 525 } 526 527 // Stand-alone block like { print "x" }. 528 type BlockStmt struct { 529 Body Stmts 530 } 531 532 func (s *BlockStmt) String() string { 533 return "{\n" + s.Body.String() + "}" 534 } 535 536 // Function is the AST for a user-defined function. 537 type Function struct { 538 Name string 539 Params []string 540 Arrays []bool 541 Body Stmts 542 } 543 544 func (f *Function) String() string { 545 return "function " + f.Name + "(" + strings.Join(f.Params, ", ") + ") {\n" + 546 f.Body.String() + "}" 547 } 548 549 func trimParens(s string) string { 550 if strings.HasPrefix(s, "(") && strings.HasSuffix(s, ")") { 551 s = s[1 : len(s)-1] 552 } 553 return s 554 }