summaryrefslogblamecommitdiff
path: root/khb/khs_exec.ml
blob: ff050c6ea88d35dae3fbf9860d7c42af43532583 (plain) (tree)
































































































































































































































                                                                                   
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 }