Compare commits

...

2 Commits

Author SHA1 Message Date
TEC 55a82a774b
Correct oversights in effect value checking
There are two issues that are fixed here:
- Comparing Bool-valued effects with UInt8 status codes
- Checking status with equal not egal, when 0x00 == false and 0x01 ==
  true. This is a problem since the Bool values are not directly
  comparable to UInt8 values.
2024-06-03 15:41:15 +08:00
TEC 709e16d66c
Set minimum Julia to 1.9 2024-05-09 14:41:15 +08:00
3 changed files with 107 additions and 83 deletions

View File

@ -15,7 +15,8 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
PkgExt = "Pkg"
[compat]
InteractiveUtils = "1.11.0"
JuliaSyntaxHighlighting = "1.11.0"
Pkg = "1.11.0"
StyledStrings = "1.11.0"
InteractiveUtils = "1.9"
JuliaSyntaxHighlighting = "1"
Pkg = "1.9"
StyledStrings = "1"
julia = "1.9"

View File

@ -79,93 +79,85 @@ function about(io::IO, fn::Function, @nospecialize(argtypes::Type{<:Tuple}))
println(io, S" {light:$(highlight(mcall))} {shadow,bold:@} $msrcpretty")
end
println(io)
@static if VERSION >= v"1.8"
about(io, Base.infer_effects(fn, argtypes))
about(io, Base.infer_effects(fn, argtypes))
end
struct CompatibleCoreCompilerConstants end
function Base.getproperty(::CompatibleCoreCompilerConstants, name::Symbol)
if isdefined(Core.Compiler, name)
getglobal(Core.Compiler, name)
end
end
@static if VERSION >= v"1.8"
struct CompatibleCoreCompilerConstants end
const C4 = CompatibleCoreCompilerConstants()
function Base.getproperty(::CompatibleCoreCompilerConstants, name::Symbol)
if isdefined(Core.Compiler, name)
getglobal(Core.Compiler, name)
function about(io::IO, effects::Core.Compiler.Effects)
function effectinfo(io::IO, field::Symbol, name::String, labels::Pair{<:Union{UInt8, Bool, Nothing}, AnnotatedString{String}}...;
prefix::AbstractString = "", suffix::AbstractString = "")
hasproperty(effects, field) || return
value = getproperty(effects, field)
icon, accent = if value === C4.ALWAYS_TRUE || value === true
'✔', :success
elseif value === C4.ALWAYS_FALSE || value === false
'✗', :error
else
'~', :warning
end
end
const C4 = CompatibleCoreCompilerConstants()
function about(io::IO, effects::Core.Compiler.Effects)
function effectinfo(io::IO, field::Symbol, name::String, labels::Pair{<:Union{UInt8, Bool, Nothing}, AnnotatedString{String}}...;
prefix::AbstractString = "", suffix::AbstractString = "")
hasproperty(effects, field) || return
value = @static if VERSION >= v"1.9"
getproperty(effects, field)
else # v1.8
getproperty(effects, field).state
end
icon, accent = if value == C4.ALWAYS_TRUE || value === true
'✔', :success
elseif value == C4.ALWAYS_FALSE || value === false
'✗', :error
else
'~', :warning
end
msg = S"{bold,italic,grey:???}"
for (id, label) in labels
if id == value
msg = label
break
end
end
name_pad_width = 13
dispwidth = last(displaysize(io))
declr = S" {bold,$accent:$icon $(rpad(name, name_pad_width))} "
print(io, declr)
indent = name_pad_width + 5
desc = S"{grey:$prefix$(ifelse(isempty(prefix), \"\", \" \"))$msg$(ifelse(isempty(suffix), \"\", \" \"))$suffix}"
desclines = wraplines(desc, dispwidth - indent, indent)
for (i, line) in enumerate(desclines)
i > 1 && print(io, ' '^indent)
println(io, line)
msg = S"{bold,italic,grey:???}"
for (id, label) in labels
if id == value
msg = label
break
end
end
println(io, S"{bold:Method effects:}")
effectinfo(io, :consistent, "consistent",
C4.ALWAYS_TRUE => S"guaranteed to",
C4.ALWAYS_FALSE => S"might {italic:not}",
C4.CONSISTENT_IF_NOTRETURNED => S"when the return value never involved newly allocated mutable objects, will",
C4.CONSISTENT_IF_INACCESSIBLEMEMONLY => S"when {code:inaccessible memory only} is also proven, will",
suffix = "return or terminate consistently")
effectinfo(io, :effect_free, "effect free",
C4.ALWAYS_TRUE => S"guaranteed to be",
C4.ALWAYS_FALSE => S"might {italic:not} be",
C4.EFFECT_FREE_IF_INACCESSIBLEMEMONLY => S"when {code:inaccessible memory only} is also proven, is",
suffix = "free from externally semantically visible side effects")
effectinfo(io, :nothrow, "no throw",
C4.ALWAYS_TRUE => S"guaranteed to never",
C4.ALWAYS_FALSE => S"may",
suffix = "throw an exception")
effectinfo(io, :terminates, "terminates",
C4.ALWAYS_TRUE => S"guaranteed to",
C4.ALWAYS_FALSE => S"might {italic:not}",
suffix = "always terminate")
effectinfo(io, :notaskstate, "no task state",
C4.ALWAYS_TRUE => S"guaranteed not to access task state (allowing migration between tasks)",
C4.ALWAYS_FALSE => S"may access task state (preventing migration between tasks)")
effectinfo(io, :inaccessiblememonly, "inaccessible memory only",
C4.ALWAYS_TRUE => S"guaranteed to never access or modify externally accessible mutable memory",
C4.ALWAYS_FALSE => S"may access or modify externally accessible mutable memory",
C4.INACCESSIBLEMEM_OR_ARGMEMONLY => S"may access or modify mutable memory {italic:iff} pointed to by its call arguments")
effectinfo(io, :noub, "no undefined behaviour",
C4.ALWAYS_TRUE => S"guaranteed to never",
C4.ALWAYS_FALSE => S"may",
C4.NOUB_IF_NOINBOUNDS => S"so long as {code,julia_macro:@inbounds} is not used or propagated, will not",
suffix = "execute undefined behaviour")
effectinfo(io, :nonoverlayed, "non-overlayed",
true => S"never calls any methods from an overlayed method table",
false => S"{warning:may} call methods from an overlayed method table")
name_pad_width = 13
dispwidth = last(displaysize(io))
declr = S" {bold,$accent:$icon $(rpad(name, name_pad_width))} "
print(io, declr)
indent = name_pad_width + 5
desc = S"{grey:$prefix$(ifelse(isempty(prefix), \"\", \" \"))$msg$(ifelse(isempty(suffix), \"\", \" \"))$suffix}"
desclines = wraplines(desc, dispwidth - indent, indent)
for (i, line) in enumerate(desclines)
i > 1 && print(io, ' '^indent)
println(io, line)
end
end
println(io, S"{bold:Method effects:}")
effectinfo(io, :consistent, "consistent",
C4.ALWAYS_TRUE => S"guaranteed to",
C4.ALWAYS_FALSE => S"might {italic:not}",
C4.CONSISTENT_IF_NOTRETURNED => S"when the return value never involved newly allocated mutable objects, will",
C4.CONSISTENT_IF_INACCESSIBLEMEMONLY => S"when {code:inaccessible memory only} is also proven, will",
suffix = "return or terminate consistently")
effectinfo(io, :effect_free, "effect free",
C4.ALWAYS_TRUE => S"guaranteed to be",
C4.ALWAYS_FALSE => S"might {italic:not} be",
C4.EFFECT_FREE_IF_INACCESSIBLEMEMONLY => S"when {code:inaccessible memory only} is also proven, is",
suffix = "free from externally semantically visible side effects")
effectinfo(io, :nothrow, "no throw",
true => S"guaranteed to never",
false => S"may",
suffix = "throw an exception")
effectinfo(io, :terminates, "terminates",
true => S"guaranteed to",
false => S"might {italic:not}",
suffix = "always terminate")
effectinfo(io, :notaskstate, "no task state",
true => S"guaranteed not to access task state (allowing migration between tasks)",
false => S"may access task state (preventing migration between tasks)")
effectinfo(io, :inaccessiblememonly, "inaccessible memory only",
C4.ALWAYS_TRUE => S"guaranteed to never access or modify externally accessible mutable memory",
C4.ALWAYS_FALSE => S"may access or modify externally accessible mutable memory",
C4.INACCESSIBLEMEM_OR_ARGMEMONLY => S"may access or modify mutable memory {italic:iff} pointed to by its call arguments")
effectinfo(io, :noub, "no undefined behaviour",
C4.ALWAYS_TRUE => S"guaranteed to never",
C4.ALWAYS_FALSE => S"may",
C4.NOUB_IF_NOINBOUNDS => S"so long as {code,julia_macro:@inbounds} is not used or propagated, will not",
suffix = "execute undefined behaviour")
effectinfo(io, :nonoverlayed, "non-overlayed",
true => S"never calls any methods from an overlayed method table",
false => S"{warning:may} call methods from an overlayed method table")
end
about(io::IO, fn::Function, sig::NTuple{N, <:Type}) where {N} = about(io, fn, Tuple{sig...})

View File

@ -69,6 +69,7 @@ function memorylayout(io::IO, value::T) where {T}
freprs = AnnotatedString[]
fshows = AnnotatedString[]
for (; face, name, type, size, ispointer) in sinfo
size <= 0 && continue
push!(ffaces, face)
push!(fnames, string(name))
push!(ftypes, string(type))
@ -451,4 +452,34 @@ function elaboration(io::IO, char::Char)
end
end
function elaboration(io::IO, str::String)
charfreq = Dict{Char, Int}()
for char in str
charfreq[char] = get(charfreq, char, 0) + 1
end
charset_index =
maximum(c -> if Int(c) < 127; 2
elseif Int(c) < 255; 3
else 4 end,
keys(charfreq),
init = 1)
charset = ["None", "ASCII", "Extended ASCII", "Unicode"][charset_index]
println(io, S" {emphasis:•} Character set: {emphasis:$charset}")
control_character_counts = map(
c -> get(charfreq, first(c), 0), CONTROL_CHARACTERS)
if !all(iszero, control_character_counts)
println(io, S" {emphasis:•} Contains \
{about_count:$(sum(control_character_counts))} \
instances of {about_count:$(sum(>(0), control_character_counts))} \
control characters:")
for ((char, info), count) in zip(CONTROL_CHARACTERS, control_character_counts)
count > 0 &&
println(io, S" {emphasis:} {julia_char:$(sprint(show, char))} ({about_count:$count}): $(join(info, ' '))")
end
end
if startswith(str, '\ufeff')
println(io, S" {emphasis:•} Prefixed by BOM (byte-order mark)")
end
end
# TODO struct