Repository: JuliaLang/julia
File: contrib/juliac/abi_export.jl (Julia)

Code before:
    (name, symbol) = let
        symbol = length(method.ccallable) > 2 ? Symbol(method.ccallable[3]) : method.name
        iob = IOBuffer()
        print(IOContext(iob, :print_method_signature_only => true), method)
        str = String(take!(iob))
        if symbol !== method.name && startswith(str, String(method.name))
            # Make a best-effort attempt to use the exported name
            #
            # Note: the `startswith` check is to make sure we support 'functor's in arg0,
            # which Base.@ccallable supports as long as they are singletons.
            str = replace(str, String(method.name) => String(symbol); count = 1)
        end
        (str, String(symbol))
    end

    argnames = String.(Base.method_argnames(method))
    let indented_println(args...) = println(ctx.io, " " ^ indent, args...)
        indented_println("{")
        indented_println("  \"symbol\": ", escape_string_json(symbol), ",")
        indented_println("  \"name\": ", escape_string_json(name), ",")
        indented_println("  \"arguments\": [")
        for i in 2:length(sig.parameters)
            print(ctx.io, " " ^ (indent + 4))
            print(ctx.io, "{")
            print(ctx.io, " \"name\": ", escape_string_json(argnames[i]), ",")
            print(ctx.io, " \"type\": ", ctx.type_ids[sig.parameters[i]])
            println(ctx.io, i == length(sig.parameters) ? " }" : " },")
        end
        indented_println("  ],")
        indented_println("  \"returns\": { \"type\": ", ctx.type_ids[rt], " }")
        print(ctx.io, " " ^ indent, "}")
    end
end

function emit_abi_info!(ctx::TypeEmitter, exported::Vector{Core.Method}, types::IdSet{DataType})
    println(ctx.io, "{")

    # assign an ID to each type, so that we can refer to them
    for (i, T) in enumerate(types)
        ctx.type_ids[T] = i
    end

    # print exported functions
    println(ctx.io, "  \"functions\": [")
    for (i, method) in enumerate(exported)
        emit_method_info!(ctx, method; indent = 4)
        println(ctx.io, i == length(exported) ? "" : ",")
    end
    println(ctx.io, "  ],")

    # print type / structure information

Review comment (suggestion):
Should this be `typeid` or `type_id` instead of just `type`? I don't feel strongly about this, but I suspect it might be clearer that it's a reference within the json file.

Code after:
function emit_method_info!(ctx::TypeEmitter, method::Core.Method; indent::Int = 0)
    (rt, sig) = method.ccallable
    (name, symbol) = let
        symbol = length(method.ccallable) > 2 ? Symbol(method.ccallable[3]) : method.name
        iob = IOBuffer()
        print(IOContext(iob, :print_method_signature_only => true), method)
        str = String(take!(iob))
        if symbol !== method.name && startswith(str, String(method.name))
            # Make a best-effort attempt to use the exported name
            #
            # Note: the `startswith` check is to make sure we support 'functor's in arg0,
            # which Base.@ccallable supports as long as they are singletons.
            str = replace(str, String(method.name) => String(symbol); count = 1)
        end
        (str, String(symbol))
    end

    argnames = String.(Base.method_argnames(method))
    let indented_println(args...) = println(ctx.io, " " ^ indent, args...)
        indented_println("{")
        indented_println("  \"symbol\": ", escape_string_json(symbol), ",")
        indented_println("  \"name\": ", escape_string_json(name), ",")
        indented_println("  \"arguments\": [")
        for i in 2:length(sig.parameters)
            print(ctx.io, " " ^ (indent + 4))
            print(ctx.io, "{")
            print(ctx.io, " \"name\": ", escape_string_json(argnames[i]), ",")
            print(ctx.io, " \"type_id\": ", ctx.type_ids[sig.parameters[i]])
            println(ctx.io, i == length(sig.parameters) ? " }" : " },")
        end
        indented_println("  ],")
        indented_println("  \"returns\": { \"type_id\": ", ctx.type_ids[rt], " }")
        print(ctx.io, " " ^ indent, "}")
    end
end

function emit_abi_info!(ctx::TypeEmitter, exported::Vector{Core.Method}, types::IdSet{DataType})
    println(ctx.io, "{")

    # assign an ID to each type, so that we can refer to them
    for (i, T) in enumerate(types)
        ctx.type_ids[T] = i
    end

    # print exported functions
    println(ctx.io, "  \"functions\": [")
    for (i, method) in enumerate(exported)
        emit_method_info!(ctx, method; indent = 4)
        println(ctx.io, i == length(exported) ? "" : ",")
    end
    println(ctx.io, "  ],")