expr.go (18493B)
1 // Copyright 2020 The Ebiten Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package shader 16 17 import ( 18 "fmt" 19 "go/ast" 20 gconstant "go/constant" 21 "go/token" 22 "regexp" 23 "strconv" 24 25 "github.com/hajimehoshi/ebiten/v2/internal/shaderir" 26 ) 27 28 func canTruncateToInteger(v gconstant.Value) bool { 29 return gconstant.ToInt(v).Kind() != gconstant.Unknown 30 } 31 32 var textureVariableRe = regexp.MustCompile(`\A__t(\d+)\z`) 33 34 func (cs *compileState) parseExpr(block *block, expr ast.Expr, markLocalVariableUsed bool) ([]shaderir.Expr, []shaderir.Type, []shaderir.Stmt, bool) { 35 switch e := expr.(type) { 36 case *ast.BasicLit: 37 switch e.Kind { 38 case token.INT: 39 return []shaderir.Expr{ 40 { 41 Type: shaderir.NumberExpr, 42 Const: gconstant.MakeFromLiteral(e.Value, e.Kind, 0), 43 }, 44 }, []shaderir.Type{{Main: shaderir.Int}}, nil, true 45 case token.FLOAT: 46 return []shaderir.Expr{ 47 { 48 Type: shaderir.NumberExpr, 49 Const: gconstant.MakeFromLiteral(e.Value, e.Kind, 0), 50 }, 51 }, []shaderir.Type{{Main: shaderir.Float}}, nil, true 52 default: 53 cs.addError(e.Pos(), fmt.Sprintf("literal not implemented: %#v", e)) 54 } 55 56 case *ast.BinaryExpr: 57 var stmts []shaderir.Stmt 58 59 // Prase LHS first for the order of the statements. 60 lhs, ts, ss, ok := cs.parseExpr(block, e.X, markLocalVariableUsed) 61 if !ok { 62 return nil, nil, nil, false 63 } 64 if len(lhs) != 1 { 65 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a binary operator: %s", e.X)) 66 return nil, nil, nil, false 67 } 68 stmts = append(stmts, ss...) 69 lhst := ts[0] 70 71 rhs, ts, ss, ok := cs.parseExpr(block, e.Y, markLocalVariableUsed) 72 if !ok { 73 return nil, nil, nil, false 74 } 75 if len(rhs) != 1 { 76 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a binary operator: %s", e.Y)) 77 return nil, nil, nil, false 78 } 79 stmts = append(stmts, ss...) 80 rhst := ts[0] 81 82 if lhs[0].Type == shaderir.NumberExpr && rhs[0].Type == shaderir.NumberExpr { 83 op := e.Op 84 // https://golang.org/pkg/go/constant/#BinaryOp 85 // "To force integer division of Int operands, use op == token.QUO_ASSIGN instead of 86 // token.QUO; the result is guaranteed to be Int in this case." 87 if op == token.QUO && lhs[0].Const.Kind() == gconstant.Int && rhs[0].Const.Kind() == gconstant.Int { 88 op = token.QUO_ASSIGN 89 } 90 var v gconstant.Value 91 var t shaderir.Type 92 switch op { 93 case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ: 94 v = gconstant.MakeBool(gconstant.Compare(lhs[0].Const, op, rhs[0].Const)) 95 t = shaderir.Type{Main: shaderir.Bool} 96 default: 97 v = gconstant.BinaryOp(lhs[0].Const, op, rhs[0].Const) 98 if v.Kind() == gconstant.Float { 99 t = shaderir.Type{Main: shaderir.Float} 100 } else { 101 t = shaderir.Type{Main: shaderir.Int} 102 } 103 } 104 105 return []shaderir.Expr{ 106 { 107 Type: shaderir.NumberExpr, 108 Const: v, 109 }, 110 }, []shaderir.Type{t}, stmts, true 111 } 112 113 op, ok := shaderir.OpFromToken(e.Op) 114 if !ok { 115 cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op)) 116 return nil, nil, nil, false 117 } 118 119 var t shaderir.Type 120 switch { 121 case op == shaderir.LessThanOp || op == shaderir.LessThanEqualOp || op == shaderir.GreaterThanOp || op == shaderir.GreaterThanEqualOp || op == shaderir.EqualOp || op == shaderir.NotEqualOp || op == shaderir.AndAnd || op == shaderir.OrOr: 122 t = shaderir.Type{Main: shaderir.Bool} 123 case lhs[0].Type == shaderir.NumberExpr && rhs[0].Type != shaderir.NumberExpr: 124 if rhst.Main == shaderir.Int { 125 if !canTruncateToInteger(lhs[0].Const) { 126 cs.addError(e.Pos(), fmt.Sprintf("constant %s truncated to integer", lhs[0].Const.String())) 127 return nil, nil, nil, false 128 } 129 lhs[0].ConstType = shaderir.ConstTypeInt 130 } 131 t = rhst 132 case lhs[0].Type != shaderir.NumberExpr && rhs[0].Type == shaderir.NumberExpr: 133 if lhst.Main == shaderir.Int { 134 if !canTruncateToInteger(rhs[0].Const) { 135 cs.addError(e.Pos(), fmt.Sprintf("constant %s truncated to integer", rhs[0].Const.String())) 136 return nil, nil, nil, false 137 } 138 rhs[0].ConstType = shaderir.ConstTypeInt 139 } 140 t = lhst 141 case lhst.Equal(&rhst): 142 t = lhst 143 case lhst.Main == shaderir.Float || lhst.Main == shaderir.Int: 144 switch rhst.Main { 145 case shaderir.Int: 146 t = lhst 147 case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4, shaderir.Mat2, shaderir.Mat3, shaderir.Mat4: 148 t = rhst 149 default: 150 cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String())) 151 return nil, nil, nil, false 152 } 153 case rhst.Main == shaderir.Float || rhst.Main == shaderir.Int: 154 switch lhst.Main { 155 case shaderir.Int: 156 t = rhst 157 case shaderir.Float, shaderir.Vec2, shaderir.Vec3, shaderir.Vec4, shaderir.Mat2, shaderir.Mat3, shaderir.Mat4: 158 t = lhst 159 default: 160 cs.addError(e.Pos(), fmt.Sprintf("types don't match: %s %s %s", lhst.String(), e.Op, rhst.String())) 161 return nil, nil, nil, false 162 } 163 case lhst.Main == shaderir.Vec2 && rhst.Main == shaderir.Mat2 || 164 lhst.Main == shaderir.Mat2 && rhst.Main == shaderir.Vec2: 165 t = shaderir.Type{Main: shaderir.Vec2} 166 case lhst.Main == shaderir.Vec3 && rhst.Main == shaderir.Mat3 || 167 lhst.Main == shaderir.Mat3 && rhst.Main == shaderir.Vec3: 168 t = shaderir.Type{Main: shaderir.Vec3} 169 case lhst.Main == shaderir.Vec4 && rhst.Main == shaderir.Mat4 || 170 lhst.Main == shaderir.Mat4 && rhst.Main == shaderir.Vec4: 171 t = shaderir.Type{Main: shaderir.Vec4} 172 default: 173 cs.addError(e.Pos(), fmt.Sprintf("invalid expression: %s %s %s", lhst.String(), e.Op, rhst.String())) 174 return nil, nil, nil, false 175 } 176 177 return []shaderir.Expr{ 178 { 179 Type: shaderir.Binary, 180 Op: op, 181 Exprs: []shaderir.Expr{lhs[0], rhs[0]}, 182 }, 183 }, []shaderir.Type{t}, stmts, true 184 185 case *ast.CallExpr: 186 var ( 187 callee shaderir.Expr 188 args []shaderir.Expr 189 argts []shaderir.Type 190 stmts []shaderir.Stmt 191 ) 192 193 // Parse the argument first for the order of the statements. 194 for _, a := range e.Args { 195 es, ts, ss, ok := cs.parseExpr(block, a, markLocalVariableUsed) 196 if !ok { 197 return nil, nil, nil, false 198 } 199 if len(es) > 1 && len(e.Args) > 1 { 200 cs.addError(e.Pos(), fmt.Sprintf("single-value context and multiple-value context cannot be mixed: %s", e.Fun)) 201 return nil, nil, nil, false 202 } 203 args = append(args, es...) 204 argts = append(argts, ts...) 205 stmts = append(stmts, ss...) 206 } 207 208 // TODO: When len(ss) is not 0? 209 es, _, ss, ok := cs.parseExpr(block, e.Fun, markLocalVariableUsed) 210 if !ok { 211 return nil, nil, nil, false 212 } 213 if len(es) != 1 { 214 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a callee: %s", e.Fun)) 215 return nil, nil, nil, false 216 } 217 callee = es[0] 218 stmts = append(stmts, ss...) 219 220 // For built-in functions, we can call this in this position. Return an expression for the function 221 // call. 222 if callee.Type == shaderir.BuiltinFuncExpr { 223 if callee.BuiltinFunc == shaderir.Len || callee.BuiltinFunc == shaderir.Cap { 224 if len(args) != 1 { 225 cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 1 but %d", callee.BuiltinFunc, len(args))) 226 return nil, nil, nil, false 227 } 228 if argts[0].Main != shaderir.Array { 229 cs.addError(e.Pos(), fmt.Sprintf("%s takes an array but %s", callee.BuiltinFunc, argts[0].String())) 230 return nil, nil, nil, false 231 } 232 return []shaderir.Expr{ 233 { 234 Type: shaderir.NumberExpr, 235 Const: gconstant.MakeInt64(int64(argts[0].Length)), 236 ConstType: shaderir.ConstTypeInt, 237 }, 238 }, []shaderir.Type{{Main: shaderir.Int}}, stmts, true 239 } 240 241 var t shaderir.Type 242 switch callee.BuiltinFunc { 243 case shaderir.BoolF: 244 t = shaderir.Type{Main: shaderir.Bool} 245 case shaderir.IntF: 246 t = shaderir.Type{Main: shaderir.Int} 247 case shaderir.FloatF: 248 t = shaderir.Type{Main: shaderir.Float} 249 case shaderir.Vec2F: 250 t = shaderir.Type{Main: shaderir.Vec2} 251 case shaderir.Vec3F: 252 t = shaderir.Type{Main: shaderir.Vec3} 253 case shaderir.Vec4F: 254 t = shaderir.Type{Main: shaderir.Vec4} 255 case shaderir.Mat2F: 256 t = shaderir.Type{Main: shaderir.Mat2} 257 case shaderir.Mat3F: 258 t = shaderir.Type{Main: shaderir.Mat3} 259 case shaderir.Mat4F: 260 t = shaderir.Type{Main: shaderir.Mat4} 261 case shaderir.Step: 262 t = argts[1] 263 case shaderir.Smoothstep: 264 t = argts[2] 265 case shaderir.Length, shaderir.Distance, shaderir.Dot: 266 t = shaderir.Type{Main: shaderir.Float} 267 case shaderir.Cross: 268 t = shaderir.Type{Main: shaderir.Vec3} 269 case shaderir.Texture2DF: 270 t = shaderir.Type{Main: shaderir.Vec4} 271 default: 272 t = argts[0] 273 } 274 return []shaderir.Expr{ 275 { 276 Type: shaderir.Call, 277 Exprs: append([]shaderir.Expr{callee}, args...), 278 }, 279 }, []shaderir.Type{t}, stmts, true 280 } 281 282 if callee.Type != shaderir.FunctionExpr { 283 cs.addError(e.Pos(), fmt.Sprintf("function callee must be a funciton name but %s", e.Fun)) 284 return nil, nil, nil, false 285 } 286 287 f := cs.funcs[callee.Index] 288 289 for i, p := range f.ir.InParams { 290 if args[i].Type == shaderir.NumberExpr && p.Main == shaderir.Int { 291 if !cs.forceToInt(e, &args[i]) { 292 return nil, nil, nil, false 293 } 294 } 295 } 296 297 var outParams []int 298 for _, p := range f.ir.OutParams { 299 idx := block.totalLocalVariableNum() 300 block.vars = append(block.vars, variable{ 301 typ: p, 302 }) 303 args = append(args, shaderir.Expr{ 304 Type: shaderir.LocalVariable, 305 Index: idx, 306 }) 307 outParams = append(outParams, idx) 308 } 309 310 if t := f.ir.Return; t.Main != shaderir.None { 311 if len(outParams) != 0 { 312 cs.addError(e.Pos(), fmt.Sprintf("a function returning value cannot have out-params so far: %s", e.Fun)) 313 return nil, nil, nil, false 314 } 315 316 idx := block.totalLocalVariableNum() 317 block.vars = append(block.vars, variable{ 318 typ: t, 319 }) 320 321 // Calling the function should be done eariler to treat out-params correctly. 322 stmts = append(stmts, shaderir.Stmt{ 323 Type: shaderir.Assign, 324 Exprs: []shaderir.Expr{ 325 { 326 Type: shaderir.LocalVariable, 327 Index: idx, 328 }, 329 { 330 Type: shaderir.Call, 331 Exprs: append([]shaderir.Expr{callee}, args...), 332 }, 333 }, 334 }) 335 336 // The actual expression here is just a local variable that includes the result of the 337 // function call. 338 return []shaderir.Expr{ 339 { 340 Type: shaderir.LocalVariable, 341 Index: idx, 342 }, 343 }, []shaderir.Type{t}, stmts, true 344 } 345 346 // Even if the function doesn't return anything, calling the function should be done eariler to keep 347 // the evaluation order. 348 stmts = append(stmts, shaderir.Stmt{ 349 Type: shaderir.ExprStmt, 350 Exprs: []shaderir.Expr{ 351 { 352 Type: shaderir.Call, 353 Exprs: append([]shaderir.Expr{callee}, args...), 354 }, 355 }, 356 }) 357 358 if len(outParams) == 0 { 359 // TODO: Is this an error? 360 } 361 362 var exprs []shaderir.Expr 363 for _, p := range outParams { 364 exprs = append(exprs, shaderir.Expr{ 365 Type: shaderir.LocalVariable, 366 Index: p, 367 }) 368 } 369 return exprs, f.ir.OutParams, stmts, true 370 371 case *ast.Ident: 372 if e.Name == "_" { 373 // In the context where a local variable is marked as used, any expressions must have its 374 // meaning. Then, a blank identifier is not available there. 375 if markLocalVariableUsed { 376 cs.addError(e.Pos(), fmt.Sprintf("cannot use _ as value")) 377 return nil, nil, nil, false 378 } 379 return []shaderir.Expr{ 380 { 381 Type: shaderir.Blank, 382 }, 383 }, []shaderir.Type{{}}, nil, true 384 } 385 if i, t, ok := block.findLocalVariable(e.Name, markLocalVariableUsed); ok { 386 return []shaderir.Expr{ 387 { 388 Type: shaderir.LocalVariable, 389 Index: i, 390 }, 391 }, []shaderir.Type{t}, nil, true 392 } 393 if c, ok := block.findConstant(e.Name); ok { 394 return []shaderir.Expr{ 395 { 396 Type: shaderir.NumberExpr, 397 Const: c.value, 398 ConstType: c.ctyp, 399 }, 400 }, []shaderir.Type{c.typ}, nil, true 401 } 402 if i, ok := cs.findFunction(e.Name); ok { 403 return []shaderir.Expr{ 404 { 405 Type: shaderir.FunctionExpr, 406 Index: i, 407 }, 408 }, nil, nil, true 409 } 410 if i, ok := cs.findUniformVariable(e.Name); ok { 411 return []shaderir.Expr{ 412 { 413 Type: shaderir.UniformVariable, 414 Index: i, 415 }, 416 }, []shaderir.Type{cs.ir.Uniforms[i]}, nil, true 417 } 418 if f, ok := shaderir.ParseBuiltinFunc(e.Name); ok { 419 return []shaderir.Expr{ 420 { 421 Type: shaderir.BuiltinFuncExpr, 422 BuiltinFunc: f, 423 }, 424 }, nil, nil, true 425 } 426 if m := textureVariableRe.FindStringSubmatch(e.Name); m != nil { 427 i, _ := strconv.Atoi(m[1]) 428 return []shaderir.Expr{ 429 { 430 Type: shaderir.TextureVariable, 431 Index: i, 432 }, 433 }, nil, nil, true 434 } 435 if e.Name == "true" || e.Name == "false" { 436 return []shaderir.Expr{ 437 { 438 Type: shaderir.NumberExpr, 439 Const: gconstant.MakeBool(e.Name == "true"), 440 }, 441 }, []shaderir.Type{{Main: shaderir.Bool}}, nil, true 442 } 443 cs.addError(e.Pos(), fmt.Sprintf("unexpected identifier: %s", e.Name)) 444 445 case *ast.ParenExpr: 446 return cs.parseExpr(block, e.X, markLocalVariableUsed) 447 448 case *ast.SelectorExpr: 449 exprs, _, stmts, ok := cs.parseExpr(block, e.X, true) 450 if !ok { 451 return nil, nil, nil, false 452 } 453 if len(exprs) != 1 { 454 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a selector: %s", e.X)) 455 return nil, nil, nil, false 456 } 457 var t shaderir.Type 458 switch len(e.Sel.Name) { 459 case 1: 460 t.Main = shaderir.Float 461 case 2: 462 t.Main = shaderir.Vec2 463 case 3: 464 t.Main = shaderir.Vec3 465 case 4: 466 t.Main = shaderir.Vec4 467 default: 468 cs.addError(e.Pos(), fmt.Sprintf("unexpected swizzling: %s", e.Sel.Name)) 469 return nil, nil, nil, false 470 } 471 return []shaderir.Expr{ 472 { 473 Type: shaderir.FieldSelector, 474 Exprs: []shaderir.Expr{ 475 exprs[0], 476 { 477 Type: shaderir.SwizzlingExpr, 478 Swizzling: e.Sel.Name, 479 }, 480 }, 481 }, 482 }, []shaderir.Type{t}, stmts, true 483 484 case *ast.UnaryExpr: 485 exprs, t, stmts, ok := cs.parseExpr(block, e.X, markLocalVariableUsed) 486 if !ok { 487 return nil, nil, nil, false 488 } 489 if len(exprs) != 1 { 490 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a unary operator: %s", e.X)) 491 return nil, nil, nil, false 492 } 493 494 if exprs[0].Type == shaderir.NumberExpr { 495 v := gconstant.UnaryOp(e.Op, exprs[0].Const, 0) 496 t := shaderir.Type{Main: shaderir.Int} 497 if v.Kind() == gconstant.Float { 498 t = shaderir.Type{Main: shaderir.Float} 499 } 500 return []shaderir.Expr{ 501 { 502 Type: shaderir.NumberExpr, 503 Const: v, 504 }, 505 }, []shaderir.Type{t}, stmts, true 506 } 507 508 var op shaderir.Op 509 switch e.Op { 510 case token.ADD: 511 op = shaderir.Add 512 case token.SUB: 513 op = shaderir.Sub 514 case token.NOT: 515 op = shaderir.NotOp 516 default: 517 cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op)) 518 return nil, nil, nil, false 519 } 520 return []shaderir.Expr{ 521 { 522 Type: shaderir.Unary, 523 Op: op, 524 Exprs: exprs, 525 }, 526 }, t, stmts, true 527 528 case *ast.CompositeLit: 529 t, ok := cs.parseType(block, e.Type) 530 if !ok { 531 return nil, nil, nil, false 532 } 533 if t.Main == shaderir.Array && t.Length == -1 { 534 t.Length = len(e.Elts) 535 } 536 537 idx := block.totalLocalVariableNum() 538 block.vars = append(block.vars, variable{ 539 typ: t, 540 }) 541 542 var stmts []shaderir.Stmt 543 for i, e := range e.Elts { 544 exprs, _, ss, ok := cs.parseExpr(block, e, markLocalVariableUsed) 545 if !ok { 546 return nil, nil, nil, false 547 } 548 if len(exprs) != 1 { 549 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a composite literal")) 550 return nil, nil, nil, false 551 } 552 stmts = append(stmts, ss...) 553 stmts = append(stmts, shaderir.Stmt{ 554 Type: shaderir.Assign, 555 Exprs: []shaderir.Expr{ 556 { 557 Type: shaderir.Index, 558 Exprs: []shaderir.Expr{ 559 { 560 Type: shaderir.LocalVariable, 561 Index: idx, 562 }, 563 { 564 Type: shaderir.NumberExpr, 565 Const: gconstant.MakeInt64(int64(i)), 566 ConstType: shaderir.ConstTypeInt, 567 }, 568 }, 569 }, 570 exprs[0], 571 }, 572 }) 573 } 574 575 return []shaderir.Expr{ 576 { 577 Type: shaderir.LocalVariable, 578 Index: idx, 579 }, 580 }, []shaderir.Type{t}, stmts, true 581 582 case *ast.IndexExpr: 583 var stmts []shaderir.Stmt 584 585 // Parse the index first 586 exprs, _, ss, ok := cs.parseExpr(block, e.Index, markLocalVariableUsed) 587 if !ok { 588 return nil, nil, nil, false 589 } 590 stmts = append(stmts, ss...) 591 592 if len(exprs) != 1 { 593 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at an index expression")) 594 return nil, nil, nil, false 595 } 596 idx := exprs[0] 597 if idx.Type == shaderir.NumberExpr { 598 if !canTruncateToInteger(idx.Const) { 599 cs.addError(e.Pos(), fmt.Sprintf("constant %s truncated to integer", idx.Const.String())) 600 return nil, nil, nil, false 601 } 602 idx.ConstType = shaderir.ConstTypeInt 603 } 604 605 exprs, ts, ss, ok := cs.parseExpr(block, e.X, markLocalVariableUsed) 606 if !ok { 607 return nil, nil, nil, false 608 } 609 stmts = append(stmts, ss...) 610 if len(exprs) != 1 { 611 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at an index expression")) 612 return nil, nil, nil, false 613 } 614 x := exprs[0] 615 t := ts[0] 616 617 var typ shaderir.Type 618 switch t.Main { 619 case shaderir.Vec2, shaderir.Vec3, shaderir.Vec4: 620 typ = shaderir.Type{Main: shaderir.Float} 621 case shaderir.Mat2: 622 typ = shaderir.Type{Main: shaderir.Vec2} 623 case shaderir.Mat3: 624 typ = shaderir.Type{Main: shaderir.Vec3} 625 case shaderir.Mat4: 626 typ = shaderir.Type{Main: shaderir.Vec4} 627 case shaderir.Array: 628 typ = t.Sub[0] 629 default: 630 cs.addError(e.Pos(), fmt.Sprintf("index operator cannot be applied to the type %s", t.String())) 631 return nil, nil, nil, false 632 } 633 634 return []shaderir.Expr{ 635 { 636 Type: shaderir.Index, 637 Exprs: []shaderir.Expr{ 638 x, 639 idx, 640 }, 641 }, 642 }, []shaderir.Type{typ}, stmts, true 643 644 default: 645 cs.addError(e.Pos(), fmt.Sprintf("expression not implemented: %#v", e)) 646 } 647 return nil, nil, nil, false 648 }