flitter/generators/nim/generate_nim.ml
2018-06-06 17:31:17 +09:00

1115 lines
32 KiB
OCaml

open Common
open Parse_info
open Ast_cpp
module Flag = Flag_parsing_cpp
let process_either _of_a _of_b =
function
| Left left -> "" ^ _of_a left
| Right right -> "" ^ _of_b right
let is_empty s =
(s = "")
let gen_indent num_spaces =
let rec aux acc num_spaces =
match num_spaces with
| 0 -> acc
| rest -> aux (acc^" ") (num_spaces-1)
in
aux "" num_spaces
let replace search sub str =
Str.global_replace (Str.regexp search) sub str
let indent ?(level=2) str =
let indent_str = gen_indent level
and search = Str.regexp "\n" in
indent_str ^ String.trim (Str.global_replace search ("\n" ^ indent_str) str)
let process_option ofa x =
match x with
| None -> ""
| Some stuff -> "" ^ ofa stuff
let process_tuple_option ofa x =
match x with
| None -> ("", "")
| Some stuff -> ofa stuff
let process_list ?(delimiter=", ") _of_a node =
let map = List.map _of_a node
in String.concat delimiter map
let rec process_info token =
process_token token
and process_token tok =
match tok.token with
| OriginTok loc -> loc.str
| FakeTokStr (v1, opt) -> ""
| Ab -> ""
| ExpandedTok (tok1, tok2, integer) -> tok1.str
and wrap _of_a (v1, v2) =
_of_a v1
and wrap2 _of_a (v1, v2) =
let v1 = _of_a v1 and v2 = process_info v2 in
v1 ^ v2
and process_paren _of_a (paren1, arglist, paren2) =
let paren1 = process_token paren1
and arglist = _of_a arglist
and paren2 = process_token paren2
in paren1 ^ arglist ^ paren2
and process_brace ?(include_braces=false) _of_a (br1, arglist, br2) =
if include_braces then
"{" ^ _of_a arglist ^ "}"
else
_of_a arglist
and process_bracket _of_a (br1, arglist, br2) =
let br1 = process_token br1
and arglist = _of_a arglist
and br2 = process_token br2 in
br1 ^ arglist ^ br2
and process_angle _of_a (ang1, args, ang2) =
let ang1 = process_token ang1
and args = _of_a args
and ang2 = process_token ang2
in ang1 ^ args ^ ang2
and process_comma_list ?(delimiter=", ") _of_a node =
process_list ~delimiter:delimiter (wrap _of_a) node
and process_comma_list2 _of_a =
process_list (process_either _of_a process_token)
let rec process_token tok =
match tok.token with
| OriginTok loc -> loc.str
| FakeTokStr (v1, opt) -> ""
| Ab -> ""
| ExpandedTok (tok1, tok2, integer) ->
tok1.str
and process_include_kind = function
| Local -> ""
| Standard -> ""
| Weird -> ""
and process_define_expr expr =
""
and process_constant =
function
| String (str, is_wchar) -> str
| MultiString -> ""
| Char (str, is_wchar) -> str
| Int str -> str
| Float (str, ftype) -> str
| Bool bval -> string_of_bool bval
and process_ident ident =
match ident with
| IdIdent (name, tok) ->
process_token tok
| IdTemplateId (ident, args) ->
""
| IdDestructor (tok, simple_ident) ->
let (_, idtok) = simple_ident in
"destructor" ^ process_token idtok
| IdOperator (tok, operator) ->
""
| IdConverter (tok, fullType) ->
""
and process_argument arg =
process_either process_expression process_weird_arg arg
and process_weird_arg =
function
| ArgType arg_type -> process_fullType arg_type
| ArgAction arg_action -> process_action_macro arg_action
and process_action_macro =
function
| ActMisc act_misc ->
process_list process_token act_misc
and process_typeC (tc, tok_list) =
process_typeCbis tc
and process_floatType =
function
| CFloat -> "cfloat"
| CDouble -> "cdouble"
| CLongDouble -> "clongdouble"
and process_intType =
function
| CChar -> "cchar"
| Si signed -> process_signed signed
| CBool -> "cbool"
| WChar_t -> "cwchar_t"
and process_signed (sign, base) =
let sign = process_sign sign and base = process_base base
in "c" ^ sign ^ base (* cuchar, cint, cuint, etc. *)
and process_base =
function
| CChar2 -> "char"
| CShort -> "short"
| CInt -> "int"
| CLong -> "long"
| CLongLong -> "longlong"
and process_sign =
function
| Signed -> ""
| UnSigned -> "u"
and process_baseType =
function
| Void -> "void"
| IntType intType -> process_intType intType
| FloatType floatType -> process_floatType floatType
and process_param_name =
function
| None -> ""
| Some (name, tok) -> process_token tok ^ ": "
and process_parameter {
p_name = p_name;
p_type = p_type;
p_register = p_register;
p_val = p_val
} =
let type_str = process_fullType p_type
and p_name = process_param_name p_name in
p_name ^ type_str
and process_functionType {
ft_ret = ft_ret;
ft_params = ft_params;
ft_dots = ft_dots;
ft_const = ft_const;
ft_throw = ft_throw
} =
let ret_type = process_fullType ft_ret
and paren_str =
process_paren (process_comma_list process_parameter) ft_params in
paren_str ^ ": " ^ ret_type
and process_simple_ident (name, tok) =
name
and process_e_val (tok, cexpr) =
let equals = process_token tok (* equals sign *)
and cexpr = process_constExpression cexpr (* const expr *)
in " " ^ equals ^ " " ^ cexpr
and process_enum_elem { e_name = e_name; e_val = e_val } =
let e_name = process_simple_ident e_name
and e_val = process_option process_e_val e_val in
e_name ^ e_val
and process_constExpression expr = process_expression expr
and process_template_arguments args =
process_angle (process_comma_list process_template_argument) args
and process_template_argument arg =
process_either process_fullType process_expression arg
and process_qualifier =
function
| QClassname ((name, info)) ->
name ^ process_info info
| QTemplateId ((name, args)) ->
let ident = process_simple_ident name
and args = process_template_arguments args in
ident ^ args
and process_name (v1, v2, v3) =
let v1 = process_option process_token v1
and v2 =
process_list
(fun (v1, v2) ->
let v1 = process_qualifier v1
and v2 = process_token v2 in
v1 ^ v2)
v2
and v3 = process_ident v3
in v1 ^ v2 ^ v3
and process_either_ft_or_expr ft_or_expr =
process_either process_fullType process_expression ft_or_expr
and process_structUnion =
function
| Struct -> "struct"
| Union -> "union"
| Class -> "class"
and process_typeCbis =
function
| BaseType btype ->
process_baseType btype
| Pointer point ->
"ptr " ^ process_fullType point
| Reference ref ->
"ref " ^ process_fullType ref
| Array ((arr, typ)) ->
let arr = process_bracket (process_option process_constExpression) arr
and typ = process_fullType typ
in arr ^ typ
| FunctionType ftype ->
process_functionType ftype
| EnumDef ((name, ident, elements)) ->
let ident = process_option process_simple_ident ident
and elements =
process_brace (process_comma_list process_enum_elem) elements
in ident ^ " = enum\n" ^ elements
| StructDef sdef ->
"" (*process_class_definition sdef*)
| EnumName ((enum, name)) ->
process_simple_ident name
| StructUnionName ((stype_tok, name)) ->
let (stype, _) = stype_tok in
let stype = process_structUnion stype
and name = process_simple_ident name in
stype ^ " " ^ name
| TypeName ((tname)) ->
process_name tname
| TypenameKwd ((tname (* 'typename' *), tdef_name)) ->
process_name tdef_name
| TypeOf ((typeof, tdef)) ->
process_paren process_either_ft_or_expr tdef
| ParenType paren ->
process_paren process_fullType paren
and process_info token =
process_token token
and process_expression (expr, toks) =
process_exprbis toks expr
and process_fixOp expr =
function
| Dec -> "- 1"
| Inc -> "+ 1"
and process_binaryOp =
function
| Arith arith ->
process_arithOp arith
| Logical log ->
process_logicalOp log
and process_arithOp =
function
| Plus -> "+"
| Minus -> "-"
| Mul -> "*"
| Div -> "/"
| Mod -> "mod"
| DecLeft -> "shl"
| DecRight -> "shr"
| And -> "and"
| Or -> "or"
| Xor -> "xor"
and process_logicalOp =
function
| Inf -> "<"
| Sup -> ">"
| InfEq -> "<="
| SupEq -> ">="
| Eq -> "=="
| NotEq -> "!="
| AndLog -> "and"
| OrLog -> "or"
and process_unaryOp expr =
let expr = process_expression expr in
function
| GetRef -> "addr " ^ expr
| DeRef -> expr ^ "[]"
| UnPlus -> "+" ^ expr
| UnMinus -> "-" ^ expr
| Tilde -> "not " ^ expr
| Not -> "not " ^ expr
| GetRefLabel -> failwith "Ref labels are not supported in flitter!"
and process_assignOp =
function
| SimpleAssign -> "="
| OpAssign arith ->
process_arithOp arith
and process_exprbis toks =
function
| Id ((name, info)) ->
let (_, _, ident) = name in
process_ident ident
| C const ->
let res = match toks with
| [] -> ""
| main_tok :: _ -> process_token main_tok in
res
| Call ((expr, args)) ->
let name = process_expression expr
and args = process_paren (process_comma_list process_argument) args in
name ^ args
| CondExpr ((binary, first_option, second_option)) ->
let bin = process_expression binary
and first_op = process_option process_expression first_option
and second_op = process_expression second_option in
"if " ^ bin ^ ": " ^ first_op ^ " else: " ^ second_op
| Sequence ((v1, v2)) ->
(*let v1 = process_expression v1
and v2 = process_expression v2
in Ocaml.VSum (("Sequence", [ v1; v2 ]))*)
""
| Assignment ((left, op, right)) ->
let left = process_expression left
and op = process_assignOp op
and right = process_expression right in
left ^ " " ^ op ^ " " ^ right
| Postfix ((expr, op)) ->
let expr = process_expression expr in
let op_expr =
match op with
| Dec -> "postDec(" ^ expr ^ ")"
| Inc -> "postInc(" ^ expr ^ ")" in
op_expr
| Infix ((expr, op)) ->
let expr = process_expression expr in
let op_expr =
match op with
| Dec -> "preDec(" ^ expr ^ ")"
| Inc -> "preInc(" ^ expr ^ ")" in
op_expr
| Unary ((expr, op)) ->
process_unaryOp expr op
| Binary ((left, op, right)) ->
let left = process_expression left
and op = process_binaryOp op
and right = process_expression right
in left ^ " " ^ op ^ " " ^ right
| ArrayAccess ((expr, bracket_expr)) ->
let expr = process_expression expr
and bracket_expr = process_bracket process_expression bracket_expr in
expr ^ bracket_expr
| RecordAccess ((expr, field)) ->
let expr = process_expression expr
and field = process_name field in
expr ^ "." ^ field
| RecordPtAccess ((expr, field)) ->
let expr = process_expression expr
and field = process_name field in
expr ^ "." ^ field
| RecordStarAccess ((left, right)) ->
(*
* Not sure what this is, exactly. The nim code
* will have it commented out for now.
*)
let left = process_expression left
and right = process_expression right in
"# " ^ left ^ process_list process_token toks ^ right
| RecordPtStarAccess ((left, right)) ->
(*
* Not sure what this is, exactly. The nim code
* will have it commented out for now.
*)
let left = process_expression left
and right = process_expression right in
"# " ^ left ^ process_list process_token toks ^ right
| SizeOfExpr ((sizeof, expr)) ->
let expr = process_expression expr in
"sizeof(" ^ expr ^ ")"
| SizeOfType ((sizeof, fullType)) ->
let ty = process_paren process_fullType fullType in
"sizeof" ^ ty
| Cast (((left, fullType, right), expr)) ->
let fullType = process_fullType fullType
and expr = process_expression expr in
"cast[" ^ fullType ^ "](" ^ expr ^ ")"
| StatementExpr v1 ->
process_paren process_compound v1
| GccConstructor ((v1, v2)) ->
(*
* Not sure what this is, exactly. The nim code
* will have it commented out for now.
*)
let v1 = process_paren process_fullType v1
and v2 = process_brace (process_comma_list process_initialiser) v2 in
"# " ^ v1 ^ process_list process_token toks ^ v2
| This v1 ->
(*let v1 = process_tok v1 in Ocaml.VSum (("This", [ v1 ]))*)
""
| ConstructedObject ((fullType, params)) ->
let fullType = process_fullType fullType
and params = process_paren (process_comma_list process_argument) params in
fullType ^ params
| TypeId ((v1, v2)) ->
(*let v1 = process_tok v1
and v2 = process_paren process_either_ft_or_expr v2
in Ocaml.VSum (("TypeId", [ v1; v2 ]))*)
""
| CplusplusCast ((cast_op, fullType, expr)) ->
(*let v1 = process_wrap2 process_cast_operator v1
and v2 = process_angle process_fullType v2
and v3 = process_paren process_expression v3
in Ocaml.VSum (("CplusplusCast", [ v1; v2; v3 ]))*)
""
| New ((v1, v2, v3, v4, v5)) ->
(*let v1 = Ocaml.process_option process_tok v1
and v2 = process_tok v2
and v3 = Ocaml.process_option (process_paren (process_comma_list process_argument)) v3
and v4 = process_fullType v4
and v5 = Ocaml.process_option (process_paren (process_comma_list process_argument)) v5
in Ocaml.VSum (("New", [ v1; v2; v3; v4; v5 ]))*)
""
| Delete ((v1, v2)) ->
(*let v1 = Ocaml.process_option process_tok v1
and v2 = process_expression v2
in Ocaml.VSum (("Delete", [ v1; v2 ]))*)
""
| DeleteArray ((tok, expr)) ->
let tok = process_option process_token tok
and expr = process_expression expr
in tok ^ expr
| Throw throw ->
process_option process_expression throw
| ParenExpr paren_expr ->
process_paren process_expression paren_expr
| ExprTodo -> "TODO"
and process_selection =
function
| If ((if_tok, paren_expr, stmt1, else_tok, stmt2)) ->
let paren_expr = process_paren process_expression paren_expr
and stmt1 = process_statement stmt1
and else_tok = process_option process_token else_tok
and stmt2 = process_statement stmt2 in
"if" ^ paren_expr ^
stmt1 ^ "\n" ^
replace "elseif" "elif" (else_tok ^ stmt2)
| Switch ((v1, v2, v3)) ->
let v1 = process_token v1
and v2 = process_paren process_expression v2
and v3 = process_statement v3
in v1 ^ v2 ^ v3
and process_iteration =
function
| While ((v1, v2, v3)) ->
let v1 = process_token v1
and v2 = process_paren process_expression v2
and v3 = process_statement v3
in v1 ^ v2 ^ v3
| DoWhile ((v1, v2, v3, v4, v5)) ->
let v1 = process_token v1
and v2 = process_statement v2
and v3 = process_token v3
and v4 = process_paren process_expression v4
and v5 = process_token v5
in v1 ^ v2 ^ v3 ^ v4 ^v5
| For ((v1, v2, v3)) ->
let v1 = process_token v1
and v2 =
process_paren
(fun (v1, v2, v3) ->
let v1 = wrap process_exprStatement v1
and v2 = wrap process_exprStatement v2
and v3 = wrap process_exprStatement v3
in v1 ^ v2 ^ v3)
v2
and v3 = process_statement v3
in v1 ^ v2 ^ v3
| MacroIteration ((v1, v2, v3)) ->
let v1 = process_simple_ident v1
and v2 = process_paren (process_comma_list process_argument) v2
and v3 = process_statement v3
in v1 ^ v2 ^ v3
and process_jump =
function
| Goto goto -> failwith "# XXX goto not supported: " ^ goto
| Continue -> "continue"
| Break -> "break"
| Return -> "return"
| ReturnExpr ret_expr ->
"return " ^ process_expression ret_expr
| GotoComputed goto_comp ->
failwith "#[ XXX goto not supported: " ^ process_expression goto_comp ^ "]#"
and process_handler (v1, v2, v3) =
let v1 = process_token v1
and v2 = process_paren process_exception_declaration v2
and v3 = process_compound v3
in v1 ^ v2 ^ v3
and process_exception_declaration =
function
| ExnDeclEllipsis exn_ellipsis ->
process_token exn_ellipsis
| ExnDecl exn_decl ->
process_parameter exn_decl
and get_tydef_prefix name storage =
match storage with
| NoSto -> ""
| StoTypedef st_tdef ->
"type " ^ name ^ " = "
| Sto (sto, tok) -> ""
and process_onedecl {
v_namei = v_namei;
v_type = v_type;
v_storage = v_storage
} =
let name =
process_tuple_option
(fun (name, init) ->
let name = process_name name
and init = process_option process_init init
in
pr (name ^ " " ^ init);
(name, init))
v_namei in
let res = process_onedeclFullType "" name v_storage v_type in
replace "ptr cchar" "cstring" res
and
process_class_definition ?(name_override=None) {
c_kind = c_kind;
c_name = c_name;
c_inherit = c_inherit;
c_members = (_, c_members, _)
} =
let members =
process_list ~delimiter:"\n" process_class_member_sequencable c_members in
let _ =
process_option
(fun (v1, v2) ->
let v1 = process_token v1
and v2 = process_comma_list process_base_clause v2
in v1 ^ v2)
c_inherit in
let name = match name_override with
| None -> process_option process_name c_name
| Some x -> x in
let _ = wrap2 process_structUnion c_kind in
"type\n" ^
indent (name ^ " = object\n" ^
indent (members))
and
process_base_clause {
i_name = v_i_name;
i_virtual = v_i_virtual;
i_access = v_i_access
} =
let access = process_option (wrap2 process_access_spec) v_i_access in
let virtual_tok = process_option process_token v_i_virtual in
let name = process_name v_i_name in
name ^ access ^ virtual_tok
and process_access_spec =
function
| Public -> "*"
| Private -> ""
| Protected -> ""
and process_exn_spec (v1, v2) =
let v1 = process_token v1
and v2 = process_paren (process_comma_list2 process_name) v2
in v1 ^ v2
and process_method_decl = function
| ConstructorDecl ((v1, v2, v3)) ->
let (v1, _) = v1
and v2 = process_paren (process_comma_list process_parameter) v2
and v3 = process_token v3
in v1 ^ v2 ^ v3
| DestructorDecl ((v1, v2, v3, v4, v5)) ->
let v1 = process_token v1
and (v2, _) = v2
and v3 = process_paren (process_option process_token) v3
and v4 = process_option process_exn_spec v4
and v5 = process_token v5
in v1 ^ v2 ^ v3 ^ v4 ^ v5
| MethodDecl ((v1, v2, v3)) ->
let v1 = process_onedecl v1
and v2 =
process_option
(fun (v1, v2) ->
let v1 = process_token v1
and v2 = process_token v2
in v1 ^ v2)
v2
and v3 = process_token v3
in v1 ^ v2 ^ v3
and process_template_parameters v =
process_angle (process_comma_list process_parameter) v
and process_class_member =
function
| Access ((v1, v2)) ->
let v1 = wrap2 process_access_spec v1
and v2 = process_token v2
in v1 ^ v2
| MemberField (fieldkinds, semi) ->
process_comma_list process_fieldkind fieldkinds
| MemberFunc v1 ->
process_func_or_else v1
| MemberDecl v1 ->
process_method_decl v1
| QualifiedIdInClass ((v1, v2)) ->
let v1 = process_name v1
and v2 = process_token v2
in v1 ^ v2
| TemplateDeclInClass v1 ->
let v1 =
(match v1 with
| (v1, v2, v3) ->
let v1 = process_token v1
and v2 = process_template_parameters v2
and v3 = process_declaration v3
in v1 ^ v2 ^ v3)
in v1
| UsingDeclInClass v1 ->
let v1 =
(match v1 with
| (v1, v2, v3) ->
let v1 = process_token v1
and v2 = process_name v2
and v3 = process_token v3
in v1 ^ v2 ^ v3)
in v1
| EmptyField v1 ->
process_token v1
and process_fieldkind =
function
| FieldDecl field_decl ->
process_onedecl field_decl
| BitField ((v1, v2, v3, v4)) ->
let v1 = process_option process_simple_ident v1
and v2 = process_token v2
and v3 = process_fullType v3
and v4 = process_constExpression v4
in v1 ^ v2 ^ v3 ^ v4
and process_class_member_sequencable =
function
| ClassElem elem ->
process_class_member elem
| CppDirectiveStruct dir_struct ->
process_cpp_directive dir_struct
| IfdefStruct ifdef_struct ->
process_ifdef_directive ifdef_struct
and process_onedeclFullType prefix (name, init) storage (qualifier, (typeCbis, tok_list)) =
match typeCbis with
| BaseType btype ->
if is_empty(init) then
name ^ ": " ^ prefix ^ process_baseType btype
else
"var " ^ name ^ ": " ^ prefix ^ process_baseType btype ^ " = " ^ init
| Pointer point ->
process_onedeclFullType "ptr " (name, init) storage point
| Reference ref ->
process_onedeclFullType "ref " (name, init) storage ref
| Array ((arr, typ)) ->
let arr = process_bracket (process_option process_constExpression) arr
and typ = process_fullType typ
in arr ^ typ
| FunctionType ftype ->
let ret = match storage with
| NoSto -> "proc " ^ name^init ^ process_functionType ftype
| StoTypedef st_tdef ->
"type " ^ name^init ^ " = " ^ "proc " ^ process_functionType ftype
| Sto sto -> "proc " ^ name^init ^ process_functionType ftype in
ret
| EnumDef ((_, ident, elements)) ->
let ident = process_option process_simple_ident ident
and elements =
process_brace (process_comma_list process_enum_elem) elements
in
let ty_str = "type " ^ ident ^ " = enum " ^ elements
and let_stmt = if is_empty(init) then
"\nvar " ^ name ^ ": " ^ ident
else
"\nvar " ^ name ^ ": " ^ ident ^ " = " ^ init in
if is_empty(name) then ty_str else ty_str ^ let_stmt
| StructDef sdef ->
if is_empty(name) then
process_class_definition sdef
else
process_class_definition ~name_override:(Some name) sdef
| EnumName ((enum, name)) ->
process_simple_ident name
| StructUnionName ((stype_tok, sname)) ->
let sname = process_simple_ident sname in
"var " ^ name ^ " = " ^ sname ^ " @ " ^ init
| TypeName ((tname)) ->
process_name tname
| TypenameKwd ((tname (* 'typename' *), tdef_name)) ->
process_name tdef_name
| TypeOf ((typeof, tdef)) ->
process_paren process_either_ft_or_expr tdef
| ParenType (left, type_inf, right) ->
process_onedeclFullType "" (name, init) storage type_inf
and process_storage st = process_storagebis st
and process_storagebis =
function
| NoSto -> ""
| StoTypedef st_tdef ->
process_token st_tdef
| Sto sto -> wrap2 process_storageClass sto
and process_storageClass =
function
| Auto -> "auto"
| Static -> "static"
| Register -> "register"
| Extern -> "extern"
and process_init =
function
| EqInit ((equals, init)) ->
let init = process_initialiser init
in init
| ObjInit v1 ->
process_paren (process_comma_list process_argument) v1
and process_block_declaration =
function
| DeclList ((decl, semi_col)) ->
process_comma_list process_onedecl decl
| MacroDecl ((v1, v2, v3, v4)) ->
let v1 = process_list process_token v1
and v2 = process_simple_ident v2
and v3 = process_paren (process_comma_list process_argument) v3
and v4 = process_token v4
in v1 ^ v2 ^ v3 ^ v4
| UsingDecl v1 ->
let v1 =
(match v1 with
| (v1, v2, v3) ->
let v1 = process_token v1
and v2 = process_name v2
and v3 = process_token v3
in v1 ^ v2 ^ v3)
in v1
| UsingDirective ((v1, v2, v3, v4)) ->
let v1 = process_token v1
and v2 = process_token v2
and v3 = process_name v3
and v4 = process_token v4
in v1 ^ v2 ^ v3 ^ v4
| NameSpaceAlias ((v1, v2, v3, v4, v5)) ->
let v1 = process_token v1
and v2 = process_simple_ident v2
and v3 = process_token v3
and v4 = process_name v4
and v5 = process_token v5
in v1 ^ v2 ^ v3 ^ v4 ^ v5
| Asm ((v1, v2, v3, v4)) ->
let v1 = process_token v1
and v2 = process_option process_token v2
and v3 = process_paren process_asmbody v3
and v4 = process_token v4
in v1 ^ v2 ^ v3 ^ v4
and process_asmbody (v1, v2) =
let v1 = process_list process_token v1
and v2 = process_list (wrap process_colon) v2
in v1 ^ v2
and process_colon =
function
| Colon v1 ->
let v1 = process_comma_list process_colon_option v1
in v1
and process_colon_option v = wrap process_colon_optionbis v
and process_colon_optionbis =
function
| ColonMisc -> "colonmisc"
| ColonExpr v1 ->
let v1 = process_paren process_expression v1
in v1
and process_statement stmt = wrap process_statementbis stmt
and process_statementbis =
function
| Compound comp ->
":\n" ^ indent (process_compound comp)
| ExprStatement expr ->
process_exprStatement expr
| Labeled labeled ->
process_labeled labeled
| Selection selection ->
process_selection selection
| Iteration iter ->
process_iteration iter
| Jump jump ->
process_jump jump
| DeclStmt decl ->
process_block_declaration decl
| Try ((tok, comp, handler_list)) ->
let comp = process_compound comp
and handler_list = process_list process_handler handler_list
in "try: " ^ comp ^ handler_list
| NestedFunc nest_func ->
process_func_definition nest_func
| MacroStmt -> ""
| StmtTodo -> "# TODO"
and process_compound comp =
process_brace (process_list ~delimiter:"\n" process_statement_sequencable) comp
and process_statement_sequencable =
function
| StmtElem stmt ->
process_statement stmt
| CppDirectiveStmt direc ->
process_cpp_directive direc
| IfdefStmt ifdef ->
process_ifdef_directive ifdef
and process_ifdef_directive if_def = wrap2 process_ifdefkind if_def
and process_ifdefkind =
function (* TODO fix this for Nim *)
| Ifdef -> "ifdef"
| IfdefElse -> "ifdefelse"
| IfdefElseif -> "ifdefelseif"
| IfdefEndif -> "ifdefendif"
and process_exprStatement expr_stmt =
process_option process_expression expr_stmt
and process_labeled =
function
| Label ((name, stmt)) ->
let stmt = process_statement stmt
in name ^ " " ^ stmt
| Case ((expr, stmt)) ->
let expr = process_expression expr
and stmt = process_statement stmt
in expr ^ " " ^stmt
| CaseRange ((expr1, expr2, stmt)) ->
let expr1 = process_expression expr1
and expr2 = process_expression expr2
and stmt = process_statement stmt
in expr1 ^ expr2 ^ stmt
| Default def ->
process_statement def
and process_initialiser =
function
| InitExpr expr ->
process_expression expr
| InitList init_list ->
process_brace
~include_braces:true (process_comma_list process_initialiser) init_list
| InitDesignators ((v1, v2, v3)) ->
let v1 = process_list process_designator v1
and v2 = process_token v2
and v3 = process_initialiser v3
in v1 ^ v2 ^ v3
| InitFieldOld ((v1, v2, v3)) ->
let v1 = process_simple_ident v1
and v2 = process_token v2
and v3 = process_initialiser v3
in v1 ^ v2 ^ v3
| InitIndexOld ((v1, v2)) ->
let v1 = process_bracket process_expression v1
and v2 = process_initialiser v2
in v1 ^ v2
and process_designator =
function
| DesignatorField ((v1, v2)) ->
let v1 = process_token v1
and v2 = process_simple_ident v2
in v1 ^ v2
| DesignatorIndex v1 ->
process_bracket process_expression v1
| DesignatorRange v1 ->
process_bracket
(fun (v1, v2, v3) ->
let v1 = process_expression v1
and v2 = process_token v2
and v3 = process_expression v3
in v1 ^ v2 ^ v3)
v1
and process_define_val =
function
| DefinePrintWrapper ((if_tok, expr_paren, name)) ->
let expr_paren = process_paren process_expression expr_paren
and name = process_name name in
expr_paren ^ name
| DefineExpr expr ->
process_expression expr
| DefineStmt stmt ->
process_statement stmt
| DefineType dtype ->
process_fullType dtype
| DefineDoWhileZero (stmt, tok_list) ->
process_statement stmt
| DefineFunction dfunc ->
process_func_definition dfunc
| DefineInit init ->
process_initialiser init
| DefineText (str, toks) ->
str
| DefineEmpty -> ""
| DefineTodo -> ""
and process_define _tok ident kind value =
match kind with
| DefineVar ->
let (idname, _ ) = ident in
"const " ^ idname ^ " = " ^ process_define_val value
| DefineFunc func ->
""
(*let (idname, _) = ident
in *)
and process_include ((tok, kind, path)) =
let include_file =
match kind with
| Local -> path
| Standard -> path
| Weird ->
let search = Str.regexp "_"
and lower = String.lowercase_ascii path
in Str.global_replace search "." lower
in "#" ^ include_file ^ " " ^ process_token tok
and process_cpp_directive = function
| Define ((tok, ident, kind, value)) ->
process_define tok ident kind value
| Include ((tok, inc_kind, path)) ->
process_include (tok, inc_kind, path)
| Undef ((name, tok)) ->
process_token tok
| PragmaAndCo tok ->
process_token tok
and process_func_definition {
f_name = f_name;
f_type = f_type;
f_storage = f_storage;
f_body = f_body
} =
let name = process_name f_name
and def_str = process_functionType f_type
and body = process_compound f_body in
"proc " ^ name ^ def_str ^ " =\n" ^ (indent body)
and process_func_or_else =
function
| FunctionOrMethod func_meth ->
process_func_definition func_meth
| Constructor ((func)) ->
process_func_definition func
| Destructor func ->
process_func_definition func
and process_declaration =
function
| BlockDecl block ->
process_block_declaration block
| Func func ->
process_func_or_else func
| TemplateDecl (v1, v2, v3) ->
(*let v1 = process_tok v1
and v2 = process_template_parameters v2
and v3 = process_declaration v3
in Ocaml.VSum (("TemplateDecl", [ v1; v2; v3 ]))*)
""
| TemplateSpecialization ((v1, v2, v3)) ->
(*let v1 = process_tok v1
and v2 = process_angle Ocaml.process_unit v2
and v3 = process_declaration v3
in Ocaml.VSum (("TemplateSpecialization", [ v1; v2; v3 ]))*)
""
| ExternC ((v1, v2, v3)) ->
(*let v1 = process_tok v1
and v2 = process_tok v2
and v3 = process_declaration v3
in Ocaml.VSum (("ExternC", [ v1; v2; v3 ]))*)
""
| ExternCList ((v1, v2, v3)) ->
(*let v1 = process_tok v1
and v2 = process_tok v2
and v3 = process_brace (Ocaml.process_list process_declaration_sequencable) v3
in Ocaml.VSum (("ExternCList", [ v1; v2; v3 ]))*)
""
| NameSpace ((v1, v2, v3)) ->
(*let v1 = process_tok v1
and v2 = process_wrap2 Ocaml.process_string v2
and v3 = process_brace (Ocaml.process_list process_declaration_sequencable) v3
in Ocaml.VSum (("NameSpace", [ v1; v2; v3 ]))*)
""
| NameSpaceExtend ((v1, v2)) ->
(*let v1 = Ocaml.process_string v1
and v2 = Ocaml.process_list process_declaration_sequencable v2
in Ocaml.VSum (("NameSpaceExtend", [ v1; v2 ]))*)
""
| NameSpaceAnon ((v1, v2)) ->
(*let v1 = process_tok v1
and v2 = process_brace (Ocaml.process_list process_declaration_sequencable) v2
in Ocaml.VSu:m (("NameSpaceAnon", [ v1; v2 ]))*)
""
| EmptyDef def -> ""
| DeclTodo -> "# TODO"
and process_fullType ((qualifier, typeC)) =
process_typeC typeC
and process_toplevel = function
| NotParsedCorrectly node -> "# Error parsing: " ^ process_list ~delimiter:"" process_token node
| DeclElem node -> process_declaration node
| CppDirectiveDecl node -> process_cpp_directive node
| IfdefDecl node -> ""
| MacroTop ((v1, v2, v3)) -> "# MacroTop"
| MacroVarTop ((v1, v2)) -> "# MacroVarTop"
let iter_ast ast =
List.map process_toplevel ast
let generate_nim cfile ?(macro_files = []) =
Parse_cpp.init_defs cfile;
List.iter Parse_cpp.add_defs macro_files;
let ast = Parse_cpp.parse_program cfile in
let res = iter_ast ast in
String.concat "\n" res
let test_gen_nim file =
let macro_list = [!Flag.macros_h] in
let nim_str = generate_nim file ~macro_files:macro_list in
pr nim_str
let actions () = [
"-generate-nim", " <file>",
Common.mk_action_1_arg test_gen_nim;
]