162162# Debug log file for dumping parsed code
163163const _debug_log = Ref {Union{Nothing,IO}} (nothing )
164164
165- function core_parser_hook (code, filename:: String , lineno:: Int , offset:: Int , options:: Symbol )
165+ # fl_parse has several peculiarities in the exact for which error expressions take.
166+ function build_base_compat_expr (stream, rule; filename= " none" , first_line= 1 )
167+ if ! any_error (stream)
168+ return build_tree (Expr, stream; filename= filename, first_line= first_line)
169+ end
170+ pos_before_comments = last_non_whitespace_byte (stream)
171+ errspec = first_tree_error (stream)
172+ tag = _incomplete_tag (errspec, pos_before_comments)
173+ if _has_v1_10_hooks
174+ exc = ParseError (stream, filename= filename, first_line= first_line,
175+ incomplete_tag= tag)
176+ msg = sprint (showerror, exc)
177+ error_ex = Expr (tag === :none ? :error : :incomplete ,
178+ Meta. ParseError (msg, exc))
179+ elseif tag != = :none
180+ # Hack: For older Julia versions, replicate the messages which
181+ # Base.incomplete_tag() will match
182+ msg =
183+ tag === :string ? " incomplete: invalid string syntax" :
184+ tag === :comment ? " incomplete: unterminated multi-line comment #= ... =#" :
185+ tag === :block ? " incomplete: construct requires end" :
186+ tag === :cmd ? " incomplete: invalid \" `\" syntax" :
187+ tag === :char ? " incomplete: invalid character literal" :
188+ " incomplete: premature end of input"
189+ error_ex = Expr (:incomplete , msg)
190+ else
191+ # In the flisp parser errors are normally `Expr(:error, msg)` where
192+ # `msg` is a String. By using a JuliaSyntax.ParseError for msg
193+ # we can do fancy error reporting instead.
194+ error_ex = Expr (:error , ParseError (stream, filename= filename, first_line= first_line))
195+ end
196+ if rule != :all
197+ return error_ex
198+ end
199+ # When encountering a toplevel error, the reference parser
200+ # * truncates the top level expression arg list before that error
201+ # * includes the last line number
202+ # * appends the error message
203+ source = SourceFile (stream, filename= filename, first_line= first_line)
204+ topex = build_tree (Expr, stream, source)
205+ @assert topex. head == :toplevel
206+ i = findfirst (_has_nested_error, topex. args)
207+ if i > 1 && topex. args[i- 1 ] isa LineNumberNode
208+ i -= 1
209+ end
210+ resize! (topex. args, i- 1 )
211+ push! (topex. args, LineNumberNode (source_line (source, first_byte (errspec. node)), filename))
212+ push! (topex. args, error_ex)
213+ return topex
214+ end
215+
216+ function core_parser_hook (code, filename:: String , first_line:: Int , offset:: Int , rule:: Symbol )
166217 try
167218 # TODO : Check that we do all this input wrangling without copying the
168219 # code buffer
@@ -178,90 +229,17 @@ function core_parser_hook(code, filename::String, lineno::Int, offset::Int, opti
178229 if ! isnothing (_debug_log[])
179230 print (_debug_log[], """
180231 #-#-#-------------------------------
181- # ENTER filename=$filename , lineno= $lineno , offset=$offset , options= $options "
232+ # ENTER filename=$filename , first_line= $first_line , offset=$offset , rule= $rule "
182233 #-#-#-------------------------------
183234 """ )
184235 write (_debug_log[], code)
185236 end
186237
187238 stream = ParseStream (code, offset+ 1 )
188- if options === :statement || options === :atom
189- # To copy the flisp parser driver:
190- # * Parsing atoms consumes leading trivia
191- # * Parsing statements consumes leading+trailing trivia
192- bump_trivia (stream)
193- if peek (stream) == K " EndMarker"
194- # If we're at the end of stream after skipping whitespace, just
195- # return `nothing` to indicate this rather than attempting to
196- # parse a statement or atom and failing.
197- return Core. svec (nothing , last_byte (stream))
198- end
199- end
200- parse! (stream; rule= options)
201- if options === :statement
202- bump_trivia (stream; skip_newlines= false )
203- if peek (stream) == K " NewlineWs"
204- bump (stream)
205- end
206- end
207-
208- if any_error (stream)
209- pos_before_comments = last_non_whitespace_byte (stream)
210- errspec = first_tree_error (stream)
211- tag = _incomplete_tag (errspec, pos_before_comments)
212- if _has_v1_10_hooks
213- exc = ParseError (stream, filename= filename, first_line= lineno,
214- incomplete_tag= tag)
215- msg = sprint (showerror, exc)
216- error_ex = Expr (tag === :none ? :error : :incomplete ,
217- Meta. ParseError (msg, exc))
218- elseif tag != = :none
219- # Hack: For older Julia versions, replicate the messages which
220- # Base.incomplete_tag() will match
221- msg =
222- tag === :string ? " incomplete: invalid string syntax" :
223- tag === :comment ? " incomplete: unterminated multi-line comment #= ... =#" :
224- tag === :block ? " incomplete: construct requires end" :
225- tag === :cmd ? " incomplete: invalid \" `\" syntax" :
226- tag === :char ? " incomplete: invalid character literal" :
227- " incomplete: premature end of input"
228- error_ex = Expr (:incomplete , msg)
229- else
230- # In the flisp parser errors are normally `Expr(:error, msg)` where
231- # `msg` is a String. By using a JuliaSyntax.ParseError for msg
232- # we can do fancy error reporting instead.
233- error_ex = Expr (:error , ParseError (stream, filename= filename, first_line= lineno))
234- end
235- ex = if options === :all
236- # When encountering a toplevel error, the reference parser
237- # * truncates the top level expression arg list before that error
238- # * includes the last line number
239- # * appends the error message
240- source = SourceFile (stream, filename= filename, first_line= lineno)
241- topex = build_tree (Expr, stream, source)
242- @assert topex. head == :toplevel
243- i = findfirst (_has_nested_error, topex. args)
244- if i > 1 && topex. args[i- 1 ] isa LineNumberNode
245- i -= 1
246- end
247- resize! (topex. args, i- 1 )
248- push! (topex. args, LineNumberNode (source_line (source, first_byte (errspec. node)), filename))
249- push! (topex. args, error_ex)
250- topex
251- else
252- error_ex
253- end
254- else
255- # TODO : Figure out a way to show warnings. Meta.parse() has no API
256- # to communicate this, and we also can't show them to stdout as
257- # this is too side-effectful and can result in double-reporting in
258- # the REPL.
259- #
260- # show_diagnostics(stdout, stream.diagnostics, code)
261- #
262- ex = build_tree (Expr, stream; filename= filename, first_line= lineno)
263- end
239+ parse! (stream; rule= rule, incremental= true )
264240
241+ ex = all_trivia (stream) ? nothing :
242+ build_base_compat_expr (stream, rule; filename= filename, first_line= first_line)
265243 # Note the next byte in 1-based indexing is `last_byte(stream) + 1` but
266244 # the Core hook must return an offset (ie, it's 0-based) so the factors
267245 # of one cancel here.
@@ -294,15 +272,15 @@ function core_parser_hook(code, filename::String, lineno::Int, offset::Int, opti
294272 offset= offset,
295273 code= code)
296274
297- _fl_parse_hook (code, filename, lineno , offset, options )
275+ _fl_parse_hook (code, filename, first_line , offset, rule )
298276 end
299277end
300278
301279# Core._parse gained a `lineno` argument in
302280# https://github.com/JuliaLang/julia/pull/43876
303281# Prior to this, the following signature was needed:
304- function core_parser_hook (code, filename, offset, options )
305- core_parser_hook (code, filename, 1 , offset, options )
282+ function core_parser_hook (code, filename, offset, rule )
283+ core_parser_hook (code, filename, 1 , offset, rule )
306284end
307285
308286if _has_v1_10_hooks
0 commit comments