github.com/guardangely/gopher-lua@v0.0.0-20200324075529-f92e6f279f59/parse/parser.go.y (about) 1 %{ 2 package parse 3 4 import ( 5 "github.com/guardangely/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 $$ = $2 400 $$.SetLine($1.Pos.Line) 401 } 402 403 afunctioncall: 404 '(' functioncall ')' { 405 $2.(*ast.FuncCallExpr).AdjustRet = true 406 $$ = $2 407 } 408 409 functioncall: 410 prefixexp args { 411 $$ = &ast.FuncCallExpr{Func: $1, Args: $2} 412 $$.SetLine($1.Line()) 413 } | 414 prefixexp ':' TIdent args { 415 $$ = &ast.FuncCallExpr{Method: $3.Str, Receiver: $1, Args: $4} 416 $$.SetLine($1.Line()) 417 } 418 419 args: 420 '(' ')' { 421 if yylex.(*Lexer).PNewLine { 422 yylex.(*Lexer).TokenError($1, "ambiguous syntax (function call x new statement)") 423 } 424 $$ = []ast.Expr{} 425 } | 426 '(' exprlist ')' { 427 if yylex.(*Lexer).PNewLine { 428 yylex.(*Lexer).TokenError($1, "ambiguous syntax (function call x new statement)") 429 } 430 $$ = $2 431 } | 432 tableconstructor { 433 $$ = []ast.Expr{$1} 434 } | 435 string { 436 $$ = []ast.Expr{$1} 437 } 438 439 function: 440 TFunction funcbody { 441 $$ = &ast.FunctionExpr{ParList:$2.ParList, Stmts: $2.Stmts} 442 $$.SetLine($1.Pos.Line) 443 $$.SetLastLine($2.LastLine()) 444 } 445 446 funcbody: 447 '(' parlist ')' block TEnd { 448 $$ = &ast.FunctionExpr{ParList: $2, Stmts: $4} 449 $$.SetLine($1.Pos.Line) 450 $$.SetLastLine($5.Pos.Line) 451 } | 452 '(' ')' block TEnd { 453 $$ = &ast.FunctionExpr{ParList: &ast.ParList{HasVargs: false, Names: []string{}}, Stmts: $3} 454 $$.SetLine($1.Pos.Line) 455 $$.SetLastLine($4.Pos.Line) 456 } 457 458 parlist: 459 T3Comma { 460 $$ = &ast.ParList{HasVargs: true, Names: []string{}} 461 } | 462 namelist { 463 $$ = &ast.ParList{HasVargs: false, Names: []string{}} 464 $$.Names = append($$.Names, $1...) 465 } | 466 namelist ',' T3Comma { 467 $$ = &ast.ParList{HasVargs: true, Names: []string{}} 468 $$.Names = append($$.Names, $1...) 469 } 470 471 472 tableconstructor: 473 '{' '}' { 474 $$ = &ast.TableExpr{Fields: []*ast.Field{}} 475 $$.SetLine($1.Pos.Line) 476 } | 477 '{' fieldlist '}' { 478 $$ = &ast.TableExpr{Fields: $2} 479 $$.SetLine($1.Pos.Line) 480 } 481 482 483 fieldlist: 484 field { 485 $$ = []*ast.Field{$1} 486 } | 487 fieldlist fieldsep field { 488 $$ = append($1, $3) 489 } | 490 fieldlist fieldsep { 491 $$ = $1 492 } 493 494 field: 495 TIdent '=' expr { 496 $$ = &ast.Field{Key: &ast.StringExpr{Value:$1.Str}, Value: $3} 497 $$.Key.SetLine($1.Pos.Line) 498 } | 499 '[' expr ']' '=' expr { 500 $$ = &ast.Field{Key: $2, Value: $5} 501 } | 502 expr { 503 $$ = &ast.Field{Value: $1} 504 } 505 506 fieldsep: 507 ',' { 508 $$ = "," 509 } | 510 ';' { 511 $$ = ";" 512 } 513 514 %% 515 516 func TokenName(c int) string { 517 if c >= TAnd && c-TAnd < len(yyToknames) { 518 if yyToknames[c-TAnd] != "" { 519 return yyToknames[c-TAnd] 520 } 521 } 522 return string([]byte{byte(c)}) 523 } 524