open Ast
type ('a, 'b) either = Left of 'a | Right of 'b
let either_split eithers =
let rec split_eithers (left, right) = function
| [] -> (List.rev left, List.rev right)
| (Left(a))::rest -> split_eithers (a::left, right) rest
| (Right(b))::rest -> split_eithers (left, b::right) rest in
split_eithers ([], []) eithers
let filter_option list =
let rec do_filter rlist = function
| [] -> List.rev rlist
| None::tl -> do_filter rlist tl
| (Some(v))::tl -> do_filter (v::rlist) tl in
do_filter [] list
let option_as_list = function
| Some(v) -> [v]
| _ -> []
let decide_option x = function
| true -> Some(x)
| _ -> None
let rec lexical_compare list1 list2 = match list1, list2 with
| [], [] -> 0
| [], _ -> -1
| _, [] -> 1
| (x::xs), (y::ys) -> if x < y then -1 else if x > y then 1 else lexical_compare xs ys
let find_all_min cmp alist =
let rec min_find found items = match found, items with
| _, [] -> List.rev found
| [], i::is -> min_find [i] is
| (f::fs), (i::is) -> let result = cmp i f in
if result = 0 then min_find (i::found) is
else if result < 0 then min_find [i] is
else min_find found is in
min_find [] alist
let (|->) value func =
match value with
| Left(v) -> func(v)
| Right(problem) -> Right(problem)
let rec seq init actions = match init, actions with
| Right(issue), _ -> Right(issue)
| Left(data), [] -> Left(data)
| Left(data), act::ions -> seq (act data) ions
let get_statement_count stmt_list =
let rec do_count stmts blocks counts = match stmts, blocks with
| [], [] -> counts
| [], _ -> do_count blocks [] counts
| (stmt::rest), _ -> match stmt with
| Decl(_) -> do_count rest blocks (counts + 1)
| Expr(_) -> do_count rest blocks (counts + 1)
| Return(_) -> do_count rest blocks (counts + 1)
| Super(_) -> do_count rest blocks (counts + 1)
| While(_, block) -> do_count rest (block @ blocks) (counts + 1)
| If(parts) ->
let ifblocks = List.map snd parts in
let ifstmts = List.flatten ifblocks in
do_count rest (ifstmts @ blocks) (counts + 1) in
do_count stmt_list [] 0