summaryrefslogtreecommitdiff
path: root/khb/khs_exec.ml
blob: ff050c6ea88d35dae3fbf9860d7c42af43532583 (plain) (blame)
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
open Util
open Khs_ast


type kprog =
    {
        pinstr: khs_stmt array;
        plabels: int Smap.t;
    }

type kbval =
    | VNone
    | VInt of int
    | VBool of bool
    | VStr of string
type kval = 
    | Single of kbval
    | Many of kbval Smap.t

type chanid = kbval

type kprocstatus =
    | PSExec
    | PSSend of chanid * kval
    | PSRecv of chanid
    | PSExecRecvd of kval
    | PSDone

type kproc =
    {
        xspawn: kproc -> int -> unit;
        xnewchan: kproc -> kval;
        xprog: kprog;
        mutable xvals: kbval Smap.t;
        mutable xstatus: kprocstatus;
        mutable xpos: int
    }

let psep = "\\"
let framevar = "#"


(* Procedures on values *)

(* Strange semantics : all type conversions are allowed *)
let int_of_kbval = function
    | VInt i -> i
    | VBool true -> 1
    | VBool false -> 0
    | VNone -> 0
    | VStr s -> int_of_string s
let str_of_kbval = function
    | VInt i -> string_of_int i
    | VBool true -> "1"
    | VBool false -> "0"
    | VNone -> ""
    | VStr s -> s
let bool_of_kbval = function
    | VInt i -> i <> 0
    | VBool b -> b
    | VNone -> false
    | VStr s -> (int_of_string s) <> 0

let kval_of_kbval v = Single v
let kbval_of_kval = function
    | Single v -> v
    | Many a ->
        try Smap.find "" a
        with Not_found -> VNone

let int_of_kval v = int_of_kbval (kbval_of_kval v)
let bool_of_kval v = bool_of_kbval (kbval_of_kval v)
let str_of_kval v = str_of_kbval (kbval_of_kval v)

let kval_descr = function
    | Single v -> "'" ^ str_of_kbval v ^ "'"
    | Many a ->
        if Smap.cardinal a = 1 then
            Smap.fold (fun k v s -> str_of_kbval v) a ""
        else
            Smap.fold (fun k v s -> s ^ "\n  " ^ k ^ " : '" ^ str_of_kbval v ^ "'")
                a "{"
            ^ "\n}"

(* Variable loading and setting *)
let load_kval proc key =
    let n = String.length key in
    let ret = ref Smap.empty in
    Smap.iter (fun k v ->
        if k = key || 
            (String.length k > n && 
                String.sub k 0 (n+1) = key ^ psep)
        then
            ret := Smap.add (String.sub k n (String.length k - n)) v !ret)
        proc.xvals;
    (* Format.printf "Load %s : %s@." key (kval_descr (Many (!ret))); *)
    Many(!ret)
let save_kval proc key value =
    (* Format.printf "Set %s = %s@." key (kval_descr value); *)
    match value with
    | Single s -> proc.xvals <- Smap.add key s proc.xvals
    | Many m ->
        Smap.iter
            (fun k v -> proc.xvals <- Smap.add (key ^ k) v proc.xvals)
            m
let unset_kval proc key =
    let n = String.length key in
    let f k _ =
        k <> key &&
        (String.length k < n + 1 ||
            String.sub k 0 (n+1) <> key ^ psep)
    in
    proc.xvals <- Smap.filter f proc.xvals

(* Expression evaluation *)
let rec eval_expr proc = function
    | EEmpty -> Single VNone
    | EInt i -> Single (VInt i)
    | EBool b -> Single (VBool b)
    | EStr s -> Single (VStr s)
    | ELocal l -> 
        Single(VStr(str_of_kval (load_kval proc framevar) ^ psep ^ l))
    | EFrame -> Single(VStr framevar)
    | EBinary(e1, op, e2) ->
        let v1, v2 = eval_expr proc e1, eval_expr proc e2 in
        let r = match op with
        | PLUS -> VInt(int_of_kval v1 + int_of_kval v2)
        | MINUS -> VInt(int_of_kval v1 - int_of_kval v2)
        | TIMES -> VInt(int_of_kval v1 * int_of_kval v2)
        | DIV -> VInt(int_of_kval v1 / int_of_kval v2)
        | MOD -> VInt(int_of_kval v1 mod int_of_kval v2)
        | EQUAL -> VBool(kbval_of_kval v1 = kbval_of_kval v2)
            (* EQUAL does not test values in depth ! *)
        | NEQUAL -> VBool(kbval_of_kval v1 <> kbval_of_kval v2)
        | GT -> VBool(int_of_kval v1 > int_of_kval v2)
        | LT -> VBool(int_of_kval v1 < int_of_kval v2)
        | GE -> VBool(int_of_kval v1 >= int_of_kval v2)
        | LE -> VBool(int_of_kval v1 <= int_of_kval v2)
        | AND -> VBool(bool_of_kval v1 && bool_of_kval v2)
        | OR -> VBool(bool_of_kval v1 || bool_of_kval v2)
        | XOR -> VBool(bool_of_kval v1 ^^ bool_of_kval v2)
        in Single r
    | EUnary(op, e) ->
        let v = eval_expr proc e in
        let r = match op with
        | MINUS -> VInt(-(int_of_kval v))
        | NOT -> VBool(not(bool_of_kval v))
        in Single r
    | ETernary(cond, e1, e2) ->
        if bool_of_kval (eval_expr proc cond) then
            eval_expr proc e1
        else
            eval_expr proc e2
    | ECat(e1, e2) ->
        Single(VStr(
            str_of_kval (eval_expr proc e1)
                ^ psep
                ^ str_of_kval (eval_expr proc e2)))
    | ELoad(x) ->
        load_kval proc (str_of_kval (eval_expr proc x))
    | ENewChan -> proc.xnewchan proc

let exec_stmt proc =
    match proc.xprog.pinstr.(proc.xpos) with
    | SLabel _ -> 
        proc.xpos <- proc.xpos + 1 (* nothing to do *)
    | SSet(var, v) ->
        let var = str_of_kval (eval_expr proc var) in
        let v = eval_expr proc v in
        save_kval proc var v;
        proc.xpos <- proc.xpos + 1
    | SGoto pos ->
        let pos = str_of_kval (eval_expr proc pos) in
        begin
            try 
                proc.xpos <- Smap.find pos proc.xprog.plabels
            with Not_found ->
                    proc.xstatus <- PSDone
        end
    | SPar pos ->
        let pos = str_of_kval (eval_expr proc pos) in
        begin
            try
                proc.xspawn proc (Smap.find pos proc.xprog.plabels)
            with Not_found -> ()
        end;
        proc.xpos <- proc.xpos + 1
    | SRecv(var, chan) ->
        begin match proc.xstatus with
        | PSExec ->
            let chan = kbval_of_kval (eval_expr proc (ELoad chan)) in
            proc.xstatus <- PSRecv chan
        | PSExecRecvd v ->
            let var = str_of_kval (eval_expr proc var) in
            save_kval proc var v;
            proc.xstatus <- PSExec;
            proc.xpos <- proc.xpos + 1
        | _ -> assert false
        end
    | SSend(v, chan) ->
        let chan = kbval_of_kval (eval_expr proc (ELoad chan)) in
        let v = eval_expr proc v in
        proc.xpos <- proc.xpos + 1;
        proc.xstatus <- PSSend(chan, v)
    | SUnset(l) ->
        List.iter (unset_kval proc)
            (List.map (fun e -> str_of_kval (eval_expr proc e)) l);
        proc.xpos <- proc.xpos + 1;
    | SExit ->
        proc.xstatus <- PSDone
    

(* Load program, ie find labels *)
let load_program p =
    let labels = ref Smap.empty in
    Array.iteri
        (fun i x ->
            match x with
            | SLabel l -> labels := Smap.add l i !labels
            | _ -> ())
        p;
    { pinstr = p; plabels = !labels }