Skip to content

Commit e9ac362

Browse files
mlechutopolarity
andcommitted
Code review, other fixes
Co-authored-by: Cody Tapscott <[email protected]>
1 parent ab0d19f commit e9ac362

File tree

2 files changed

+44
-21
lines changed

2 files changed

+44
-21
lines changed

src/validation.jl

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,18 @@ This should serve three purposes:
6161
produce correct output given `st` (possibly by throwing a LoweringError).
6262
(3) The place we throw helpful user-facing errors given malformed ASTs.
6363
64-
Only AST structure is checked. Checking that required attributes exist, that
65-
leaf-only (or not) kinds are leaves (or not), and that syntax flags are valid
66-
per kind should be done in a separate pass that doesn't need to consider
67-
structure.
64+
Only AST structure is checked. Roughly, this means "kinds and child counts in
65+
context". A tree `t` has valid structure if, given the kinds and child count of
66+
all its ancestors, and the position within its parent of `t` and all its
67+
ancestors, we know how to lower `t` to IR.
68+
69+
We don't check some other things:
70+
- This pass assumes that required attributes exist, that leaf-only (or not)
71+
kinds are leaves (or not), and that syntax flags are valid per kind; these can
72+
be checked beforehand in a linear pass over the nodes.
73+
- Scope issues are caught later in lowering, e.g. declaring something local and
74+
global.
75+
6876
"""
6977
function valid_st1(st::SyntaxTree)
7078
vcx = Validation1Context()
@@ -104,8 +112,9 @@ vst1_value(vcx::Validation1Context, st::SyntaxTree; need_value=true) = @stm st b
104112
(leaf, when=kind(leaf) in KSet"""Identifier Value Symbol Integer Float
105113
String Char Bool CmdString HexInt OctInt BinInt""") -> true
106114

107-
# Container nodes that may or may not be values depending on their
108-
# contents; callers of vst1_value can specify that they don't need a value.
115+
# Container nodes that may or may not be values depending on their contents;
116+
# callers of vst1_value can specify that they don't need a value. Most
117+
# other forms are always a value.
109118
[K"block" _...] -> vst1_block(vcx, st; need_value)
110119
[K"let" [K"block" decls...] body] -> allv(vst1_symdecl_or_assign, vcx, decls) &
111120
vst1_block(with(vcx, :in_gscope=>false), body; need_value)
@@ -163,12 +172,7 @@ vst1_value(vcx::Validation1Context, st::SyntaxTree; need_value=true) = @stm st b
163172
fail(vcx, st, "`comparison` expects n>=3 args and odd n") :
164173
# TODO: xs[2:2:end] should just be identifier or (. identifier)
165174
allv(vst1_value, vcx, xs[2:2:end]) & allv(vst1_value, vcx, xs[1:2:end])
166-
# docstring-annotated call should have calldecl structure
167-
([K"doc" [K"string" strs...] callex],
168-
when=vst1_function_calldecl(with(vcx, :speculative=>true), st[2])) ->
169-
allv(vst1_value, vcx, strs)
170-
[K"doc" [K"string" strs...] x] ->
171-
allv(vst1_value, vcx, strs) & vst1_stmt(vcx, x)
175+
[K"doc" [K"string" strs...] x] -> allv(vst1_value, vcx, strs) & vst1_documented(vcx, x)
172176
[K"<:" x y] -> vst1_value(vcx, x) & vst1_value(vcx, y)
173177
[K">:" x y] -> vst1_value(vcx, x) & vst1_value(vcx, y)
174178
[K"-->" x y] -> vst1_value(vcx, x) & vst1_value(vcx, y)
@@ -187,7 +191,8 @@ vst1_value(vcx::Validation1Context, st::SyntaxTree; need_value=true) = @stm st b
187191
[K"global" [K"=" l r]] ->
188192
vst1_assign_lhs(vcx, l; disallow_type=!vcx.toplevel) &
189193
vst1_value(vcx, r)
190-
# TODO: local is always OK as a value, but non-assigning should probably not be
194+
# syntax TODO: local is always OK as a value, but non-assigning should probably not be
195+
# TODO: fail if immediate toplevel?
191196
[K"local" xs...] -> allv(vst1_symdecl_or_assign, vcx, xs)
192197

193198
# Forms not produced by the parser
@@ -221,6 +226,17 @@ vst1_value(vcx::Validation1Context, st::SyntaxTree; need_value=true) = @stm st b
221226
vst1_value(vcx, t) & vst1_value(vcx, fptr) & vst1_value(vcx, rt) & vst1_value(vcx, argt_svec)
222227
[K"scope_block" x] -> vst1_value(vcx, x; need_value)
223228

229+
# Only from macro expansions producing Expr(:toplevel, ...). We don't want
230+
# to recurse on the contained expression since `K"escape"` can wrap nearly
231+
# any node. This is OK since (1) if we're running `valid_st1`
232+
# pre-desugaring, this form is not recognized by desugaring and wrapped in a
233+
# `toplevel` anyway, so we'll see the expanded version later. (2) If we're
234+
# running `valid_st0`, macros are not expanded, so this form won't appear.
235+
([K"hygienic_scope" x [K"Value"] [K"Value"]]) ->
236+
vcx.unexpanded || fail(vcx, st, "`hygienic_scope` not valid after macro expansion")
237+
[K"hygienic_scope" x [K"Value"]] ->
238+
vcx.unexpanded || fail(vcx, st, "`hygienic_scope` not valid after macro expansion")
239+
224240
# forms normalized by expand_forms_1, so not valid in st1. TODO: we should
225241
# consider doing each of these normalizations before macro expansion rather
226242
# than after.
@@ -229,17 +245,15 @@ vst1_value(vcx::Validation1Context, st::SyntaxTree; need_value=true) = @stm st b
229245
([K"char" [K"Char"]], when=vcx.unexpanded) -> true
230246
([K"var" [K"Identifier"]], when=vcx.unexpanded) -> true
231247

232-
# Invalid forms for which we want to produce detailed errors.
233-
# TODO: the number of these cases is unbounded (e.g. bad kind or number of
234-
# arguments to any of the kinds above); move them to a separate function to
235-
# stop cluttering the grammar?
248+
# Invalid forms for which we want to produce detailed errors
236249
[K"..." _...] -> fail(vcx, st, "unexpected splat not in `call`, `tuple`, `curly`, or array expression")
237250
[K"parameters" _...] -> fail(vcx, st, "unexpected keyword-separating semicolon outside of call or tuple")
238251
[K"braces" _...] -> fail(vcx, st, "`braces` outside of `where` is reserved for future use")
239252
[K"bracescat" _...] -> fail(vcx, st, "`bracescat` is reserved for future use")
240253
[K"do" _...] -> fail(vcx, st, "unexpected `do` outside of `call`")
241254
[K"Placeholder"] -> fail(vcx, st, "all-underscore identifiers are write-only and their values cannot be used in expressions")
242255
[K"atomic" _...] -> fail(vcx, st, "unimplemented or unsupported `atomic` declaration")
256+
[K"::" x] -> fail(vcx, st, "`::` must be written `value::type` outside function argument lists")
243257
(_, when=need_value && kind(st) in KSet"symbolic_label symbolic_goto") ->
244258
fail(vcx, st, "misplaced `$(kind(st))` in value position")
245259
([K"global" _...], when=need_value) ->
@@ -267,7 +281,6 @@ vst1_stmt(vcx::Validation1Context, st::SyntaxTree) = @stm st begin
267281
(_, run=pass_or_err(vst1_value, vcx, st; need_value=false), when=run.known) -> run.pass
268282
([K"global" xs...], when=vcx.toplevel) -> allv(vst1_symdecl_or_assign, vcx, xs)
269283
([K"global" xs...], when=!vcx.toplevel) -> allv(vst1_inner_global_decl, vcx, xs)
270-
[K"local" xs...] -> allv(vst1_symdecl_or_assign, vcx, xs) # TODO: fail if immediate toplevel
271284
[K"symbolic_label"] -> true
272285
[K"symbolic_goto"] -> true
273286

@@ -831,6 +844,15 @@ vst1_iter(vcx, st) = @stm st begin
831844
_ -> fail(vcx, st, "malformed `in`")
832845
end
833846

847+
vst1_documented(vcx, st) = @stm st begin
848+
(_, when=kind(st) in KSet"function macro = struct abstract primitive const global Symbol inert module") ->
849+
vst1_stmt(vcx, st)
850+
# doc-only cases
851+
(_, when=kind(st) in KSet". Identifier tuple") -> vst1_stmt(vcx, st)
852+
(callex, when=vst1_function_calldecl(with(vcx, :speculative=>true), st)) -> true
853+
_ -> fail(vcx, st, "`$(kind(st))` cannot be annotated with a docstring")
854+
end
855+
834856
"""
835857
For convenience, much of the validation code for st0 (non-macro-expanded trees) is
836858
shared with that for st1 (macro-expanded trees). The main differences:
@@ -852,7 +874,7 @@ function valid_st0(st::SyntaxTree)
852874
return valid
853875
end
854876
valid_st0(vcx, st) = @stm st begin
855-
_ -> vst1_stmt(vcx, st)
877+
_ -> vst1_stmt(with(vcx, :unexpanded=>true), st)
856878
end
857879

858880
"""
@@ -866,7 +888,8 @@ end
866888

867889
vst0_quoted(vcx, st) = @stm st begin
868890
([K"$" x], when=vcx.quote_level===1) -> valid_st0(with(vcx, :quote_level=>0), x)
869-
[K"quote"] -> vst0_quoted(with(vcx, :quote_level=>vcx.quote_level+1), st)
891+
[K"$" x] -> vst0_quoted(with(vcx, :quote_level=>vcx.quote_level-1), x)
892+
[K"quote" x] -> vst0_quoted(with(vcx, :quote_level=>vcx.quote_level+1), x)
870893
_ -> allv(vst0_quoted, vcx, children(st))
871894
end
872895

test/misc_ir.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ x::T
227227
#---------------------
228228
LoweringError:
229229
::T
230-
└─┘ ── invalid syntax: unknown kind `::` or number of arguments (1)
230+
└─┘ ── `::` must be written `value::type` outside function argument lists
231231

232232
########################################
233233
# Error: braces vector syntax

0 commit comments

Comments
 (0)