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