1// Copyright 2021 The Tint 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 15package resolver 16 17import ( 18 "fmt" 19 "sort" 20 21 "dawn.googlesource.com/tint/tools/src/cmd/intrinsic-gen/ast" 22 "dawn.googlesource.com/tint/tools/src/cmd/intrinsic-gen/sem" 23 "dawn.googlesource.com/tint/tools/src/cmd/intrinsic-gen/tok" 24) 25 26type resolver struct { 27 a *ast.AST 28 s *sem.Sem 29 30 globals scope 31 functions map[string]*sem.Function 32 enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher 33} 34 35// Resolve processes the AST 36func Resolve(a *ast.AST) (*sem.Sem, error) { 37 r := resolver{ 38 a: a, 39 s: sem.New(), 40 globals: newScope(nil), 41 functions: map[string]*sem.Function{}, 42 enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{}, 43 } 44 // Declare and resolve all the enumerators 45 for _, e := range a.Enums { 46 if err := r.enum(e); err != nil { 47 return nil, err 48 } 49 } 50 // Declare and resolve all the ty types 51 for _, p := range a.Types { 52 if err := r.ty(p); err != nil { 53 return nil, err 54 } 55 } 56 // Declare and resolve the type matchers 57 for _, m := range a.Matchers { 58 if err := r.matcher(m); err != nil { 59 return nil, err 60 } 61 } 62 // Declare and resolve the functions 63 for _, f := range a.Functions { 64 if err := r.function(f); err != nil { 65 return nil, err 66 } 67 } 68 69 // Calculate the unique parameter names 70 r.s.UniqueParameterNames = r.calculateUniqueParameterNames() 71 72 return r.s, nil 73} 74 75// enum() resolves an enum declaration. 76// The resulting sem.Enum is appended to Sem.Enums, and the enum and all its 77// entries are registered with the global scope. 78func (r *resolver) enum(e ast.EnumDecl) error { 79 s := &sem.Enum{ 80 Decl: e, 81 Name: e.Name, 82 } 83 84 // Register the enum 85 r.s.Enums = append(r.s.Enums, s) 86 if err := r.globals.declare(s, e.Source); err != nil { 87 return err 88 } 89 90 // Register each of the enum entries 91 for _, ast := range e.Entries { 92 entry := &sem.EnumEntry{ 93 Name: ast.Name, 94 Enum: s, 95 } 96 if internal := ast.Decorations.Take("internal"); internal != nil { 97 entry.IsInternal = true 98 if len(internal.Values) != 0 { 99 return fmt.Errorf("%v unexpected value for internal decoration", ast.Source) 100 } 101 } 102 if len(ast.Decorations) != 0 { 103 return fmt.Errorf("%v unknown decoration", ast.Decorations[0].Source) 104 } 105 if err := r.globals.declare(entry, e.Source); err != nil { 106 return err 107 } 108 s.Entries = append(s.Entries, entry) 109 } 110 111 return nil 112} 113 114// ty() resolves a type declaration. 115// The resulting sem.Type is appended to Sem.Types, and the type is registered 116// with the global scope. 117func (r *resolver) ty(a ast.TypeDecl) error { 118 t := &sem.Type{ 119 Decl: a, 120 Name: a.Name, 121 } 122 123 // Register the type 124 r.s.Types = append(r.s.Types, t) 125 if err := r.globals.declare(t, a.Source); err != nil { 126 return err 127 } 128 129 // Create a new scope for resolving template parameters 130 s := newScope(&r.globals) 131 132 // Resolve the type template parameters 133 templateParams, err := r.templateParams(&s, a.TemplateParams) 134 if err != nil { 135 return err 136 } 137 t.TemplateParams = templateParams 138 139 // Scan for decorations 140 if d := a.Decorations.Take("display"); d != nil { 141 if len(d.Values) != 1 { 142 return fmt.Errorf("%v expected a single value for 'display' decoration", d.Source) 143 } 144 t.DisplayName = d.Values[0] 145 } 146 if len(a.Decorations) != 0 { 147 return fmt.Errorf("%v unknown decoration", a.Decorations[0].Source) 148 } 149 150 return nil 151} 152 153// matcher() resolves a match declaration to either a sem.TypeMatcher or 154// sem.EnumMatcher. 155// The resulting matcher is appended to either Sem.TypeMatchers or 156// Sem.EnumMatchers, and is registered with the global scope. 157func (r *resolver) matcher(a ast.MatcherDecl) error { 158 // Determine whether this is a type matcher or enum matcher by resolving the 159 // first option 160 firstOption, err := r.lookupNamed(&r.globals, a.Options[0]) 161 if err != nil { 162 return err 163 } 164 165 // Resolve to a sem.TypeMatcher or a sem.EnumMatcher 166 switch firstOption := firstOption.(type) { 167 case *sem.Type: 168 options := map[sem.Named]tok.Source{} 169 m := &sem.TypeMatcher{ 170 Decl: a, 171 Name: a.Name, 172 } 173 174 // Register the matcher 175 r.s.TypeMatchers = append(r.s.TypeMatchers, m) 176 if err := r.globals.declare(m, a.Source); err != nil { 177 return err 178 } 179 180 // Resolve each of the types in the options list 181 for _, ast := range m.Decl.Options { 182 ty, err := r.lookupType(&r.globals, ast) 183 if err != nil { 184 return err 185 } 186 m.Types = append(m.Types, ty) 187 if s, dup := options[ty]; dup { 188 return fmt.Errorf("%v duplicate option '%v' in matcher\nFirst declared here: %v", ast.Source, ast.Name, s) 189 } 190 options[ty] = ast.Source 191 } 192 193 return nil 194 195 case *sem.EnumEntry: 196 enum := firstOption.Enum 197 m := &sem.EnumMatcher{ 198 Decl: a, 199 Name: a.Name, 200 Enum: enum, 201 } 202 203 // Register the matcher 204 r.s.EnumMatchers = append(r.s.EnumMatchers, m) 205 if err := r.globals.declare(m, a.Source); err != nil { 206 return err 207 } 208 209 // Resolve each of the enums in the options list 210 for _, ast := range m.Decl.Options { 211 entry := enum.FindEntry(ast.Name) 212 if entry == nil { 213 return fmt.Errorf("%v enum '%v' does not contain '%v'", ast.Source, enum.Name, ast.Name) 214 } 215 m.Options = append(m.Options, entry) 216 } 217 218 return nil 219 } 220 return fmt.Errorf("'%v' cannot be used for matcher", a.Name) 221} 222 223// function() resolves a function overload declaration. 224// The the first overload for the function creates and appends the sem.Function 225// to Sem.Functions. Subsequent overloads append their resolved overload to the 226// sem.Function.Overloads list. 227func (r *resolver) function(a ast.FunctionDecl) error { 228 // If this is the first overload of the function, create and register the 229 // semantic function. 230 f := r.functions[a.Name] 231 if f == nil { 232 f = &sem.Function{Name: a.Name} 233 r.functions[a.Name] = f 234 r.s.Functions = append(r.s.Functions, f) 235 } 236 237 // Create a new scope for resolving template parameters 238 s := newScope(&r.globals) 239 240 // Resolve the declared template parameters 241 templateParams, err := r.templateParams(&s, a.TemplateParams) 242 if err != nil { 243 return err 244 } 245 246 // Construct the semantic overload 247 overload := &sem.Overload{ 248 Decl: a, 249 Function: f, 250 Parameters: make([]sem.Parameter, len(a.Parameters)), 251 TemplateParams: templateParams, 252 } 253 254 // Process overload decorations 255 if stageDeco := a.Decorations.Take("stage"); stageDeco != nil { 256 for stageDeco != nil { 257 for _, stage := range stageDeco.Values { 258 switch stage { 259 case "vertex": 260 overload.CanBeUsedInStage.Vertex = true 261 case "fragment": 262 overload.CanBeUsedInStage.Fragment = true 263 case "compute": 264 overload.CanBeUsedInStage.Compute = true 265 default: 266 return fmt.Errorf("%v unknown stage '%v'", stageDeco.Source, stage) 267 } 268 } 269 stageDeco = a.Decorations.Take("stage") 270 } 271 } else { 272 overload.CanBeUsedInStage = sem.StageUses{ 273 Vertex: true, 274 Fragment: true, 275 Compute: true, 276 } 277 } 278 if deprecated := a.Decorations.Take("deprecated"); deprecated != nil { 279 overload.IsDeprecated = true 280 if len(deprecated.Values) != 0 { 281 return fmt.Errorf("%v unexpected value for deprecated decoration", deprecated.Source) 282 } 283 } 284 if len(a.Decorations) != 0 { 285 return fmt.Errorf("%v unknown decoration", a.Decorations[0].Source) 286 } 287 288 // Append the overload to the function 289 f.Overloads = append(f.Overloads, overload) 290 291 // Sort the template parameters by resolved type. Append these to 292 // sem.Overload.OpenTypes or sem.Overload.OpenNumbers based on their kind. 293 for _, param := range templateParams { 294 switch param := param.(type) { 295 case *sem.TemplateTypeParam: 296 overload.OpenTypes = append(overload.OpenTypes, param) 297 case *sem.TemplateEnumParam, *sem.TemplateNumberParam: 298 overload.OpenNumbers = append(overload.OpenNumbers, param) 299 } 300 } 301 302 // Update high-water marks of open types / numbers 303 if r.s.MaxOpenTypes < len(overload.OpenTypes) { 304 r.s.MaxOpenTypes = len(overload.OpenTypes) 305 } 306 if r.s.MaxOpenNumbers < len(overload.OpenNumbers) { 307 r.s.MaxOpenNumbers = len(overload.OpenNumbers) 308 } 309 310 // Resolve the parameters 311 for i, p := range a.Parameters { 312 usage, err := r.fullyQualifiedName(&s, p.Type) 313 if err != nil { 314 return err 315 } 316 overload.Parameters[i] = sem.Parameter{ 317 Name: p.Name, 318 Type: usage, 319 } 320 } 321 322 // Resolve the return type 323 if a.ReturnType != nil { 324 usage, err := r.fullyQualifiedName(&s, *a.ReturnType) 325 if err != nil { 326 return err 327 } 328 switch usage.Target.(type) { 329 case *sem.Type, *sem.TemplateTypeParam: 330 overload.ReturnType = &usage 331 default: 332 return fmt.Errorf("%v cannot use '%v' as return type. Must be a type or template type", a.ReturnType.Source, a.ReturnType.Name) 333 } 334 } 335 336 return nil 337} 338 339// fullyQualifiedName() resolves the ast.TemplatedName to a sem.FullyQualifiedName. 340func (r *resolver) fullyQualifiedName(s *scope, arg ast.TemplatedName) (sem.FullyQualifiedName, error) { 341 target, err := r.lookupNamed(s, arg) 342 if err != nil { 343 return sem.FullyQualifiedName{}, err 344 } 345 346 if entry, ok := target.(*sem.EnumEntry); ok { 347 // The target resolved to an enum entry. 348 // Automagically transform this into a synthetic matcher with a single 349 // option. i.e. 350 // This: 351 // enum E{ a b c } 352 // fn F(b) 353 // Becomes: 354 // enum E{ a b c } 355 // matcher b 356 // fn F(b) 357 // We don't really care right now that we have a symbol collision 358 // between E.b and b, as the generators return different names for 359 // these. 360 matcher, ok := r.enumEntryMatchers[entry] 361 if !ok { 362 matcher = &sem.EnumMatcher{ 363 Name: entry.Name, 364 Enum: entry.Enum, 365 Options: []*sem.EnumEntry{entry}, 366 } 367 r.enumEntryMatchers[entry] = matcher 368 r.s.EnumMatchers = append(r.s.EnumMatchers, matcher) 369 } 370 target = matcher 371 } 372 373 fqn := sem.FullyQualifiedName{ 374 Target: target, 375 TemplateArguments: make([]interface{}, len(arg.TemplateArgs)), 376 } 377 for i, a := range arg.TemplateArgs { 378 arg, err := r.fullyQualifiedName(s, a) 379 if err != nil { 380 return sem.FullyQualifiedName{}, err 381 } 382 fqn.TemplateArguments[i] = arg 383 } 384 return fqn, nil 385} 386 387// templateParams() resolves the ast.TemplateParams into list of sem.TemplateParam. 388// Each sem.TemplateParam is registered with the scope s. 389func (r *resolver) templateParams(s *scope, l ast.TemplateParams) ([]sem.TemplateParam, error) { 390 out := []sem.TemplateParam{} 391 for _, ast := range l { 392 param, err := r.templateParam(ast) 393 if err != nil { 394 return nil, err 395 } 396 s.declare(param, ast.Source) 397 out = append(out, param) 398 } 399 return out, nil 400} 401 402// templateParams() resolves the ast.TemplateParam into sem.TemplateParam, which 403// is either a sem.TemplateEnumParam or a sem.TemplateTypeParam. 404func (r *resolver) templateParam(a ast.TemplateParam) (sem.TemplateParam, error) { 405 if a.Type.Name == "num" { 406 return &sem.TemplateNumberParam{Name: a.Name}, nil 407 } 408 409 if a.Type.Name != "" { 410 resolved, err := r.lookupNamed(&r.globals, a.Type) 411 if err != nil { 412 return nil, err 413 } 414 switch r := resolved.(type) { 415 case *sem.Enum: 416 return &sem.TemplateEnumParam{Name: a.Name, Enum: r}, nil 417 case *sem.EnumMatcher: 418 return &sem.TemplateEnumParam{Name: a.Name, Enum: r.Enum, Matcher: r}, nil 419 case *sem.TypeMatcher: 420 return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil 421 default: 422 return nil, fmt.Errorf("%v invalid template parameter type '%v'", a.Source, a.Type.Name) 423 } 424 } 425 426 return &sem.TemplateTypeParam{Name: a.Name}, nil 427} 428 429// lookupType() searches the scope `s` and its ancestors for the sem.Type with 430// the given name. 431func (r *resolver) lookupType(s *scope, a ast.TemplatedName) (*sem.Type, error) { 432 resolved, err := r.lookupNamed(s, a) 433 if err != nil { 434 return nil, err 435 } 436 // Something with the given name was found... 437 if ty, ok := resolved.(*sem.Type); ok { 438 return ty, nil 439 } 440 // ... but that something was not a sem.Type 441 return nil, fmt.Errorf("%v '%v' resolves to %v but type is expected", a.Source, a.Name, describe(resolved)) 442} 443 444// lookupNamed() searches `s` and its ancestors for the sem.Named object with 445// the given name. If there are template arguments for the name `a`, then 446// lookupNamed() performs basic validation that those arguments can be passed 447// to the named object. 448func (r *resolver) lookupNamed(s *scope, a ast.TemplatedName) (sem.Named, error) { 449 target := s.lookup(a.Name) 450 if target == nil { 451 return nil, fmt.Errorf("%v cannot resolve '%v'", a.Source, a.Name) 452 } 453 454 // Something with the given name was found... 455 var params []sem.TemplateParam 456 var ty sem.ResolvableType 457 switch target := target.object.(type) { 458 case *sem.Type: 459 ty = target 460 params = target.TemplateParams 461 case *sem.TypeMatcher: 462 ty = target 463 params = target.TemplateParams 464 case sem.TemplateParam: 465 if len(a.TemplateArgs) != 0 { 466 return nil, fmt.Errorf("%v '%v' template parameters do not accept template arguments", a.Source, a.Name) 467 } 468 return target.(sem.Named), nil 469 case sem.Named: 470 return target, nil 471 default: 472 panic(fmt.Errorf("Unknown resolved type %T", target)) 473 } 474 // ... and that something takes template parameters 475 // Check the number of templated name template arguments match the number of 476 // templated parameters for the target. 477 args := a.TemplateArgs 478 if len(params) != len(args) { 479 return nil, fmt.Errorf("%v '%v' requires %d template arguments, but %d were provided", a.Source, a.Name, len(params), len(args)) 480 } 481 482 // Check templated name template argument kinds match the parameter kinds 483 for i, ast := range args { 484 param := params[i] 485 arg, err := r.lookupNamed(s, args[i]) 486 if err != nil { 487 return nil, err 488 } 489 490 if err := checkCompatible(arg, param); err != nil { 491 return nil, fmt.Errorf("%v %w", ast.Source, err) 492 } 493 } 494 return ty, nil 495} 496 497// calculateUniqueParameterNames() iterates over all the parameters of all 498// overloads, calculating the list of unique parameter names 499func (r *resolver) calculateUniqueParameterNames() []string { 500 set := map[string]struct{}{"": {}} 501 names := []string{} 502 for _, f := range r.s.Functions { 503 for _, o := range f.Overloads { 504 for _, p := range o.Parameters { 505 if _, dup := set[p.Name]; !dup { 506 set[p.Name] = struct{}{} 507 names = append(names, p.Name) 508 } 509 } 510 } 511 } 512 sort.Strings(names) 513 return names 514} 515 516// describe() returns a string describing a sem.Named 517func describe(n sem.Named) string { 518 switch n := n.(type) { 519 case *sem.Type: 520 return "type '" + n.Name + "'" 521 case *sem.TypeMatcher: 522 return "type matcher '" + n.Name + "'" 523 case *sem.Enum: 524 return "enum '" + n.Name + "'" 525 case *sem.EnumMatcher: 526 return "enum matcher '" + n.Name + "'" 527 case *sem.TemplateTypeParam: 528 return "template type" 529 case *sem.TemplateEnumParam: 530 return "template enum '" + n.Enum.Name + "'" 531 case *sem.EnumEntry: 532 return "enum entry '" + n.Enum.Name + "." + n.Name + "'" 533 case *sem.TemplateNumberParam: 534 return "template number" 535 default: 536 panic(fmt.Errorf("unhandled type %T", n)) 537 } 538} 539 540// checkCompatible() returns an error if `arg` cannot be used as an argument for 541// a parameter of `param`. 542func checkCompatible(arg, param sem.Named) error { 543 // asEnum() returns the underlying sem.Enum if n is a enum matcher, 544 // templated enum parameter or an enum entry, otherwise nil 545 asEnum := func(n sem.Named) *sem.Enum { 546 switch n := n.(type) { 547 case *sem.EnumMatcher: 548 return n.Enum 549 case *sem.TemplateEnumParam: 550 return n.Enum 551 case *sem.EnumEntry: 552 return n.Enum 553 default: 554 return nil 555 } 556 } 557 558 if arg := asEnum(arg); arg != nil { 559 param := asEnum(param) 560 if arg == param { 561 return nil 562 } 563 } 564 565 anyNumber := "any number" 566 // asNumber() returns anyNumber if n is a TemplateNumberParam. 567 // TODO(bclayton): Once we support number ranges [e.g.: fn F<N: 1..4>()], we 568 // should check number ranges are compatible 569 asNumber := func(n sem.Named) interface{} { 570 switch n.(type) { 571 case *sem.TemplateNumberParam: 572 return anyNumber 573 default: 574 return nil 575 } 576 } 577 578 if arg := asNumber(arg); arg != nil { 579 param := asNumber(param) 580 if arg == param { 581 return nil 582 } 583 } 584 585 anyType := &sem.Type{} 586 // asNumber() returns the sem.Type, sem.TypeMatcher if the named object 587 // resolves to one of these, or anyType if n is a unconstrained template 588 // type parameter. 589 asResolvableType := func(n sem.Named) sem.ResolvableType { 590 switch n := n.(type) { 591 case *sem.TemplateTypeParam: 592 if n.Type != nil { 593 return n.Type 594 } 595 return anyType 596 case *sem.Type: 597 return n 598 case *sem.TypeMatcher: 599 return n 600 default: 601 return nil 602 } 603 } 604 605 if arg := asResolvableType(arg); arg != nil { 606 param := asResolvableType(param) 607 if arg == param || param == anyType { 608 return nil 609 } 610 } 611 612 return fmt.Errorf("cannot use %v as %v", describe(arg), describe(param)) 613} 614 615// scope is a basic hierarchical name to object table 616type scope struct { 617 objects map[string]objectAndSource 618 parent *scope 619} 620 621// objectAndSource is a sem.Named object with a source 622type objectAndSource struct { 623 object sem.Named 624 source tok.Source 625} 626 627// newScope returns a newly initalized scope 628func newScope(parent *scope) scope { 629 return scope{objects: map[string]objectAndSource{}, parent: parent} 630} 631 632// lookup() searches the scope and then its parents for the symbol with the 633// given name. 634func (s *scope) lookup(name string) *objectAndSource { 635 if o, found := s.objects[name]; found { 636 return &o 637 } 638 if s.parent == nil { 639 return nil 640 } 641 return s.parent.lookup(name) 642} 643 644// declare() declares the symbol with the given name, erroring on symbol 645// collision. 646func (s *scope) declare(object sem.Named, source tok.Source) error { 647 name := object.GetName() 648 if existing := s.lookup(name); existing != nil { 649 return fmt.Errorf("%v '%v' already declared\nFirst declared here: %v", source, name, existing.source) 650 } 651 s.objects[name] = objectAndSource{object, source} 652 return nil 653} 654