Skip to content

Commit

Permalink
make "const" declaration imply "local" in an inner scope block
Browse files Browse the repository at this point in the history
closes #3235
  • Loading branch information
JeffBezanson committed Jun 15, 2013
1 parent 8e5e35f commit e440245
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 24 deletions.
10 changes: 5 additions & 5 deletions doc/manual/variables-and-scoping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ The constructs introducing such blocks are:

Notably missing from this list are
:ref:`begin blocks <man-compound-expressions>`, which do
*not* introduce a new scope block.
*not* introduce new scope blocks.

Certain constructs introduce new variables into the current innermost
scope. When a variable is introduced into a scope, it is also inherited
by all inner scopes unless one of those inner scopes explicitly
overrides it. These constructs which introduce new variables into the
current scope are as follows:

- A declaration ``local x`` introduces a new local variable.
- A declaration ``local x`` or ``const x`` introduces a new local variable.
- A declaration ``global x`` makes ``x`` in the current scope and inner
scopes refer to the global variable of that name.
- A function's arguments are introduced as new local variables into the
Expand Down Expand Up @@ -91,8 +91,8 @@ a global variable ``x``)::

A variable that is not assigned to or otherwise introduced locally
defaults to global, so this function would return the value of the
global ``x`` if there is such a variable, or produce an error if no such
global exists. As a consequence, the only way to assign to a global
global ``x`` if there were such a variable, or produce an error if no such
global existed. As a consequence, the only way to assign to a global
variable inside a non-top-level scope is to explicitly declare the
variable as global within some scope, since otherwise the assignment
would introduce a new local rather than assigning to the global. This
Expand Down Expand Up @@ -217,7 +217,7 @@ behave identically. We can use ``let`` to create a new binding for
2

Since the ``begin`` construct does not introduce a new scope, it can be
useful to use the zero-argument ``let`` to just introduce a new scope
useful to use a zero-argument ``let`` to just introduce a new scope
block without creating any new bindings::

julia> begin
Expand Down
2 changes: 2 additions & 0 deletions src/jlfrontend.scm
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
(append
;; vars assigned at the outer level
(filter (lambda (x) (not (some-gensym? x))) (find-assigned-vars e '()))
;; vars declared const outside any scope block
(find-decls 'const e '())
;; vars assigned anywhere, if they have been defined as global
(filter defined-julia-global (find-possible-globals e)))))

Expand Down
35 changes: 16 additions & 19 deletions src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -2111,37 +2111,34 @@ So far only the second case can actually occur.
(apply append! (map (lambda (x) (find-assigned-vars x env))
e))))))

(define (find-local-decls e env)
(define (find-decls kind e env)
(if (or (not (pair? e)) (quoted? e))
'()
(case (car e)
((lambda scope-block) '())
((local) (list (decl-var (cadr e))))
(else
(apply append! (map (lambda (x) (find-local-decls x env))
e))))))
(cond ((or (eq? (car e) 'lambda) (eq? (car e) 'scope-block))
'())
((eq? (car e) kind)
(list (decl-var (cadr e))))
(else
(apply append! (map (lambda (x) (find-decls kind x env))
e))))))

(define (find-local!-decls e env)
(if (or (not (pair? e)) (quoted? e))
'()
(case (car e)
((lambda scope-block) '())
((local!) (list (decl-var (cadr e))))
(else
(apply append! (map (lambda (x) (find-local!-decls x env))
e))))))
(define (find-local-decls e env) (find-decls 'local e env))
(define (find-local!-decls e env) (find-decls 'local! e env))

(define (find-locals e env)
(define (find-locals e env glob)
(delete-duplicates
(append! (check-dups (find-local-decls e env))
;; const decls on non-globals also introduce locals
(diff (find-decls 'const e env) glob)
(find-local!-decls e env)
(find-assigned-vars e env))))

;; local variable identification
;; convert (scope-block x) to `(scope-block ,@locals ,x)
;; where locals is a list of (local x) expressions, derived from two sources:
;; 1. (local x) expressions inside this scope-block and lambda
;; 2. variables assigned inside this scope-block that don't exist in outer
;; 2. (const x) expressions in a scope-block where x is not declared global
;; 3. variables assigned inside this scope-block that don't exist in outer
;; scopes
(define (add-local-decls e env)
(if (or (not (pair? e)) (quoted? e)) e
Expand All @@ -2155,7 +2152,7 @@ So far only the second case can actually occur.
(vars (find-locals
;; being declared global prevents a variable
;; assignment from introducing a local
(cadr e) (append env glob)))
(cadr e) (append env glob) glob))
(body (add-local-decls (cadr e) (append vars glob env))))
`(scope-block ,@(map (lambda (v) `(local ,v))
vars)
Expand Down
14 changes: 14 additions & 0 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,20 @@ function let_undef()
end
@test_fails let_undef()

# const implies local in a local scope block
function const_implies_local()
let
x = 1
local y
let
const x = 0
y = x
end
x, y
end
end
@test const_implies_local() === (1, 0)

a = cell(3)
for i=1:3
let ii = i
Expand Down

0 comments on commit e440245

Please sign in to comment.