-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlambda.go
More file actions
109 lines (104 loc) · 2.77 KB
/
Copy pathlambda.go
File metadata and controls
109 lines (104 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package analysis
import (
"slices"
"strings"
"github.com/ProCode-Software/klar/internal/ast"
"github.com/ProCode-Software/klar/internal/klarerrs"
"github.com/ProCode-Software/klar/internal/ranges"
)
type Lambda struct {
Params []Type // Variadic param is a List
// Arity can be calculated lazily, but if the declaration contains
// params with default values, this should be provided manually.
arity Arity
Variadic bool
Return Type
}
func (*Lambda) Kind() Kind { return KindFunction }
func (l *Lambda) String() string {
var b strings.Builder
b.WriteString("func(")
for i, param := range l.Params {
if i > 0 {
b.WriteString(", ")
}
if i == len(l.Params)-1 && l.Variadic {
b.WriteString("...")
b.WriteString(param.(*List).Elem.String())
continue
}
b.WriteString(param.String())
}
b.WriteByte(')')
if l.Return != nil && l.Return.Kind() != NothingType {
b.WriteString(" -> ")
b.WriteString(l.Return.String())
}
return b.String()
}
func (l *Lambda) Underlying() Type { return l }
func (l *Lambda) Arity() Arity {
if l.arity != (Arity{0, 0}) {
return l.arity
}
a := Arity{len(l.Params), len(l.Params)}
if l.Variadic {
a.MaxParams = -1
}
// Decrease if the params end in consecutive options or params with default values
if a.MinParams > 0 {
for _, param := range slices.Backward(l.Params) {
if param.Kind() == KindOptional {
a.MinParams--
continue
}
if vr, ok := param.(*Variable); ok && vr.Object.Flags.Has(HasDefault) {
a.MinParams--
continue
}
break
}
}
l.arity = a
return a
}
func (c *Checker) checkFunctionType(expr *ast.FunctionType, ctx *Context) Type {
l := &Lambda{Params: make([]Type, 0, len(expr.Parameters.Values))}
for i, pair := range expr.Parameters.Values {
typ, variadic := c.parseTypeOrVariadic(pair.Value, ctx)
for range max(len(pair.Keys), 1) {
l.Params = append(l.Params, typ)
}
if variadic {
l.Variadic = true
// Ensure this is the last and only paramerer
if len(pair.Keys) > 1 || i < len(expr.Parameters.Values)-1 {
var node ast.Node
var after ranges.Range
if len(pair.Keys) > 1 {
// `(k1, k2: ...Int, _: Int)`
node = pair.Keys[0]
after = ranges.Range{
pair.Keys[1].Position,
expr.Parameters.Values[len(expr.Parameters.Values)-1].Range.End,
}
} else {
// `(k: ...Int, _: Int)`
node = pair
after = ranges.FromSlice(expr.Parameters.Values[i+1:])
}
err := klarerrs.Node(klarerrs.ErrVariadicNotLast, node)
err.Label = "This should be the last parameter"
// Highlight the params after this
err.AddHighlight("It should go after these", after)
c.fileError(err, ctx.File)
}
}
}
if expr.ReturnType != nil {
l.Return = c.parseType(expr.ReturnType, ctx)
} else {
l.Return = NothingType
}
return l
}