summaryrefslogtreecommitdiff
path: root/Jennisys/Resolver.fs
blob: 59c6904d9621f56503b5278bb4342269ef954c6f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//  ####################################################################
///   Utilities for resolving the "Unresolved" constants with respect to 
///   a given context (heap/env/ctx)
///
///   author: Aleksandar Milicevic (t-alekm@microsoft.com)
//  ####################################################################

module Resolver

open Ast
open AstUtils 
open Printer
open EnvUtils

// resolving values
exception ConstResolveFailed of string
 
//  ================================================================
/// Resolves a given Const (cst) with respect to a given env/ctx. 
///
/// If unable to resolve, it just delegates the task to the
/// failResolver function
//  ================================================================
let rec ResolveCont (env,ctx) failResolver cst =
  match cst with
  | Unresolved(_) as u -> 
      // see if it is in the env map first
      let envVal = Map.tryFind cst env
      match envVal with
      | Some(c) -> ResolveCont (env,ctx) failResolver c
      | None -> 
          // not found in the env map --> check the equality sets
          let eq = ctx |> Set.filter (fun eqSet -> Set.contains u eqSet)
                       |> Utils.SetToOption
          match eq with 
          | Some(eqSet) -> 
              let cOpt = eqSet |> Set.filter (function Unresolved(_) -> false | _ -> true)
                               |> Utils.SetToOption
              match cOpt with 
              | Some(c) -> c
              | _ -> failResolver cst (env,ctx)
          | _ -> failResolver cst (env,ctx)
  | SeqConst(cseq) -> 
      let resolvedLst = cseq |> List.rev |> List.fold (fun acc c -> ResolveCont (env,ctx) failResolver c :: acc) []
      SeqConst(resolvedLst)
  | SetConst(cset) ->
      let resolvedSet = cset |> Set.fold (fun acc c -> acc |> Set.add (ResolveCont (env,ctx) failResolver c)) Set.empty
      SetConst(resolvedSet)
  | _ -> cst

//  =====================================================================
/// Tries to resolve a given Const (cst) with respect to a given env/ctx. 
///
/// If unable to resolve, just returns the original Unresolved const.
//  =====================================================================
let TryResolve (env,ctx) cst = 
  ResolveCont (env,ctx) (fun c (e,x) -> c) cst

//  ==============================================================
/// Resolves a given Const (cst) with respect to a given env/ctx. 
///
/// If unable to resolve, raises a ConstResolveFailed exception
//  ==============================================================
let Resolve (env,ctx) cst =
  ResolveCont (env,ctx) (fun c (e,x) -> raise (ConstResolveFailed("failed to resolve " + c.ToString()))) cst
   
//  =================================================================
/// Evaluates a given expression with respect to a given heap/env/ctx       
//  =================================================================
let Eval (heap,env,ctx) expr = 
  let rec __EvalResolver expr = 
    match expr with
    | IdLiteral(id) when id = "this" -> GetThisLoc env
    | IdLiteral(id) ->
        match TryResolve (env,ctx) (Unresolved(id)) with 
        | Unresolved(_) -> __EvalResolver (Dot(IdLiteral("this"), id))
        | _ as c -> c
    | Dot(e, str) -> 
        let discr = __EvalResolver e
        let h2 = Map.filter (fun (loc,Var(fldName,_)) v -> loc = discr && fldName = str) heap |> Map.toList
        match h2 with
        | ((_,_),x) :: [] -> x
        | _ :: _ -> failwithf "can't evaluate expression deterministically: %s.%s resolves to multiple locations." (PrintConst discr) str
        | [] -> failwithf "can't find value for %s.%s" (PrintConst discr) str
    | _ -> failwith "NOT IMPLEMENTED YET"
  try 
    let unresolvedConst = EvalSym (fun e -> __EvalResolver e |> Resolve (env,ctx)) expr
    Some(TryResolve (env,ctx) unresolvedConst)
  with
    ex -> None