expr.go (18200B)
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 { 224 if len(args) != 1 { 225 cs.addError(e.Pos(), fmt.Sprintf("number of len's arguments must be 1 but %d", len(args))) 226 return nil, nil, nil, false 227 } 228 if argts[0].Main != shaderir.Array { 229 cs.addError(e.Pos(), fmt.Sprintf("len takes an array but %s", 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 i, ok := cs.findFunction(e.Name); ok { 394 return []shaderir.Expr{ 395 { 396 Type: shaderir.FunctionExpr, 397 Index: i, 398 }, 399 }, nil, nil, true 400 } 401 if i, ok := cs.findUniformVariable(e.Name); ok { 402 return []shaderir.Expr{ 403 { 404 Type: shaderir.UniformVariable, 405 Index: i, 406 }, 407 }, []shaderir.Type{cs.ir.Uniforms[i]}, nil, true 408 } 409 if f, ok := shaderir.ParseBuiltinFunc(e.Name); ok { 410 return []shaderir.Expr{ 411 { 412 Type: shaderir.BuiltinFuncExpr, 413 BuiltinFunc: f, 414 }, 415 }, nil, nil, true 416 } 417 if m := textureVariableRe.FindStringSubmatch(e.Name); m != nil { 418 i, _ := strconv.Atoi(m[1]) 419 return []shaderir.Expr{ 420 { 421 Type: shaderir.TextureVariable, 422 Index: i, 423 }, 424 }, nil, nil, true 425 } 426 if e.Name == "true" || e.Name == "false" { 427 return []shaderir.Expr{ 428 { 429 Type: shaderir.NumberExpr, 430 Const: gconstant.MakeBool(e.Name == "true"), 431 }, 432 }, []shaderir.Type{{Main: shaderir.Bool}}, nil, true 433 } 434 cs.addError(e.Pos(), fmt.Sprintf("unexpected identifier: %s", e.Name)) 435 436 case *ast.ParenExpr: 437 return cs.parseExpr(block, e.X, markLocalVariableUsed) 438 439 case *ast.SelectorExpr: 440 exprs, _, stmts, ok := cs.parseExpr(block, e.X, true) 441 if !ok { 442 return nil, nil, nil, false 443 } 444 if len(exprs) != 1 { 445 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a selector: %s", e.X)) 446 return nil, nil, nil, false 447 } 448 var t shaderir.Type 449 switch len(e.Sel.Name) { 450 case 1: 451 t.Main = shaderir.Float 452 case 2: 453 t.Main = shaderir.Vec2 454 case 3: 455 t.Main = shaderir.Vec3 456 case 4: 457 t.Main = shaderir.Vec4 458 default: 459 cs.addError(e.Pos(), fmt.Sprintf("unexpected swizzling: %s", e.Sel.Name)) 460 return nil, nil, nil, false 461 } 462 return []shaderir.Expr{ 463 { 464 Type: shaderir.FieldSelector, 465 Exprs: []shaderir.Expr{ 466 exprs[0], 467 { 468 Type: shaderir.SwizzlingExpr, 469 Swizzling: e.Sel.Name, 470 }, 471 }, 472 }, 473 }, []shaderir.Type{t}, stmts, true 474 475 case *ast.UnaryExpr: 476 exprs, t, stmts, ok := cs.parseExpr(block, e.X, markLocalVariableUsed) 477 if !ok { 478 return nil, nil, nil, false 479 } 480 if len(exprs) != 1 { 481 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a unary operator: %s", e.X)) 482 return nil, nil, nil, false 483 } 484 485 if exprs[0].Type == shaderir.NumberExpr { 486 v := gconstant.UnaryOp(e.Op, exprs[0].Const, 0) 487 t := shaderir.Type{Main: shaderir.Int} 488 if v.Kind() == gconstant.Float { 489 t = shaderir.Type{Main: shaderir.Float} 490 } 491 return []shaderir.Expr{ 492 { 493 Type: shaderir.NumberExpr, 494 Const: v, 495 }, 496 }, []shaderir.Type{t}, stmts, true 497 } 498 499 var op shaderir.Op 500 switch e.Op { 501 case token.ADD: 502 op = shaderir.Add 503 case token.SUB: 504 op = shaderir.Sub 505 case token.NOT: 506 op = shaderir.NotOp 507 default: 508 cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op)) 509 return nil, nil, nil, false 510 } 511 return []shaderir.Expr{ 512 { 513 Type: shaderir.Unary, 514 Op: op, 515 Exprs: exprs, 516 }, 517 }, t, stmts, true 518 519 case *ast.CompositeLit: 520 t, ok := cs.parseType(block, e.Type) 521 if !ok { 522 return nil, nil, nil, false 523 } 524 if t.Main == shaderir.Array && t.Length == -1 { 525 t.Length = len(e.Elts) 526 } 527 528 idx := block.totalLocalVariableNum() 529 block.vars = append(block.vars, variable{ 530 typ: t, 531 }) 532 533 var stmts []shaderir.Stmt 534 for i, e := range e.Elts { 535 exprs, _, ss, ok := cs.parseExpr(block, e, markLocalVariableUsed) 536 if !ok { 537 return nil, nil, nil, false 538 } 539 if len(exprs) != 1 { 540 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a composite literal")) 541 return nil, nil, nil, false 542 } 543 stmts = append(stmts, ss...) 544 stmts = append(stmts, shaderir.Stmt{ 545 Type: shaderir.Assign, 546 Exprs: []shaderir.Expr{ 547 { 548 Type: shaderir.Index, 549 Exprs: []shaderir.Expr{ 550 { 551 Type: shaderir.LocalVariable, 552 Index: idx, 553 }, 554 { 555 Type: shaderir.NumberExpr, 556 Const: gconstant.MakeInt64(int64(i)), 557 ConstType: shaderir.ConstTypeInt, 558 }, 559 }, 560 }, 561 exprs[0], 562 }, 563 }) 564 } 565 566 return []shaderir.Expr{ 567 { 568 Type: shaderir.LocalVariable, 569 Index: idx, 570 }, 571 }, []shaderir.Type{t}, stmts, true 572 573 case *ast.IndexExpr: 574 var stmts []shaderir.Stmt 575 576 // Parse the index first 577 exprs, _, ss, ok := cs.parseExpr(block, e.Index, markLocalVariableUsed) 578 if !ok { 579 return nil, nil, nil, false 580 } 581 stmts = append(stmts, ss...) 582 583 if len(exprs) != 1 { 584 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at an index expression")) 585 return nil, nil, nil, false 586 } 587 idx := exprs[0] 588 if idx.Type == shaderir.NumberExpr { 589 if !canTruncateToInteger(idx.Const) { 590 cs.addError(e.Pos(), fmt.Sprintf("constant %s truncated to integer", idx.Const.String())) 591 return nil, nil, nil, false 592 } 593 idx.ConstType = shaderir.ConstTypeInt 594 } 595 596 exprs, ts, ss, ok := cs.parseExpr(block, e.X, markLocalVariableUsed) 597 if !ok { 598 return nil, nil, nil, false 599 } 600 stmts = append(stmts, ss...) 601 if len(exprs) != 1 { 602 cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at an index expression")) 603 return nil, nil, nil, false 604 } 605 x := exprs[0] 606 t := ts[0] 607 608 var typ shaderir.Type 609 switch t.Main { 610 case shaderir.Vec2, shaderir.Vec3, shaderir.Vec4: 611 typ = shaderir.Type{Main: shaderir.Float} 612 case shaderir.Mat2: 613 typ = shaderir.Type{Main: shaderir.Vec2} 614 case shaderir.Mat3: 615 typ = shaderir.Type{Main: shaderir.Vec3} 616 case shaderir.Mat4: 617 typ = shaderir.Type{Main: shaderir.Vec4} 618 case shaderir.Array: 619 typ = t.Sub[0] 620 default: 621 cs.addError(e.Pos(), fmt.Sprintf("index operator cannot be applied to the type %s", t.String())) 622 return nil, nil, nil, false 623 } 624 625 return []shaderir.Expr{ 626 { 627 Type: shaderir.Index, 628 Exprs: []shaderir.Expr{ 629 x, 630 idx, 631 }, 632 }, 633 }, []shaderir.Type{typ}, stmts, true 634 635 default: 636 cs.addError(e.Pos(), fmt.Sprintf("expression not implemented: %#v", e)) 637 } 638 return nil, nil, nil, false 639 }