forked from grailbio/reflow
/
decl.go
139 lines (127 loc) · 3.12 KB
/
decl.go
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2017 GRAIL, Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package syntax
import (
"bytes"
"fmt"
"github.com/grailbio/reflow/internal/scanner"
"github.com/grailbio/reflow/types"
"github.com/grailbio/reflow/values"
)
// DeclKind is the type of declaration.
type DeclKind int
const (
// DeclError is an illegal declaration.
DeclError DeclKind = iota
// DeclAssign is an assignment declaration (rvalue expression).
DeclAssign
// DeclDeclare is a "pure" declaration (type only).
DeclDeclare
// DeclType declares a type alias
DeclType
)
// A Decl is a Reflow declaration.
type Decl struct {
// Position contains the source position of the node.
// It is set by the parser.
scanner.Position
// Comment stores an optional comment attached to the declaration.
Comment string
// Kind is the Decl's op; see above.
Kind DeclKind
// Ident is the identifier in a DeclDeclare and DeclType.
Ident string
// Pat stores the pattern for this declaration.
Pat *Pat
// Expr stores the rvalue expression for this declaration.
Expr *Expr
// Type stores the type for DeclDeclare and DeclType.
Type *types.T
}
// ID returns the best identifier for this declaration, or else id.
func (d *Decl) ID(id string) string {
switch d.Kind {
case DeclDeclare, DeclType:
if id != "" {
return id + "." + d.Ident
}
return d.Ident
case DeclAssign:
if d.Pat.Kind == PatIdent {
if id != "" {
return id + "." + d.Ident + d.Pat.Ident
}
return d.Ident + d.Pat.Ident
}
}
return id
}
// Init type checks this declaration. Type errors are returned.
func (d *Decl) Init(sess *Session, env *types.Env) error {
d.init(sess, env)
if d.Type == nil {
panic("d type is nil")
}
d.Type = expand(d.Type, env)
if d.Expr != nil {
return d.Expr.err()
}
return nil
}
func (d *Decl) init(sess *Session, env *types.Env) {
switch d.Kind {
case DeclError:
d.Type = typeError
return
case DeclDeclare, DeclType:
return
case DeclAssign:
d.Expr.init(sess, env)
d.Type = d.Expr.Type.Assign(nil)
}
}
// Eval evaluates this declaration with the given environment and session.
func (d *Decl) Eval(sess *Session, env *values.Env, ident string) (values.T, error) {
return d.Expr.eval(sess, env, d.ID(ident))
}
// Equal tests whether Decl d is equivalent to Decl e.
func (d *Decl) Equal(e *Decl) bool {
if d.Kind == DeclError {
return false
}
if d.Kind != e.Kind {
return false
}
if !d.Pat.Equal(e.Pat) {
return false
}
switch d.Kind {
default:
panic("error")
case DeclAssign:
return d.Expr.Equal(e.Expr)
case DeclDeclare, DeclType:
return d.Type.Equal(e.Type)
}
}
// String renders a tree-formatted version of d.
func (d *Decl) String() string {
b := new(bytes.Buffer)
if d.Type != nil {
b.WriteString("<" + d.Type.String() + ">")
}
switch d.Kind {
default:
panic("error")
case DeclError:
b.WriteString("error")
case DeclAssign:
fmt.Fprintf(b, "assign(%s, %s)", d.Pat, d.Expr)
case DeclDeclare:
fmt.Fprintf(b, "declare(%s, %s)", d.Ident, d.Type)
case DeclType:
fmt.Fprintf(b, "type(%s %s)", d.Ident, d.Type)
}
return b.String()
}