github.com/dfcfw/lua@v0.0.0-20230325031207-0cc7ffb7b8b9/parse/parser.go.y (about)

     1  %{
     2  package parse
     3  
     4  import "github.com/dfcfw/lua/ast"
     5  %}
     6  %type<stmts> chunk
     7  %type<stmts> chunk1
     8  %type<stmts> block
     9  %type<stmt>  stat
    10  %type<stmts> elseifs
    11  %type<stmt>  laststat
    12  %type<funcname> funcname
    13  %type<funcname> funcname1
    14  %type<exprlist> varlist
    15  %type<expr> var
    16  %type<namelist> namelist
    17  %type<exprlist> exprlist
    18  %type<expr> expr
    19  %type<expr> string
    20  %type<expr> prefixexp
    21  %type<expr> functioncall
    22  %type<expr> afunctioncall
    23  %type<exprlist> args
    24  %type<expr> function
    25  %type<funcexpr> funcbody
    26  %type<parlist> parlist
    27  %type<expr> tableconstructor
    28  %type<fieldlist> fieldlist
    29  %type<field> field
    30  %type<fieldsep> fieldsep
    31  
    32  %union {
    33    token  ast.Token
    34  
    35    stmts    []ast.Stmt
    36    stmt     ast.Stmt
    37  
    38    funcname *ast.FuncName
    39    funcexpr *ast.FunctionExpr
    40  
    41    exprlist []ast.Expr
    42    expr   ast.Expr
    43  
    44    fieldlist []*ast.Field
    45    field     *ast.Field
    46    fieldsep  string
    47  
    48    namelist []string
    49    parlist  *ast.ParList
    50  }
    51  
    52  /* Reserved words */
    53  %token<token> TAnd TBreak TDo TElse TElseIf TEnd TFalse TFor TFunction TIf TIn TLocal TNil TNot TOr TReturn TRepeat TThen TTrue TUntil TWhile TGoto
    54  
    55  /* Literals */
    56  %token<token> TEqeq TNeq TLte TGte T2Comma T3Comma T2Colon TIdent TNumber TString '{' '('
    57  
    58  /* Operators */
    59  %left TOr
    60  %left TAnd
    61  %left '>' '<' TGte TLte TEqeq TNeq
    62  %right T2Comma
    63  %left '+' '-'
    64  %left '*' '/' '%'
    65  %right UNARY /* not # -(unary) */
    66  %right '^'
    67  
    68  %%
    69  
    70  chunk: 
    71          chunk1 {
    72              $$ = $1
    73              if l, ok := yylex.(*Lexer); ok {
    74                  l.Stmts = $$
    75              }
    76          } |
    77          chunk1 laststat {
    78              $$ = append($1, $2)
    79              if l, ok := yylex.(*Lexer); ok {
    80                  l.Stmts = $$
    81              }
    82          } | 
    83          chunk1 laststat ';' {
    84              $$ = append($1, $2)
    85              if l, ok := yylex.(*Lexer); ok {
    86                  l.Stmts = $$
    87              }
    88          }
    89  
    90  chunk1: 
    91          {
    92              $$ = []ast.Stmt{}
    93          } |
    94          chunk1 stat {
    95              $$ = append($1, $2)
    96          } | 
    97          chunk1 ';' {
    98              $$ = $1
    99          }
   100  
   101  block: 
   102          chunk {
   103              $$ = $1
   104          }
   105  
   106  stat:
   107          varlist '=' exprlist {
   108              $$ = &ast.AssignStmt{Lhs: $1, Rhs: $3}
   109              $$.SetLine($1[0].Line())
   110          } |
   111          /* 'stat = functioncal' causes a reduce/reduce conflict */
   112          prefixexp {
   113              if _, ok := $1.(*ast.FuncCallExpr); !ok {
   114                 yylex.(*Lexer).Error("parse error")
   115              } else {
   116                $$ = &ast.FuncCallStmt{Expr: $1}
   117                $$.SetLine($1.Line())
   118              }
   119          } |
   120          TDo block TEnd {
   121              $$ = &ast.DoBlockStmt{Stmts: $2}
   122              $$.SetLine($1.Pos.Line)
   123              $$.SetLastLine($3.Pos.Line)
   124          } |
   125          TWhile expr TDo block TEnd {
   126              $$ = &ast.WhileStmt{Condition: $2, Stmts: $4}
   127              $$.SetLine($1.Pos.Line)
   128              $$.SetLastLine($5.Pos.Line)
   129          } |
   130          TRepeat block TUntil expr {
   131              $$ = &ast.RepeatStmt{Condition: $4, Stmts: $2}
   132              $$.SetLine($1.Pos.Line)
   133              $$.SetLastLine($4.Line())
   134          } |
   135          TIf expr TThen block elseifs TEnd {
   136              $$ = &ast.IfStmt{Condition: $2, Then: $4}
   137              cur := $$
   138              for _, elseif := range $5 {
   139                  cur.(*ast.IfStmt).Else = []ast.Stmt{elseif}
   140                  cur = elseif
   141              }
   142              $$.SetLine($1.Pos.Line)
   143              $$.SetLastLine($6.Pos.Line)
   144          } |
   145          TIf expr TThen block elseifs TElse block TEnd {
   146              $$ = &ast.IfStmt{Condition: $2, Then: $4}
   147              cur := $$
   148              for _, elseif := range $5 {
   149                  cur.(*ast.IfStmt).Else = []ast.Stmt{elseif}
   150                  cur = elseif
   151              }
   152              cur.(*ast.IfStmt).Else = $7
   153              $$.SetLine($1.Pos.Line)
   154              $$.SetLastLine($8.Pos.Line)
   155          } |
   156          TFor TIdent '=' expr ',' expr TDo block TEnd {
   157              $$ = &ast.NumberForStmt{Name: $2.Str, Init: $4, Limit: $6, Stmts: $8}
   158              $$.SetLine($1.Pos.Line)
   159              $$.SetLastLine($9.Pos.Line)
   160          } |
   161          TFor TIdent '=' expr ',' expr ',' expr TDo block TEnd {
   162              $$ = &ast.NumberForStmt{Name: $2.Str, Init: $4, Limit: $6, Step:$8, Stmts: $10}
   163              $$.SetLine($1.Pos.Line)
   164              $$.SetLastLine($11.Pos.Line)
   165          } |
   166          TFor namelist TIn exprlist TDo block TEnd {
   167              $$ = &ast.GenericForStmt{Names:$2, Exprs:$4, Stmts: $6}
   168              $$.SetLine($1.Pos.Line)
   169              $$.SetLastLine($7.Pos.Line)
   170          } |
   171          TFunction funcname funcbody {
   172              $$ = &ast.FuncDefStmt{Name: $2, Func: $3}
   173              $$.SetLine($1.Pos.Line)
   174              $$.SetLastLine($3.LastLine())
   175          } |
   176          TLocal TFunction TIdent funcbody {
   177              $$ = &ast.LocalAssignStmt{Names:[]string{$3.Str}, Exprs: []ast.Expr{$4}}
   178              $$.SetLine($1.Pos.Line)
   179              $$.SetLastLine($4.LastLine())
   180          } | 
   181          TLocal namelist '=' exprlist {
   182              $$ = &ast.LocalAssignStmt{Names: $2, Exprs:$4}
   183              $$.SetLine($1.Pos.Line)
   184          } |
   185          TLocal namelist {
   186              $$ = &ast.LocalAssignStmt{Names: $2, Exprs:[]ast.Expr{}}
   187              $$.SetLine($1.Pos.Line)
   188          } |
   189          T2Colon TIdent T2Colon {
   190              $$ = &ast.LabelStmt{Name: $2.Str}
   191              $$.SetLine($1.Pos.Line)
   192          } |
   193          TGoto TIdent {
   194              $$ = &ast.GotoStmt{Label: $2.Str}
   195              $$.SetLine($1.Pos.Line)
   196          }
   197  
   198  elseifs: 
   199          {
   200              $$ = []ast.Stmt{}
   201          } | 
   202          elseifs TElseIf expr TThen block {
   203              $$ = append($1, &ast.IfStmt{Condition: $3, Then: $5})
   204              $$[len($$)-1].SetLine($2.Pos.Line)
   205          }
   206  
   207  laststat:
   208          TReturn {
   209              $$ = &ast.ReturnStmt{Exprs:nil}
   210              $$.SetLine($1.Pos.Line)
   211          } |
   212          TReturn exprlist {
   213              $$ = &ast.ReturnStmt{Exprs:$2}
   214              $$.SetLine($1.Pos.Line)
   215          } |
   216          TBreak  {
   217              $$ = &ast.BreakStmt{}
   218              $$.SetLine($1.Pos.Line)
   219          }
   220  
   221  funcname: 
   222          funcname1 {
   223              $$ = $1
   224          } |
   225          funcname1 ':' TIdent {
   226              $$ = &ast.FuncName{Func:nil, Receiver:$1.Func, Method: $3.Str}
   227          }
   228  
   229  funcname1:
   230          TIdent {
   231              $$ = &ast.FuncName{Func: &ast.IdentExpr{Value:$1.Str}}
   232              $$.Func.SetLine($1.Pos.Line)
   233          } | 
   234          funcname1 '.' TIdent {
   235              key:= &ast.StringExpr{Value:$3.Str}
   236              key.SetLine($3.Pos.Line)
   237              fn := &ast.AttrGetExpr{Object: $1.Func, Key: key}
   238              fn.SetLine($3.Pos.Line)
   239              $$ = &ast.FuncName{Func: fn}
   240          }
   241  
   242  varlist:
   243          var {
   244              $$ = []ast.Expr{$1}
   245          } | 
   246          varlist ',' var {
   247              $$ = append($1, $3)
   248          }
   249  
   250  var:
   251          TIdent {
   252              $$ = &ast.IdentExpr{Value:$1.Str}
   253              $$.SetLine($1.Pos.Line)
   254          } |
   255          prefixexp '[' expr ']' {
   256              $$ = &ast.AttrGetExpr{Object: $1, Key: $3}
   257              $$.SetLine($1.Line())
   258          } | 
   259          prefixexp '.' TIdent {
   260              key := &ast.StringExpr{Value:$3.Str}
   261              key.SetLine($3.Pos.Line)
   262              $$ = &ast.AttrGetExpr{Object: $1, Key: key}
   263              $$.SetLine($1.Line())
   264          }
   265  
   266  namelist:
   267          TIdent {
   268              $$ = []string{$1.Str}
   269          } | 
   270          namelist ','  TIdent {
   271              $$ = append($1, $3.Str)
   272          }
   273  
   274  exprlist:
   275          expr {
   276              $$ = []ast.Expr{$1}
   277          } |
   278          exprlist ',' expr {
   279              $$ = append($1, $3)
   280          }
   281  
   282  expr:
   283          TNil {
   284              $$ = &ast.NilExpr{}
   285              $$.SetLine($1.Pos.Line)
   286          } | 
   287          TFalse {
   288              $$ = &ast.FalseExpr{}
   289              $$.SetLine($1.Pos.Line)
   290          } | 
   291          TTrue {
   292              $$ = &ast.TrueExpr{}
   293              $$.SetLine($1.Pos.Line)
   294          } | 
   295          TNumber {
   296              $$ = &ast.NumberExpr{Value: $1.Str}
   297              $$.SetLine($1.Pos.Line)
   298          } | 
   299          T3Comma {
   300              $$ = &ast.Comma3Expr{}
   301              $$.SetLine($1.Pos.Line)
   302          } |
   303          function {
   304              $$ = $1
   305          } | 
   306          prefixexp {
   307              $$ = $1
   308          } |
   309          string {
   310              $$ = $1
   311          } |
   312          tableconstructor {
   313              $$ = $1
   314          } |
   315          expr TOr expr {
   316              $$ = &ast.LogicalOpExpr{Lhs: $1, Operator: "or", Rhs: $3}
   317              $$.SetLine($1.Line())
   318          } |
   319          expr TAnd expr {
   320              $$ = &ast.LogicalOpExpr{Lhs: $1, Operator: "and", Rhs: $3}
   321              $$.SetLine($1.Line())
   322          } |
   323          expr '>' expr {
   324              $$ = &ast.RelationalOpExpr{Lhs: $1, Operator: ">", Rhs: $3}
   325              $$.SetLine($1.Line())
   326          } |
   327          expr '<' expr {
   328              $$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "<", Rhs: $3}
   329              $$.SetLine($1.Line())
   330          } |
   331          expr TGte expr {
   332              $$ = &ast.RelationalOpExpr{Lhs: $1, Operator: ">=", Rhs: $3}
   333              $$.SetLine($1.Line())
   334          } |
   335          expr TLte expr {
   336              $$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "<=", Rhs: $3}
   337              $$.SetLine($1.Line())
   338          } |
   339          expr TEqeq expr {
   340              $$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "==", Rhs: $3}
   341              $$.SetLine($1.Line())
   342          } |
   343          expr TNeq expr {
   344              $$ = &ast.RelationalOpExpr{Lhs: $1, Operator: "~=", Rhs: $3}
   345              $$.SetLine($1.Line())
   346          } |
   347          expr T2Comma expr {
   348              $$ = &ast.StringConcatOpExpr{Lhs: $1, Rhs: $3}
   349              $$.SetLine($1.Line())
   350          } |
   351          expr '+' expr {
   352              $$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "+", Rhs: $3}
   353              $$.SetLine($1.Line())
   354          } |
   355          expr '-' expr {
   356              $$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "-", Rhs: $3}
   357              $$.SetLine($1.Line())
   358          } |
   359          expr '*' expr {
   360              $$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "*", Rhs: $3}
   361              $$.SetLine($1.Line())
   362          } |
   363          expr '/' expr {
   364              $$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "/", Rhs: $3}
   365              $$.SetLine($1.Line())
   366          } |
   367          expr '%' expr {
   368              $$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "%", Rhs: $3}
   369              $$.SetLine($1.Line())
   370          } |
   371          expr '^' expr {
   372              $$ = &ast.ArithmeticOpExpr{Lhs: $1, Operator: "^", Rhs: $3}
   373              $$.SetLine($1.Line())
   374          } |
   375          '-' expr %prec UNARY {
   376              $$ = &ast.UnaryMinusOpExpr{Expr: $2}
   377              $$.SetLine($2.Line())
   378          } |
   379          TNot expr %prec UNARY {
   380              $$ = &ast.UnaryNotOpExpr{Expr: $2}
   381              $$.SetLine($2.Line())
   382          } |
   383          '#' expr %prec UNARY {
   384              $$ = &ast.UnaryLenOpExpr{Expr: $2}
   385              $$.SetLine($2.Line())
   386          }
   387  
   388  string: 
   389          TString {
   390              $$ = &ast.StringExpr{Value: $1.Str}
   391              $$.SetLine($1.Pos.Line)
   392          } 
   393  
   394  prefixexp:
   395          var {
   396              $$ = $1
   397          } |
   398          afunctioncall {
   399              $$ = $1
   400          } |
   401          functioncall {
   402              $$ = $1
   403          } |
   404          '(' expr ')' {
   405              if ex, ok := $2.(*ast.Comma3Expr); ok {
   406                  ex.AdjustRet = true
   407              }
   408              $$ = $2
   409              $$.SetLine($1.Pos.Line)
   410          }
   411  
   412  afunctioncall:
   413          '(' functioncall ')' {
   414              $2.(*ast.FuncCallExpr).AdjustRet = true
   415              $$ = $2
   416          }
   417  
   418  functioncall:
   419          prefixexp args {
   420              $$ = &ast.FuncCallExpr{Func: $1, Args: $2}
   421              $$.SetLine($1.Line())
   422          } |
   423          prefixexp ':' TIdent args {
   424              $$ = &ast.FuncCallExpr{Method: $3.Str, Receiver: $1, Args: $4}
   425              $$.SetLine($1.Line())
   426          }
   427  
   428  args:
   429          '(' ')' {
   430              if yylex.(*Lexer).PNewLine {
   431                 yylex.(*Lexer).TokenError($1, "ambiguous syntax (function call x new statement)")
   432              }
   433              $$ = []ast.Expr{}
   434          } |
   435          '(' exprlist ')' {
   436              if yylex.(*Lexer).PNewLine {
   437                 yylex.(*Lexer).TokenError($1, "ambiguous syntax (function call x new statement)")
   438              }
   439              $$ = $2
   440          } |
   441          tableconstructor {
   442              $$ = []ast.Expr{$1}
   443          } | 
   444          string {
   445              $$ = []ast.Expr{$1}
   446          }
   447  
   448  function:
   449          TFunction funcbody {
   450              $$ = &ast.FunctionExpr{ParList:$2.ParList, Stmts: $2.Stmts}
   451              $$.SetLine($1.Pos.Line)
   452              $$.SetLastLine($2.LastLine())
   453          }
   454  
   455  funcbody:
   456          '(' parlist ')' block TEnd {
   457              $$ = &ast.FunctionExpr{ParList: $2, Stmts: $4}
   458              $$.SetLine($1.Pos.Line)
   459              $$.SetLastLine($5.Pos.Line)
   460          } | 
   461          '(' ')' block TEnd {
   462              $$ = &ast.FunctionExpr{ParList: &ast.ParList{HasVargs: false, Names: []string{}}, Stmts: $3}
   463              $$.SetLine($1.Pos.Line)
   464              $$.SetLastLine($4.Pos.Line)
   465          }
   466  
   467  parlist:
   468          T3Comma {
   469              $$ = &ast.ParList{HasVargs: true, Names: []string{}}
   470          } | 
   471          namelist {
   472            $$ = &ast.ParList{HasVargs: false, Names: []string{}}
   473            $$.Names = append($$.Names, $1...)
   474          } | 
   475          namelist ',' T3Comma {
   476            $$ = &ast.ParList{HasVargs: true, Names: []string{}}
   477            $$.Names = append($$.Names, $1...)
   478          }
   479  
   480  
   481  tableconstructor:
   482          '{' '}' {
   483              $$ = &ast.TableExpr{Fields: []*ast.Field{}}
   484              $$.SetLine($1.Pos.Line)
   485          } |
   486          '{' fieldlist '}' {
   487              $$ = &ast.TableExpr{Fields: $2}
   488              $$.SetLine($1.Pos.Line)
   489          }
   490  
   491  
   492  fieldlist:
   493          field {
   494              $$ = []*ast.Field{$1}
   495          } | 
   496          fieldlist fieldsep field {
   497              $$ = append($1, $3)
   498          } | 
   499          fieldlist fieldsep {
   500              $$ = $1
   501          }
   502  
   503  field:
   504          TIdent '=' expr {
   505              $$ = &ast.Field{Key: &ast.StringExpr{Value:$1.Str}, Value: $3}
   506              $$.Key.SetLine($1.Pos.Line)
   507          } | 
   508          '[' expr ']' '=' expr {
   509              $$ = &ast.Field{Key: $2, Value: $5}
   510          } |
   511          expr {
   512              $$ = &ast.Field{Value: $1}
   513          }
   514  
   515  fieldsep:
   516          ',' {
   517              $$ = ","
   518          } | 
   519          ';' {
   520              $$ = ";"
   521          }
   522  
   523  %%
   524  
   525  func TokenName(c int) string {
   526  	if c >= TAnd && c-TAnd < len(yyToknames) {
   527  		if yyToknames[c-TAnd] != "" {
   528  			return yyToknames[c-TAnd]
   529  		}
   530  	}
   531      return string([]byte{byte(c)})
   532  }
   533