Package org.yinwang.pysonar

Source Code of org.yinwang.pysonar.JSONDump

package org.yinwang.pysonar;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.google.common.collect.Lists;
import org.yinwang.pysonar.ast.FunctionDef;
import org.yinwang.pysonar.ast.Node;
import org.yinwang.pysonar.ast.Str;
import org.yinwang.pysonar.types.FunType;
import org.yinwang.pysonar.types.Type;
import org.yinwang.pysonar.types.UnionType;

import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;


public class JSONDump {

    private static Logger log = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);

    private static Set<String> seenDef = new HashSet<>();
    private static Set<String> seenRef = new HashSet<>();
    private static Set<String> seenDocs = new HashSet<>();


    private static String dirname(String path) {
        return new File(path).getParent();
    }


    private static Analyzer newAnalyzer(String srcpath, String[] inclpaths) throws Exception {
        Analyzer idx = new Analyzer();
        for (String inclpath : inclpaths) {
            idx.addPath(inclpath);
        }

        idx.analyze(srcpath);
        idx.finish();

        if (idx.semanticErrors.size() > 0) {
            log.info("Analyzer errors:");
            for (Entry<String, List<Diagnostic>> entry : idx.semanticErrors.entrySet()) {
                String k = entry.getKey();
                log.info("  Key: " + k);
                List<Diagnostic> diagnostics = entry.getValue();
                for (Diagnostic d : diagnostics) {
                    log.info("    " + d);
                }
            }
        }

        return idx;
    }


    private static void writeSymJson(Binding binding, JsonGenerator json) throws IOException {
        if (binding.start < 0) {
            return;
        }

        String name = binding.name;
        boolean isExported = !(
                Binding.Kind.VARIABLE == binding.kind ||
                        Binding.Kind.PARAMETER == binding.kind ||
                        Binding.Kind.SCOPE == binding.kind ||
                        Binding.Kind.ATTRIBUTE == binding.kind ||
                        (name.length() == 0 || name.charAt(0) == '_' || name.startsWith("lambda%")));

        String path = binding.qname.replace('.', '/').replace("%20", ".");

        if (!seenDef.contains(path)) {
            seenDef.add(path);
            json.writeStartObject();
            json.writeStringField("name", name);
            json.writeStringField("path", path);
            json.writeStringField("file", binding.fileOrUrl);
            json.writeNumberField("identStart", binding.start);
            json.writeNumberField("identEnd", binding.end);
            json.writeNumberField("defStart", binding.bodyStart);
            json.writeNumberField("defEnd", binding.bodyEnd);
            json.writeBooleanField("exported", isExported);
            json.writeStringField("kind", binding.kind.toString());

            if (Binding.Kind.FUNCTION == binding.kind ||
                    Binding.Kind.METHOD == binding.kind ||
                    Binding.Kind.CONSTRUCTOR == binding.kind)
            {
                json.writeObjectFieldStart("funcData");

                // get args expression
                String argExpr = null;
                Type t = binding.type;

                if (t instanceof UnionType) {
                    t = ((UnionType) t).firstUseful();
                }

                if (t != null && t instanceof FunType) {
                    FunctionDef func = ((FunType) t).func;
                    if (func != null) {
                        argExpr = func.getArgumentExpr();
                    }
                }

                String typeExpr = binding.type.toString();

                json.writeNullField("params");

                String signature = argExpr == null ? "" : argExpr + "\n" + typeExpr;
                json.writeStringField("signature", signature);
                json.writeEndObject();
            }

            json.writeEndObject();
        }
    }


    private static void writeRefJson(Node ref, Binding binding, JsonGenerator json) throws IOException {
        if (binding.getFile() != null) {
            String path = binding.qname.replace(".", "/").replace("%20", ".");
            String key = ref.file + ":" + ref.start;
            if (!seenRef.contains(key)) {
                seenRef.add(key);
                if (binding.start >= 0 && ref.start >= 0 && !binding.isBuiltin()) {
                    json.writeStartObject();
                    json.writeStringField("sym", path);
                    json.writeStringField("file", ref.file);
                    json.writeNumberField("start", ref.start);
                    json.writeNumberField("end", ref.end);
                    json.writeBooleanField("builtin", binding.isBuiltin());
                    json.writeEndObject();
                }
            }
        }
    }


    private static void writeDocJson(Binding binding, Analyzer idx, JsonGenerator json) throws Exception {
        String path = binding.qname.replace('.', '/').replace("%20", ".");

        if (!seenDocs.contains(path)) {
            seenDocs.add(path);

            Str doc = binding.getDocstring();

            if (doc != null) {
                json.writeStartObject();
                json.writeStringField("sym", path);
                json.writeStringField("file", binding.fileOrUrl);
                json.writeStringField("body", doc.value);
                json.writeNumberField("start", doc.start);
                json.writeNumberField("end", doc.end);
                json.writeEndObject();
            }
        }
    }


    /*
     * Precondition: srcpath and inclpaths are absolute paths
     */
    private static void graph(String srcpath,
                              String[] inclpaths,
                              OutputStream symOut,
                              OutputStream refOut,
                              OutputStream docOut) throws Exception
    {
        // Compute parent dirs, sort by length so potential prefixes show up first
        List<String> parentDirs = Lists.newArrayList(inclpaths);
        parentDirs.add(dirname(srcpath));
        Collections.sort(parentDirs, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                int diff = s1.length() - s2.length();
                if (0 == diff) {
                    return s1.compareTo(s2);
                }
                return diff;
            }
        });

        Analyzer idx = newAnalyzer(srcpath, inclpaths);
        idx.multilineFunType = true;
        JsonFactory jsonFactory = new JsonFactory();
        JsonGenerator symJson = jsonFactory.createGenerator(symOut);
        JsonGenerator refJson = jsonFactory.createGenerator(refOut);
        JsonGenerator docJson = jsonFactory.createGenerator(docOut);
        JsonGenerator[] allJson = {symJson, refJson, docJson};
        for (JsonGenerator json : allJson) {
            json.writeStartArray();
        }

        for (Binding b : idx.getAllBindings()) {
            String path = b.qname.replace('.', '/').replace("%20", ".");

            if (b.getFile() != null) {
                if (b.getFile().startsWith(srcpath)) {
                    writeSymJson(b, symJson);
                    writeDocJson(b, idx, docJson);
                }
            }

            for (Node ref : b.refs) {
                if (ref.file != null) {
                    if (ref.file.startsWith(srcpath)) {
                        writeRefJson(ref, b, refJson);
                    }
                }
            }
        }

        for (JsonGenerator json : allJson) {
            json.writeEndArray();
            json.close();
        }
    }


    private static void info(Object msg) {
        System.out.println(msg);
    }


    private static void usage() {
        info("Usage: java org.yinwang.pysonar.dump <source-path> <include-paths> <out-root> [verbose]");
        info("  <source-path> is path to source unit (package directory or module file) that will be graphed");
        info("  <include-paths> are colon-separated paths to included libs");
        info("  <out-root> is the prefix of the output files.  There are 3 output files: <out-root>-doc, <out-root>-sym, <out-root>-ref");
        info("  [verbose] if set, then verbose logging is used (optional)");
    }


    public static void main(String[] args) throws Exception {
        if (args.length < 3 || args.length > 4) {
            usage();
            return;
        }

        log.setLevel(Level.SEVERE);
        if (args.length >= 4) {
            log.setLevel(Level.ALL);
            log.info("LOGGING VERBOSE");
            log.info("ARGS: " + Arrays.toString(args));
        }

        String srcpath = args[0];
        String[] inclpaths = args[1].split(":");
        String outroot = args[2];

        String symFilename = outroot + "-sym";
        String refFilename = outroot + "-ref";
        String docFilename = outroot + "-doc";
        OutputStream symOut = null, refOut = null, docOut = null;
        try {
            docOut = new BufferedOutputStream(new FileOutputStream(docFilename));
            symOut = new BufferedOutputStream(new FileOutputStream(symFilename));
            refOut = new BufferedOutputStream(new FileOutputStream(refFilename));
            _.msg("graphing: " + srcpath);
            graph(srcpath, inclpaths, symOut, refOut, docOut);
            docOut.flush();
            symOut.flush();
            refOut.flush();
        } catch (FileNotFoundException e) {
            System.err.println("Could not find file: " + e);
            return;
        } finally {
            if (docOut != null) {
                docOut.close();
            }
            if (symOut != null) {
                symOut.close();
            }
            if (refOut != null) {
                refOut.close();
            }
        }
        log.info("SUCCESS");
    }
}
TOP

Related Classes of org.yinwang.pysonar.JSONDump

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.