diff --git a/base/LineEdit.jl b/base/LineEdit.jl index 72833ea4204a3..1e2707f645647 100644 --- a/base/LineEdit.jl +++ b/base/LineEdit.jl @@ -317,7 +317,7 @@ end # Edit functionality is_non_word_char(c) = c in " \t\n\"\\'`@\$><=:;|&{}()[].,+-*/?%^~" -function reset_key_repeats(f::Function, s::MIState) +function reset_key_repeats(f, s::MIState) key_repeats_sav = s.key_repeats try s.key_repeats = 0 @@ -747,7 +747,7 @@ immutable KeyAlias KeyAlias(seq) = new(normalize_key(seq)) end -match_input(k::Function, s, term, cs, keymap) = (update_key_repeats(s, cs); return keymap_fcn(k, s, ByteString(cs))) +match_input(k, s, term, cs, keymap) = (update_key_repeats(s, cs); return keymap_fcn(k, s, ByteString(cs))) match_input(k::Void, s, term, cs, keymap) = (s,p) -> return :ok match_input(k::KeyAlias, s, term, cs, keymap) = match_input(keymap, s, IOBuffer(k.seq), Char[], keymap) function match_input(k::Dict, s, term=terminal(s), cs=Char[], keymap = k) @@ -762,7 +762,7 @@ function match_input(k::Dict, s, term=terminal(s), cs=Char[], keymap = k) end keymap_fcn(f::Void, s, c) = (s, p) -> return :ok -function keymap_fcn(f::Function, s, c) +function keymap_fcn(f, s, c) return (s, p) -> begin r = f(s, p, c) if isa(r, Symbol) @@ -1102,7 +1102,7 @@ function reset_state(s::PrefixSearchState) end end -function transition(f::Function, s::PrefixSearchState, mode) +function transition(f, s::PrefixSearchState, mode) if isdefined(s,:mi) transition(f,s.mi,mode) end @@ -1532,7 +1532,7 @@ activate(m::ModalInterface, s::MIState, termbuf, term::TextTerminal) = activate(s.current_mode, s, termbuf, term) commit_changes(t::UnixTerminal, termbuf) = write(t, takebuf_array(termbuf.out_stream)) -function transition(f::Function, s::MIState, mode) +function transition(f, s::MIState, mode) if mode == :abort s.aborted = true return diff --git a/base/base.jl b/base/base.jl index 0eec65edca597..709cd66ef4e24 100644 --- a/base/base.jl +++ b/base/base.jl @@ -76,6 +76,7 @@ function finalizer(o::ANY, f::Union{Function,Ptr}) end ccall(:jl_gc_add_finalizer, Void, (Any,Any), o, f) end +finalizer(o::ANY, f::ANY) = finalizer(o, eval(:(o->($f)(o)))) finalize(o::ANY) = ccall(:jl_finalize, Void, (Any,), o) diff --git a/base/boot.jl b/base/boot.jl index dde5d0ec32fb9..9a0b8a9b39680 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -297,6 +297,8 @@ _new(:TopNode, :Symbol) _new(:NewvarNode, :Symbol) _new(:QuoteNode, :ANY) _new(:GenSym, :Int) +_new(:Box, :ANY) +eval(:(Core.call(::Type{Box}) = $(Expr(:new, :Box)))) eval(:(Core.call(::Type{LineNumberNode}, f::Symbol, l::Int) = $(Expr(:new, :LineNumberNode, :f, :l)))) eval(:(Core.call(::Type{GlobalRef}, m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s)))) diff --git a/base/client.jl b/base/client.jl index 70aacb8610913..0284564730e67 100644 --- a/base/client.jl +++ b/base/client.jl @@ -126,7 +126,7 @@ end syntax_deprecation_warnings(warn::Bool) = ccall(:jl_parse_depwarn, Cint, (Cint,), warn) == 1 -function syntax_deprecation_warnings(f::Function, warn::Bool) +function syntax_deprecation_warnings(f, warn::Bool) prev = syntax_deprecation_warnings(warn) try f() diff --git a/base/essentials.jl b/base/essentials.jl index a43d5cf13e225..34a7ed0e364d7 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -45,6 +45,8 @@ call(T::Type{LineNumberNode}, f::Symbol, n::Int) = Core.call(T, f, n) call(T::Type{LabelNode}, n::Int) = Core.call(T, n) call(T::Type{GotoNode}, n::Int) = Core.call(T, n) call(T::Type{QuoteNode}, x::ANY) = Core.call(T, x) +call(T::Type{Box}, x::ANY) = Core.call(T, x) +call(T::Type{Box}) = Core.call(T) call(T::Type{NewvarNode}, s::Symbol) = Core.call(T, s) call(T::Type{TopNode}, s::Symbol) = Core.call(T, s) call(T::Type{Module}, args...) = Core.call(T, args...) diff --git a/base/inference.jl b/base/inference.jl index 2dad85228e78b..07ebd54ea7d3f 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -117,10 +117,10 @@ const n_ifunc = reinterpret(Int32,arraylen)+1 const t_ifunc = Array{Tuple{Int,Int,Function},1}(n_ifunc) const t_ffunc_key = Array{Function,1}(0) const t_ffunc_val = Array{Tuple{Int,Int,Function},1}(0) -function add_tfunc(f::IntrinsicFunction, minarg::Int, maxarg::Int, tfunc::Function) +function add_tfunc(f::IntrinsicFunction, minarg::Int, maxarg::Int, tfunc::ANY) t_ifunc[reinterpret(Int32,f)+1] = (minarg, maxarg, tfunc) end -function add_tfunc(f::Function, minarg::Int, maxarg::Int, tfunc::Function) +function add_tfunc(f::Function, minarg::Int, maxarg::Int, tfunc::ANY) push!(t_ffunc_key, f) push!(t_ffunc_val, (minarg, maxarg, tfunc)) end diff --git a/base/iostream.jl b/base/iostream.jl index b51b7adfaa5ab..4951de1fb0a96 100644 --- a/base/iostream.jl +++ b/base/iostream.jl @@ -200,14 +200,14 @@ function takebuf_raw(s::IOStream) return buf, sz end -function sprint(size::Integer, f::Function, args...) +function sprint(size::Integer, f, args...) s = IOBuffer(Array(UInt8,size), true, true) truncate(s,0) f(s, args...) takebuf_string(s) end -sprint(f::Function, args...) = sprint(0, f, args...) +sprint(f, args...) = sprint(0, f, args...) write(x) = write(STDOUT::IO, x) diff --git a/base/sysimg.jl b/base/sysimg.jl index 12f0246be9074..9530cc0fcf7e6 100644 --- a/base/sysimg.jl +++ b/base/sysimg.jl @@ -291,11 +291,11 @@ using .Docs using .Markdown # deprecated functions -include("deprecated.jl") +#include("deprecated.jl") # Some basic documentation -include("docs/helpdb.jl") -include("docs/basedocs.jl") +#include("docs/helpdb.jl") +#include("docs/basedocs.jl") # threads include("threads.jl") @@ -312,7 +312,7 @@ function __init__() end include = include_from_node1 -include("precompile.jl") +#include("precompile.jl") end # baremodule Base diff --git a/base/task.jl b/base/task.jl index 35b8c74effaa1..46d3199ee36b9 100644 --- a/base/task.jl +++ b/base/task.jl @@ -3,7 +3,7 @@ ## basic task functions and TLS # allow tasks to be constructed with arbitrary function objects -Task(f) = Task(()->f()) +Task(f) = Task(@eval (()->($f)())) function show(io::IO, t::Task) print(io, "Task ($(t.state)) @0x$(hex(convert(UInt, pointer_from_objref(t)), WORD_SIZE>>2))") diff --git a/base/tuple.jl b/base/tuple.jl index 5e0e6529bd9ca..893fc87e1353b 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -41,7 +41,7 @@ eltype{T,_}(::Type{NTuple{_,T}}) = T ## mapping ## -ntuple(f::Function, n::Integer) = +ntuple(f, n::Integer) = n<=0 ? () : n==1 ? (f(1),) : n==2 ? (f(1),f(2),) : diff --git a/base/util.jl b/base/util.jl index 3d3347d7f1cc4..b62343554ada3 100644 --- a/base/util.jl +++ b/base/util.jl @@ -307,7 +307,7 @@ end ## printing with color ## -function with_output_color(f::Function, color::Symbol, io::IO, args...) +function with_output_color(f, color::Symbol, io::IO, args...) buf = IOBuffer() have_color && print(buf, get(text_colors, color, color_normal)) try f(buf, args...) diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 41fa7bd740898..bcab0d0bab3d2 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -18,10 +18,10 @@ `(incomplete ,msg) e)) (begin - ;;(newline) - ;;(display "unexpected error: ") - ;;(prn e) - ;;(print-stack-trace (stacktrace)) + (newline) + (display "unexpected error: ") + (prn e) + (print-stack-trace (stacktrace)) '(error "malformed expression")))) thk)) @@ -103,8 +103,33 @@ (pair? (cadr e)) (eq? (caadr e) '=) (symbol? (cadadr e)) (eq? (cadr (caddr e)) (cadadr e)))) +(define (lift-toplevel- e) + (if (atom? e) (cons e '()) + (let* ((rec (map lift-toplevel- e)) + (e2 (map car rec)) + (tl (apply append (map cdr rec)))) + (if (eq? (car e) 'toplevel-butlast) + (cons (last e2) (append tl (butlast (cdr e2)))) + (cons e2 tl))))) + +(define (lift-toplevel x) + (if (and (pair? x) (memq (car x) '(toplevel body))) + (cons (car x) + (apply append (map (lambda (e) + (let ((e (lift-toplevel e))) + (if (and (pair? e) (eq? (car e) 'toplevel)) + (cdr e) + (list e)))) + (cdr x)))) + (let ((e (lift-toplevel- x))) + (if (null? (cdr e)) + (car e) + (if (and (pair? (car e)) (eq? (caar e) 'toplevel)) + `(toplevel ,@(cdr e) ,@(cdar e)) + `(toplevel ,@(cdr e) ,(car e))))))) + (define (expand-toplevel-expr- e) - (let ((ex (expand-toplevel-expr-- e))) + (let ((ex (lift-toplevel (expand-toplevel-expr-- e)))) (cond ((contains (lambda (x) (equal? x '(top ccall))) ex) ex) ((simple-assignment? ex) (cadr ex)) ((and (length= ex 2) (eq? (car ex) 'body)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 4963f7dfcefbf..ca7a50583e5f3 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -438,6 +438,11 @@ ((eq? (car lhs) 'kw) (cadr lhs)) (else lhs)))) +(define (unwrap-getfield-expr e) + (if (and (length= e 4) (eq? (car e) 'call) (equal? (cadr e) '(top getfield))) + (cadr (last e)) + e)) + (define (method-expr-static-parameters m) (if (eq? (car (cadr (caddr m))) 'lambda) (cadr (cadr (caddr m))) @@ -470,7 +475,9 @@ (error "function static parameter names not unique")) (if (any (lambda (x) (memq x names)) anames) (error "function argument and static parameter names must be distinct"))) - (if (not (or (sym-ref? name) + ;; TODO: this is currently broken by the code in closure-convert that + ;; puts a lowered method name expression back into a front-end AST + #;(if (not (or (sym-ref? name) (and (pair? name) (eq? (car name) 'kw) (sym-ref? (cadr name))))) (error (string "invalid method name \"" (deparse name) "\""))) @@ -2962,7 +2969,7 @@ So far only the second case can actually occur. (define (caddddr x) (car (cdr (cdr (cdr (cdr x)))))) ; convert each lambda's (locals ...) to -; ((localvars...) var-info-lst captured-var-infos) +; (var-info-lst captured-var-infos gensyms static_params) ; where var-info-lst is a list of var-info records (define (analyze-vars e env captvars sp) (if (or (atom? e) (quoted? e)) @@ -3083,10 +3090,245 @@ So far only the second case can actually occur. (define (analyze-variables e) (analyze-vars e '() '() '())) +(define (clear-capture-bits vinfos) + (map (lambda (vi) (list (car vi) (cadr vi) (logand (caddr vi) (lognot 5)))) + vinfos)) + +(define (convert-lambda lam fname tname) + `(lambda ,(cons fname (lam:args lam)) + (,(cons `(,fname Any 0) + (clear-capture-bits (car (lam:vinfo lam)))) + () + ,(caddr (lam:vinfo lam)) + ,(cadddr (lam:vinfo lam))) + ,(closure-convert (cadddr lam) fname lam))) + +(define (cl-convert e) (closure-convert e #f #f)) + +(define (internal-toplevel-exprs e) + (filter (lambda (x) (and (not (and (pair? x) (eq? (car x) 'return))) + (not (equal? x '(null))))) + (cdr (flatten-blocks `(block ,e))))) + +(define (convert-assignment var rhs fname lam) + (let ((vi (assq var (car (lam:vinfo lam)))) + (cv (assq var (cadr (lam:vinfo lam))))) + (cond + ((and cv (vinfo:asgn cv)) + `(call (top setfield!) (call (top getfield) ,fname (inert ,var)) + (inert contents) + ,rhs)) + ((and vi (vinfo:asgn vi) (vinfo:capt vi)) + `(call (top setfield!) ,var (inert contents) ,rhs)) + (else + `(= ,var ,rhs))))) + +(define (arg-type-lowered a) + (let ((t (arg-type a))) + (if (vararg? t) + `(call (top apply_type) Vararg ,(cadr t)) + t))) + +#| +Function redesign plan + +This can be done with a few intermediate stages. + +1. Introduce the following hacked-together closure converter to lift all +inner functions to the top level as type and `call` definitions. + +2. Remove the front end's dependence on intermediate lambdas. Instead, +all temp vars can be locals of a top level thunk, which is just a +LambdaStaticData that can be called directly (the jl_function_t wrapper +we used to put around it is superfluous in this case). + +3. Decide how to handle method defs wrapped in `let`. Possibly just make +a closure like normal, then do + +@eval f(x...) = ($(ClosureType(a, b, c)))(x...) + +4. Now jl_function_t can be removed, along with the old implementation of +closure conversion which is mostly in codegen.cpp. The captured vars +field in ASTs can be removed. + +5. At this stage the call ABI for f(x) can effectively be + +if isa(f,MethodTable) + jl_apply_generic(f, {x}, 1) +else + call(f, x) +end + +5.1. Maybe introduce Function abstract type. + +6. Move MethodTable into TypeName. Lower f(x)=2x to + +immutable _ftype; end +call(::_ftype, x) = 2x +const f = _ftype() + +Definitions of `call` now need to be intercepted to modify the MethodTable +of the TypeName of the first argument. + +The ABI for f(x) is now + +jl_call({f, x}, 2) + +where jl_apply_generic has been renamed jl_call. + +7. Figure out how to pass in static parameters in --compile=no mode. + +8. propagate static parameters into closure types, so e.g. closure method +signatures can depend on them. + +|# +(define (closure-convert e fname lam) + (if (and (not lam) + (not (and (pair? e) (memq (car e) '(lambda method macro))))) + (if (atom? e) e + (cons (car e) (map (lambda (x) (closure-convert x fname lam)) + (cdr e)))) + (cond + ((symbol? e) + (let ((vi (assq e (car (lam:vinfo lam)))) + (cv (assq e (cadr (lam:vinfo lam))))) + (cond ((eq? e fname) e) + (cv + (let ((access `(call (top getfield) ,fname (inert ,e)))) + (if (vinfo:asgn cv) + `(call (top getfield) ,access (inert contents)) + access))) + (vi + (if (and (vinfo:asgn vi) (vinfo:capt vi)) + `(call (top getfield) ,e (inert contents)) + e)) + (else e)))) + ((atom? e) e) + (else + (case (car e) + ((quote inert) e) + ((=) + (let ((var (cadr e)) + (rhs (closure-convert (caddr e) fname lam))) + (convert-assignment var rhs fname lam))) + ((newvar) + (let ((vi (assq (cadr e) (car (lam:vinfo lam))))) + (if (and vi (vinfo:asgn vi) (vinfo:capt vi)) + `(= ,(cadr e) (call (top Box))) + e))) + ((const) + (if (or (assq (cadr e) (car (lam:vinfo lam))) + (assq (cadr e) (cadr (lam:vinfo lam)))) + '(null) + e)) + #;((call) + (let ((f (cadr e))) + (if (and (pair? f) (eq? (car f) 'lambda) + (null? (cadr f)) + (length= (cadddr f) 2)) + (cadr (cadr (cadddr f))) + (cons (car e) + (map (lambda (x) (closure-convert x fname lam)) + (cdr e)))))) + ((macro) e) + ((method) + (if (length= e 2) + e ;; function f end + (let* ((name (unwrap-getfield-expr (method-expr-name e))) + ;; TODO: force global mode if method-expr-name returns a getfield expr + (lam2 (cadddr e)) + (tname (named-gensy name)) + (vis (lam:vinfo lam2)) + (cvs (cadr (lam:vinfo lam2)))) + (if (and (null? cvs) (or (not lam) (eq? name 'call))) + `(method ,(cadr e) ,(caddr e) + (lambda ,(cadr lam2) + (,(clear-capture-bits (car vis)) + ,@(cdr vis)) + ,(closure-convert (cadddr lam2) 'anon + (if (any vinfo:capt (car vis)) + lam2 #f))) + ,(last e)) + `(toplevel-butlast + ,@(internal-toplevel-exprs + (julia-expand-for-cl-convert + `(type #f ,tname + (block ,@(map car cvs))))) + (method call + (call (top svec) + (call (top apply_type) Tuple ,tname ,@(cdddr (caddr (caddr e)))) + ,(cadddr (caddr e))) + ,(convert-lambda lam2 name tname) + ,(last e)) + ,(let ((the-closure `(call ,tname ,@(map car cvs)))) + (if (and lam (or (assq name (car (lam:vinfo lam))) + (assq name (cadr (lam:vinfo lam))))) + (convert-assignment name the-closure fname lam) + ;; otherwise, adding method with free variables to a global function. + ;; lowered to @eval f(x, y...) = ($(clo(fv)))(x, y...) + `(call + (top eval) + ,(current-julia-module) + ,(cadr + (julia-expand-for-cl-convert + `(quote + (= (call ,name ,@(map (lambda (arg type) + (if (symbol? arg) + `(|::| ,arg ,type) + arg)) + (cadr lam2) + (cdddr (caddr (caddr e))))) + (call ($ ,the-closure) + ,@(map (lambda (arg) (if (symbol? arg) + arg + (list '... arg))) + (cadr lam2))))))))))))))) + ((lambda) + (let ((name (gensy)) + (tname (named-gensy 'anon)) + (vis (lam:vinfo e)) + (cvs (cadr (lam:vinfo e)))) + (if (and (null? cvs) #;(null? (cadr e)) (not lam)) + `(lambda ,(cadr e) + (,(clear-capture-bits (car vis)) + ,@(cdr vis)) + ,(closure-convert (cadddr e) 'anon + (if (any vinfo:capt (car vis)) + e #f))) + `(toplevel-butlast + ,@(internal-toplevel-exprs + (julia-expand-for-cl-convert + `(type #f ,tname + (block ,@(map car cvs))))) + (method call + (call (top svec) + (call (top apply_type) Tuple ,tname ,@(map arg-type-lowered (cadr e))) + (call (top svec))) + ,(convert-lambda e name tname) + #f) + (call ,tname ,@(map car cvs)))))) + ((body) + ;; insert Box allocations for captured/assigned arguments + (let ((args (if lam (map arg-name (lam:args lam)) + '()))) + `(body + ,@(apply append + (map (lambda (arg) + (let ((vi (assq arg (car (lam:vinfo lam))))) + (if (and vi (vinfo:asgn vi) (vinfo:capt vi)) + `((= ,arg (call (top Box) ,arg))) + '()))) + args)) + ,@(map (lambda (x) (closure-convert x fname lam)) + (cdr e))))) + (else (cons (car e) + (map (lambda (x) (closure-convert x fname lam)) + (cdr e))))))))) + (define (not-bool e) (cond ((memq e '(true #t)) 'false) - ((memq e '(false #f)) 'true) - (else `(call (top !) ,e)))) + ((memq e '(false #f)) 'true) + (else `(call (top !) ,e)))) ;; remove if, _while, block, break-block, and break ;; replaced with goto and gotoifnot @@ -3575,12 +3817,21 @@ So far only the second case can actually occur. ;; expander entry point -(define (julia-expand1 ex) +(define (julia-expand-for-cl-convert ex) (to-goto-form + (analyze-variables + (renumber-jlgensym + (flatten-scopes + (identify-locals + (julia-expand0 ex))))))) + +(define (julia-expand1 ex) + (cl-convert + (to-goto-form (analyze-variables (renumber-jlgensym (flatten-scopes - (identify-locals ex)))))) + (identify-locals ex))))))) (define (julia-expand01 ex) (to-LFF