• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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