blob: 71dcdf145741a7fa5f4ad4d4119ff14c21b2d638 [file] [log] [blame] [edit]
open Ds
open Al
open Al_util
open Print
type state =
| Step of int
| StepInstr of string * int
| Continue of int
let debug = ref false
let break_points = ref []
let is_bp name =
List.exists
(fun bp -> bp = String.lowercase_ascii name || bp = String.uppercase_ascii name)
!break_points
let state = ref (Step 1)
let help_msg =
"
h
help: print help message
b {algorithm name}*
break {algorithm name}*: add break points
rm {algorithm name}*
remove {algorithm name}*: remove break points
bp
breakpoints: print all break points
s {number}?
step {number}?: take n steps
si {number}?
stepinstr {number}?: step n AL instructions
c {number}?
continue {number}?: continue steps until meet n break points
al: print al context stack
wasm: print wasm context stack
store {field} {index}: print a value in store
lookup {variable name}: lookup the variable
q
quit: quit
"
let allow_command ctx =
let is_entry name il = name |> lookup_algo |> body_of_algo = il in
match !state with
| Step n ->
if n = 1 then
true
else
(state := Step (n-1); false)
| StepInstr (name, n) when name == AlContext.get_name ctx ->
if n = 1 then
true
else
(state := StepInstr (name, n-1); false)
| Continue n ->
(match ctx with
| AlContext.Al (name, _, il, _, _) :: _
when is_bp name && is_entry name il ->
if n = 1 then
true
else
(state := Continue (n-1); false)
| _ -> false
)
| _ -> false
let rec do_debug ctx =
let _ = print_string "\ndebugger> " in
read_line ()
|> String.split_on_char ' '
|> handle_command ctx;
and handle_command ctx = function
| ("h" | "help") :: _ ->
print_endline help_msg;
do_debug ctx
| ("b" | "break") :: t -> break_points := !break_points @ t; do_debug ctx
| ("rm" | "remove") :: t ->
break_points := List.filter (fun e -> not (List.mem e t)) !break_points;
do_debug ctx
| ("bp" | "breakpoints") :: _ ->
print_endline (String.concat " " !break_points);
do_debug ctx
| ("s" | "step") :: t ->
(match t with
| n :: _ when Option.is_some (int_of_string_opt n) ->
state := Step (int_of_string n)
| _ ->
state := Step 1
)
| ("si" | "stepinstr") :: t ->
(match ctx with
| (AlContext.Al (name, _, il, _, _) | AlContext.Enter (name, il, _)) :: _
when List.length il > 0 ->
(match t with
| n :: _ when Option.is_some (int_of_string_opt n) ->
state := StepInstr (name, int_of_string n)
| _ ->
state := StepInstr (name, 1)
)
| _ ->
handle_command ctx ("step" :: t)
)
| ("c" | "continue") :: t ->
(match t with
| n :: _ when Option.is_some (int_of_string_opt n) ->
state := Continue (int_of_string n)
| _ ->
state := Continue 1
)
| "al" :: _ ->
ctx
|> List.map AlContext.string_of_context
|> List.iter print_endline;
do_debug ctx
| "wasm" :: _ ->
WasmContext.string_of_context_stack () |> print_endline;
do_debug ctx
| "store" :: field :: n :: _ ->
(try
let idx = int_of_string n in
Store.access field
|> unwrap_listv
|> (!)
|> (fun arr -> Array.get arr idx)
|> string_of_value
|> print_endline;
with _ -> ()
);
do_debug ctx
| "lookup" :: s :: _ ->
(match ctx with
| (Al (_, _, _, env, _) | Enter (_, _, env)) :: _ ->
lookup_env_opt s env
|> Option.map string_of_value
|> Option.iter print_endline;
| _ -> ()
);
do_debug ctx
| ("q" | "quit") :: _ -> debug := false
| _ -> do_debug ctx
let run ctx =
if !debug && allow_command ctx then do_debug ctx