tint: Add type constructors and converters support to intrinsic-gen
These are currently not used, but the first step towards moving type constructors and converters over to using the intrinisc table. This will simplify maintenance of type functions, and will greatly simplify the [AbstractInt -> i32|u32] [AbstractFloat -> f32|f16] logic. Bug: tint:1504 Change-Id: I15526670a6ff801e66551ab5adc37b1570ac49de Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90242 Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
2b3dcf45b7
commit
5a69597698
|
@ -25,11 +25,13 @@ import (
|
||||||
|
|
||||||
// AST is the parsed syntax tree of the intrinsic definition file
|
// AST is the parsed syntax tree of the intrinsic definition file
|
||||||
type AST struct {
|
type AST struct {
|
||||||
Enums []EnumDecl
|
Enums []EnumDecl
|
||||||
Types []TypeDecl
|
Types []TypeDecl
|
||||||
Matchers []MatcherDecl
|
Matchers []MatcherDecl
|
||||||
Builtins []IntrinsicDecl
|
Builtins []IntrinsicDecl
|
||||||
Operators []IntrinsicDecl
|
Constructors []IntrinsicDecl
|
||||||
|
Converters []IntrinsicDecl
|
||||||
|
Operators []IntrinsicDecl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a AST) String() string {
|
func (a AST) String() string {
|
||||||
|
@ -50,6 +52,14 @@ func (a AST) String() string {
|
||||||
fmt.Fprintf(&sb, "%v", b)
|
fmt.Fprintf(&sb, "%v", b)
|
||||||
fmt.Fprintln(&sb)
|
fmt.Fprintln(&sb)
|
||||||
}
|
}
|
||||||
|
for _, o := range a.Constructors {
|
||||||
|
fmt.Fprintf(&sb, "%v", o)
|
||||||
|
fmt.Fprintln(&sb)
|
||||||
|
}
|
||||||
|
for _, o := range a.Converters {
|
||||||
|
fmt.Fprintf(&sb, "%v", o)
|
||||||
|
fmt.Fprintln(&sb)
|
||||||
|
}
|
||||||
for _, o := range a.Operators {
|
for _, o := range a.Operators {
|
||||||
fmt.Fprintf(&sb, "%v", o)
|
fmt.Fprintf(&sb, "%v", o)
|
||||||
fmt.Fprintln(&sb)
|
fmt.Fprintln(&sb)
|
||||||
|
@ -103,7 +113,7 @@ func (m MatcherDecl) Format(w fmt.State, verb rune) {
|
||||||
m.Options.Format(w, verb)
|
m.Options.Format(w, verb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntrinsicKind is either a Builtin or Operator
|
// IntrinsicKind is either a Builtin, Operator, Constructor or Converter
|
||||||
type IntrinsicKind string
|
type IntrinsicKind string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -113,6 +123,12 @@ const (
|
||||||
// Operator is a unary or binary operator.
|
// Operator is a unary or binary operator.
|
||||||
// Declared with 'op'.
|
// Declared with 'op'.
|
||||||
Operator IntrinsicKind = "operator"
|
Operator IntrinsicKind = "operator"
|
||||||
|
// Constructor is a type constructor function.
|
||||||
|
// Declared with 'ctor'.
|
||||||
|
Constructor IntrinsicKind = "constructor"
|
||||||
|
// Converter is a type conversion function.
|
||||||
|
// Declared with 'conv'.
|
||||||
|
Converter IntrinsicKind = "converter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IntrinsicDecl describes a builtin or operator declaration
|
// IntrinsicDecl describes a builtin or operator declaration
|
||||||
|
@ -133,6 +149,10 @@ func (i IntrinsicDecl) Format(w fmt.State, verb rune) {
|
||||||
fmt.Fprintf(w, "fn ")
|
fmt.Fprintf(w, "fn ")
|
||||||
case Operator:
|
case Operator:
|
||||||
fmt.Fprintf(w, "op ")
|
fmt.Fprintf(w, "op ")
|
||||||
|
case Constructor:
|
||||||
|
fmt.Fprintf(w, "ctor ")
|
||||||
|
case Converter:
|
||||||
|
fmt.Fprintf(w, "conv ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "%v", i.Name)
|
fmt.Fprintf(w, "%v", i.Name)
|
||||||
i.TemplateParams.Format(w, verb)
|
i.TemplateParams.Format(w, verb)
|
||||||
|
|
|
@ -37,14 +37,15 @@ type IntrinsicTable struct {
|
||||||
NMatchers []sem.Named
|
NMatchers []sem.Named
|
||||||
NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers
|
NMatcherIndex map[sem.Named]int // [object -> index] in NMatchers
|
||||||
|
|
||||||
MatcherIndices []int // kMatcherIndices table content
|
MatcherIndices []int // kMatcherIndices table content
|
||||||
OpenTypes []OpenType // kOpenTypes table content
|
OpenTypes []OpenType // kOpenTypes table content
|
||||||
OpenNumbers []OpenNumber // kOpenNumbers table content
|
OpenNumbers []OpenNumber // kOpenNumbers table content
|
||||||
Parameters []Parameter // kParameters table content
|
Parameters []Parameter // kParameters table content
|
||||||
Overloads []Overload // kOverloads table content
|
Overloads []Overload // kOverloads table content
|
||||||
Builtins []Intrinsic // kBuiltins table content
|
Builtins []Intrinsic // kBuiltins table content
|
||||||
UnaryOperators []Intrinsic // kUnaryOperators table content
|
UnaryOperators []Intrinsic // kUnaryOperators table content
|
||||||
BinaryOperators []Intrinsic // kBinaryOperators table content
|
BinaryOperators []Intrinsic // kBinaryOperators table content
|
||||||
|
ConstructorsAndConverters []Intrinsic // kConstructorsAndConverters table content
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenType is used to create the C++ OpenTypeInfo structure
|
// OpenType is used to create the C++ OpenTypeInfo structure
|
||||||
|
@ -372,6 +373,7 @@ func buildIntrinsicTable(s *sem.Sem) (*IntrinsicTable, error) {
|
||||||
{s.Builtins, &b.Builtins},
|
{s.Builtins, &b.Builtins},
|
||||||
{s.UnaryOperators, &b.UnaryOperators},
|
{s.UnaryOperators, &b.UnaryOperators},
|
||||||
{s.BinaryOperators, &b.BinaryOperators},
|
{s.BinaryOperators, &b.BinaryOperators},
|
||||||
|
{s.ConstructorsAndConverters, &b.ConstructorsAndConverters},
|
||||||
} {
|
} {
|
||||||
out := make([]Intrinsic, len(intrinsics.in))
|
out := make([]Intrinsic, len(intrinsics.in))
|
||||||
for i, f := range intrinsics.in {
|
for i, f := range intrinsics.in {
|
||||||
|
|
|
@ -97,6 +97,8 @@ func (l *lexer) lex() error {
|
||||||
case l.match("op", tok.Operator):
|
case l.match("op", tok.Operator):
|
||||||
case l.match("enum", tok.Enum):
|
case l.match("enum", tok.Enum):
|
||||||
case l.match("type", tok.Type):
|
case l.match("type", tok.Type):
|
||||||
|
case l.match("ctor", tok.Constructor):
|
||||||
|
case l.match("conv", tok.Converter):
|
||||||
case l.match("match", tok.Match):
|
case l.match("match", tok.Match):
|
||||||
case unicode.IsLetter(l.peek(0)) || l.peek(0) == '_':
|
case unicode.IsLetter(l.peek(0)) || l.peek(0) == '_':
|
||||||
l.tok(l.count(alphaNumericOrUnderscore), tok.Identifier)
|
l.tok(l.count(alphaNumericOrUnderscore), tok.Identifier)
|
||||||
|
|
|
@ -58,6 +58,12 @@ func TestLexTokens(t *testing.T) {
|
||||||
{"type", tok.Token{Kind: tok.Type, Runes: []rune("type"), Source: tok.Source{
|
{"type", tok.Token{Kind: tok.Type, Runes: []rune("type"), Source: tok.Source{
|
||||||
S: loc(1, 1, 0), E: loc(1, 5, 4),
|
S: loc(1, 1, 0), E: loc(1, 5, 4),
|
||||||
}}},
|
}}},
|
||||||
|
{"ctor", tok.Token{Kind: tok.Constructor, Runes: []rune("ctor"), Source: tok.Source{
|
||||||
|
S: loc(1, 1, 0), E: loc(1, 5, 4),
|
||||||
|
}}},
|
||||||
|
{"conv", tok.Token{Kind: tok.Converter, Runes: []rune("conv"), Source: tok.Source{
|
||||||
|
S: loc(1, 1, 0), E: loc(1, 5, 4),
|
||||||
|
}}},
|
||||||
{"enum", tok.Token{Kind: tok.Enum, Runes: []rune("enum"), Source: tok.Source{
|
{"enum", tok.Token{Kind: tok.Enum, Runes: []rune("enum"), Source: tok.Source{
|
||||||
S: loc(1, 1, 0), E: loc(1, 5, 4),
|
S: loc(1, 1, 0), E: loc(1, 5, 4),
|
||||||
}}},
|
}}},
|
||||||
|
|
|
@ -71,6 +71,12 @@ func (p *parser) parse() (*ast.AST, error) {
|
||||||
case tok.Operator:
|
case tok.Operator:
|
||||||
out.Operators = append(out.Operators, p.operatorDecl(decorations))
|
out.Operators = append(out.Operators, p.operatorDecl(decorations))
|
||||||
decorations = nil
|
decorations = nil
|
||||||
|
case tok.Constructor:
|
||||||
|
out.Constructors = append(out.Constructors, p.constructorDecl(decorations))
|
||||||
|
decorations = nil
|
||||||
|
case tok.Converter:
|
||||||
|
out.Converters = append(out.Converters, p.converterDecl(decorations))
|
||||||
|
decorations = nil
|
||||||
default:
|
default:
|
||||||
p.err = fmt.Errorf("%v unexpected token '%v'", t.Source, t.Kind)
|
p.err = fmt.Errorf("%v unexpected token '%v'", t.Source, t.Kind)
|
||||||
}
|
}
|
||||||
|
@ -195,6 +201,47 @@ func (p *parser) operatorDecl(decos ast.Decorations) ast.IntrinsicDecl {
|
||||||
}
|
}
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *parser) constructorDecl(decos ast.Decorations) ast.IntrinsicDecl {
|
||||||
|
p.expect(tok.Constructor, "constructor declaration")
|
||||||
|
name := p.next()
|
||||||
|
f := ast.IntrinsicDecl{
|
||||||
|
Source: name.Source,
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Decorations: decos,
|
||||||
|
Name: string(name.Runes),
|
||||||
|
}
|
||||||
|
if p.peekIs(0, tok.Lt) {
|
||||||
|
f.TemplateParams = p.templateParams()
|
||||||
|
}
|
||||||
|
f.Parameters = p.parameters()
|
||||||
|
if p.match(tok.Arrow) != nil {
|
||||||
|
ret := p.templatedName()
|
||||||
|
f.ReturnType = &ret
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) converterDecl(decos ast.Decorations) ast.IntrinsicDecl {
|
||||||
|
p.expect(tok.Converter, "converter declaration")
|
||||||
|
name := p.next()
|
||||||
|
f := ast.IntrinsicDecl{
|
||||||
|
Source: name.Source,
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Decorations: decos,
|
||||||
|
Name: string(name.Runes),
|
||||||
|
}
|
||||||
|
if p.peekIs(0, tok.Lt) {
|
||||||
|
f.TemplateParams = p.templateParams()
|
||||||
|
}
|
||||||
|
f.Parameters = p.parameters()
|
||||||
|
if p.match(tok.Arrow) != nil {
|
||||||
|
ret := p.templatedName()
|
||||||
|
f.ReturnType = &ret
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
func (p *parser) parameters() ast.Parameters {
|
func (p *parser) parameters() ast.Parameters {
|
||||||
l := ast.Parameters{}
|
l := ast.Parameters{}
|
||||||
p.expect(tok.Lparen, "function parameter list")
|
p.expect(tok.Lparen, "function parameter list")
|
||||||
|
|
|
@ -370,6 +370,254 @@ func TestParser(t *testing.T) {
|
||||||
},
|
},
|
||||||
Parameters: ast.Parameters{},
|
Parameters: ast.Parameters{},
|
||||||
}},
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F()",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"[[deco]] ctor F()",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
Decorations: ast.Decorations{
|
||||||
|
{Name: "deco", Values: []string{}},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F(a)",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Type: ast.TemplatedName{Name: "a"}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F(a: T)",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Name: "a", Type: ast.TemplatedName{Name: "T"}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F(a, b)",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Type: ast.TemplatedName{Name: "a"}},
|
||||||
|
{Type: ast.TemplatedName{Name: "b"}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F<A : B<C> >()",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
TemplateParams: ast.TemplateParams{
|
||||||
|
{
|
||||||
|
Name: "A", Type: ast.TemplatedName{
|
||||||
|
Name: "B",
|
||||||
|
TemplateArgs: ast.TemplatedNames{
|
||||||
|
{Name: "C"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F<T>(a: X, b: Y<T>)",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
TemplateParams: ast.TemplateParams{
|
||||||
|
{Name: "T"},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Name: "a", Type: ast.TemplatedName{Name: "X"}},
|
||||||
|
{Name: "b", Type: ast.TemplatedName{
|
||||||
|
Name: "Y",
|
||||||
|
TemplateArgs: []ast.TemplatedName{{Name: "T"}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F() -> X",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
ReturnType: &ast.TemplatedName{Name: "X"},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"ctor F() -> X<T>",
|
||||||
|
ast.AST{
|
||||||
|
Constructors: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Constructor,
|
||||||
|
Name: "F",
|
||||||
|
ReturnType: &ast.TemplatedName{
|
||||||
|
Name: "X",
|
||||||
|
TemplateArgs: []ast.TemplatedName{{Name: "T"}},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F()",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"[[deco]] conv F()",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
Decorations: ast.Decorations{
|
||||||
|
{Name: "deco", Values: []string{}},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F(a)",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Type: ast.TemplatedName{Name: "a"}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F(a: T)",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Name: "a", Type: ast.TemplatedName{Name: "T"}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F(a, b)",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Type: ast.TemplatedName{Name: "a"}},
|
||||||
|
{Type: ast.TemplatedName{Name: "b"}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F<A : B<C> >()",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
TemplateParams: ast.TemplateParams{
|
||||||
|
{
|
||||||
|
Name: "A", Type: ast.TemplatedName{
|
||||||
|
Name: "B",
|
||||||
|
TemplateArgs: ast.TemplatedNames{
|
||||||
|
{Name: "C"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F<T>(a: X, b: Y<T>)",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
TemplateParams: ast.TemplateParams{
|
||||||
|
{Name: "T"},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{
|
||||||
|
{Name: "a", Type: ast.TemplatedName{Name: "X"}},
|
||||||
|
{Name: "b", Type: ast.TemplatedName{
|
||||||
|
Name: "Y",
|
||||||
|
TemplateArgs: []ast.TemplatedName{{Name: "T"}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F() -> X",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
ReturnType: &ast.TemplatedName{Name: "X"},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"conv F() -> X<T>",
|
||||||
|
ast.AST{
|
||||||
|
Converters: []ast.IntrinsicDecl{{
|
||||||
|
Kind: ast.Converter,
|
||||||
|
Name: "F",
|
||||||
|
ReturnType: &ast.TemplatedName{
|
||||||
|
Name: "X",
|
||||||
|
TemplateArgs: []ast.TemplatedName{{Name: "T"}},
|
||||||
|
},
|
||||||
|
Parameters: ast.Parameters{},
|
||||||
|
}},
|
||||||
}},
|
}},
|
||||||
} {
|
} {
|
||||||
got, err := parser.Parse(test.src, "file.txt")
|
got, err := parser.Parse(test.src, "file.txt")
|
||||||
|
|
|
@ -27,23 +27,25 @@ type resolver struct {
|
||||||
a *ast.AST
|
a *ast.AST
|
||||||
s *sem.Sem
|
s *sem.Sem
|
||||||
|
|
||||||
globals scope
|
globals scope
|
||||||
builtins map[string]*sem.Intrinsic
|
builtins map[string]*sem.Intrinsic
|
||||||
unaryOperators map[string]*sem.Intrinsic
|
unaryOperators map[string]*sem.Intrinsic
|
||||||
binaryOperators map[string]*sem.Intrinsic
|
binaryOperators map[string]*sem.Intrinsic
|
||||||
enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher
|
constructorsAndConverters map[string]*sem.Intrinsic
|
||||||
|
enumEntryMatchers map[*sem.EnumEntry]*sem.EnumMatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve processes the AST
|
// Resolve processes the AST
|
||||||
func Resolve(a *ast.AST) (*sem.Sem, error) {
|
func Resolve(a *ast.AST) (*sem.Sem, error) {
|
||||||
r := resolver{
|
r := resolver{
|
||||||
a: a,
|
a: a,
|
||||||
s: sem.New(),
|
s: sem.New(),
|
||||||
globals: newScope(nil),
|
globals: newScope(nil),
|
||||||
builtins: map[string]*sem.Intrinsic{},
|
builtins: map[string]*sem.Intrinsic{},
|
||||||
unaryOperators: map[string]*sem.Intrinsic{},
|
unaryOperators: map[string]*sem.Intrinsic{},
|
||||||
binaryOperators: map[string]*sem.Intrinsic{},
|
binaryOperators: map[string]*sem.Intrinsic{},
|
||||||
enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{},
|
constructorsAndConverters: map[string]*sem.Intrinsic{},
|
||||||
|
enumEntryMatchers: map[*sem.EnumEntry]*sem.EnumMatcher{},
|
||||||
}
|
}
|
||||||
// Declare and resolve all the enumerators
|
// Declare and resolve all the enumerators
|
||||||
for _, e := range a.Enums {
|
for _, e := range a.Enums {
|
||||||
|
@ -85,6 +87,21 @@ func Resolve(a *ast.AST) (*sem.Sem, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Declare and resolve type constructors and converters
|
||||||
|
for _, c := range a.Constructors {
|
||||||
|
if err := r.intrinsic(c, r.constructorsAndConverters, &r.s.ConstructorsAndConverters); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, c := range a.Converters {
|
||||||
|
if len(c.Parameters) != 1 {
|
||||||
|
return nil, fmt.Errorf("%v conversions must have a single parameter", c.Source)
|
||||||
|
}
|
||||||
|
if err := r.intrinsic(c, r.constructorsAndConverters, &r.s.ConstructorsAndConverters); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate the unique parameter names
|
// Calculate the unique parameter names
|
||||||
r.s.UniqueParameterNames = r.calculateUniqueParameterNames()
|
r.s.UniqueParameterNames = r.calculateUniqueParameterNames()
|
||||||
|
|
||||||
|
@ -440,6 +457,8 @@ func (r *resolver) templateParam(a ast.TemplateParam) (sem.TemplateParam, error)
|
||||||
return &sem.TemplateEnumParam{Name: a.Name, Enum: r.Enum, Matcher: r}, nil
|
return &sem.TemplateEnumParam{Name: a.Name, Enum: r.Enum, Matcher: r}, nil
|
||||||
case *sem.TypeMatcher:
|
case *sem.TypeMatcher:
|
||||||
return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil
|
return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil
|
||||||
|
case *sem.Type:
|
||||||
|
return &sem.TemplateTypeParam{Name: a.Name, Type: r}, nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("%v invalid template parameter type '%v'", a.Source, a.Type.Name)
|
return nil, fmt.Errorf("%v invalid template parameter type '%v'", a.Source, a.Type.Name)
|
||||||
}
|
}
|
||||||
|
@ -525,6 +544,7 @@ func (r *resolver) calculateUniqueParameterNames() []string {
|
||||||
r.s.Builtins,
|
r.s.Builtins,
|
||||||
r.s.UnaryOperators,
|
r.s.UnaryOperators,
|
||||||
r.s.BinaryOperators,
|
r.s.BinaryOperators,
|
||||||
|
r.s.ConstructorsAndConverters,
|
||||||
} {
|
} {
|
||||||
for _, i := range intrinsics {
|
for _, i := range intrinsics {
|
||||||
for _, o := range i.Overloads {
|
for _, o := range i.Overloads {
|
||||||
|
|
|
@ -141,6 +141,40 @@ type f32
|
||||||
type T<x>
|
type T<x>
|
||||||
fn f(T< T<f32> >)`,
|
fn f(T< T<f32> >)`,
|
||||||
success,
|
success,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type f32
|
||||||
|
op -(f32)`,
|
||||||
|
success,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type f32
|
||||||
|
type T<x>
|
||||||
|
op +(T<f32>, T<f32>)`,
|
||||||
|
success,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type f32
|
||||||
|
ctor f32(f32)`,
|
||||||
|
success,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type f32
|
||||||
|
type T<x>
|
||||||
|
ctor f32(T<f32>)`,
|
||||||
|
success,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type f32
|
||||||
|
type i32
|
||||||
|
conv f32(i32)`,
|
||||||
|
success,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type f32
|
||||||
|
type T<x>
|
||||||
|
conv f32(T<f32>)`,
|
||||||
|
success,
|
||||||
}, {
|
}, {
|
||||||
`enum E {A A}`,
|
`enum E {A A}`,
|
||||||
`
|
`
|
||||||
|
@ -363,6 +397,125 @@ op << <M: m>(P<M>)`,
|
||||||
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
|
type i
|
||||||
|
enum e { a }
|
||||||
|
ctor F(i) -> e`,
|
||||||
|
`file.txt:3:14 cannot use 'e' as return type. Must be a type or template type`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type T<x>
|
||||||
|
ctor F(T<u>)`,
|
||||||
|
`file.txt:2:10 cannot resolve 'u'`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type x
|
||||||
|
ctor F<T>(T<x>)`,
|
||||||
|
`file.txt:2:11 'T' template parameters do not accept template arguments`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type A<N: num>
|
||||||
|
type B
|
||||||
|
ctor F(A<B>)`,
|
||||||
|
`file.txt:3:10 cannot use type 'B' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type A<N>
|
||||||
|
enum E { b }
|
||||||
|
ctor F(A<b>)`,
|
||||||
|
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type T
|
||||||
|
type P<N: num>
|
||||||
|
match m: T
|
||||||
|
ctor F(P<m>)`,
|
||||||
|
`file.txt:4:10 cannot use type matcher 'm' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type P<N: num>
|
||||||
|
enum E { b }
|
||||||
|
ctor F(P<E>)`,
|
||||||
|
`file.txt:3:10 cannot use enum 'E' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type P<N: num>
|
||||||
|
enum E { a b }
|
||||||
|
match m: a | b
|
||||||
|
ctor F(P<m>)`,
|
||||||
|
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type P<N: num>
|
||||||
|
enum E { a b }
|
||||||
|
match m: a | b
|
||||||
|
ctor F<M: m>(P<M>)`,
|
||||||
|
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
conv F()`,
|
||||||
|
`file.txt:1:6 conversions must have a single parameter`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type i
|
||||||
|
conv F(i, i, i)`,
|
||||||
|
`file.txt:2:6 conversions must have a single parameter`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type i
|
||||||
|
enum e { a }
|
||||||
|
conv F(i) -> e`,
|
||||||
|
`file.txt:3:14 cannot use 'e' as return type. Must be a type or template type`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type T<x>
|
||||||
|
conv F(T<u>)`,
|
||||||
|
`file.txt:2:10 cannot resolve 'u'`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type x
|
||||||
|
conv F<T>(T<x>)`,
|
||||||
|
`file.txt:2:11 'T' template parameters do not accept template arguments`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type A<N: num>
|
||||||
|
type B
|
||||||
|
conv F(A<B>)`,
|
||||||
|
`file.txt:3:10 cannot use type 'B' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type A<N>
|
||||||
|
enum E { b }
|
||||||
|
conv F(A<b>)`,
|
||||||
|
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type T
|
||||||
|
type P<N: num>
|
||||||
|
match m: T
|
||||||
|
conv F(P<m>)`,
|
||||||
|
`file.txt:4:10 cannot use type matcher 'm' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type P<N: num>
|
||||||
|
enum E { b }
|
||||||
|
conv F(P<E>)`,
|
||||||
|
`file.txt:3:10 cannot use enum 'E' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type P<N: num>
|
||||||
|
enum E { a b }
|
||||||
|
match m: a | b
|
||||||
|
conv F(P<m>)`,
|
||||||
|
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
type P<N: num>
|
||||||
|
enum E { a b }
|
||||||
|
match m: a | b
|
||||||
|
conv F<M: m>(P<M>)`,
|
||||||
|
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
enum E { a }
|
enum E { a }
|
||||||
type T<X: a>`,
|
type T<X: a>`,
|
||||||
`file.txt:2:8 invalid template parameter type 'a'`,
|
`file.txt:2:8 invalid template parameter type 'a'`,
|
||||||
|
|
|
@ -22,13 +22,14 @@ import (
|
||||||
|
|
||||||
// Sem is the root of the semantic tree
|
// Sem is the root of the semantic tree
|
||||||
type Sem struct {
|
type Sem struct {
|
||||||
Enums []*Enum
|
Enums []*Enum
|
||||||
Types []*Type
|
Types []*Type
|
||||||
TypeMatchers []*TypeMatcher
|
TypeMatchers []*TypeMatcher
|
||||||
EnumMatchers []*EnumMatcher
|
EnumMatchers []*EnumMatcher
|
||||||
Builtins []*Intrinsic
|
Builtins []*Intrinsic
|
||||||
UnaryOperators []*Intrinsic
|
UnaryOperators []*Intrinsic
|
||||||
BinaryOperators []*Intrinsic
|
BinaryOperators []*Intrinsic
|
||||||
|
ConstructorsAndConverters []*Intrinsic
|
||||||
// Maximum number of open-types used across all builtins
|
// Maximum number of open-types used across all builtins
|
||||||
MaxOpenTypes int
|
MaxOpenTypes int
|
||||||
// Maximum number of open-numbers used across all builtins
|
// Maximum number of open-numbers used across all builtins
|
||||||
|
|
|
@ -30,6 +30,8 @@ const (
|
||||||
Match Kind = "match"
|
Match Kind = "match"
|
||||||
Function Kind = "fn"
|
Function Kind = "fn"
|
||||||
Operator Kind = "op"
|
Operator Kind = "op"
|
||||||
|
Constructor Kind = "ctor"
|
||||||
|
Converter Kind = "conv"
|
||||||
Type Kind = "type"
|
Type Kind = "type"
|
||||||
Enum Kind = "enum"
|
Enum Kind = "enum"
|
||||||
And Kind = "&"
|
And Kind = "&"
|
||||||
|
|
Loading…
Reference in New Issue