open Ast
open Utils

let rec print_prog prog = print_endline("GLOBAL SCOPE:"); print_env prog.prog_env;print_endline("function definitions:");
    print_function_data_list prog.prog_functions

and print_env env = print_endline("variables:"); print_variables env.variables; print_endline("structs:"); 
    print_structs env.structs; print_endline("return type:"); print_type env.ret_type; print_endline("\nfunction signatures:");
    print_functions env.functions

and print_variables variables = List.iter print_variable variables;

and print_variable variable = 
    let (name, typ, value) = variable in
        print_type(typ); print_string( name ^ " = ");
        begin match value with
              [] -> print_endline("")
            | _ ->  print_endline(List.hd value)
        end

and print_type = function
      Int -> print_string("int ")
    | Double -> print_string("double ")
    | List(type_spec) -> print_string("list<"); print_type(type_spec); print_string("> ")
    | String -> print_string("string ")
    | Struct(str) -> print_string("struct " ^ str ^ " ")

and print_structs structs = List.iter print_struct structs

and print_struct struc = 
    let (name, member_list) = struc in print_endline("struct " ^ name ^ " = {");
        List.iter print_struct_member member_list; print_endline("}")

and print_struct_member member = print_string("\t"); print_type (snd member); print_endline(fst member)

and print_functions functions = List.iter print_func_sig functions

and print_func_sig func = print_string((fst (fst func)) ^ "("); print_func_sig_params (snd func);
    print_endline(")")

and print_func_sig_params params = List.iter print_func_sig_param params

and print_func_sig_param param = print_string((fst param) ^ ", ")

and print_function_data_list func_data_list = List.iter print_function_data func_data_list

and print_function_data func = print_endline("\nSCOPE OF " ^ (fst func.func_definition.func_decl) ^ ":");
    print_env func.func_env;
    print_endline("function body:");
    print_type func.func_definition.type_spec; 
    print_string((fst func.func_definition.func_decl) ^ "(");
    print_function_params (snd func.func_definition.func_decl); print_endline("){");
    print_function_stmts func.func_definition.func_body.stmt_list; print_endline("}")

and print_function_params params = List.iter print_function_param params

and print_function_param param = print_type (snd param); print_string((fst param) ^ ",")

and print_function_stmts stmt_list = List.iter print_stmt stmt_list

and print_stmt = function
      Stmt(expr) -> print_expr expr; print_endline(";")
    | Stmt_block(stmt_list) -> print_endline("{"); List.iter print_stmt stmt_list; print_endline("}")
    | Stmt_if(expr, stmt) -> print_string("if("); print_expr expr; print_endline(") then"); print_stmt stmt
    | Stmt_ifelse(expr, stmt1, stmt2) -> print_string("if("); print_expr expr; print_endline(") then");
        print_stmt stmt1; print_endline("else"); print_stmt stmt2 
    | Stmt_for(expr_opt1, expr_opt2, expr_opt3, stmt) -> print_string("for("); print_expr_opt expr_opt1;
        print_string("; "); print_expr_opt expr_opt2; print_string("; "); print_expr_opt expr_opt3;
        print_endline(")"); print_stmt stmt
    | Stmt_break -> print_endline("break;")
    | Stmt_ret(expr) -> print_string("return "); print_expr expr; print_endline(";")
    | Stmt_noop -> print_endline(";")

and print_expr = function
      Expr_func(str, expr_list_opt) -> print_string(str ^ "("); List.iter print_expr expr_list_opt;
        print_string(")")
    | Expr_const(constant) -> print_constant constant
    | Expr_op(str, expr) -> print_string(str); print_expr expr
    | Expr_lval(lvalue) -> print_lval lvalue
    | Expr_lval_op(lvalue, str) -> print_lval lvalue; print_string(str)
    | Expr_binop(expr1, str, expr2) -> print_string("[");print_expr expr1; print_string(" " ^ str ^ " "); print_expr expr2;print_string("]")
    | Expr_asgop(lvalue, str, expr) -> print_lval lvalue; print_string(" " ^ str ^ " "); print_expr expr
    | Expr_paren(expr) ->  print_string("("); print_expr expr; print_string(")")

and print_expr_opt = function
      Expr_opt(None) -> ()
    | Expr_opt(Some(expr)) -> print_expr expr

and print_constant = function
      Const_int(int) -> print_string(string_of_int(int))
    | Const_dbl(dbl) -> print_string(string_of_float(dbl))
    | Const_str(str) -> print_string(str)

and print_lval = function
      Lval_id(str) -> print_string(str)
    | Lval_arr(lval, expr) -> print_lval lval; print_string("["); print_expr expr; print_string("]")
    | Lval_struct(lval, str) -> print_lval lval; print_string("." ^ str)
