Math.NET Numerics
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

194 lines
7.9 KiB

// (c) Microsoft Corporation. All rights reserved
#light
/// Anything to do with special names of identifiers and other lexical rules
module (* internal *) Microsoft.FSharp.Compiler.Range
open System.IO
open System.Collections.Generic
open Microsoft.FSharp.Text.Printf
open Internal.Utilities
open Internal.Utilities.Pervasives
open Microsoft.FSharp.Compiler.AbstractIL
open Microsoft.FSharp.Compiler.AbstractIL.Internal
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.Lib
open Microsoft.FSharp.Compiler.Lib.Bits
type file_idx = int32
type pos = int32
type range = int64
(* { rangeFile: string;
rangeBegin: pos;
rangeEnd: pos } *)
(* { posLine: int; posCol: int } *)
let col_nbits = 9
let line_nbits = 16
let pos_nbits = line_nbits + col_nbits
let _ = assert (pos_nbits <= 32)
let pos_col_mask = mask32 0 col_nbits
let line_col_mask = mask32 col_nbits line_nbits
let mk_pos l c =
let l = max 0 l in
let c = max 0 c in
( c &&& pos_col_mask)
||| ((l <<< col_nbits) &&& line_col_mask)
let inline (lsr) (x:int) (y:int) = int32 (uint32 x >>> y)
let line_of_pos p = (p lsr col_nbits)
let col_of_pos p = (p &&& pos_col_mask)
let bits_of_pos (x:pos) :int32 = x
let pos_of_bits (x:int32) : pos = x
let file_idx_nbits = 14
let start_line_nbits = line_nbits
let start_col_nbits = col_nbits
let end_line_nbits = line_nbits
let end_col_nbits = col_nbits
let _ = assert (file_idx_nbits + start_line_nbits + start_col_nbits + end_line_nbits + end_col_nbits = 64)
let file_idx_mask = mask64 0 file_idx_nbits
let start_line_mask = mask64 (file_idx_nbits) start_line_nbits
let start_col_mask = mask64 (file_idx_nbits + start_line_nbits) start_col_nbits
let end_line_mask = mask64 (file_idx_nbits + start_line_nbits + start_col_nbits) end_line_nbits
let end_col_mask = mask64 (file_idx_nbits + start_line_nbits + start_col_nbits + end_line_nbits) end_col_nbits
let mk_file_idx_range fidx b e =
int64(fidx)
||| (int64(line_of_pos b) <<< file_idx_nbits)
||| (int64(col_of_pos b) <<< (file_idx_nbits + start_line_nbits))
||| (int64(line_of_pos e) <<< (file_idx_nbits + start_line_nbits + start_col_nbits))
||| (int64(col_of_pos e) <<< (file_idx_nbits + start_line_nbits + start_col_nbits + end_line_nbits))
let file_idx_of_range r = int32(r &&& file_idx_mask)
let start_line_of_range r = int32((r &&& start_line_mask) >>> file_idx_nbits)
let start_col_of_range r = int32((r &&& start_col_mask) >>> (file_idx_nbits + start_line_nbits))
let end_line_of_range r = int32((r &&& end_line_mask) >>> (file_idx_nbits + start_line_nbits + start_col_nbits))
let end_col_of_range r = int32((r &&& end_col_mask) >>> (file_idx_nbits + start_line_nbits + start_col_nbits + end_line_nbits))
// This is just a standard unique-index table
type FileIndexTable() =
class
let indexToFileTable = new ResizeArray<_>(11)
let fileToIndexTable = new Dictionary<string,int>(11)
member t.FileToIndex f =
let mutable res = 0 in
let ok = fileToIndexTable.TryGetValue(f,&res) in
if ok then res
else
lock fileToIndexTable (fun () ->
let mutable res = 0 in
let ok = fileToIndexTable.TryGetValue(f,&res) in
if ok then res
else
let n = indexToFileTable.Count in
indexToFileTable.Add(f);
fileToIndexTable.[f] <- n;
n)
member t.IndexToFile n =
(if n < 0 then failwithf "file_of_file_idx: negative argument: n = %d\n" n);
(if n >= indexToFileTable.Count then failwithf "file_of_file_idx: invalid argument: n = %d\n" n);
indexToFileTable.[n]
end
let maxFileIndex = pown32 file_idx_nbits
// WARNING: Global Mutable State, holding a mapping between integers and filenames
let fileIndexTable = new FileIndexTable()
// Note if we exceed the maximum number of files we'll start to report incorrect file names
let file_idx_of_file f = fileIndexTable.FileToIndex(f) % maxFileIndex
let file_of_file_idx n = fileIndexTable.IndexToFile(n)
let mk_range f b e = mk_file_idx_range (file_idx_of_file f) b e
let file_of_range r = file_of_file_idx (file_idx_of_range r)
(* end representation, start derived ops *)
let start_of_range r = mk_pos (start_line_of_range r) (start_col_of_range r)
let end_of_range r = mk_pos (end_line_of_range r) (end_col_of_range r)
let dest_file_idx_range r = file_idx_of_range r,start_of_range r,end_of_range r
let dest_range r = file_of_range r,start_of_range r,end_of_range r
let dest_pos p = line_of_pos p,col_of_pos p
let trim_range_right r n =
let fidx,p1,p2 = dest_file_idx_range r in
let l2,c2 = dest_pos p2 in
mk_file_idx_range fidx p1 (mk_pos l2 (max 0 (c2 - n)))
let pos_ord p1 p2 = Pair.order (Int32.order ,Int32.order) (dest_pos p1) (dest_pos p2)
(* range_ord: not a total order, but enough to sort on ranges *)
let range_ord r1 r2 = Pair.order (String.order,pos_ord) (file_of_range r1,start_of_range r1) (file_of_range r2,start_of_range r2)
let output_pos (os:TextWriter) m = fprintf os "(%d,%d)" (line_of_pos m) (col_of_pos m)
let output_range (os:TextWriter) m = fprintf os "%s%a-%a" (file_of_range m) output_pos (start_of_range m) output_pos (end_of_range m)
let boutput_pos os m = bprintf os "(%d,%d)" (line_of_pos m) (col_of_pos m)
let boutput_range os m = bprintf os "%s%a-%a" (file_of_range m) boutput_pos (start_of_range m) boutput_pos (end_of_range m)
let start_range_of_range m = let f,s,e = dest_file_idx_range m in mk_file_idx_range f s s
let end_range_of_range m = let f,s,e = dest_file_idx_range m in mk_file_idx_range f e e
let pos_gt p1 p2 =
(line_of_pos p1 > line_of_pos p2 or
(line_of_pos p1 = line_of_pos p2 &&
col_of_pos p1 > col_of_pos p2))
let pos_eq p1 p2 = (line_of_pos p1 = line_of_pos p2 && col_of_pos p1 = col_of_pos p2)
let pos_geq p1 p2 = pos_eq p1 p2 or pos_gt p1 p2
let union_ranges m1 m2 =
if file_idx_of_range m1 <> file_idx_of_range m2 then m2 else
let b =
if pos_geq (start_of_range m1) (start_of_range m2) then (start_of_range m2)
else (start_of_range m1) in
let e =
if pos_geq (end_of_range m1) (end_of_range m2) then (end_of_range m1)
else (end_of_range m2) in
mk_file_idx_range (file_idx_of_range m1) b e
let range_contains_range m1 m2 =
(file_of_range m1) = (file_of_range m2) &&
pos_geq (start_of_range m2) (start_of_range m1) &&
pos_geq (end_of_range m1) (end_of_range m2)
let range_contains_pos m1 p =
pos_geq p (start_of_range m1) &&
pos_geq (end_of_range m1) p
let range_before_pos m1 p =
pos_geq p (end_of_range m1)
let rangeN filename line = mk_range filename (mk_pos line 0) (mk_pos line 80)
let pos0 = mk_pos 1 0
let range0 = rangeN "unknown" 1
let rangeStartup = rangeN "startup" 1
let rangeCmdArgs = rangeN "commandLineArgs" 0
// Store a file_idx in the pos_fname field, so we don't have to look up the
// file_idx hash table to map back from pos_fname to a file_idx during lexing
let encode_file_idx idx =
Bytes.utf8_bytes_as_string (Bytes.of_intarray [| (idx &&& 0x7F);
((idx lsr 7) &&& 0x7F) |])
let encode_file file = file |> file_idx_of_file |> encode_file_idx
let _ = assert (file_idx_nbits <= 14) (* this encoding is size limited *)
let decode_file_idx (s:string) =
if String.length s = 0 then 0 else
let idx = (int32 s.[0])
||| ((int32 s.[1]) <<< 7) in
idx
(* For Diagnostics *)
let string_of_pos pos = let line,col = line_of_pos pos,col_of_pos pos in sprintf "(%d,%d)" line col
let string_of_range r = sprintf "%s%s-%s" (file_of_range r) (string_of_pos (start_of_range r)) (string_of_pos (end_of_range r))