@@ -5,6 +5,8 @@ module Parser =
55 let mutable index = 0
66 member _.Peek () = tokens.[ index]
77 member _.PeekAt ( offset : int ) = tokens.[ index + offset]
8+ member _.TokenAt ( i : int ) = tokens.[ i]
9+ member _.Index = index
810 member _.Mark () = index
911 member _.Restore ( mark : int ) = index <- mark
1012 member _.Next () =
@@ -161,6 +163,23 @@ module Parser =
161163 progress <- true
162164 consumed
163165
166+ let hasNonLayoutTokenBeforeOnSameLine ( tokenIndex : int ) ( line : int ) =
167+ let mutable i = tokenIndex - 1
168+ let mutable keepSearching = true
169+ let mutable foundSameLine = false
170+ while keepSearching && i >= 0 do
171+ let tok = stream.TokenAt( i)
172+ match tok.Kind with
173+ | Newline ->
174+ keepSearching <- false
175+ | Indent
176+ | Dedent ->
177+ i <- i - 1
178+ | _ ->
179+ foundSameLine <- tok.Span.Start.Line = line
180+ keepSearching <- false
181+ foundSameLine
182+
164183 let mutable allowIndentedApplication = true
165184 let mutable allowBinaryNewlineSkipping = true
166185
@@ -185,22 +204,12 @@ module Parser =
185204 stream.Expect( Colon, " Expected ':' after inline record type field name" ) |> ignore
186205 let fieldType = parseTypeRef()
187206 fields.Add( fieldName, fieldType)
188- consumeLayoutSeparators() |> ignore
189207 if stream.Peek() .Kind = RBrace then
190208 raise ( ParseException { Message = " Inline record type must define at least one field" ; Span = stream.Peek() .Span })
191209 parseField()
192- let mutable keepParsing = true
193- while keepParsing do
194- let hasSeparator =
195- if stream.Match( Semicolon) then
196- consumeLayoutSeparators() |> ignore
197- true
198- else
199- consumeLayoutSeparators()
200- if hasSeparator && stream.Peek() .Kind <> RBrace then
210+ while stream.Match( Semicolon) do
211+ if stream.Peek() .Kind <> RBrace then
201212 parseField()
202- else
203- keepParsing <- false
204213 stream.Expect( RBrace, " Expected '}' in inline record type" ) |> ignore
205214 TRRecord ( fields |> Seq.toList)
206215 | LParen ->
@@ -507,7 +516,12 @@ module Parser =
507516 let rp = stream.Expect( RParen, " Expected ')' after expression" )
508517 EParen( first, mkSpanFrom lp.Span rp.Span)
509518 | LBracket ->
519+ let lbIndex = stream.Index
510520 let lb = stream.Next()
521+ let immediateMultiline = stream.Peek() .Kind = Newline
522+ let hasSameLinePrefix = hasNonLayoutTokenBeforeOnSameLine lbIndex lb.Span.Start.Line
523+ if immediateMultiline && hasSameLinePrefix then
524+ raise ( ParseException { Message = " For multiline list literals, '[' must be on its own line" ; Span = lb.Span })
511525 consumeLayoutSeparators() |> ignore
512526 if stream.Match( RBracket) then
513527 EList([], mkSpanFrom lb.Span lb.Span)
@@ -537,7 +551,12 @@ module Parser =
537551 let rb = stream.Expect( RBracket, " Expected ']' in list literal" )
538552 EList( elements |> Seq.toList, mkSpanFrom lb.Span rb.Span)
539553 | LBrace ->
554+ let lbIndex = stream.Index
540555 let lb = stream.Next()
556+ let immediateMultiline = stream.Peek() .Kind = Newline
557+ let hasSameLinePrefix = hasNonLayoutTokenBeforeOnSameLine lbIndex lb.Span.Start.Line
558+ if immediateMultiline && hasSameLinePrefix then
559+ raise ( ParseException { Message = " For multiline record/map literals, '{' must be on its own line" ; Span = lb.Span })
541560 consumeLayoutSeparators() |> ignore
542561 if stream.Match( RBrace) then
543562 EMap([], mkSpanFrom lb.Span lb.Span)
0 commit comments