diff --git a/src/generator/codegen.jl b/src/generator/codegen.jl index 11b96b30..3ee732cf 100644 --- a/src/generator/codegen.jl +++ b/src/generator/codegen.jl @@ -320,6 +320,85 @@ function emit_setproperty!(dag, node, options) return dag end +function get_names_types(root_cursor, cursor, options) + field_cursors = fields(getCursorType(cursor)) + field_cursors = isempty(field_cursors) ? children(cursor) : field_cursors + tys = [] + fsyms = [] + for field_cursor in field_cursors + n = name(field_cursor) + if isempty(n) + _emit_getproperty_ptr!(root_cursor, field_cursor, options) + continue + end + fsym = make_symbol_safe(n) + fty = getCursorType(field_cursor) + ty = translate(tojulia(fty), options) + push!(tys, ty) + push!(fsyms, fsym) + end + fsyms, tys +end + +function emit_constructor!(dag, node::ExprNode{<:AbstractUnionNodeType}, options) + sym = make_symbol_safe(node.id) + fsyms, tys = get_names_types(node.cursor, node.cursor, options) + union_sym = Symbol(:__U_, sym) + push!(node.exprs, :(const $union_sym = Union{$(tys...)})) + body = Expr(:block, + :(ref = Ref{$sym}()), + :(ptr = Base.unsafe_convert(Ptr{$sym}, ref)), + ) + + if get(options, "union_single_constructor", false) + branch_args = map(zip(fsyms, tys)) do (fsym, ty) + cond = :(val isa $ty) + assign = :(ptr.$fsym = val) + (cond, assign) + end + + first_args, rest = Iterators.peel(branch_args) + ex = Expr(:if, first_args...) + push!(body.args, ex) + foreach(rest) do (cond, assign) + _ex = Expr(:elseif, cond, assign) + push!(ex.args, _ex) + ex = _ex + end + + push!(body.args, :(ref[])) + push!(node.exprs, Expr(:function, Expr(:call, sym, :(val::$union_sym)), body)) + else + foreach(zip(fsyms, tys)) do (fsym, ty) + _body = copy(body) + append!(_body.args, + [ + :(ptr.$fsym = $fsym), + :(ref[]), + ] + ) + func = Expr(:function, :($sym($fsym::$ty)), _body) + push!(node.exprs, func) + end + end +end + +function emit_constructor!(dag, node::ExprNode{<:StructLayout}, options) + sym = make_symbol_safe(node.id) + fsyms, tys = get_names_types(node.cursor, node.cursor, options) + body = quote + ref = Ref{$sym}() + ptr = Base.unsafe_convert(Ptr{$sym}, ref) + $((:(ptr.$fsym = $fsym) for fsym in fsyms)...) + ref[] + end + + rm_line_num_node!(body) + + func = Expr(:function, Expr(:call, sym, (:($fsym::$ty) for (fsym, ty) in zip(fsyms, tys))...), body) + push!(node.exprs, func) +end + function emit!(dag::ExprDAG, node::ExprNode{<:AbstractStructNodeType}, options::Dict; args...) struct_sym = make_symbol_safe(node.id) block = Expr(:block) @@ -435,6 +514,11 @@ function emit!(dag::ExprDAG, node::ExprNode{<:RecordLayouts}, options::Dict; arg emit_getproperty!(dag, node, options) emit_setproperty!(dag, node, options) + opt = get(options, "add_record_constructors", []) + if (opt isa Bool && opt) || sym in opt + emit_constructor!(dag, node, options) + end + return dag end