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