Source

love studio / LoveStudio / LuaAnalyzer / Utils.fs

Full commit
[<AutoOpen>]
module LuaAnalyzer.Utils

open System.Diagnostics.Contracts

type Range = int*int

/// (fullPathName,moduleName,contents,lastModifiedTime)
type LuaModule = string*string*string*int64

/// Returns a string describing the order of the given integer
let orderStr (i : int) =
    let iStr = i.ToString()
    match iStr.[iStr.Length-1] with
    | '1' ->
        iStr + "st"
    | '2' ->
        iStr + "nd"
    | '3' ->
        iStr + "rd"
    | _ ->
        iStr + "th"

/// True iff lo <= pos <= hi
/// where (lo,hi) = rng
let inRange (pos : int) (rng : Range) =
    match rng with
    | (l,h) ->
        l <= pos && pos <= h 

/// Takes the union of the two maps, where ctx2's entries
/// replace ctx1's entries where the two contexts have equal keys.
let cover<'a,'b when 'a : comparison> (ctx1 : Map<'a,'b>) (ctx2 : Map<'a,'b>) : Map<'a,'b> =
    Map.fold (fun c k v -> Map.add k v c) ctx1 ctx2

/// Let n = min(under.Length, over.Length)
/// Returns a list which is equal to under, except for its first n elements,
/// which are equal to those of over. 
let coverList<'a> (under : List<'a>) (over : List<'a>) =
    Contract.Ensures (Contract.Result<List<'a>>().Length = under.Length)

    let getNext (i : int) =
        if i < over.Length then
            over.[i]
        else
            under.[i]

    List.init under.Length getNext
    
/// Let n = min(under.Length, over.Length)
/// Returns a list which is equal to under, except for its first n elements,
/// which are replaced with the corresponding elements of over, whenever such
/// elements are not None.
let coverListOpt<'a> (under : List<'a>) (over : List< Option<'a> >) =
    Contract.Ensures (Contract.Result<List<'a>>().Length = under.Length)

    let getNext (i : int) =
        if i < over.Length && over.[i].IsSome then
            over.[i].Value
        else
            under.[i]

    List.init under.Length getNext

/// Pads the given list with the given item until it reaches the target length
let padList<'A> (lst : List<'A>) (item : 'A) (targetLength : int) =
    Contract.Requires(lst.Length <= targetLength)
    Contract.Ensures(Contract.Result<List<'A>>().Length = targetLength)

    let padding = List.init (targetLength-lst.Length) (fun _ -> item)
    List.append lst padding

/// Pop n elements from the back of the list
let popnBack<'A> (lst : List<'A>) (numPops : int) =
    Contract.Ensures (Contract.Result<List<'A>>().Length = lst.Length - numPops) 
    
    let rlst = ref (List.rev lst)
    for i in 1..numPops do
        rlst := List.tail (!rlst)

    List.rev !rlst

/// Returns a list which is the result of modifying lst to have length targetLength.
///
/// If lst.Length is greater than targetLength, returns a list containing the
/// first targetLength elements of lst. 
///
/// If lst.Length is less than targetLength, returns a list which is equivalent
/// to lst with filler appended to it (targetLength-lst.Length) times.
///
/// Otherwise returns lst
let sizeListTo<'A> (lst : List<'A>) (targetLength : int) (filler : 'A) =
    Contract.Ensures(Contract.Result<List<'A>>().Length = targetLength)

    if lst.Length < targetLength then
        padList lst filler targetLength
    else
        popnBack lst (lst.Length-targetLength)