• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37610

03 Sep 2023 03:55PM UTC coverage: 86.433% (-0.8%) from 87.218%
#37610

push

local

web-flow
Standardize the entry-point for Julia execution (#50974)

This is a bit of a straw-man proposal (though I think mergable if people
agree) to standardize the execution entrypoint for Julia scripts. I
think there's at least four different ways that people might run a
script:

- As `julia main.jl`
- As a PkgCompiler sysimage, then calling the main entry point
- As a PkgCompiler "app", with the magic `julia_main` function
- As a StaticCompiler product with an explicit entrypoint specified on
the API.

The main problem I have with all of these variants is that they're all
different and it's kind of a pain to move between them. Here I propose
that we standardize on `Main.main(ARGS)` as the entrypoint for all
scripts. Downstream from that proposal, this PR then makes the following
changes:

1. If a system image has an existing `Main.main`, that is the entry
point for `julia -Jsysimage.so`.
2. If not, and the sysimage has a REPL, we call REPL.main (we could
handle this by defaulting `Main.main` to a weak import of `REPL.main`,
but for the purpose of this PR, it's an explicit fallback. That said, I
do want to emhpasize the direction of moving the REPL to be "just
another app".
3. If the REPL code is called and passed a script file, the REPL
executes any newly defined Main.main after loading the script file. As a
result, `julia` behaves the same as if we had generated a new system
image after loading `main.jl` and then running julia with that system
image.

The further downstream implication of this is that I'd like to get rid
of the distinction between PkgCompiler apps and system images. An app is
simply a system image with a `Main.main` function defined (note that
currently PkgCompiler uses `julia_main` instead).

---------

Co-authored-by: Martijn Visser <mgvisser@gmail.com>

25 of 25 new or added lines in 2 files covered. (100.0%)

73492 of 85028 relevant lines covered (86.43%)

13617619.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.31
/stdlib/Markdown/src/parse/parse.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
mutable struct MD
4
    content::Vector{Any}
5
    meta::Dict{Symbol, Any}
6

7
    MD(content::AbstractVector, meta::Dict = Dict()) =
36,079✔
8
        new(content, meta)
9
end
10

11
MD(xs...) = MD(vcat(xs...))
11,058✔
12

13
function MD(cfg::Config, xs...)
×
14
    md = MD(xs...)
10,807✔
15
    md.meta[:config] = cfg
10,807✔
16
    return md
10,807✔
17
end
18

19
config(md::MD) = md.meta[:config]::Config
45,568✔
20

21
# Forward some array methods
22

23
Base.push!(md::MD, x) = push!(md.content, x)
27,578✔
24
Base.getindex(md::MD, args...) = md.content[args...]
×
25
Base.setindex!(md::MD, args...) = setindex!(md.content, args...)
×
26
Base.lastindex(md::MD) = lastindex(md.content)
×
27
Base.firstindex(md::MD) = firstindex(md.content)
×
28
Base.length(md::MD) = length(md.content)
×
29
Base.isempty(md::MD) = isempty(md.content)
×
30
Base.copy(md::MD) = MD(copy(md.content), copy(md.meta))
×
31

32
==(a::MD, b::MD) = (html(a) == html(b))
9✔
33

34
# Parser functions:
35
#   md – should be modified appropriately
36
#   return – basically, true if parse was successful
37
#     false uses the next parser in the queue, true
38
#     goes back to the beginning
39
#
40
# Inner parsers:
41
#   return – element to use or nothing
42

43
# Inner parsing
44

45
function parseinline(stream::IO, md::MD, parsers::Vector{Function})
50,468✔
46
    for parser in parsers
50,468✔
47
        inner = parser(stream, md)
57,512✔
48
        inner ≡ nothing || return inner
103,746✔
49
    end
11,278✔
50
end
51

52
function parseinline(stream::IO, md::MD, config::Config)
26,398✔
53
    content = []
26,398✔
54
    buffer = IOBuffer()
26,398✔
55
    while !eof(stream)
1,891,306✔
56
        char = peek(stream, Char)
1,864,908✔
57
        if haskey(config.inner, char) &&
1,864,908✔
58
                (inner = parseinline(stream, md, config.inner[char])) !== nothing
59
            c = String(take!(buffer))
46,234✔
60
            !isempty(c) && push!(content, c)
46,234✔
61
            buffer = IOBuffer()
46,234✔
62
            push!(content, inner)
46,234✔
63
        else
64
            write(buffer, read(stream, Char))
1,818,674✔
65
        end
66
    end
1,864,908✔
67
    c = String(take!(buffer))
26,398✔
68
    !isempty(c) && push!(content, c)
26,398✔
69
    return content
26,398✔
70
end
71

72
parseinline(s::AbstractString, md::MD, c::Config) =
7,495✔
73
    parseinline(IOBuffer(s), md, c)
74

75
parseinline(s, md::MD) = parseinline(s, md, config(md))
26,398✔
76

77
# Block parsing
78

79
function parse(stream::IO, block::MD, config::Config; breaking = false)
117,744✔
80
    skipblank(stream)
58,872✔
81
    eof(stream) && return false
58,872✔
82
    for parser in (breaking ? config.breaking : [config.breaking; config.regular])
48,065✔
83
        parser(stream, block) && return true
369,216✔
84
    end
356,269✔
85
    return false
17,559✔
86
end
87

88
parse(stream::IO, block::MD; breaking = false) =
36,118✔
89
  parse(stream, block, config(block), breaking = breaking)
90

91
function parse(stream::IO; flavor = julia)
21,614✔
92
    isa(flavor, Symbol) && (flavor = flavors[flavor])
78✔
93
    markdown = MD(flavor)
10,807✔
94
    while parse(stream, markdown, flavor) end
70,819✔
95
    return markdown
10,807✔
96
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc