File: static-shadowing-checking.lisp

package info (click to toggle)
acl2 8.6%2Bdfsg-3
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 1,138,276 kB
  • sloc: lisp: 17,818,294; java: 125,359; python: 28,122; javascript: 23,458; cpp: 18,851; ansic: 11,569; perl: 7,678; xml: 5,591; sh: 3,978; makefile: 3,840; ruby: 2,633; yacc: 1,126; ml: 763; awk: 295; csh: 233; lex: 197; php: 178; tcl: 49; asm: 23; haskell: 17
file content (219 lines) | stat: -rw-r--r-- 8,972 bytes parent folder | download | duplicates (2)
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
; Yul Library
;
; Copyright (C) 2025 Kestrel Institute (http://www.kestrel.edu)
;
; License: A 3-clause BSD license. See the LICENSE file distributed with ACL2.
;
; Author: Alessandro Coglio (www.alessandrocoglio.info)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package "YUL")

(include-book "abstract-syntax")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defxdoc+ static-shadowing-checking
  :parents (static-semantics)
  :short "Static shadowing checking of Yul."
  :long
  (xdoc::topstring
   (xdoc::p
    "According to [Yul: Specification of Yul: Scoping Rules],
     a variable declaration cannot shadow a variable
     that is visible at the point in which the variable declaration occurs.
     The notion of `visible' applies
     not only to variables declared in outer blocks in the same function,
     but also to variables declared in blocks in outer functions:
     the former variables are accessible, while the latter are not.")
   (xdoc::p
    "For instance, consider the following Yul code:")
   (xdoc::codeblock
    "function f () {"
    "  let x"
    "  function g () {"
    "    let y"
    "    // here"
    "  }"
    "}"
    )
   (xdoc::p
    "At the point marked as `here',
     @('x') is visible but not accessible,
     while @('y') is both visible and accessible.")
   (xdoc::p
    "The non-shadowing of outer variables in the same function
     (e.g. the non-shadowing of @('y') in function @('g'))
     is checked as part of the safety checks
     formalized in @(see static-safety-checking).
     This is necessary for safety,
     because the dynamic semantics has
     a single variable scope (not a stack of scopes),
     as formalized in @(see static-safety-checking).")
   (xdoc::p
    "The non-shadowing of outer variables in different functions
     (e.g. the non-shadowing of @('x') in function @('g'))
     is not needed for safe execution,
     because when the body of a function (e.g. @('g')) is executed,
     a new variable scope is started,
     and the function has no access to outside variables (e.g. to @('x')).
     Nonetheless, it is part of the Yul static semantics:
     the Yul team has explained that its purpose is
     just to prevent human error.
     Thus, we formalize these checks here,
     separately from the safety checks.")
   (xdoc::p
    "The shadowing restrictions formalized here
     only apply to variables, not to functions.
     Variables and functions are subject to
     different visibility and accessibility rules;
     all the rules that apply to functions
     are parts of the safety checks."))
  :order-subtopics t
  :default-parent t)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defines check-shadow-statements/blocks/cases/fundefs
  :short "Check the additional shadowing constraints on
          statements, blocks, cases, and function definitions."
  :long
  (xdoc::topstring
   (xdoc::p
    "We recursively visit statements, blocks, etc.,
     accumulating all the variables declared so far,
     which form all the visible variables,
     both accessible and inaccessble.
     We check that each declared variable is not already visible.")
   (xdoc::p
    "Note that these checks overlap with the safety checks,
     for what concerns visible and accessible variables,
     while they are additional checks
     for what concerns visible but inaccessible variables.
     Restricting the checks to just visible but inaccessible variables
     would be more complicated than checking all the visible variables."))

  (define check-shadow-statement ((stmt statementp) (vars identifier-setp))
    :returns (new-vars identifier-set-resultp)
    :short "Check variable shadowing in a statement."
    :long
    (xdoc::topstring
     (xdoc::p
      "If the check is successful,
       we return a possibly updated set of visible variables.
       The set is actually updated only by variable declarations.")
     (xdoc::p
      "Since the scope of a loop's initialization block
       extends to the whole loop,
       we first check the list of statments of the initialization block,
       obtaining a possibly updated set of visible variables,
       which is used to check the update and body blocks of the loop."))
    (statement-case
     stmt
     :block (b* (((okf &) (check-shadow-block stmt.get vars)))
              (identifier-set-fix vars))
     :variable-single (if (set::in stmt.name (identifier-set-fix vars))
                          (reserrf (list :shadowed-var stmt.name))
                        (set::insert stmt.name (identifier-set-fix vars)))
     :variable-multi (b* ((declared (set::mergesort stmt.names))
                          (shadowed (set::intersect declared
                                                    (identifier-set-fix vars))))
                       (if (set::emptyp shadowed)
                           (set::union declared (identifier-set-fix vars))
                         (reserrf (list :shadowed-vars shadowed))))
     :assign-single (identifier-set-fix vars)
     :assign-multi (identifier-set-fix vars)
     :funcall (identifier-set-fix vars)
     :if (b* (((okf &) (check-shadow-block stmt.body vars)))
           (identifier-set-fix vars))
     :for (b* ((stmts (block->statements stmt.init))
               ((okf vars1) (check-shadow-statement-list stmts vars))
               ((okf &) (check-shadow-block stmt.update vars1))
               ((okf &) (check-shadow-block stmt.body vars1)))
            (identifier-set-fix vars))
     :switch (b* (((okf &) (check-shadow-swcase-list stmt.cases vars))
                  ((okf &) (check-shadow-block-option stmt.default vars)))
               (identifier-set-fix vars))
     :leave (identifier-set-fix vars)
     :break (identifier-set-fix vars)
     :continue (identifier-set-fix vars)
     :fundef (b* (((okf &) (check-shadow-fundef stmt.get vars)))
               (identifier-set-fix vars)))
    :measure (statement-count stmt))

  (define check-shadow-statement-list ((stmts statement-listp)
                                       (vars identifier-setp))
    :returns (new-vars identifier-set-resultp)
    :short "Check variable shadowing in a list of statements."
    (b* (((when (endp stmts)) (identifier-set-fix vars))
         ((okf vars) (check-shadow-statement (car stmts) vars))
         ((okf vars) (check-shadow-statement-list (cdr stmts) vars)))
      vars)
    :measure (statement-list-count stmts))

  (define check-shadow-block ((block blockp) (vars identifier-setp))
    :returns (_ reserr-optionp)
    :short "Check variable shadowing in a block."
    :long
    (xdoc::topstring
     (xdoc::p
      "We return no information in case of success,
       because the variables declared in a block
       are not visible after the block."))
    (b* (((okf &) (check-shadow-statement-list (block->statements block) vars)))
      nil)
    :measure (block-count block))

  (define check-shadow-block-option ((block? block-optionp)
                                     (vars identifier-setp))
    :returns (_ reserr-optionp)
    :short "Check variable shadowing in an optional block."
    (block-option-case
     block?
     :none nil
     :some (check-shadow-block block?.val vars))
    :measure (block-option-count block?))

  (define check-shadow-swcase ((case swcasep) (vars identifier-setp))
    :returns (_ reserr-optionp)
    :short "Check variable shadowing in a case."
    (check-shadow-block (swcase->body case) vars)
    :measure (swcase-count case))

  (define check-shadow-swcase-list ((cases swcase-listp) (vars identifier-setp))
    :returns (_ reserr-optionp)
    :short "Check variable shadowing in a list of cases."
    (b* (((when (endp cases)) nil)
         ((okf &) (check-shadow-swcase (car cases) vars))
         ((okf &) (check-shadow-swcase-list (cdr cases) vars)))
      nil)
    :measure (swcase-list-count cases))

  (define check-shadow-fundef ((fundef fundefp) (vars identifier-setp))
    :returns (_ reserr-optionp)
    :short "Check variable shadowing in a function definition."
    :long
    (xdoc::topstring
     (xdoc::p
      "First we ensure that the function's inputs and outputs
       are not already visible.
       We add them to the visible variables,
       and we check the body."))
    (b* ((inputs (fundef->inputs fundef))
         (outputs (fundef->outputs fundef))
         (declared (set::mergesort (append inputs outputs)))
         (shadowed (set::intersect declared (identifier-set-fix vars)))
         ((unless (set::emptyp shadowed))
          (reserrf (list :shadowed-vars shadowed)))
         (vars (set::union (identifier-set-fix vars) declared)))
      (check-shadow-block (fundef->body fundef) vars))
    :measure (fundef-count fundef))

  :verify-guards nil ; done below

  ///

  (verify-guards check-shadow-statement)

  (fty::deffixequiv-mutual check-shadow-statements/blocks/cases/fundefs))