5 func checkRecursive(contract *Contract) bool {
6 for _, clause := range contract.Clauses {
7 for _, stmt := range clause.statements {
8 if l, ok := stmt.(*lockStatement); ok {
9 if c, ok := l.program.(*callExpr); ok {
10 if references(c.fn, contract.Name) {
20 func prohibitSigParams(contract *Contract) error {
21 for _, p := range contract.Params {
22 if p.Type == sigType {
23 return fmt.Errorf("contract parameter \"%s\" has type Signature, but contract parameters cannot have type Signature", p.Name)
29 func prohibitValueParams(contract *Contract) error {
30 for _, p := range contract.Params {
31 if p.Type == valueType {
32 return fmt.Errorf("Value-typed contract parameter \"%s\" must appear in a \"locks\" clause", p.Name)
35 for _, c := range contract.Clauses {
36 for _, p := range c.Params {
37 if p.Type == valueType {
38 return fmt.Errorf("Value-typed parameter \"%s\" of clause \"%s\" must appear in a \"requires\" clause", p.Name, c.Name)
45 func requireAllParamsUsedInClauses(params []*Param, clauses []*Clause) error {
46 for _, p := range params {
48 for _, c := range clauses {
49 err := requireAllParamsUsedInClause([]*Param{p}, c)
56 return fmt.Errorf("parameter \"%s\" is unused", p.Name)
62 func requireAllParamsUsedInClause(params []*Param, clause *Clause) error {
63 for _, p := range params {
65 for _, stmt := range clause.statements {
66 switch s := stmt.(type) {
67 case *verifyStatement:
68 used = references(s.expr, p.Name)
70 used = references(s.locked, p.Name) || references(s.program, p.Name)
71 case *unlockStatement:
72 used = references(s.expr, p.Name)
79 for _, r := range clause.Reqs {
80 if references(r.amountExpr, p.Name) || references(r.assetExpr, p.Name) {
87 return fmt.Errorf("parameter \"%s\" is unused in clause \"%s\"", p.Name, clause.Name)
93 func references(expr expression, name string) bool {
94 switch e := expr.(type) {
96 return references(e.left, name) || references(e.right, name)
98 return references(e.expr, name)
100 if references(e.fn, name) {
103 for _, a := range e.args {
104 if references(a, name) {
110 return string(e) == name
112 for _, elt := range []expression(e) {
113 if references(elt, name) {
122 func requireAllValuesDisposedOnce(contract *Contract, clause *Clause) error {
123 err := valueDisposedOnce(contract.Value, clause)
127 for _, req := range clause.Reqs {
128 err = valueDisposedOnce(req.Name, clause)
136 func valueDisposedOnce(name string, clause *Clause) error {
138 for _, s := range clause.statements {
139 switch stmt := s.(type) {
140 case *unlockStatement:
141 if references(stmt.expr, name) {
145 if references(stmt.locked, name) {
152 return fmt.Errorf("value \"%s\" not disposed in clause \"%s\"", name, clause.Name)
156 return fmt.Errorf("value \"%s\" disposed multiple times in clause \"%s\"", name, clause.Name)
160 func referencedBuiltin(expr expression) *builtin {
161 if v, ok := expr.(varRef); ok {
162 for _, b := range builtins {
163 if string(v) == b.name {
171 func assignIndexes(clause *Clause) {
173 for _, s := range clause.statements {
174 switch stmt := s.(type) {
176 stmt.index = nextIndex
179 case *unlockStatement:
185 func typeCheckClause(contract *Contract, clause *Clause, env *environ) error {
186 for _, s := range clause.statements {
187 switch stmt := s.(type) {
188 case *verifyStatement:
189 if t := stmt.expr.typ(env); t != boolType {
190 return fmt.Errorf("expression in verify statement in clause \"%s\" has type \"%s\", must be Boolean", clause.Name, t)
194 if t := stmt.locked.typ(env); t != valueType {
195 return fmt.Errorf("expression in lock statement in clause \"%s\" has type \"%s\", must be Value", clause.Name, t)
197 if t := stmt.program.typ(env); t != progType {
198 return fmt.Errorf("program in lock statement in clause \"%s\" has type \"%s\", must be Program", clause.Name, t)
201 case *unlockStatement:
202 if t := stmt.expr.typ(env); t != valueType {
203 return fmt.Errorf("expression \"%s\" in unlock statement of clause \"%s\" has type \"%s\", must be Value", stmt.expr, clause.Name, t)
205 if stmt.expr.String() != contract.Value {
206 return fmt.Errorf("expression in unlock statement of clause \"%s\" must be the contract value", clause.Name)