Skip to content

Commit 9eb28b2

Browse files
committed
Use flags for struct/module variants and allow empty return nodes
Various AST cleanups: * `struct` and `mutable struct` are distinguished with flags not children * `module` and `baremodule` are distinguished with flags not children * `return` now parses with empty children rather than with an invisible K"nothing" as the only child.
1 parent f6c66cb commit 9eb28b2

File tree

7 files changed

+84
-50
lines changed

7 files changed

+84
-50
lines changed

src/expr.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
278278
pushfirst!(args[2].args, loc)
279279
end
280280
elseif headsym === :module
281+
pushfirst!(args, !has_flags(node, BARE_MODULE_FLAG))
281282
pushfirst!(args[3].args, loc)
282283
elseif headsym == :inert || (headsym == :quote && length(args) == 1 &&
283284
!(a1 = only(args); a1 isa Expr || a1 isa QuoteNode ||
@@ -303,11 +304,13 @@ function _to_expr(node::SyntaxNode; iteration_spec=false, need_linenodes=true,
303304
args[1] = Expr(headsym, args[1].args...)
304305
headsym = :const
305306
end
306-
elseif headsym == :return && isempty(args)
307+
elseif headsym === :return && isempty(args)
307308
push!(args, nothing)
308-
elseif headsym == :juxtapose
309+
elseif headsym === :juxtapose
309310
headsym = :call
310311
pushfirst!(args, :*)
312+
elseif headsym === :struct
313+
pushfirst!(args, has_flags(node, MUTABLE_FLAG))
311314
end
312315
return Expr(headsym, args...)
313316
end

src/hooks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ function _incomplete_tag(n::SyntaxNode)
6262
elseif kp in KSet"for while function if"
6363
return i == 1 ? :other : :block
6464
elseif kp in KSet"module struct"
65-
return i == 2 ? :other : :block
65+
return i == 1 ? :other : :block
6666
elseif kp == K"do"
6767
return i < 3 ? :other : :block
6868
else

src/parse_stream.jl

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,38 @@
55
# TODO: Use `primitive type SyntaxFlags 16 end` rather than an alias?
66
const RawFlags = UInt16
77
const EMPTY_FLAGS = RawFlags(0)
8-
# Applied to tokens which are syntax trivia after parsing
8+
9+
# Set for tokens or ranges which are syntax trivia after parsing
910
const TRIVIA_FLAG = RawFlags(1<<0)
1011

11-
# Record whether operators are dotted
12+
# Token flags - may be set for operator kinded tokens
13+
# Operator is dotted
1214
const DOTOP_FLAG = RawFlags(1<<1)
13-
# Record whether operator has a suffix
14-
const SUFFIXED_FLAG = RawFlags(1<<2)
15+
# Operator has a suffix
16+
const SUFFIXED_FLAG = RawFlags(1<<2)
1517

18+
# Set for K"call", K"dotcall" or any syntactic operator heads
1619
# Distinguish various syntaxes which are mapped to K"call"
1720
const PREFIX_CALL_FLAG = RawFlags(0<<3)
1821
const INFIX_FLAG = RawFlags(1<<3)
1922
const PREFIX_OP_FLAG = RawFlags(2<<3)
2023
const POSTFIX_OP_FLAG = RawFlags(3<<3)
2124

22-
# The next two bits could overlap with the previous two if necessary
23-
# Set when kind == K"String" was triple-delimited as with """ or ```
25+
# The following flags are quite head-specific and may overlap
26+
27+
# Set when K"string" or K"cmdstring" was triple-delimited as with """ or ```
2428
const TRIPLE_STRING_FLAG = RawFlags(1<<5)
25-
# Set when a string or identifier needs "raw string" unescaping
29+
# Set when a K"string", K"cmdstring" or K"Identifier" needs raw string unescaping
2630
const RAW_STRING_FLAG = RawFlags(1<<6)
2731

28-
const PARENS_FLAG = RawFlags(1<<7)
32+
# Set for K"tuple", K"block" or K"macrocall" which are delimited by parentheses
33+
const PARENS_FLAG = RawFlags(1<<5)
34+
35+
# Set for K"struct" when mutable
36+
const MUTABLE_FLAG = RawFlags(1<<5)
37+
38+
# Set for K"module" when it's not bare (`module`, not `baremodule`)
39+
const BARE_MODULE_FLAG = RawFlags(1<<5)
2940

3041
# Flags holding the dimension of an nrow or other UInt8 not held in the source
3142
const NUMERIC_FLAGS = RawFlags(RawFlags(0xff)<<8)
@@ -78,10 +89,18 @@ function untokenize(head::SyntaxHead; unique=true, include_flag_suff=true)
7889
is_infix_op_call(head) && (str = str*"-i")
7990
is_prefix_op_call(head) && (str = str*"-pre")
8091
is_postfix_op_call(head) && (str = str*"-post")
81-
has_flags(head, TRIPLE_STRING_FLAG) && (str = str*"-s")
82-
has_flags(head, RAW_STRING_FLAG) && (str = str*"-r")
83-
has_flags(head, PARENS_FLAG) && (str = str*"-p")
84-
is_suffixed(head) && (str = str*"-S")
92+
93+
if kind(head) in KSet"string cmdstring Identifier"
94+
has_flags(head, TRIPLE_STRING_FLAG) && (str = str*"-s")
95+
has_flags(head, RAW_STRING_FLAG) && (str = str*"-r")
96+
elseif kind(head) in KSet"tuple block macrocall"
97+
has_flags(head, PARENS_FLAG) && (str = str*"-p")
98+
elseif kind(head) == K"struct"
99+
has_flags(head, MUTABLE_FLAG) && (str = str*"-mut")
100+
elseif kind(head) == K"module"
101+
has_flags(head, BARE_MODULE_FLAG) && (str = str*"-bare")
102+
end
103+
is_suffixed(head) && (str = str*"-suf")
85104
n = numeric_flags(head)
86105
n != 0 && (str = str*"-"*string(n))
87106
end

src/parser.jl

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ function parse_comparison(ps::ParseState, subtype_comparison=false)
763763
mark = position(ps)
764764
if subtype_comparison && is_reserved_word(peek(ps))
765765
# Recovery
766-
# struct try end ==> (struct false (error (try)) (block))
766+
# struct try end ==> (struct (error (try)) (block))
767767
name = untokenize(peek(ps))
768768
bump(ps)
769769
emit(ps, mark, K"error", error="Invalid type name `$name`")
@@ -1764,8 +1764,8 @@ function parse_struct_field(ps::ParseState)
17641764
parse_eq(ps)
17651765
if const_field
17661766
# Const fields https://github.com/JuliaLang/julia/pull/43305
1767-
#v1.8: struct A const a end ==> (struct false A (block (const x)))
1768-
#v1.7: struct A const a end ==> (struct false A (block (error (const x))))
1767+
#v1.8: struct A const a end ==> (struct A (block (const x)))
1768+
#v1.7: struct A const a end ==> (struct A (block (error (const x))))
17691769
emit(ps, mark, K"const")
17701770
min_supported_version(v"1.8", ps, mark, "`const` struct field")
17711771
end
@@ -1929,24 +1929,23 @@ function parse_resword(ps::ParseState)
19291929
bump_closing_token(ps, K"end")
19301930
emit(ps, mark, K"abstract")
19311931
elseif word in KSet"struct mutable"
1932-
# struct A <: B \n a::X \n end ==> (struct false (<: A B) (block (::-i a X)))
1933-
# struct A \n a \n b \n end ==> (struct false A (block a b))
1934-
#v1.7: struct A const a end ==> (struct false A (block (error (const a))))
1935-
#v1.8: struct A const a end ==> (struct false A (block (const a)))
1936-
if word == K"mutable"
1937-
# mutable struct A end ==> (struct true A (block))
1932+
# struct A <: B \n a::X \n end ==> (struct (<: A B) (block (::-i a X)))
1933+
# struct A \n a \n b \n end ==> (struct A (block a b))
1934+
#v1.7: struct A const a end ==> (struct A (block (error (const a))))
1935+
#v1.8: struct A const a end ==> (struct A (block (const a)))
1936+
is_mut = word == K"mutable"
1937+
if is_mut
1938+
# mutable struct A end ==> (struct-mut A (block))
19381939
bump(ps, TRIVIA_FLAG)
1939-
bump_invisible(ps, K"true")
19401940
else
1941-
# struct A end ==> (struct false A (block))
1942-
bump_invisible(ps, K"false")
1941+
# struct A end ==> (struct A (block))
19431942
end
19441943
@check peek(ps) == K"struct"
19451944
bump(ps, TRIVIA_FLAG)
19461945
parse_subtype_spec(ps)
19471946
parse_block(ps, parse_struct_field)
19481947
bump_closing_token(ps, K"end")
1949-
emit(ps, mark, K"struct")
1948+
emit(ps, mark, K"struct", is_mut ? MUTABLE_FLAG : EMPTY_FLAGS)
19501949
elseif word == K"primitive"
19511950
# primitive type A 32 end ==> (primitive A 32)
19521951
# primitive type A 32 ; end ==> (primitive A 32)
@@ -1986,22 +1985,22 @@ function parse_resword(ps::ParseState)
19861985
error="unexpected token after $(untokenize(word))")
19871986
end
19881987
elseif word in KSet"module baremodule"
1989-
# module A end ==> (module true A (block))
1990-
# baremodule A end ==> (module false A (block))
1988+
# module A end ==> (module A (block))
1989+
# baremodule A end ==> (module-bare A (block))
19911990
bump(ps, TRIVIA_FLAG)
1992-
bump_invisible(ps, (word == K"module") ? K"true" : K"false")
19931991
if is_reserved_word(peek(ps))
1994-
# module do \n end ==> (module true (error do) (block))
1992+
# module do \n end ==> (module (error do) (block))
19951993
bump(ps, error="Invalid module name")
19961994
else
1997-
# module $A end ==> (module true ($ A) (block))
1995+
# module $A end ==> (module ($ A) (block))
19981996
parse_unary_prefix(ps)
19991997
end
2000-
# module A \n a \n b \n end ==> (module true A (block a b))
2001-
# module A \n "x"\na \n end ==> (module true A (block (doc (string "x") a)))
1998+
# module A \n a \n b \n end ==> (module A (block a b))
1999+
# module A \n "x"\na \n end ==> (module A (block (doc (string "x") a)))
20022000
parse_block(ps, parse_docstring)
20032001
bump_closing_token(ps, K"end")
2004-
emit(ps, mark, K"module")
2002+
emit(ps, mark, K"module",
2003+
word == K"baremodule" ? BARE_MODULE_FLAG : EMPTY_FLAGS)
20052004
elseif word == K"export"
20062005
# export a ==> (export a)
20072006
# export @a ==> (export @a)

test/expr.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,4 +312,18 @@
312312
@test parse(Expr, "return x") == Expr(:return, :x)
313313
@test parse(Expr, "return") == Expr(:return, nothing)
314314
end
315+
316+
@testset "struct" begin
317+
@test parse(Expr, "struct A end") ==
318+
Expr(:struct, false, :A, Expr(:block, LineNumberNode(1)))
319+
@test parse(Expr, "mutable struct A end") ==
320+
Expr(:struct, true, :A, Expr(:block, LineNumberNode(1)))
321+
end
322+
323+
@testset "module" begin
324+
@test parse(Expr, "module A end") ==
325+
Expr(:module, true, :A, Expr(:block, LineNumberNode(1), LineNumberNode(1)))
326+
@test parse(Expr, "baremodule A end") ==
327+
Expr(:module, false, :A, Expr(:block, LineNumberNode(1), LineNumberNode(1)))
328+
end
315329
end

test/hooks.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838

3939
@testset "Expr(:incomplete)" begin
4040
JuliaSyntax.enable_in_core!()
41-
4241
@test Meta.isexpr(Meta.parse("[x"), :incomplete)
4342

4443
for (str, tag) in [

test/parser.jl

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -467,13 +467,13 @@ tests = [
467467
"primitive type A \$N end" => "(primitive A (\$ N))"
468468
"primitive type A <: B \n 8 \n end" => "(primitive (<: A B) 8)"
469469
# struct
470-
"struct A <: B \n a::X \n end" => "(struct false (<: A B) (block (::-i a X)))" => Expr(:struct, false, Expr(:<:, :A, :B), Expr(:block, Expr(:(::), :a, :X)))
471-
"struct A \n a \n b \n end" => "(struct false A (block a b))" => Expr(:struct, false, :A, Expr(:block, :a, :b))
472-
"mutable struct A end" => "(struct true A (block))"
473-
((v=v"1.8",), "struct A const a end") => "(struct false A (block (const a)))" => Expr(:struct, false, :A, Expr(:block, Expr(:const, :a)))
474-
((v=v"1.7",), "struct A const a end") => "(struct false A (block (error (const a))))"
475-
"struct A end" => "(struct false A (block))" => Expr(:struct, false, :A, Expr(:block))
476-
"struct try end" => "(struct false (error (try)) (block))"
470+
"struct A <: B \n a::X \n end" => "(struct (<: A B) (block (::-i a X)))" => Expr(:struct, false, Expr(:<:, :A, :B), Expr(:block, Expr(:(::), :a, :X)))
471+
"struct A \n a \n b \n end" => "(struct A (block a b))" => Expr(:struct, false, :A, Expr(:block, :a, :b))
472+
"mutable struct A end" => "(struct-mut A (block))"
473+
((v=v"1.8",), "struct A const a end") => "(struct A (block (const a)))" => Expr(:struct, false, :A, Expr(:block, Expr(:const, :a)))
474+
((v=v"1.7",), "struct A const a end") => "(struct A (block (error (const a))))"
475+
"struct A end" => "(struct A (block))" => Expr(:struct, false, :A, Expr(:block))
476+
"struct try end" => "(struct (error (try)) (block))"
477477
# return
478478
"return\nx" => "(return)"
479479
"return)" => "(return)"
@@ -483,12 +483,12 @@ tests = [
483483
"break" => "(break)"
484484
"continue" => "(continue)"
485485
# module/baremodule
486-
"module A end" => "(module true A (block))"
487-
"baremodule A end" => "(module false A (block))"
488-
"module do \n end" => "(module true (error (do)) (block))"
489-
"module \$A end" => "(module true (\$ A) (block))"
490-
"module A \n a \n b \n end" => "(module true A (block a b))"
491-
"""module A \n "x"\na\n end""" => """(module true A (block (doc (string "x") a)))"""
486+
"module A end" => "(module A (block))"
487+
"baremodule A end" => "(module-bare A (block))"
488+
"module do \n end" => "(module (error (do)) (block))"
489+
"module \$A end" => "(module (\$ A) (block))"
490+
"module A \n a \n b \n end" => "(module A (block a b))"
491+
"""module A \n "x"\na\n end""" => """(module A (block (doc (string "x") a)))"""
492492
# export
493493
"export a" => "(export a)" => Expr(:export, :a)
494494
"export @a" => "(export @a)" => Expr(:export, Symbol("@a"))

0 commit comments

Comments
 (0)