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  }