(* AST representation for the union of all interesting languages: *) type expr = And of expr list | Or of expr list | Not of expr | Add of expr list | Eq of expr * expr | Lte of expr * expr | Gte of expr * expr | Var of string | LocalVar of string | Const of string | Method of string | Bool of bool | Int of int | HexInt of int | Str of string | Array of expr list | Hash of (expr * expr) list | Regexp of string | Call of expr * expr list | AnonFunction of (string * string) list * stmt list (* [arg type, arg name], body *) | RawExpr of string and stmt = If of expr * stmt list * stmt option | While of expr * stmt list | Switch of expr * (expr list * stmt list) list (* var, [ vals, code; ... ]. vals=[] for default case *) | Break | Return of expr option | RawStmt of string | Optional of stmt option | StmtList of stmt list | CallStmt of expr * expr list | Block of stmt list | DeclVar of string * string | InitVar of string * string * expr | Assign of expr * expr | Function of string * string * (string * string) list * stmt list (* return type, name, [arg type, arg name], body *) | Enum of string * string list | Comment of string | Newline (* Code-generating functions based primarily on C++ (and other languages will override the specific cases where their syntax differs): *) let needsBrackets = function Not _ -> false | Eq _ -> false | Lte _ -> false | Gte _ -> false | Var _ -> false | LocalVar _ -> false | Const _ -> false | Bool _ -> false | Int _ -> false | Str _ -> false | Call _ -> false | _ -> true let maybeNeedsBrackets = function Var _ -> false | Bool _ -> false | Int _ -> false | Str _ -> false | _ -> true let rec addBrackets printExpr e = if needsBrackets e then "(" ^ printExpr e ^ ")" else printExpr e and reallyAddBrackets printExpr e = (* TODO: these function names are rubbish *) if maybeNeedsBrackets e then "(" ^ printExpr e ^ ")" else printExpr e and printExpr_base printExpr = function And es -> String.concat " && " (List.map (addBrackets printExpr) es) | Or es -> String.concat " || " (List.map (addBrackets printExpr) es) | Not e -> "!" ^ (reallyAddBrackets printExpr e) | Add es -> String.concat " + " (List.map (addBrackets printExpr) es) | Eq (e0, e1) -> addBrackets printExpr e0 ^ " == " ^ addBrackets printExpr e1 | Lte (e0, e1) -> addBrackets printExpr e0 ^ " <= " ^ addBrackets printExpr e1 | Gte (e0, e1) -> addBrackets printExpr e0 ^ " >= " ^ addBrackets printExpr e1 | Var v -> v | LocalVar v -> v | Const v -> v | Method v -> v | Bool b -> if b then "true" else "false" | Int i -> string_of_int i | HexInt i -> Printf.sprintf "0x%04X" i | Str s -> "\"" ^ (Str.global_replace (Str.regexp "\"") "\\\"" (Str.global_replace (Str.regexp "\\") "\\\\" s)) ^ "\"" | Array es -> "{ " ^ String.concat ", " (List.map printExpr es) ^ " }" | Hash es -> "{ " ^ String.concat ", " (List.map (fun (n, v) -> printExpr n ^ ": " ^ printExpr v) es) ^ " }" | Regexp r -> "/" ^ r ^ "/" | Call (n, es) -> (printExpr n) ^ "(" ^ (String.concat ", " (List.map printExpr es)) ^ ")" | AnonFunction (args, body) -> failwith "AnonFunction not implemented in this language" | RawExpr r -> r let indent lines = List.map (fun s -> " " ^ (Str.global_replace (Str.regexp "\n") "\n " s)) lines let printStmtLines_base printExpr printStmtLines = function If (cond, body, els) -> ["if (" ^ printExpr cond ^ ")"; "{"] @ (indent (List.concat (List.map printStmtLines body))) @ ["}"] @ (match els with Some s -> "else" :: printStmtLines s | None -> []) | While (cond, body) -> ["while (" ^ printExpr cond ^ ")"; "{"] @ (indent (List.concat (List.map printStmtLines body))) @ ["}"] | Switch (expr, cases) -> ["switch (" ^ printExpr expr ^ ")"; "{"] @ List.concat (List.map (fun (es, body) -> let case = if es = [] then ["default:"] else List.map (fun e -> "case " ^ printExpr e ^ ":") es in match body with | [Return r] -> (* special case for lookup-table switches, with more condensed output *) case @ indent (List.concat (List.map printStmtLines body)) | _ -> case @ ["{"] @ indent (List.concat (List.map printStmtLines body)) @ ["}"; ""] ) cases) @ ["}"] | Break -> ["break;"] | Return None -> ["return;"] | Return (Some e) -> ["return " ^ printExpr e ^ ";"] | RawStmt s -> [s] | Optional None -> [] | Optional (Some s) -> printStmtLines s | StmtList s -> List.concat (List.map printStmtLines s) | CallStmt (n, es) -> [printExpr (Call (n, es)) ^ ";"] | Block s -> ["{"] @ (indent (List.concat (List.map printStmtLines s))) @ ["}"] | DeclVar (t, n) -> [t ^ " " ^ n ^ ";"] | InitVar (t, n, e) -> [t ^ " " ^ n ^ " = " ^ printExpr e ^ ";"] | Assign (n, e) -> [printExpr n ^ " = " ^ printExpr e ^ ";"] | Function (ret, name, args, body) -> [ret ^ " " ^ name ^ "(" ^ (String.concat ", " (List.map (fun (a,b) -> a ^ " " ^ b) args)) ^ ")"; "{"] @ (indent (List.concat (List.map printStmtLines body))) @ ["}"] | Enum (name, vals) -> ["enum " ^ name; "{"] @ (indent (List.map (fun s -> s ^ ",") vals)) @ ["};"; ""] | Comment c -> ["/* " ^ c ^ " */"] | Newline -> [""]