Skip to content

Commit f70d385

Browse files
vasily-kirichenkoKevinRansom
authored andcommitted
make Internal.Utilities.Text.Lexing.Position a struct
use a structs instead of couple Tuples in LexFilter
1 parent 8b219f2 commit f70d385

File tree

3 files changed

+96
-73
lines changed

3 files changed

+96
-73
lines changed

src/fsharp/LexFilter.fs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -403,12 +403,18 @@ type LexbufState(startPos: Position,
403403
member x.EndPos = endPos
404404
member x.PastEOF = pastEOF
405405

406+
[<Struct>]
407+
type PositionTuple =
408+
val X: Position
409+
val Y: Position
410+
new (x: Position, y: Position) = { X = x; Y = y }
411+
406412
/// Used to save the state related to a token
407413
[<Class>]
408414
type TokenTup =
409415
val Token : token
410416
val LexbufState : LexbufState
411-
val LastTokenPos: Position * Position
417+
val LastTokenPos: PositionTuple
412418
new (token,state,lastTokenPos) = { Token=token; LexbufState=state;LastTokenPos=lastTokenPos }
413419

414420
/// Returns starting position of the token
@@ -485,6 +491,12 @@ let (|TyparsCloseOp|_|) (txt:string) =
485491
| _ -> None
486492
Some([| for _c in angles do yield GREATER |],afterOp)
487493

494+
[<Struct>]
495+
type PositionWithColumn =
496+
val Position: Position
497+
val Column: int
498+
new (position: Position, column: int) = { Position = position; Column = column }
499+
488500
//----------------------------------------------------------------------------
489501
// build a LexFilter
490502
//--------------------------------------------------------------------------*)
@@ -553,7 +565,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
553565
let tokenLexbufState = getLexbufState()
554566
savedLexbufState <- tokenLexbufState
555567
haveLexbufState <- true
556-
TokenTup(token,tokenLexbufState,(lastTokenStart,lastTokenEnd))
568+
TokenTup(token,tokenLexbufState,PositionTuple(lastTokenStart,lastTokenEnd))
557569

558570
//----------------------------------------------------------------------------
559571
// Fetch a raw token, either from the old lexer or from our delayedStack
@@ -623,7 +635,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
623635
let pushCtxt tokenTup (newCtxt:Context) =
624636
let rec unindentationLimit strict stack =
625637
match newCtxt,stack with
626-
| _, [] -> (newCtxt.StartPos, -1)
638+
| _, [] -> PositionWithColumn(newCtxt.StartPos, -1)
627639

628640
// ignore Vanilla because a SeqBlock is always coming
629641
| _, (CtxtVanilla _ :: rest) -> unindentationLimit strict rest
@@ -635,8 +647,8 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
635647
// '(match' limited by minimum of two
636648
| _,(((CtxtMatch _) as ctxt1) :: CtxtSeqBlock _ :: (CtxtParen ((BEGIN | LPAREN),_) as ctxt2) :: _rest)
637649
-> if ctxt1.StartCol <= ctxt2.StartCol
638-
then (ctxt1.StartPos,ctxt1.StartCol)
639-
else (ctxt2.StartPos,ctxt2.StartCol)
650+
then PositionWithColumn(ctxt1.StartPos,ctxt1.StartCol)
651+
else PositionWithColumn(ctxt2.StartPos,ctxt2.StartCol)
640652

641653
// 'let ... = function' limited by 'let', precisely
642654
// This covers the common form
@@ -645,15 +657,15 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
645657
// | Case1 -> ...
646658
// | Case2 -> ...
647659
| (CtxtMatchClauses _), (CtxtFunction _ :: CtxtSeqBlock _ :: (CtxtLetDecl _ as limitCtxt) :: _rest)
648-
-> (limitCtxt.StartPos,limitCtxt.StartCol)
660+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol)
649661

650662
// Otherwise 'function ...' places no limit until we hit a CtxtLetDecl etc... (Recursive)
651663
| (CtxtMatchClauses _), (CtxtFunction _ :: rest)
652664
-> unindentationLimit false rest
653665

654666
// 'try ... with' limited by 'try'
655667
| _,(CtxtMatchClauses _ :: (CtxtTry _ as limitCtxt) :: _rest)
656-
-> (limitCtxt.StartPos,limitCtxt.StartCol)
668+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol)
657669

658670
// 'fun ->' places no limit until we hit a CtxtLetDecl etc... (Recursive)
659671
| _,(CtxtFun _ :: rest)
@@ -672,7 +684,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
672684
// This is a serious thing to allow, but is required since there is no "return" in this language.
673685
// Without it there is no way of escaping special cases in large bits of code without indenting the main case.
674686
| CtxtSeqBlock _, (CtxtElse _ :: (CtxtIf _ as limitCtxt) :: _rest)
675-
-> (limitCtxt.StartPos,limitCtxt.StartCol)
687+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol)
676688

677689
// Permitted inner-construct precise block alighnment:
678690
// interface ...
@@ -683,7 +695,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
683695
// with ...
684696
// end
685697
| CtxtWithAsAugment _,((CtxtInterfaceHead _ | CtxtMemberHead _ | CtxtException _ | CtxtTypeDefns _) as limitCtxt :: _rest)
686-
-> (limitCtxt.StartPos,limitCtxt.StartCol)
698+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol)
687699

688700
// Permit unindentation via parentheses (or begin/end) following a 'then', 'else' or 'do':
689701
// if nr > 0 then (
@@ -754,12 +766,12 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
754766
// 'type C = interface ... ' limited by 'type'
755767
// 'type C = struct ... ' limited by 'type'
756768
| _,(CtxtParen ((CLASS | STRUCT | INTERFACE),_) :: CtxtSeqBlock _ :: (CtxtTypeDefns _ as limitCtxt) :: _)
757-
-> (limitCtxt.StartPos,limitCtxt.StartCol + 1)
769+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol + 1)
758770

759771
// REVIEW: document these
760772
| _,(CtxtSeqBlock _ :: CtxtParen((BEGIN | LPAREN | LBRACK | LBRACK_BAR),_) :: CtxtVanilla _ :: (CtxtSeqBlock _ as limitCtxt) :: _)
761773
| (CtxtSeqBlock _),(CtxtParen ((BEGIN | LPAREN | LBRACE | LBRACK | LBRACK_BAR) ,_) :: CtxtSeqBlock _ :: ((CtxtTypeDefns _ | CtxtLetDecl _ | CtxtMemberBody _ | CtxtWithAsLet _) as limitCtxt) :: _)
762-
-> (limitCtxt.StartPos,limitCtxt.StartCol + 1)
774+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol + 1)
763775

764776
// Permitted inner-construct (e.g. "then" block and "else" block in overall
765777
// "if-then-else" block ) block alighnment:
@@ -768,34 +780,34 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
768780
// elif expr
769781
// else expr
770782
| (CtxtIf _ | CtxtElse _ | CtxtThen _), (CtxtIf _ as limitCtxt) :: _rest
771-
-> (limitCtxt.StartPos,limitCtxt.StartCol)
783+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol)
772784
// Permitted inner-construct precise block alighnment:
773785
// while ...
774786
// do expr
775787
// done
776788
| (CtxtDo _), ((CtxtFor _ | CtxtWhile _) as limitCtxt) :: _rest
777-
-> (limitCtxt.StartPos,limitCtxt.StartCol)
789+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol)
778790

779791

780792
// These contexts all require indentation by at least one space
781793
| _,((CtxtInterfaceHead _ | CtxtNamespaceHead _ | CtxtModuleHead _ | CtxtException _ | CtxtModuleBody (_,false) | CtxtIf _ | CtxtWithAsLet _ | CtxtLetDecl _ | CtxtMemberHead _ | CtxtMemberBody _) as limitCtxt :: _)
782-
-> (limitCtxt.StartPos,limitCtxt.StartCol + 1)
794+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol + 1)
783795

784796
// These contexts can have their contents exactly aligning
785797
| _,((CtxtParen _ | CtxtFor _ | CtxtWhen _ | CtxtWhile _ | CtxtTypeDefns _ | CtxtMatch _ | CtxtModuleBody (_,true) | CtxtNamespaceBody _ | CtxtTry _ | CtxtMatchClauses _ | CtxtSeqBlock _) as limitCtxt :: _)
786-
-> (limitCtxt.StartPos,limitCtxt.StartCol)
798+
-> PositionWithColumn(limitCtxt.StartPos,limitCtxt.StartCol)
787799

788800
match newCtxt with
789801
// Don't bother to check pushes of Vanilla blocks since we've
790802
// always already pushed a SeqBlock at this position.
791803
| CtxtVanilla _ -> ()
792804
| _ ->
793-
let p1,c1 = unindentationLimit true offsideStack
805+
let p1 = unindentationLimit true offsideStack
794806
let c2 = newCtxt.StartCol
795-
if c2 < c1 then
807+
if c2 < p1.Column then
796808
warn tokenTup
797-
(if debug then (sprintf "possible incorrect indentation: this token is offside of context at position %s, newCtxt = %A, stack = %A, newCtxtPos = %s, c1 = %d, c2 = %d" (warningStringOfPos p1) newCtxt offsideStack (stringOfPos (newCtxt.StartPos)) c1 c2)
798-
else (FSComp.SR.lexfltTokenIsOffsideOfContextStartedEarlier(warningStringOfPos p1)) )
809+
(if debug then (sprintf "possible incorrect indentation: this token is offside of context at position %s, newCtxt = %A, stack = %A, newCtxtPos = %s, c1 = %d, c2 = %d" (warningStringOfPos p1.Position) newCtxt offsideStack (stringOfPos (newCtxt.StartPos)) p1.Column c2)
810+
else (FSComp.SR.lexfltTokenIsOffsideOfContextStartedEarlier(warningStringOfPos p1.Position)) )
799811
let newOffsideStack = newCtxt :: offsideStack
800812
if debug then dprintf "--> pushing, stack = %A\n" newOffsideStack
801813
offsideStack <- newOffsideStack
@@ -1042,7 +1054,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
10421054
// span of inserted token lasts from the col + 1 of the prev token
10431055
// to the beginning of current token
10441056
let lastTokenPos =
1045-
let pos = snd tokenTup.LastTokenPos
1057+
let pos = tokenTup.LastTokenPos.Y
10461058
pos.ShiftColumnBy 1
10471059
returnToken (lexbufStateForInsertedDummyTokens (lastTokenPos, tokenTup.LexbufState.StartPos)) tok
10481060

@@ -2151,7 +2163,7 @@ type LexFilterImpl (lightSyntaxStatus:LightSyntaxStatus, compilingFsLib, lexer,
21512163
| PERCENT_OP s -> (s = "%") || (s = "%%")
21522164
| _ -> true) &&
21532165
nextTokenIsAdjacent tokenTup &&
2154-
not (prevWasAtomicEnd && (snd(tokenTup.LastTokenPos) = startPosOfTokenTup tokenTup))) ->
2166+
not (prevWasAtomicEnd && (tokenTup.LastTokenPos.Y = startPosOfTokenTup tokenTup))) ->
21552167

21562168
let plus =
21572169
match tokenTup.Token with

src/utils/prim-lexing.fs

Lines changed: 57 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,53 +9,65 @@ namespace Internal.Utilities.Text.Lexing
99
open Microsoft.FSharp.Collections
1010
open System.Collections.Generic
1111

12-
// REVIEW: This type showed up on a parsing-intensive performance measurement.
13-
// REVIEW: Consider whether it can be smaller or can be a struct.
14-
type internal Position =
15-
{ /// The file name index for the position, use fileOfFileIndex in range.fs to decode
16-
posFileIndex: int;
17-
/// The line number for the position
18-
posLineNum: int;
19-
/// The line number for the position in the original source file
20-
posOriginalLineNum : int;
21-
/// The absolute offset of the beginning of the line
22-
posStartOfLineOffset: int;
23-
/// The absolute offset of the column for the position
24-
posColumnOffset: int; }
25-
member x.FileIndex = x.posFileIndex
26-
member x.Line = x.posLineNum
27-
member x.OriginalLine = x.posOriginalLineNum
28-
member x.AbsoluteOffset = x.posColumnOffset
29-
member x.StartOfLine = x.posStartOfLineOffset
30-
member x.StartOfLineAbsoluteOffset = x.posStartOfLineOffset
31-
member x.Column = x.posColumnOffset - x.posStartOfLineOffset
32-
member pos.NextLine =
33-
{ pos with
34-
posOriginalLineNum = pos.OriginalLine + 1;
35-
posLineNum = pos.Line+1;
36-
posStartOfLineOffset = pos.AbsoluteOffset }
37-
member pos.EndOfToken n = {pos with posColumnOffset=pos.posColumnOffset + n }
38-
member pos.ShiftColumnBy by = {pos with posColumnOffset = pos.posColumnOffset + by}
39-
member pos.ColumnMinusOne = { pos with posColumnOffset = pos.posStartOfLineOffset-1 }
40-
41-
member pos.ApplyLineDirective (fileIdx, line) =
42-
{pos with posFileIndex = fileIdx;
43-
posStartOfLineOffset= pos.posColumnOffset;
44-
posLineNum=line };
45-
46-
static member Empty =
47-
{ posFileIndex=0;
48-
posLineNum= 0;
49-
posOriginalLineNum = 0;
50-
posStartOfLineOffset= 0;
51-
posColumnOffset=0 }
12+
[<Struct>]
13+
type internal Position =
14+
val FileIndex: int
15+
val Line: int
16+
val OriginalLine: int
17+
val AbsoluteOffset: int
18+
val StartOfLineAbsoluteOffset: int
19+
member x.Column = x.AbsoluteOffset - x.StartOfLineAbsoluteOffset
20+
21+
new (fileIndex: int, line: int, originalLine: int, startOfLineAbsoluteOffset: int, absoluteOffset: int) =
22+
{ FileIndex = fileIndex
23+
Line = line
24+
OriginalLine = originalLine
25+
AbsoluteOffset = absoluteOffset
26+
StartOfLineAbsoluteOffset = startOfLineAbsoluteOffset }
27+
28+
member x.NextLine =
29+
Position (x.FileIndex,
30+
x.Line + 1,
31+
x.OriginalLine + 1,
32+
x.AbsoluteOffset,
33+
x.AbsoluteOffset)
34+
35+
member x.EndOfToken n =
36+
Position (x.FileIndex,
37+
x.Line,
38+
x.OriginalLine,
39+
x.StartOfLineAbsoluteOffset,
40+
x.AbsoluteOffset + n)
41+
42+
member x.ShiftColumnBy by =
43+
Position (x.FileIndex,
44+
x.Line,
45+
x.OriginalLine,
46+
x.StartOfLineAbsoluteOffset,
47+
x.AbsoluteOffset + by)
48+
49+
member x.ColumnMinusOne =
50+
Position (x.FileIndex,
51+
x.Line,
52+
x.OriginalLine,
53+
x.StartOfLineAbsoluteOffset,
54+
x.StartOfLineAbsoluteOffset - 1)
55+
56+
member x.ApplyLineDirective (fileIdx, line) =
57+
Position (fileIdx,
58+
line,
59+
x.OriginalLine,
60+
x.AbsoluteOffset,
61+
x.AbsoluteOffset)
62+
63+
static member Empty = Position ()
5264

5365
static member FirstLine fileIdx =
54-
{ posFileIndex= fileIdx;
55-
posStartOfLineOffset=0;
56-
posColumnOffset=0;
57-
posOriginalLineNum = 0;
58-
posLineNum=1 }
66+
Position (fileIdx,
67+
1,
68+
0,
69+
0,
70+
0)
5971

6072
type internal LexBufferFiller<'Char> = (LexBuffer<'Char> -> unit)
6173

src/utils/prim-lexing.fsi

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,20 @@ open Microsoft.FSharp.Core
1010
open Microsoft.FSharp.Control
1111

1212
/// Position information stored for lexing tokens
13-
[<Sealed>]
13+
[<Struct>]
1414
type internal Position =
15-
interface System.IComparable
1615
/// The file index for the file associated with the input stream, use fileOfFileIndex in range.fs to decode
17-
member FileIndex : int
16+
val FileIndex : int
1817
/// The line number in the input stream, assuming fresh positions have been updated
1918
/// for the new line by modifying the EndPos property of the LexBuffer.
20-
member Line : int
19+
val Line : int
2120
/// The line number for the position in the input stream, assuming fresh positions have been updated
2221
/// using for the new line
23-
member OriginalLine : int
22+
val OriginalLine : int
2423
/// The character number in the input stream
25-
member AbsoluteOffset : int
24+
val AbsoluteOffset : int
2625
/// Return absolute offset of the start of the line marked by the position
27-
member StartOfLineAbsoluteOffset : int
26+
val StartOfLineAbsoluteOffset : int
2827
/// Return the column number marked by the position, i.e. the difference between the AbsoluteOffset and the StartOfLineAbsoluteOffset
2928
member Column : int
3029
// Given a position just beyond the end of a line, return a position at the start of the next line

0 commit comments

Comments
 (0)