diff --git a/NEWS.md b/NEWS.md index 33b2cebbb2388..23c96f94fc9b8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,6 +31,10 @@ New language features the module is first loaded, and on process startup if a pre-compiled version of the module is present ([#1268]). + * Multi-line comments ([#69], [#6128]): `#= .... =#` + + * --bounds-check=yes|no compiler option + Library improvements -------------------- diff --git a/base/abstractarray.jl b/base/abstractarray.jl index e7a0e38ad1a54..c92cda269fcb8 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -331,13 +331,6 @@ imag{T<:Real}(x::AbstractArray{T}) = zero(x) \(A::Number, B::AbstractArray) = B ./ A -./(x::Number,y::AbstractArray ) = throw(MethodError(./, (x,y))) -./(x::AbstractArray, y::Number) = throw(MethodError(./, (x,y))) - -.^(x::Number,y::AbstractArray ) = throw(MethodError(.^, (x,y))) -.^(x::AbstractArray, y::Number) = throw(MethodError(.^, (x,y))) - - ## Indexing: getindex ## getindex(t::AbstractArray, i::Real) = error("indexing not defined for ", typeof(t)) diff --git a/base/array.jl b/base/array.jl index 42dc231971e16..394f95b6262fa 100644 --- a/base/array.jl +++ b/base/array.jl @@ -261,9 +261,11 @@ convert{T,n,S}(::Type{Array{T,n}}, x::Array{S,n}) = copy!(similar(x,T), x) convert{T,S,N}(::Type{AbstractArray{T,N}}, B::StridedArray{S,N}) = copy!(similar(B,T), B) -function collect{C}(T::Type, itr::C) - if method_exists(length,(C,)) - a = Array(T,length(itr)) +function collect(T::Type, itr) + if applicable(length, itr) + # when length() isn't defined this branch might pollute the + # type of the other. + a = Array(T,length(itr)::Integer) i = 0 for x in itr a[i+=1] = x @@ -276,9 +278,8 @@ function collect{C}(T::Type, itr::C) end return a end -function collect{C}(itr::C) - method_exists(eltype,(C,)) ? collect(eltype(itr),itr) : [x for x in itr] -end + +collect(itr) = collect(eltype(itr), itr) ## Indexing: getindex ## @@ -786,7 +787,7 @@ for f in (:+, :-, :div, :mod, :&, :|, :$) end end end -for f in (:.+, :.-, :.*, :./, :.%, :div, :mod, :rem, :&, :|, :$) +for f in (:.+, :.-, :.*, :./, :.\, :.%, :div, :mod, :rem, :&, :|, :$) @eval begin function ($f){T}(A::Number, B::StridedArray{T}) F = similar(B, promote_array_type(typeof(A),T)) diff --git a/base/boot.jl b/base/boot.jl index 71152e6c116ae..3095da73e6c5d 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -152,7 +152,7 @@ export #checked_smul, checked_ssub, checked_uadd, checked_umul, checked_usub, #nan_dom_err, copysign_float, ctlz_int, ctpop_int, cttz_int, #div_float, eq_float, eq_int, eqfsi64, eqfui64, flipsign_int, select_value, - #fpext64, fpiseq, fpislt, fpsiround, fpuiround, fptosi, fptoui, + #sqrt_llvm, fpext64, fpiseq, fpislt, fpsiround, fpuiround, fptosi, fptoui, #fptrunc32, le_float, lefsi64, lefui64, lesif64, #leuif64, lshr_int, lt_float, ltfsi64, ltfui64, ltsif64, ltuif64, mul_float, #mul_int, ne_float, ne_int, neg_float, neg_int, not_int, or_int, rem_float, diff --git a/base/broadcast.jl b/base/broadcast.jl index df840ae2916fa..c52192524b706 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -2,6 +2,7 @@ module Broadcast using ..Cartesian import Base.promote_eltype +import Base.@get! import Base.num_bit_chunks, Base.@_msk_end, Base.getindex_unchecked import Base.(.+), Base.(.-), Base.(.*), Base.(./), Base.(.\) import Base.(.==), Base.(.<), Base.(.!=), Base.(.<=) @@ -203,73 +204,31 @@ function gen_broadcast_function_tobitarray(genbody::Function, nd::Int, narrays:: end end -let broadcast_cache = Dict() -global broadcast! -function broadcast!(f::Function, B, As::Union(Array,BitArray)...) - nd = ndims(B) - narrays = length(As) - key = (f, nd, narrays) - if !haskey(broadcast_cache, key) - func = gen_broadcast_function(gen_broadcast_body_iter, nd, narrays, f) - broadcast_cache[key] = func - else - func = broadcast_cache[key] - end - func(B, As...) - B -end -end # let broadcast_cache - -let broadcast_cache = Dict() -global broadcast! -function broadcast!(f::Function, B::BitArray, As::Union(Array,BitArray)...) - nd = ndims(B) - narrays = length(As) - key = (f, nd, narrays) - if !haskey(broadcast_cache, key) - func = gen_broadcast_function_tobitarray(gen_broadcast_body_iter_tobitarray, nd, narrays, f) - broadcast_cache[key] = func - else - func = broadcast_cache[key] - end - func(B, As...) - B -end -end # let broadcast_cache - -let broadcast_cache = Dict() -global broadcast! -function broadcast!(f::Function, B, As...) - nd = ndims(B) - narrays = length(As) - key = (f, nd, narrays) - if !haskey(broadcast_cache, key) - func = gen_broadcast_function(gen_broadcast_body_cartesian, nd, narrays, f) - broadcast_cache[key] = func - else - func = broadcast_cache[key] - end - func(B, As...) - B -end -end # let broadcast_cache - -let broadcast_cache = Dict() -global broadcast! -function broadcast!(f::Function, B::BitArray, As...) - nd = ndims(B) - narrays = length(As) - key = (f, nd, narrays) - if !haskey(broadcast_cache, key) - func = gen_broadcast_function_tobitarray(gen_broadcast_body_cartesian_tobitarray, nd, narrays, f) - broadcast_cache[key] = func - else - func = broadcast_cache[key] - end - func(B, As...) - B +for (Bsig, Asig, gbf, gbb) in + ((BitArray , Union(Array,BitArray) , + :gen_broadcast_function_tobitarray, :gen_broadcast_body_iter_tobitarray ), + (Any , Union(Array,BitArray) , + :gen_broadcast_function , :gen_broadcast_body_iter ), + (BitArray , Any , + :gen_broadcast_function_tobitarray, :gen_broadcast_body_cartesian_tobitarray), + (Any , Any , + :gen_broadcast_function , :gen_broadcast_body_cartesian )) + + @eval let cache = Dict{Function,Dict{Int,Dict{Int,Function}}}() + global broadcast! + function broadcast!(f::Function, B::$Bsig, As::$Asig...) + nd = ndims(B) + narrays = length(As) + + cache_f = @get! cache f Dict{Int,Dict{Int,Function}}() + cache_f_na = @get! cache_f narrays Dict{Int,Function}() + func = @get! cache_f_na nd $gbf($gbb, nd, narrays, f) + + func(B, As...) + B + end + end # let broadcast_cache end -end # let broadcast_cache broadcast(f::Function, As...) = broadcast!(f, Array(promote_eltype(As...), broadcast_shape(As...)), As...) diff --git a/base/client.jl b/base/client.jl index 8f5589f887a64..aee03eb75381f 100644 --- a/base/client.jl +++ b/base/client.jl @@ -364,14 +364,17 @@ function load_juliarc() try_include(abspath(homedir(),".juliarc.jl")) end - -function _start() +function early_init() Sys.init_sysinfo() if CPU_CORES > 8 && !("OPENBLAS_NUM_THREADS" in keys(ENV)) && !("OMP_NUM_THREADS" in keys(ENV)) # Prevent openblas from stating to many threads, unless/until specifically requested ENV["OPENBLAS_NUM_THREADS"] = 8 end start_gc_msgs_task() +end + +function _start() + early_init() try any(a->(a=="--worker"), ARGS) || init_head_sched() diff --git a/base/dict.jl b/base/dict.jl index 43f9b70592dcc..945a4faa48df2 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -561,6 +561,26 @@ function get!{K,V}(default::Function, h::Dict{K,V}, key0) return v end +# NOTE: this macro is specific to Dict, not Associative, and should +# therefore not be exported as-is: it's for internal use only. +macro get!(h, key0, default) + quote + K, V = eltype($(esc(h))) + key = convert(K, $(esc(key0))) + isequal(key, $(esc(key0))) || error($(esc(key0)), " is not a valid key for type ", K) + idx = ht_keyindex2($(esc(h)), key) + if idx < 0 + idx = -idx + v = convert(V, $(esc(default))) + _setindex!($(esc(h)), v, key, idx) + else + @inbounds v = $(esc(h)).vals[idx] + end + v + end +end + + function getindex{K,V}(h::Dict{K,V}, key) index = ht_keyindex(h, key) return (index<0) ? throw(KeyError(key)) : h.vals[index]::V diff --git a/base/intfuncs.jl b/base/intfuncs.jl index dbf5007e5c366..43acccb9b7bb2 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -146,7 +146,7 @@ nextpow2(x::Integer) = oftype(x,x < 0 ? -nextpow2(unsigned(-x)) : nextpow2(unsig prevpow2(x::Unsigned) = (one(x)>>(x==0)) << ((sizeof(x)<<3)-leading_zeros(x)-1) prevpow2(x::Integer) = oftype(x,x < 0 ? -prevpow2(unsigned(-x)) : prevpow2(unsigned(x))) -ispow2(x::Integer) = ((x<=0) == (x&(x-1))) +ispow2(x::Integer) = count_ones(x)==1 # smallest a^n >= x, with integer n function nextpow(a::Real, x::Real) diff --git a/base/io.jl b/base/io.jl index 0faf10ba4988f..d93f9f565a7d0 100644 --- a/base/io.jl +++ b/base/io.jl @@ -226,17 +226,9 @@ function done(itr::EachLine, nada) true end next(itr::EachLine, nada) = (readline(itr.stream), nothing) +eltype(itr::EachLine) = ByteString -function readlines(s, fx::Function...) - a = {} - for l in eachline(s) - for f in fx - l = f(l) - end - push!(a, l) - end - return a -end +readlines(s) = collect(eachline(s)) ## IOStream diff --git a/base/math.jl b/base/math.jl index 8570ec8b3553e..e2f3d19fd0cdd 100644 --- a/base/math.jl +++ b/base/math.jl @@ -22,7 +22,7 @@ import Base: log, exp, sin, cos, tan, sinh, cosh, tanh, asin, acos, atan, asinh, acosh, atanh, sqrt, log2, log10, max, min, minmax, ceil, floor, trunc, round, ^, exp2, exp10 -import Core.Intrinsics.nan_dom_err +import Core.Intrinsics: nan_dom_err, sqrt_llvm, box, unbox # non-type specific math functions @@ -49,25 +49,22 @@ function sinpi(x::Real) return nan(x) end - rx = float(rem(x,2)) + rx = copysign(float(rem(x,2)),x) arx = abs(rx) - if arx == 0.0 - # return -0.0 iff x == -0.0 - return x == 0.0 ? x : arx - elseif arx < 0.25 + if arx < oftype(rx,0.25) return sin(pi*rx) - elseif arx <= 0.75 - arx = 0.5 - arx + elseif arx <= oftype(rx,0.75) + arx = oftype(rx,0.5) - arx return copysign(cos(pi*arx),rx) - elseif arx < 1.25 - rx = copysign(1.0,rx) - rx + elseif arx < oftype(rx,1.25) + rx = (one(rx) - arx)*sign(rx) return sin(pi*rx) - elseif arx <= 1.75 - arx = 1.5 - arx + elseif arx <= oftype(rx,1.75) + arx = oftype(rx,1.5) - arx return -copysign(cos(pi*arx),rx) else - rx = rx - copysign(2.0,rx) + rx = rx - copysign(oftype(rx,2.0),rx) return sin(pi*rx) end end @@ -81,19 +78,19 @@ function cospi(x::Real) rx = abs(float(rem(x,2))) - if rx <= 0.25 + if rx <= oftype(rx,0.25) return cos(pi*rx) - elseif rx < 0.75 - rx = 0.5 - rx + elseif rx < oftype(rx,0.75) + rx = oftype(rx,0.5) - rx return sin(pi*rx) - elseif rx <= 1.25 - rx = 1.0 - rx + elseif rx <= oftype(rx,1.25) + rx = one(rx) - rx return -cos(pi*rx) - elseif rx < 1.75 - rx = rx - 1.5 + elseif rx < oftype(rx,1.75) + rx = rx - oftype(rx,1.5) return sin(pi*rx) else - rx = 2.0 - rx + rx = oftype(rx,2.0) - rx return cos(pi*rx) end end @@ -172,25 +169,22 @@ function sind(x::Real) return nan(x) end - rx = rem(x,360.0) + rx = copysign(float(rem(x,360)),x) arx = abs(rx) - if arx == 0.0 - # return -0.0 iff x == -0.0 - return x == 0.0 ? 0.0 : arx - elseif arx < 45.0 + if arx < oftype(rx,45.0) return sin(deg2rad(rx)) - elseif arx <= 135.0 - arx = 90.0 - arx + elseif arx <= oftype(rx,135.0) + arx = oftype(rx,90.0) - arx return copysign(cos(deg2rad(arx)),rx) - elseif arx < 225.0 - rx = copysign(180.0,rx) - rx + elseif arx < oftype(rx,225.0) + rx = (oftype(rx,180.0) - arx)*sign(rx) return sin(deg2rad(rx)) elseif arx <= 315.0 - arx = 270.0 - arx + arx = oftype(rx,270.0) - arx return -copysign(cos(deg2rad(arx)),rx) else - rx = rx - copysign(360.0,rx) + rx = rx - copysign(oftype(rx,360.0),rx) return sin(deg2rad(rx)) end end @@ -203,21 +197,21 @@ function cosd(x::Real) return nan(x) end - rx = abs(rem(x,360.0)) + rx = abs(float(rem(x,360))) - if rx <= 45.0 + if rx <= oftype(rx,45.0) return cos(deg2rad(rx)) - elseif rx < 135.0 - rx = 90.0 - rx + elseif rx < oftype(rx,135.0) + rx = oftype(rx,90.0) - rx return sin(deg2rad(rx)) - elseif rx <= 225.0 - rx = 180.0 - rx + elseif rx <= oftype(rx,225.0) + rx = oftype(rx,180.0) - rx return -cos(deg2rad(rx)) - elseif rx < 315.0 - rx = rx - 270.0 + elseif rx < oftype(rx,315.0) + rx = rx - oftype(rx,270.0) return sin(deg2rad(rx)) else - rx = 360.0 - rx + rx = oftype(rx,360.0) - rx return cos(deg2rad(rx)) end end @@ -272,7 +266,7 @@ exp10(x::Integer) = exp10(float(x)) # functions that return NaN on non-NaN argument for domain error for f in (:sin, :cos, :tan, :asin, :acos, :acosh, :atanh, :log, :log2, :log10, - :lgamma, :sqrt, :log1p) + :lgamma, :log1p) @eval begin ($f)(x::Float64) = nan_dom_err(ccall(($(string(f)),libm), Float64, (Float64,), x), x) ($f)(x::Float32) = nan_dom_err(ccall(($(string(f,"f")),libm), Float32, (Float32,), x), x) @@ -281,6 +275,11 @@ for f in (:sin, :cos, :tan, :asin, :acos, :acosh, :atanh, :log, :log2, :log10, end end +sqrt(x::Float64) = box(Float64,sqrt_llvm(unbox(Float64,x))) +sqrt(x::Float32) = box(Float32,sqrt_llvm(unbox(Float32,x))) +sqrt(x::Real) = sqrt(float(x)) +@vectorize_1arg Number sqrt + for f in (:ceil, :trunc, :significand) # :rint, :nearbyint @eval begin ($f)(x::Float64) = ccall(($(string(f)),libm), Float64, (Float64,), x) @@ -410,8 +409,8 @@ modf(x) = rem(x,one(x)), trunc(x) ^(x::Float64, y::Float64) = nan_dom_err(ccall((:pow,libm), Float64, (Float64,Float64), x, y), x+y) ^(x::Float32, y::Float32) = nan_dom_err(ccall((:powf,libm), Float32, (Float32,Float32), x, y), x+y) -^(x::Float64, y::Integer) = x^float64(y) -^(x::Float32, y::Integer) = x^float32(y) +^(x::Float64, y::Integer) = ccall((:pow,libm), Float64, (Float64,Float64), x, y) +^(x::Float32, y::Integer) = ccall((:powf,libm), Float32, (Float32,Float32), x, y) # special functions diff --git a/contrib/Julia.tmbundle/Preferences/Comments.tmPreferences b/contrib/Julia.tmbundle/Preferences/Comments.tmPreferences index 33a7700e3f91b..c7b376902bd32 100644 --- a/contrib/Julia.tmbundle/Preferences/Comments.tmPreferences +++ b/contrib/Julia.tmbundle/Preferences/Comments.tmPreferences @@ -20,6 +20,30 @@ value # + + name + TM_COMMENT_START_2 + value + #= + + + name + TM_COMMENT_END_2 + value + =# + + + name + TM_COMMENT_DISABLE_INDENT_2 + value + yes + + + name + TM_COMMENT_MODE_2 + value + block + uuid diff --git a/contrib/Julia.tmbundle/Syntaxes/Julia.tmLanguage b/contrib/Julia.tmbundle/Syntaxes/Julia.tmLanguage index 437e217a07101..acf61d295307d 100644 --- a/contrib/Julia.tmbundle/Syntaxes/Julia.tmLanguage +++ b/contrib/Julia.tmbundle/Syntaxes/Julia.tmLanguage @@ -109,6 +109,30 @@ patterns + + begin + #= + beginCaptures + + 0 + + name + punctuation.definition.comment.begin.julia + + + end + =# + endCaptures + + 0 + + name + punctuation.definition.comment.end.julia + + + name + comment.block.number-sign-equals.julia + captures diff --git a/contrib/julia.xml b/contrib/julia.xml index 5d29bcda648aa..1422b0470ba2d 100644 --- a/contrib/julia.xml +++ b/contrib/julia.xml @@ -29,7 +29,7 @@ - + @@ -342,6 +342,7 @@ + @@ -433,6 +434,15 @@ + + + + + + + + + @@ -464,6 +474,7 @@ + diff --git a/deps/libuv b/deps/libuv index a37279a161589..6649b84058e82 160000 --- a/deps/libuv +++ b/deps/libuv @@ -1 +1 @@ -Subproject commit a37279a16158923480bab1c23fc8430f76a17bed +Subproject commit 6649b84058e82f52adbc1a98f0b94b8aff8c467d diff --git a/doc/conf.py b/doc/conf.py index 1a0799ceffbc9..b38dabd5670ea 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -21,6 +21,7 @@ sys.path.append(juliadoc_dir) import juliadoc +import sphinx_rtd_theme # -- General configuration ----------------------------------------------------- @@ -49,7 +50,7 @@ # General information about the project. project = u'Julia Language' AUTHORS = u"Jeff Bezanson, Stefan Karpinski, Viral Shah, Alan Edelman, et al." -copyright = u'2012-2013, '+AUTHORS +copyright = u'2012-2014, '+AUTHORS # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -112,7 +113,8 @@ #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. -html_theme_path = [juliadoc.get_theme_dir()] +html_theme_path = [juliadoc.get_theme_dir(), + sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". diff --git a/doc/index.rst b/doc/index.rst index 0f6e238b18678..50312f42d89fb 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -3,9 +3,65 @@ Julia Documentation %%%%%%%%%%%%%%%%%%%%% +* :ref:`manual` +* :ref:`stdlib` + +.. _manual: + +######## + Manual +######## + +.. toctree:: + :maxdepth: 1 + + manual/introduction + manual/getting-started + manual/variables + manual/integers-and-floating-point-numbers + manual/mathematical-operations + manual/complex-and-rational-numbers + manual/strings + manual/functions + manual/control-flow + manual/variables-and-scoping + manual/types + manual/methods + manual/constructors + manual/conversion-and-promotion + manual/modules + manual/metaprogramming + manual/arrays + manual/linear-algebra + manual/networking-and-streams + manual/parallel-computing + manual/running-external-programs + manual/calling-c-and-fortran-code + manual/embedding + manual/packages + manual/performance-tips + manual/style-guide + manual/faq + manual/noteworthy-differences + +.. _stdlib: + +################## + Standard Library +################## + .. toctree:: :maxdepth: 1 - manual/index - stdlib/index - packages/packagelist + stdlib/base + stdlib/sparse + stdlib/linalg + stdlib/constants + stdlib/file + stdlib/punctuation + stdlib/sort + stdlib/pkg + stdlib/collections + stdlib/graphics + stdlib/test + stdlib/profile diff --git a/doc/juliadoc b/doc/juliadoc index 300b72cd13fe9..88cb64ff33f25 160000 --- a/doc/juliadoc +++ b/doc/juliadoc @@ -1 +1 @@ -Subproject commit 300b72cd13fe9b54b938a0b49416e4d860181d0f +Subproject commit 88cb64ff33f25d50244c337cd3c865392a77400a diff --git a/doc/manual/getting-started.rst b/doc/manual/getting-started.rst index 2e09d7a46566a..0ed2a6863fa4d 100644 --- a/doc/manual/getting-started.rst +++ b/doc/manual/getting-started.rst @@ -98,6 +98,7 @@ those available for the ``perl`` and ``ruby`` programs:: julia [options] [program] [args...] -v --version Display version information + -h --help Print this message -q --quiet Quiet startup without banner -H --home= Load files relative to -T --tab= Set REPL tab width to @@ -116,7 +117,7 @@ those available for the ``perl`` and ``ruby`` programs:: -F Load ~/.juliarc.jl, then handle remaining inputs --color=yes|no Enable or disable color text - -h --help Print this message + --check-bounds=yes|no Emit bounds checks always or never (ignoring declarations) Resources --------- diff --git a/doc/requirements.txt b/doc/requirements.txt index 0cfb48ae2a869..6e0416e70da76 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1 +1,2 @@ -e git+https://github.com/JuliaLang/JuliaDoc.git#egg=JuliaDoc +-e git+https://github.com/snide/sphinx_rtd_theme.git#egg=sphinx_rtd_theme diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index bfe4fe1d7b2c9..9af5bfceff3de 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -1,5 +1,9 @@ .. currentmodule:: Base +********************** + The Standard Library +********************** + Introduction ------------ @@ -624,7 +628,7 @@ Iterable Collections Determine whether predicate ``p`` returns true for all elements of ``itr``. - **Example**: ``all((i) -> i>i, [4,5,6]) = true`` + **Example**: ``all(i->(4<=i<=6), [4,5,6]) = true`` .. function:: map(f, c...) -> collection diff --git a/doc/stdlib/index.rst b/doc/stdlib/index.rst index 109e968b21ce5..a45b06ee855b8 100644 --- a/doc/stdlib/index.rst +++ b/doc/stdlib/index.rst @@ -5,10 +5,6 @@ The Julia Standard Library ############################ -********* -Built-ins -********* - .. toctree:: :maxdepth: 1 @@ -19,16 +15,6 @@ Built-ins file punctuation sort - -.. _built-in-modules: - -**************** -Built-in Modules -**************** - -.. toctree:: - :maxdepth: 1 - pkg collections graphics diff --git a/doc/stdlib/linalg.rst b/doc/stdlib/linalg.rst index 2ed2edfc1d8cd..c2d72de56b745 100644 --- a/doc/stdlib/linalg.rst +++ b/doc/stdlib/linalg.rst @@ -161,7 +161,9 @@ Linear algebra functions in Julia are largely implemented by calling functions f .. function:: bkfact(A) -> BunchKaufman - Compute the Bunch-Kaufman factorization of a real symmetric or complex Hermitian matrix ``A`` and return a ``BunchKaufman`` object. The following functions are available for ``BunchKaufman`` objects: ``size``, ``\``, ``inv``, ``issym``, ``ishermitian``. + Compute the Bunch-Kaufman [Bunch1977]_ factorization of a real symmetric or complex Hermitian matrix ``A`` and return a ``BunchKaufman`` object. The following functions are available for ``BunchKaufman`` objects: ``size``, ``\``, ``inv``, ``issym``, ``ishermitian``. + + .. [Bunch1977] J R Bunch and L Kaufman, Some stable methods for calculating inertia and solving symmetric linear systems, Mathematics of Computation 31:137 (1977), 163-179. `url`_. .. function:: bkfact!(A) -> BunchKaufman @@ -306,9 +308,9 @@ Linear algebra functions in Julia are largely implemented by calling functions f Scale an array ``A`` by a scalar ``b``, returning a new array. - If ``A`` is a matrix and ``b`` is a vector, then ``scale!(A,b)`` + If ``A`` is a matrix and ``b`` is a vector, then ``scale(A,b)`` scales each column ``i`` of ``A`` by ``b[i]`` (similar to - ``A*diagm(b)``), while ``scale!(b,A)`` scales each row ``i`` of + ``A*diagm(b)``), while ``scale(b,A)`` scales each row ``i`` of ``A`` by ``b[i]`` (similar to ``diagm(b)*A``), returning a new array. Note: for large ``A``, ``scale`` can be much faster than ``A .* b`` or @@ -316,7 +318,7 @@ Linear algebra functions in Julia are largely implemented by calling functions f .. function:: scale!(A, b), scale!(b, A) - Scale an array ``A`` by a scalar ``b``, similar to ``scale`` but + Scale an array ``A`` by a scalar ``b``, similar to :func:`scale` but overwriting ``A`` in-place. If ``A`` is a matrix and ``b`` is a vector, then ``scale!(A,b)`` diff --git a/doc/stdlib/punctuation.rst b/doc/stdlib/punctuation.rst index c5422b4285bfe..0cdd88959f423 100644 --- a/doc/stdlib/punctuation.rst +++ b/doc/stdlib/punctuation.rst @@ -11,6 +11,8 @@ Extended documentation for mathematical symbols & functions is :ref:`here (int64_t)S32_MAX || i64 < (int64_t)S32_MIN) - return (jl_value_t*)jl_box_int64(i64); - return (jl_value_t*)jl_box_int32((int32_t)i64); + jl_compileropts.int_literals!=64 #endif + ) { + if (i64 > (int64_t)S32_MAX || i64 < (int64_t)S32_MIN) + return (jl_value_t*)jl_box_int64(i64); + return (jl_value_t*)jl_box_int32((int32_t)i64); + } + else { + return (jl_value_t*)jl_box_int64(i64); + } } if (issymbol(e)) { if (e == true_sym) @@ -477,6 +484,8 @@ jl_value_t *jl_parse_next(void) if (c == FL_EOF) return NULL; if (iscons(c)) { + if (cdr_(c) == FL_EOF) + return NULL; value_t a = car_(c); if (isfixnum(a)) { jl_lineno = numval(a); diff --git a/src/builtins.c b/src/builtins.c index 9e1a12018fb23..55edb077936d8 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -648,7 +648,7 @@ DLLEXPORT int jl_substrtod(char *str, size_t offset, int len, double *out) char *p; errno = 0; char *bstr = str+offset; - *out = strtod(bstr, &p); + *out = strtod_c(bstr, &p); if ((p == bstr) || (p != (bstr+len)) || (errno==ERANGE && (*out==0 || *out==HUGE_VAL || *out==-HUGE_VAL))) return 1; @@ -659,7 +659,7 @@ DLLEXPORT int jl_strtod(char *str, double *out) { char *p; errno = 0; - *out = strtod(str, &p); + *out = strtod_c(str, &p); if (p == str || (errno==ERANGE && (*out==0 || *out==HUGE_VAL || *out==-HUGE_VAL))) return 1; @@ -677,9 +677,9 @@ DLLEXPORT int jl_substrtof(char *str, int offset, int len, float *out) errno = 0; char *bstr = str+offset; #if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_) - *out = (float)strtod(bstr, &p); + *out = (float)strtod_c(bstr, &p); #else - *out = strtof(bstr, &p); + *out = strtof_c(bstr, &p); #endif if ((p == bstr) || (p != (bstr+len)) || @@ -693,9 +693,9 @@ DLLEXPORT int jl_strtof(char *str, float *out) char *p; errno = 0; #if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_) - *out = (float)strtod(str, &p); + *out = (float)strtod_c(str, &p); #else - *out = strtof(str, &p); + *out = strtof_c(str, &p); #endif if (p == str || (errno==ERANGE && (*out==0 || *out==HUGE_VALF || *out==-HUGE_VALF))) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index cf50e5fd40d35..4da8f10c0bce7 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -767,7 +767,9 @@ static Value *emit_bounds_check(Value *i, Value *len, jl_codectx_t *ctx) { Value *im1 = builder.CreateSub(i, ConstantInt::get(T_size, 1)); #if CHECK_BOUNDS==1 - if (ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true) { + if (((ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true) && + jl_compileropts.check_bounds != JL_COMPILEROPT_CHECK_BOUNDS_OFF) || + jl_compileropts.check_bounds == JL_COMPILEROPT_CHECK_BOUNDS_ON) { Value *ok = builder.CreateICmpULT(im1, len); raise_exception_unless(ok, prepare_global(jlboundserr_var), ctx); } @@ -1296,8 +1298,10 @@ static Value *emit_array_nd_index(Value *a, jl_value_t *ex, size_t nd, jl_value_ { Value *i = ConstantInt::get(T_size, 0); Value *stride = ConstantInt::get(T_size, 1); - bool bc = ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true; #if CHECK_BOUNDS==1 + bool bc = ((ctx->boundsCheck.empty() || ctx->boundsCheck.back()==true) && + jl_compileropts.check_bounds != JL_COMPILEROPT_CHECK_BOUNDS_OFF) || + jl_compileropts.check_bounds == JL_COMPILEROPT_CHECK_BOUNDS_ON; BasicBlock *failBB=NULL, *endBB=NULL; if (bc) { failBB = BasicBlock::Create(getGlobalContext(), "oob"); diff --git a/src/codegen.cpp b/src/codegen.cpp index ebed2ab9110f4..f5cdaee1e99e1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -116,8 +116,6 @@ void __attribute__(()) __stack_chk_fail() } } -#define CONDITION_REQUIRES_BOOL - #define DISABLE_FLOAT16 // llvm state @@ -2223,12 +2221,10 @@ static void emit_assignment(jl_value_t *l, jl_value_t *r, jl_codectx_t *ctx) static Value *emit_condition(jl_value_t *cond, const std::string &msg, jl_codectx_t *ctx) { Value *condV = emit_unboxed(cond, ctx); -#ifdef CONDITION_REQUIRES_BOOL if (expr_type(cond, ctx) != (jl_value_t*)jl_bool_type && condV->getType() != T_int1) { emit_typecheck(condV, (jl_value_t*)jl_bool_type, msg, ctx); } -#endif if (condV->getType() == T_int1) { return builder.CreateXor(condV, ConstantInt::get(T_int1,1)); } @@ -2589,7 +2585,8 @@ static Value *emit_expr(jl_value_t *expr, jl_codectx_t *ctx, bool isboxed, builder.SetInsertPoint(tryblk); } else if (head == boundscheck_sym) { - if (jl_array_len(ex->args) > 0) { + if (jl_array_len(ex->args) > 0 && + jl_compileropts.check_bounds == JL_COMPILEROPT_CHECK_BOUNDS_DEFAULT) { jl_value_t *arg = args[0]; if (arg == jl_true) { ctx->boundsCheck.push_back(true); diff --git a/src/flisp/read.c b/src/flisp/read.c index caaa9e64c4e4e..56a639439e56f 100644 --- a/src/flisp/read.c +++ b/src/flisp/read.c @@ -39,7 +39,7 @@ int isnumtok_base(char *tok, value_t *pval, int base) return 0; if (!((tok[0]=='0' && tok[1]=='x') || (base >= 15)) && strpbrk(tok, ".eEpP")) { - d = strtod(tok, &end); + d = strtod_c(tok, &end); if (*end == '\0') { if (pval) *pval = mk_double(d); return 1; @@ -55,7 +55,7 @@ int isnumtok_base(char *tok, value_t *pval, int base) // hexadecimal float literals else if (((tok[0]=='0' && tok[1]=='x') || (base == 16)) && strpbrk(tok, "pP")) { - d = strtod(tok, &end); + d = strtod_c(tok, &end); if (*end == '\0') { if (pval) *pval = mk_double(d); return 1; diff --git a/src/init.c b/src/init.c index 9a80112e18c0d..9ef8565bd42f6 100644 --- a/src/init.c +++ b/src/init.c @@ -62,7 +62,9 @@ extern BOOL (WINAPI *hSymRefreshModuleList)(HANDLE); char *julia_home = NULL; jl_compileropts_t jl_compileropts = { NULL, // build_path - 0 // code_coverage + 0, // code_coverage + JL_COMPILEROPT_CHECK_BOUNDS_DEFAULT, + 0 // int32_literals }; int jl_boot_file_loaded = 0; diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 3001dbbdbbd84..6d0729b558b64 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -34,6 +34,7 @@ namespace JL_I { nan_dom_err, // functions abs_float, copysign_float, flipsign_int, select_value, + sqrt_llvm, // pointer access pointerref, pointerset, pointertoref, // c interface @@ -1243,6 +1244,14 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, HANDLE(jl_alloca,1) { return builder.CreateAlloca(IntegerType::get(jl_LLVMContext, 8),JL_INT(x)); } + HANDLE(sqrt_llvm,1) { + x = FP(x); + raise_exception_unless(builder.CreateFCmpUGE(x, ConstantFP::get(x->getType(),0.0)), + prepare_global(jldomerr_var), ctx); + return builder.CreateCall(Intrinsic::getDeclaration(jl_Module, Intrinsic::sqrt, + ArrayRef(x->getType())), + x); + } default: assert(false); } @@ -1321,7 +1330,7 @@ extern "C" void jl_init_intrinsic_functions(void) ADD_I(uitofp); ADD_I(sitofp); ADD_I(fptrunc); ADD_I(fpext); ADD_I(abs_float); ADD_I(copysign_float); - ADD_I(flipsign_int); ADD_I(select_value); + ADD_I(flipsign_int); ADD_I(select_value); ADD_I(sqrt_llvm); ADD_I(pointerref); ADD_I(pointerset); ADD_I(pointertoref); ADD_I(checked_sadd); ADD_I(checked_uadd); ADD_I(checked_ssub); ADD_I(checked_usub); diff --git a/src/jlapi.c b/src/jlapi.c index da9cbc3260b11..b3105bd203642 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -51,11 +51,10 @@ DLLEXPORT void jl_init(char *julia_home_dir) jl_set_const(jl_core_module, jl_symbol("JULIA_HOME"), jl_cstr_to_string(julia_home)); jl_module_export(jl_core_module, jl_symbol("JULIA_HOME")); - jl_eval_string("Base.reinit_stdio()"); - jl_eval_string("Base.Random.librandom_init()"); - jl_eval_string("Base.init_sched()"); + jl_eval_string("Base.early_init()"); jl_eval_string("Base.init_head_sched()"); jl_eval_string("Base.init_load_path()"); + jl_exception_clear(); } DLLEXPORT void *jl_eval_string(char *str) @@ -72,6 +71,7 @@ DLLEXPORT void *jl_eval_string(char *str) JL_GC_PUSH1(&ast); r = jl_toplevel_eval(ast); JL_GC_POP(); + jl_exception_clear(); } JL_CATCH { //jl_show(jl_stderr_obj(), jl_exception_in_transit); @@ -143,6 +143,7 @@ DLLEXPORT jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs argv[i] = args[i-1]; v = jl_apply(f, args, nargs); JL_GC_POP(); + jl_exception_clear(); } JL_CATCH { v = NULL; @@ -157,6 +158,7 @@ DLLEXPORT jl_value_t *jl_call0(jl_function_t *f) JL_GC_PUSH1(&f); v = jl_apply(f, NULL, 0); JL_GC_POP(); + jl_exception_clear(); } JL_CATCH { v = NULL; @@ -171,6 +173,7 @@ DLLEXPORT jl_value_t *jl_call1(jl_function_t *f, jl_value_t *a) JL_GC_PUSH2(&f,&a); v = jl_apply(f, &a, 1); JL_GC_POP(); + jl_exception_clear(); } JL_CATCH { v = NULL; @@ -186,6 +189,7 @@ DLLEXPORT jl_value_t *jl_call2(jl_function_t *f, jl_value_t *a, jl_value_t *b) jl_value_t *args[2] = {a,b}; v = jl_apply(f, args, 2); JL_GC_POP(); + jl_exception_clear(); } JL_CATCH { v = NULL; @@ -201,6 +205,7 @@ DLLEXPORT jl_value_t *jl_call3(jl_function_t *f, jl_value_t *a, jl_value_t *b, j jl_value_t *args[3] = {a,b,c}; v = jl_apply(f, args, 3); JL_GC_POP(); + jl_exception_clear(); } JL_CATCH { v = NULL; @@ -224,6 +229,7 @@ DLLEXPORT jl_value_t *jl_get_field(jl_value_t *o, char *fld) jl_value_t *s = (jl_value_t*)jl_symbol(fld); int i = jl_field_index((jl_datatype_t*)jl_typeof(o), (jl_sym_t*)s, 1); v = jl_get_nth_field(o, i); + jl_exception_clear(); } JL_CATCH { v = NULL; diff --git a/src/jlfrontend.scm b/src/jlfrontend.scm index 0a02bc0ba3bf1..8d0fb59d63c8f 100644 --- a/src/jlfrontend.scm +++ b/src/jlfrontend.scm @@ -181,19 +181,22 @@ (set! *ts-stack* (cdr *ts-stack*))) (define (jl-parser-next) - (skip-ws-and-comments (ts:port current-token-stream)) - (let ((lineno (input-port-line (ts:port current-token-stream)))) - (let ((e (parser-wrap (lambda () - (julia-parse current-token-stream))))) - (if (eof-object? e) - e - (cons lineno - (parser-wrap - (lambda () - (if (and (pair? e) (or (eq? (car e) 'error) - (eq? (car e) 'continue))) + (let* ((err (parser-wrap + (lambda () + (skip-ws-and-comments (ts:port current-token-stream))))) + (lineno (input-port-line (ts:port current-token-stream)))) + (cons lineno + (if (pair? err) + err + (parser-wrap + (lambda () + (let ((e (julia-parse current-token-stream))) + (if (eof-object? e) e - (expand-toplevel-expr e))))))))) + (if (and (pair? e) (or (eq? (car e) 'error) + (eq? (car e) 'continue))) + e + (expand-toplevel-expr e)))))))))) ; expand a piece of raw surface syntax to an executable thunk (define (jl-expand-to-thunk expr) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index e276d1a8567d5..4d14a0ec46f0b 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -355,10 +355,34 @@ (eq? (car t) 'macrocall) (memq (cadr t) '(@int128_str @uint128_str @bigint_str)))) +; skip to end of comment, starting at #: either #... or #= .... =#. +(define (skip-comment port) + (define (skip-multiline-comment port count) + (let ((c (read-char port))) + (if (eof-object? c) + (error "incomplete: unterminated multi-line comment #= ... =#") + (begin (if (eqv? c #\=) + (let ((c (peek-char port))) + (if (eqv? c #\#) + (begin + (read-char port) + (if (> count 1) + (skip-multiline-comment port (- count 1)))) + (skip-multiline-comment port count))) + (if (eqv? c #\#) + (skip-multiline-comment port + (if (eqv? (peek-char port) #\=) (+ count 1) count)) + (skip-multiline-comment port count))))))) + + (read-char port) ; read # that was already peeked + (if (eqv? (peek-char port) #\=) + (skip-multiline-comment port 1) + (skip-to-eol port))) + (define (skip-ws-and-comments port) (skip-ws port #t) (if (eqv? (peek-char port) #\#) - (begin (skip-to-eol port) + (begin (skip-comment port) (skip-ws-and-comments port))) #t) @@ -371,7 +395,7 @@ ((char-numeric? c) (read-number port #f #f)) - ((eqv? c #\#) (skip-to-eol port) (next-token port s)) + ((eqv? c #\#) (skip-comment port) (next-token port s)) ; . is difficult to handle; it could start a number or operator ((and (eqv? c #\.) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 4691dc6811a50..fca5717b4ba73 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -2914,13 +2914,28 @@ So far only the second case can actually occur. (set-car! (cdr end-jump) (make&mark-label))))) ((block) (for-each (lambda (x) (compile x break-labels vi)) (cdr e))) - ((_while) (let ((topl (make&mark-label)) - (endl (make-label))) - (compile (cadr e) break-labels vi) - (emit `(gotoifnot ,(goto-form (caddr e)) ,endl)) - (compile (cadddr e) break-labels vi) - (emit `(goto ,topl)) - (mark-label endl))) + ((_while) + (let ((test-blk (cadr e)) + (endl (make-label))) + (if (or (atom? test-blk) (equal? test-blk '(block))) + ;; if condition is simple, compile it twice in order + ;; to generate a single branch per iteration. + (let ((topl (make-label))) + (compile test-blk break-labels vi) + (emit `(gotoifnot ,(goto-form (caddr e)) ,endl)) + (mark-label topl) + (compile (cadddr e) break-labels vi) + (compile test-blk break-labels vi) + (emit `(gotoifnot (call (top !) ,(goto-form (caddr e))) ,topl)) + (mark-label endl)) + + (let ((topl (make&mark-label))) + (compile test-blk break-labels vi) + (emit `(gotoifnot ,(goto-form (caddr e)) ,endl)) + (compile (cadddr e) break-labels vi) + (emit `(goto ,topl)) + (mark-label endl))))) + ((break-block) (let ((endl (make-label))) (compile (caddr e) (cons (list (cadr e) endl handler-level) diff --git a/src/julia.h b/src/julia.h index 83ea753b26d85..dfbf129fa2488 100644 --- a/src/julia.h +++ b/src/julia.h @@ -384,7 +384,7 @@ extern DLLEXPORT jl_datatype_t *jl_methtable_type; extern DLLEXPORT jl_datatype_t *jl_method_type; extern DLLEXPORT jl_datatype_t *jl_task_type; -extern jl_tuple_t *jl_null; +extern DLLEXPORT jl_tuple_t *jl_null; #define JL_NULL ((void*)jl_null) extern jl_value_t *jl_true; extern jl_value_t *jl_false; @@ -611,7 +611,7 @@ jl_value_t *jl_full_type(jl_value_t *v); int jl_is_type(jl_value_t *v); DLLEXPORT int jl_is_leaf_type(jl_value_t *v); int jl_has_typevars(jl_value_t *v); -int jl_subtype(jl_value_t *a, jl_value_t *b, int ta); +DLLEXPORT int jl_subtype(jl_value_t *a, jl_value_t *b, int ta); int jl_type_morespecific(jl_value_t *a, jl_value_t *b, int ta); DLLEXPORT int jl_types_equal(jl_value_t *a, jl_value_t *b); jl_value_t *jl_type_union(jl_tuple_t *types); @@ -1294,11 +1294,17 @@ void jl_print_gc_stats(JL_STREAM *s); typedef struct { char *build_path; - int code_coverage; + int8_t code_coverage; + int8_t check_bounds; + int int_literals; } jl_compileropts_t; extern DLLEXPORT jl_compileropts_t jl_compileropts; +#define JL_COMPILEROPT_CHECK_BOUNDS_DEFAULT 0 +#define JL_COMPILEROPT_CHECK_BOUNDS_ON 1 +#define JL_COMPILEROPT_CHECK_BOUNDS_OFF 2 + #ifdef __cplusplus } #endif diff --git a/src/support/Makefile b/src/support/Makefile index d284a26098b93..6eee27033d084 100644 --- a/src/support/Makefile +++ b/src/support/Makefile @@ -6,7 +6,7 @@ override CXXFLAGS += $(JCXXFLAGS) OBJS = hashing.o timefuncs.o ptrhash.o operators.o \ utf8.o ios.o htable.o bitvector.o \ - int2str.o libsupportinit.o arraylist.o + int2str.o libsupportinit.o arraylist.o strtod.o ifeq ($(OS),WINNT) OBJS += asprintf.o wcwidth.o diff --git a/src/support/libsupport.h b/src/support/libsupport.h index fd4f43ebb360f..6aa8bb9c761a8 100644 --- a/src/support/libsupport.h +++ b/src/support/libsupport.h @@ -14,6 +14,7 @@ #include "ptrhash.h" #include "bitvector.h" #include "dirpath.h" +#include "strtod.h" DLLEXPORT void libsupport_init(void); diff --git a/src/support/strtod.c b/src/support/strtod.c new file mode 100644 index 0000000000000..a99a919ddc159 --- /dev/null +++ b/src/support/strtod.c @@ -0,0 +1,291 @@ +#include "libsupport.h" +#define _GNU_SOURCE +#include +#include + +#if !defined(_OS_WINDOWS_) +// This code path should be used for systems that support the strtod_l function + +#include +#if defined(_OS_LINUX_) +extern double strtod_l(const char *nptr, char **endptr, locale_t loc); +extern float strtof_l(const char *nptr, char **endptr, locale_t loc); +#endif + +// Cache locale object +static int c_locale_initialized = 0; +static locale_t c_locale; + +locale_t get_c_locale() +{ + if(!c_locale_initialized) + { + c_locale_initialized = 1; + c_locale = newlocale(LC_ALL_MASK, "C", NULL); + } + return c_locale; +} + +double strtod_c(const char *nptr, char **endptr) +{ + return strtod_l(nptr, endptr, get_c_locale()); +} + +float strtof_c(const char *nptr, char **endptr) +{ + return strtof_l(nptr, endptr, get_c_locale()); +} + + +#else +// This code path should be used for systems that do not support the strtod_l function +// Currently this is MinGW/Windows + +// The following code is derived from the Python function _PyOS_ascii_strtod +// see http://hg.python.org/cpython/file/default/Python/pystrtod.c +// +// Copyright © 2001-2014 Python Software Foundation; All Rights Reserved +// +// The following modifications have been made: +// - Leading spaces are ignored +// - Parsing of hex floats is supported in the derived version +// - Python functions for tolower, isdigit and malloc have been replaced by the respective +// C stdlib functions + +#include + +int case_insensitive_match(const char *s, const char *t) +{ + while(*t && tolower(*s) == *t) { + s++; + t++; + } + return *t ? 0 : 1; +} + +double parse_inf_or_nan(const char *p, char **endptr) +{ + double retval; + const char *s; + int negate = 0; + + s = p; + if (*s == '-') { + negate = 1; + s++; + } + else if (*s == '+') { + s++; + } + if (case_insensitive_match(s, "inf")) { + s += 3; + if (case_insensitive_match(s, "inity")) + s += 5; + retval = negate ? -D_PINF : D_PINF; + } + else if (case_insensitive_match(s, "nan")) { + s += 3; + retval = negate ? -D_PNAN : D_PNAN; + } + else { + s = p; + retval = -1.0; + } + *endptr = (char *)s; + return retval; +} + + +double strtod_c(const char *nptr, char **endptr) +{ + char *fail_pos; + double val; + struct lconv *locale_data; + const char *decimal_point; + size_t decimal_point_len; + const char *p, *decimal_point_pos; + const char *end = NULL; /* Silence gcc */ + const char *digits_pos = NULL; + int negate = 0; + + fail_pos = NULL; + + locale_data = localeconv(); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen(decimal_point); + + decimal_point_pos = NULL; + + /* Parse infinities and nans */ + val = parse_inf_or_nan(nptr, endptr); + if (*endptr != nptr) + return val; + + /* Set errno to zero, so that we can distinguish zero results + and underflows */ + errno = 0; + + /* We process the optional sign manually, then pass the remainder to + the system strtod. This ensures that the result of an underflow + has the correct sign. */ + p = nptr; + + /* parse leading spaces */ + while (isspace(*p)) { + p++; + } + + /* Process leading sign, if present */ + if (*p == '-') { + negate = 1; + p++; + } + else if (*p == '+') { + p++; + } + + /* This code path is used for hex floats */ + if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) + { + digits_pos = p; + p += 2; + /* Check that what's left begins with a digit or decimal point */ + if (!isxdigit(*p) && *p != '.') + goto invalid_string; + + + if (decimal_point[0] != '.' || + decimal_point[1] != 0) + { + /* Look for a '.' in the input; if present, it'll need to be + swapped for the current locale's decimal point before we + call strtod. On the other hand, if we find the current + locale's decimal point then the input is invalid. */ + while (isxdigit(*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + /* locate end of number */ + while (isxdigit(*p)) + p++; + + if (*p == 'p' || *p == 'P') + p++; + if (*p == '+' || *p == '-') + p++; + while (isdigit(*p)) + p++; + end = p; + } + else if (strncmp(p, decimal_point, decimal_point_len) == 0) + goto invalid_string; + /* For the other cases, we need not convert the decimal + point */ + } + } else + { + /* Check that what's left begins with a digit or decimal point */ + if (!isdigit(*p) && *p != '.') + goto invalid_string; + + digits_pos = p; + if (decimal_point[0] != '.' || + decimal_point[1] != 0) + { + /* Look for a '.' in the input; if present, it'll need to be + swapped for the current locale's decimal point before we + call strtod. On the other hand, if we find the current + locale's decimal point then the input is invalid. */ + while (isdigit(*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + /* locate end of number */ + while (isdigit(*p)) + p++; + + if (*p == 'e' || *p == 'E') + p++; + if (*p == '+' || *p == '-') + p++; + while (isdigit(*p)) + p++; + end = p; + } + else if (strncmp(p, decimal_point, decimal_point_len) == 0) + goto invalid_string; + /* For the other cases, we need not convert the decimal + point */ + } + } + + if (decimal_point_pos) { + char *copy, *c; + /* Create a copy of the input, with the '.' converted to the + locale-specific decimal point */ + copy = (char *)malloc(end - digits_pos + + 1 + decimal_point_len); + if (copy == NULL) { + *endptr = (char *)nptr; + errno = ENOMEM; + return val; + } + + c = copy; + memcpy(c, digits_pos, decimal_point_pos - digits_pos); + c += decimal_point_pos - digits_pos; + memcpy(c, decimal_point, decimal_point_len); + c += decimal_point_len; + memcpy(c, decimal_point_pos + 1, + end - (decimal_point_pos + 1)); + c += end - (decimal_point_pos + 1); + *c = 0; + + val = strtod(copy, &fail_pos); + + if (fail_pos) + { + if (fail_pos > decimal_point_pos) + fail_pos = (char *)digits_pos + + (fail_pos - copy) - + (decimal_point_len - 1); + else + fail_pos = (char *)digits_pos + + (fail_pos - copy); + } + + free(copy); + + } + else { + val = strtod(digits_pos, &fail_pos); + } + + if (fail_pos == digits_pos) + goto invalid_string; + + if (negate && fail_pos != nptr) + val = -val; + *endptr = fail_pos; + + return val; + + invalid_string: + *endptr = (char*)nptr; + errno = EINVAL; + return -1.0; +} + + +float strtof_c(const char *nptr, char **endptr) +{ + return (float) strtod_c(nptr, endptr); +} + +#endif diff --git a/src/support/strtod.h b/src/support/strtod.h new file mode 100644 index 0000000000000..50dda8ecf8f39 --- /dev/null +++ b/src/support/strtod.h @@ -0,0 +1,8 @@ +#ifndef STRTOD_H +#define STRTOD_H + +double strtod_c(const char *nptr, char **endptr); +float strtof_c(const char *nptr, char **endptr); + +#endif + diff --git a/test/core.jl b/test/core.jl index 607fbfc2b19df..54476f617aec5 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1454,3 +1454,8 @@ x6074 = 6074 test5536(a::Union(Real, AbstractArray)...) = "Splatting" test5536(a::Union(Real, AbstractArray)) = "Non-splatting" @test test5536(5) == "Non-splatting" + +# multiline comments (#6139 and others raised in #6128) +@test 3 == include_string("1 + #=# 2") == include_string("1 + #==# 2") == include_string("1 + #===# 2") == include_string("1 + #= #= blah =# =# 2") == include_string("1 + #= #= #= nested =# =# =# 2") +@test_throws include_string("#=") +@test_throws include_string("#= #= #= =# =# =") diff --git a/test/math.jl b/test/math.jl index e6c20a5bc463b..d276da7139fd5 100644 --- a/test/math.jl +++ b/test/math.jl @@ -5,14 +5,31 @@ @test exponent(12.8) == 3 # degree-based trig functions -for x = -400:40:400 - @test_approx_eq_eps sind(x) sin(pi/180*x) eps(pi/180*x) - @test_approx_eq_eps cosd(x) cos(pi/180*x) eps(pi/180*x) +for T = (Float32,Float64) + for x = -400:40:400 + @test_approx_eq_eps sind(convert(T,x))::T convert(T,sin(pi/180*x)) eps(deg2rad(convert(T,x))) + @test_approx_eq_eps cosd(convert(T,x))::T convert(T,cos(pi/180*x)) eps(deg2rad(convert(T,x))) + end + for x = 0.0:180:720 + @test sind(convert(T,x)) === zero(T) + @test sind(-convert(T,x)) === -zero(T) + end + + for x = -3:0.3:3 + @test_approx_eq_eps sinpi(convert(T,x))::T convert(T,sin(pi*x)) eps(pi*convert(T,x)) + @test_approx_eq_eps cospi(convert(T,x))::T convert(T,cos(pi*x)) eps(pi*convert(T,x)) + end + for x = 0.0:1.0:4.0 + @test sinpi(convert(T,x)) === zero(T) + @test sinpi(-convert(T,x)) === -zero(T) + end end -for x = -3:0.3:3 - @test_approx_eq_eps sinpi(x) sin(pi*x) eps(pi*x) - @test_approx_eq_eps cospi(x) cos(pi*x) eps(pi*x) +# check type stability +for T = (Float32,Float64,BigFloat) + for f = (sind,cosd,sinpi,cospi) + @test Base.return_types(f,(T,)) == [T] + end end diff --git a/test/numbers.jl b/test/numbers.jl index 36e077d6950da..ab2cf8a5d00dc 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1751,3 +1751,15 @@ end # issue #5881 @test bits(true) == "00000001" @test bits(false) == "00000000" + +# edge cases of intrinsics +let g() = sqrt(-1.0) + @test_throws sqrt(-1.0) +end +@test sqrt(NaN) === NaN +let g() = sqrt(NaN) + @test g() === NaN +end +let g(x) = sqrt(x) + @test g(NaN) === NaN +end diff --git a/ui/repl.c b/ui/repl.c index 407b6a82a1898..d3c31272f13b5 100644 --- a/ui/repl.c +++ b/ui/repl.c @@ -42,7 +42,9 @@ static const char *opts = " -F Load ~/.juliarc.jl, then handle remaining inputs\n" " --color=yes|no Enable or disable color text\n\n" - " --code-coverage Count executions of source lines\n"; + " --code-coverage Count executions of source lines\n" + " --check-bounds=yes|no Emit bounds checks always or never (ignoring declarations)\n" + " --int-literals=32|64 Select integer literal size independent of platform\n"; void parse_opts(int *argcp, char ***argvp) { @@ -55,6 +57,8 @@ void parse_opts(int *argcp, char ***argvp) { "help", no_argument, 0, 'h' }, { "sysimage", required_argument, 0, 'J' }, { "code-coverage", no_argument, &codecov, 1 }, + { "check-bounds", required_argument, 0, 300 }, + { "int-literals", required_argument, 0, 301 }, { 0, 0, 0, 0 } }; int c; @@ -90,6 +94,22 @@ void parse_opts(int *argcp, char ***argvp) case 'h': printf("%s%s", usage, opts); exit(0); + case 300: + if (!strcmp(optarg,"yes")) + jl_compileropts.check_bounds = JL_COMPILEROPT_CHECK_BOUNDS_ON; + else if (!strcmp(optarg,"no")) + jl_compileropts.check_bounds = JL_COMPILEROPT_CHECK_BOUNDS_OFF; + break; + case 301: + if (!strcmp(optarg,"32")) + jl_compileropts.int_literals = 32; + else if (!strcmp(optarg,"64")) + jl_compileropts.int_literals = 64; + else { + ios_printf(ios_stderr, "julia: invalid integer literal size (%s)\n", optarg); + exit(1); + } + break; default: ios_printf(ios_stderr, "julia: unhandled option -- %c\n", c); ios_printf(ios_stderr, "This is a bug, please report it.\n");