@@ -1647,6 +1647,23 @@ function parse_subtype_spec(ps::ParseState)
16471647 parse_comparison (ps, true )
16481648end
16491649
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+
16501667# parse expressions or blocks introduced by syntactic reserved words.
16511668#
16521669# The caller should use peek_initial_reserved_words to determine whether
@@ -1727,8 +1744,47 @@ function parse_resword(ps::ParseState)
17271744 emit (ps, mark, K " let" )
17281745 elseif word == K " if"
17291746 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
17321788 elseif word in KSet " function macro"
17331789 parse_function (ps)
17341790 elseif word == K " abstract"
@@ -1749,6 +1805,9 @@ function parse_resword(ps::ParseState)
17491805 emit (ps, mark, K " abstract" )
17501806 elseif word in KSet " struct mutable"
17511807 # 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)))
17521811 if word == K " mutable"
17531812 # mutable struct A end ==> (struct true A (block))
17541813 bump (ps, TRIVIA_FLAG)
@@ -1760,7 +1819,7 @@ function parse_resword(ps::ParseState)
17601819 @check peek (ps) == K " struct"
17611820 bump (ps, TRIVIA_FLAG)
17621821 parse_subtype_spec (ps)
1763- parse_block (ps)
1822+ parse_block (ps, parse_struct_field )
17641823 bump_closing_token (ps, K " end" )
17651824 emit (ps, mark, K " struct" )
17661825 elseif word == K " primitive"
@@ -1888,75 +1947,24 @@ function parse_if_elseif(ps, is_elseif=false, is_elseif_whitespace_err=false)
18881947 emit (ps, mark, word)
18891948end
18901949
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)
18921953 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)
19241954 n_commas = parse_comma (ps, false )
19251955 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
19281958 # 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" )
19321960 end
1933- if has_assignment
1961+ if assign_prec
19341962 # const x = 1 ==> (const (= x 1))
19351963 # global x ~ 1 ==> (global (call-i x ~ 1))
19361964 # 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)
19591966 end
1967+ return kind (t) == K " =" && ! is_dotted (t)
19601968end
19611969
19621970# Parse function and macro definitions
0 commit comments