1- _debug_log = nothing
1+ # This file provides an adaptor to match the API expected by the Julia runtime
2+ # code in the binding Core._parse
3+
4+ # Use caller's world age.
5+ const _caller_world = typemax (UInt)
6+ const _parser_world_age = Ref {UInt} (_caller_world)
27
3- # Adaptor for the API/ABI expected by the Julia runtime code.
48function core_parser_hook (code, filename, lineno, offset, options)
9+ # `hook` is always _core_parser_hook, but that's hidden from the compiler
10+ # via a Ref to prevent invalidation / recompilation when other packages are
11+ # loaded. This wouldn't seem like it should be necessary given the use of
12+ # invoke_in_world, but it is in Julia-1.7.3. I'm not sure exactly which
13+ # latency it's removing.
14+ hook = _core_parser_hook_ref[]
15+ if _parser_world_age[] != _caller_world
16+ Base. invoke_in_world (_parser_world_age[], hook,
17+ code, filename, lineno, offset, options)
18+ else
19+ hook (code, filename, lineno, offset, options)
20+ end
21+ end
22+
23+ # Core._parse gained a `lineno` argument in
24+ # https://github.com/JuliaLang/julia/pull/43876
25+ # Prior to this, the following signature was needed:
26+ function core_parser_hook (code, filename, offset, options)
27+ core_parser_hook (code, filename, LineNumberNode (0 ), offset, options)
28+ end
29+
30+ # Debug log file for dumping parsed code
31+ const _debug_log = Ref {Union{Nothing,IO}} (nothing )
32+
33+ function _core_parser_hook (code, filename, lineno, offset, options)
534 try
635 # TODO : Check that we do all this input wrangling without copying the
736 # code buffer
@@ -10,13 +39,13 @@ function core_parser_hook(code, filename, lineno, offset, options)
1039 (ptr,len) = code
1140 code = String (unsafe_wrap (Array, ptr, len))
1241 end
13- if ! isnothing (_debug_log)
14- print (_debug_log, """
42+ if ! isnothing (_debug_log[] )
43+ print (_debug_log[] , """
1544 #-#-#-------------------------------
1645 # ENTER filename=$filename , lineno=$lineno , offset=$offset , options=$options "
1746 #-#-#-------------------------------
1847 """ )
19- write (_debug_log, code)
48+ write (_debug_log[] , code)
2049 end
2150
2251 io = IOBuffer (code)
@@ -58,8 +87,8 @@ function core_parser_hook(code, filename, lineno, offset, options)
5887 # of one cancel here.
5988 last_offset = last_byte (stream)
6089
61- if ! isnothing (_debug_log)
62- println (_debug_log, """
90+ if ! isnothing (_debug_log[] )
91+ println (_debug_log[] , """
6392 #-#-#-
6493 # EXIT last_offset=$last_offset
6594 #-#-#-
@@ -69,42 +98,59 @@ function core_parser_hook(code, filename, lineno, offset, options)
6998 # Rewrap result in an svec for use by the C code
7099 return Core. svec (ex, last_offset)
71100 catch exc
101+ if ! isnothing (_debug_log[])
102+ println (_debug_log[], """
103+ #-#-#-
104+ # ERROR EXIT
105+ # $exc
106+ #-#-#-
107+ """ )
108+ end
72109 @error (" JuliaSyntax parser failed — falling back to flisp!" ,
73110 exception= (exc,catch_backtrace ()),
74111 offset= offset,
75112 code= code)
76- end
77- return Core. Compiler. fl_parse (code, filename, offset, options)
78- end
79113
80- # Core._parse gained a `lineno` argument in
81- # https://github.com/JuliaLang/julia/pull/43876
82- # Prior to this, the following signature was needed:
83- function core_parser_hook (code, filename, offset, options)
84- core_parser_hook (code, filename, LineNumberNode (0 ), offset, options)
114+ if VERSION >= v " 1.8.0-DEV.1370" # https://github.com/JuliaLang/julia/pull/43876
115+ return Core. Compiler. fl_parse (code, filename, lineno, offset, options)
116+ else
117+ return Core. Compiler. fl_parse (code, filename, offset, options)
118+ end
119+ end
85120end
86121
87122# Hack:
88123# Meta.parse() attempts to construct a ParseError from a string if it receives
89- # `Expr(:error)`.
124+ # `Expr(:error)`. Add an override to the ParseError constructor to prevent this.
125+ # FIXME : Improve this in Base somehow?
90126Base. Meta. ParseError (e:: JuliaSyntax.ParseError ) = e
91127
92128const _default_parser = Core. _parse
129+ # NB: Never reassigned, but the compiler doesn't know this!
130+ const _core_parser_hook_ref = Ref {Function} (_core_parser_hook)
93131
94132"""
133+ enable_in_core!([enable=true; freeze_world_age, debug_filename])
134+
95135Connect the JuliaSyntax parser to the Julia runtime so that it replaces the
96- flisp parser for all parsing work.
136+ flisp parser for all parsing work. That is, JuliaSyntax will be used for
137+ `include()` `Meta.parse()`, the REPL, etc. To disable, set use
138+ `enable_in_core!(false)`.
97139
98- That is, JuliaSyntax will be used for `include()` `Meta.parse()`, the REPL, etc.
140+ Keyword arguments:
141+ * `freeze_world_age` - Use a fixed world age for the parser to prevent
142+ recompilation of the parser due to any user-defined methods (default `true`).
143+ * `debug_filename` - File name of parser debug log (defaults to `nothing` or
144+ the value of `ENV["JULIA_SYNTAX_DEBUG_FILE"]`).
99145"""
100- function enable_in_core! (enable= true )
101- debug_filename = get (ENV , " JULIA_SYNTAX_DEBUG_FILE" , nothing )
102- global _debug_log
146+ function enable_in_core! (enable= true ; freeze_world_age = true ,
147+ debug_filename = get (ENV , " JULIA_SYNTAX_DEBUG_FILE" , nothing ) )
148+ _parser_world_age[] = freeze_world_age ? Base . get_world_counter () : _caller_world
103149 if enable && ! isnothing (debug_filename)
104- _debug_log = open (debug_filename, " w" )
105- elseif ! enable && ! isnothing (_debug_log)
106- close (_debug_log)
107- _debug_log = nothing
150+ _debug_log[] = open (debug_filename, " w" )
151+ elseif ! enable && ! isnothing (_debug_log[] )
152+ close (_debug_log[] )
153+ _debug_log[] = nothing
108154 end
109155 parser = enable ? core_parser_hook : _default_parser
110156 Base. eval (Core, :(_parse = $ parser))
0 commit comments