@@ -1647,6 +1647,23 @@ function parse_subtype_spec(ps::ParseState)
1647
1647
parse_comparison (ps, true )
1648
1648
end
1649
1649
1650
+ # flisp: parse-struct-field
1651
+ function parse_struct_field (ps:: ParseState )
1652
+ mark = position (ps)
1653
+ const_field = peek (ps) == K " const"
1654
+ if const_field
1655
+ bump (ps, TRIVIA_FLAG)
1656
+ end
1657
+ parse_eq (ps)
1658
+ if const_field
1659
+ # Const fields https://github.com/JuliaLang/julia/pull/43305
1660
+ # v1.8: struct A const a end ==> (struct false A (block (const x)))
1661
+ # v1.7: struct A const a end ==> (struct false A (block (error (const x))))
1662
+ emit (ps, mark, K " const" )
1663
+ min_supported_version (v " 1.8" , ps, mark, " `const` struct field" )
1664
+ end
1665
+ end
1666
+
1650
1667
# parse expressions or blocks introduced by syntactic reserved words.
1651
1668
#
1652
1669
# The caller should use peek_initial_reserved_words to determine whether
@@ -1727,8 +1744,47 @@ function parse_resword(ps::ParseState)
1727
1744
emit (ps, mark, K " let" )
1728
1745
elseif word == K " if"
1729
1746
parse_if_elseif (ps)
1730
- elseif word in KSet " const global local"
1731
- parse_const_local_global (ps)
1747
+ elseif word in KSet " global local"
1748
+ # global x ==> (global x)
1749
+ # local x ==> (local x)
1750
+ # global x,y ==> (global x y)
1751
+ bump (ps, TRIVIA_FLAG)
1752
+ const_mark = nothing
1753
+ if peek (ps) == K " const"
1754
+ const_mark = position (ps)
1755
+ bump (ps, TRIVIA_FLAG)
1756
+ end
1757
+ had_assignment = parse_global_local_const_vars (ps)
1758
+ if ! isnothing (const_mark)
1759
+ # global const x = 1 ==> (global (const (= x 1)))
1760
+ # local const x = 1 ==> (local (const (= x 1)))
1761
+ emit (ps, const_mark, K " const" )
1762
+ if ! had_assignment
1763
+ # global const x ==> (global (error (const x)))
1764
+ emit (ps, mark, K " error" , error= " expected assignment after `const`" )
1765
+ end
1766
+ end
1767
+ emit (ps, mark, word)
1768
+ elseif word == K " const"
1769
+ # const x = 1 ==> (const (= x 1))
1770
+ bump (ps, TRIVIA_FLAG)
1771
+ scope_mark = nothing
1772
+ scope_k = peek (ps)
1773
+ if scope_k in KSet " local global"
1774
+ scope_mark = position (ps)
1775
+ bump (ps, TRIVIA_FLAG)
1776
+ end
1777
+ had_assignment = parse_global_local_const_vars (ps)
1778
+ if ! isnothing (scope_mark)
1779
+ # const global x = 1 ==> (const (global (= x 1)))
1780
+ # const local x = 1 ==> (const (local (= x 1)))
1781
+ emit (ps, scope_mark, scope_k)
1782
+ end
1783
+ emit (ps, mark, K " const" )
1784
+ if ! had_assignment
1785
+ # const x .= 1 ==> (error (const (.= x 1)))
1786
+ emit (ps, mark, K " error" , error= " expected assignment after `const`" )
1787
+ end
1732
1788
elseif word in KSet " function macro"
1733
1789
parse_function (ps)
1734
1790
elseif word == K " abstract"
@@ -1749,6 +1805,9 @@ function parse_resword(ps::ParseState)
1749
1805
emit (ps, mark, K " abstract" )
1750
1806
elseif word in KSet " struct mutable"
1751
1807
# struct A <: B \n a::X \n end ==> (struct false (<: A B) (block (:: a X)))
1808
+ # struct A \n a \n b \n end ==> (struct false A (block a b))
1809
+ # v1.7: struct A const a end ==> (struct false A (block (error (const a))))
1810
+ # v1.8: struct A const a end ==> (struct false A (block (const a)))
1752
1811
if word == K " mutable"
1753
1812
# mutable struct A end ==> (struct true A (block))
1754
1813
bump (ps, TRIVIA_FLAG)
@@ -1760,7 +1819,7 @@ function parse_resword(ps::ParseState)
1760
1819
@check peek (ps) == K " struct"
1761
1820
bump (ps, TRIVIA_FLAG)
1762
1821
parse_subtype_spec (ps)
1763
- parse_block (ps)
1822
+ parse_block (ps, parse_struct_field )
1764
1823
bump_closing_token (ps, K " end" )
1765
1824
emit (ps, mark, K " struct" )
1766
1825
elseif word == K " primitive"
@@ -1888,75 +1947,24 @@ function parse_if_elseif(ps, is_elseif=false, is_elseif_whitespace_err=false)
1888
1947
emit (ps, mark, word)
1889
1948
end
1890
1949
1891
- function parse_const_local_global (ps)
1950
+ # Like parse_assignment, but specialized so that we can omit the
1951
+ # tuple when there's commas but no assignment.
1952
+ function parse_global_local_const_vars (ps)
1892
1953
mark = position (ps)
1893
- scope_mark = mark
1894
- has_const = false
1895
- scope_k = K " None"
1896
- k = peek (ps)
1897
- if k in KSet " global local"
1898
- # global x ==> (global x)
1899
- # local x ==> (local x)
1900
- scope_k = k
1901
- bump (ps, TRIVIA_FLAG)
1902
- if peek (ps) == K " const"
1903
- # global const x = 1 ==> (const (global (= x 1)))
1904
- # local const x = 1 ==> (const (local (= x 1)))
1905
- has_const = true
1906
- bump (ps, TRIVIA_FLAG)
1907
- end
1908
- else
1909
- has_const = true
1910
- # const x = 1 ==> (const (= x 1))
1911
- bump (ps, TRIVIA_FLAG)
1912
- k = peek (ps)
1913
- if k in KSet " global local"
1914
- # const global x = 1 ==> (const (global (= x 1)))
1915
- # const local x = 1 ==> (const (local (= x 1)))
1916
- scope_k = k
1917
- scope_mark = position (ps)
1918
- bump (ps, TRIVIA_FLAG)
1919
- end
1920
- end
1921
- # Like parse_assignment, but specialized so that we can omit the
1922
- # tuple when there's commas but no assignment.
1923
- beforevar_mark = position (ps)
1924
1954
n_commas = parse_comma (ps, false )
1925
1955
t = peek_token (ps)
1926
- has_assignment = is_prec_assignment (t)
1927
- if n_commas >= 1 && (has_assignment || has_const)
1956
+ assign_prec = is_prec_assignment (t)
1957
+ if n_commas >= 1 && assign_prec
1928
1958
# const x,y = 1,2 ==> (const (= (tuple x y) (tuple 1 2)))
1929
- # Maybe nonsensical? But this is what the flisp parser does.
1930
- # v1.8: const x,y ==> (const (tuple x y))
1931
- emit (ps, beforevar_mark, K " tuple" )
1959
+ emit (ps, mark, K " tuple" )
1932
1960
end
1933
- if has_assignment
1961
+ if assign_prec
1934
1962
# const x = 1 ==> (const (= x 1))
1935
1963
# global x ~ 1 ==> (global (call-i x ~ 1))
1936
1964
# global x += 1 ==> (global (+= x 1))
1937
- parse_assignment_with_initial_ex (ps, beforevar_mark, parse_comma)
1938
- else
1939
- # global x ==> (global x)
1940
- # local x ==> (local x)
1941
- # global x,y ==> (global x y)
1942
- end
1943
- if has_const && (! has_assignment || is_dotted (t))
1944
- # Const fields https://github.com/JuliaLang/julia/pull/43305
1945
- # v1.8: const x ==> (const x)
1946
- # v1.8: const x::T ==> (const (:: x T))
1947
- # Disallowed const forms on <= 1.7
1948
- # v1.7: const x ==> (const (error x))
1949
- # v1.7: const x .= 1 ==> (const (error (.= x 1)))
1950
- min_supported_version (v " 1.8" , ps, beforevar_mark,
1951
- " `const` struct field without assignment" )
1952
- end
1953
- if scope_k != K " None"
1954
- emit (ps, scope_mark, scope_k)
1955
- end
1956
- if has_const
1957
- # TODO : Normalize `global const` during Expr conversion rather than here?
1958
- emit (ps, mark, K " const" )
1965
+ parse_assignment_with_initial_ex (ps, mark, parse_comma)
1959
1966
end
1967
+ return kind (t) == K " =" && ! is_dotted (t)
1960
1968
end
1961
1969
1962
1970
# Parse function and macro definitions
0 commit comments