datascript.instance.DataScriptInstanceTool.java Source code

Java tutorial

Introduction

Here is the source code for datascript.instance.DataScriptInstanceTool.java

Source

/* BSD License
 *
 * Copyright (c) 2006, Harald Wellmann, Harman/Becker Automotive Systems
 * All rights reserved.
 * 
 * This software is derived from previous work
 * Copyright (c) 2003, Godmar Back.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 * 
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 * 
 *     * Neither the name of Harman/Becker Automotive Systems or
 *       Godmar Back nor the names of their contributors may be used to
 *       endorse or promote products derived from this software without
 *       specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package datascript.instance;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;

import javax.imageio.spi.ServiceRegistry;

import lines.LineGeometries;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.Parser;

import antlr.Token;
import antlr.TokenStreamHiddenTokenFilter;
import antlr.TokenStreamRecognitionException;
import antlr.collections.AST;
import datascript.antlr.DataScriptEmitter;
import datascript.antlr.DataScriptLexer;
import datascript.antlr.DataScriptParser;
import datascript.antlr.DataScriptParserTokenTypes;
import datascript.antlr.DataScriptWalker;
import datascript.antlr.ExpressionEvaluator;
import datascript.antlr.TypeEvaluator;
import datascript.antlr.util.FileNameToken;
import datascript.antlr.util.TokenAST;
import datascript.antlr.util.ToolContext;
import datascript.ast.DataScriptException;
import datascript.ast.Package;
import datascript.ast.ParserException;
import datascript.ast.Scope;
import datascript.runtime.io.ByteArrayBitStreamReader;
import datascript.tools.Extension;
import datascript.tools.Parameters;

public class DataScriptInstanceTool implements Parameters {
    private static final String VERSION = "edsi 0.17.2 (10 Nov 2008)";

    private ToolContext context;
    private TokenAST rootNode;
    private DataScriptParser parser;
    private final Scope globals = new Scope();
    private final HashSet<String> allPackageFiles = new HashSet<String>();

    private final DataScriptEmitter emitter = new DataScriptEmitter();

    private List<Extension> extensions;

    /* Properties for command line parameters */
    private final Options rdsOptions = new Options();
    private CommandLine cli;
    private String fileName;
    private String srcPathName;
    private String outPathName;
    private String docPathName;

    @SuppressWarnings("unused")
    private String instanceFileName;

    private String typeName;
    private boolean checkSyntax;

    private class CmdLineParser extends org.apache.commons.cli.Parser {
        /**
         * <p>This implementation of {@link Parser}'s abstract
         * {@link Parser#flatten(Options,String[],boolean) flatten} method
         * filters all arguments, that are defined in {@link Options}.
         * </p>
         * 
         * <p>
         * <b>Note:</b> <code>stopAtNonOption</code> is not used in this
         * <code>flatten</code> method.
         * </p>
         * 
         * @param options
         *            The command line {@link Option}
         * @param arguments
         *            The command line arguments to be parsed
         * @param stopAtNonOption
         *            Specifies whether to stop flattening when an non option is
         *            found.
         * @return The <code>arguments</code> String array.
         */
        protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) {
            boolean nextIsArg = false;
            List<String> newArguments = new ArrayList<String>();
            for (String argument : arguments) {
                if (nextIsArg) {
                    nextIsArg = false;
                } else {
                    if (!options.hasOption(argument))
                        continue;
                    Option opt = options.getOption(argument);
                    nextIsArg = opt.hasArg();
                }
                newArguments.add(argument);
            }

            String[] a = new String[0];
            return newArguments.toArray(a);
        }
    }

    public DataScriptInstanceTool() {
        Token token = new FileNameToken(DataScriptParserTokenTypes.ROOT, "ROOT");
        rootNode = new TokenAST(token);
    }

    public void getOptions(org.apache.commons.cli.Options rdsOptions, String[] args) {
        org.apache.commons.cli.Option rdsOption;

        rdsOption = new Option("h", "help", false, "prints this help text and exit");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);

        rdsOption = new Option("c", false, "check syntax");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);

        rdsOption = new Option("ext", true, "path to the extension directory");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);

        rdsOption = new Option("doc", true, "path to the directory in which the generated documentation is stored."
                + "currently not used in this tool");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);

        rdsOption = new Option("out", true, "path to the directory in which the generated code is stored");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);

        rdsOption = new Option("src", true, "path to DataScript source files");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);

        rdsOption = new Option("type", true, "type of instance to be parsed");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);

        rdsOption = new Option("inst", true, "path to DataScript instance file");
        rdsOption.setRequired(false);
        rdsOptions.addOption(rdsOption);
    }

    public void parseArguments(String[] args) {
        getOptions(rdsOptions, args);
        CmdLineParser parser = new CmdLineParser();
        try {
            cli = parser.parse(rdsOptions, args, true);
        } catch (org.apache.commons.cli.ParseException pe) {
            System.err.println(pe.getMessage());
        }
    }

    public boolean checkArguments() {
        if (cli == null)
            return false;

        checkSyntax = cli.hasOption('c');
        srcPathName = cli.getOptionValue("src");
        outPathName = cli.getOptionValue("out");
        docPathName = cli.getOptionValue("doc");
        typeName = cli.getOptionValue("type");
        instanceFileName = cli.getOptionValue("inst");

        //fileName = cli.getOptionValue("");

        if (outPathName == null || outPathName.length() == 0) {
            outPathName = ".";
        } else {
            outPathName = cutLastSeparatorChar(outPathName);
        }

        if (docPathName != null && docPathName.length() == 0) {
            docPathName = null;
        } else {
            docPathName = cutLastSeparatorChar(docPathName);
        }

        if (fileName == null)
            return false;
        return true;
    }

    private static String cutLastSeparatorChar(String pathName) {
        int i = pathName.length();
        while (pathName.charAt(i - 1) == File.separatorChar)
            --i;
        if (i < pathName.length())
            pathName = pathName.substring(0, i);
        return pathName;
    }

    private void prepareExtensions(String[] args)
            throws IOException, InstantiationException, IllegalAccessException {
        if (cli == null)
            return;

        // normalize slashes and backslashes
        fileName = new File(args[args.length - 1]).getPath();

        extensions = new ArrayList<Extension>();
        ServiceLoader<Extension> loader = ServiceLoader.load(Extension.class);
        Iterator<Extension> it = loader.iterator();
        while (it.hasNext()) {
            Extension extension = it.next();
            extensions.add(extension);
            extension.getOptions(rdsOptions);
        }

        CmdLineParser parser = new CmdLineParser();
        try {
            cli = parser.parse(rdsOptions, args, false);
        } catch (ParseException pe) {
            HelpFormatter hf = new HelpFormatter();
            hf.printHelp(pe.getMessage(), rdsOptions);
        }

        for (Extension extension : extensions) {
            extension.setParameters(this);
        }
    }

    public void parseDatascript() throws Exception {
        // create tool context for information exchange between pipeline
        // components
        context = ToolContext.getInstance();
        context.setFileName(fileName);
        context.setPathName(srcPathName);

        allPackageFiles.add(fileName);
        AST unitRoot = (TokenAST) parsePackage();
        if (unitRoot != null) {
            rootNode.addChild(unitRoot);
            parseImportedPackages(unitRoot);
        }

        // Validate the syntax tree - this has no side effects.
        if (checkSyntax) {
            DataScriptWalker walker = new DataScriptWalker();
            walker.root(rootNode);
            if (context.getErrorCount() != 0)
                throw new ParserException("Walker: Parser errors.");
        }

        // create name scopes and resolve references
        TypeEvaluator typeEval = new TypeEvaluator();
        typeEval.pushScope(globals);
        typeEval.root(rootNode);
        if (context.getErrorCount() != 0)
            throw new ParserException("TypeEvaluator: Parser errors.");
        Package.linkAll();
        if (ToolContext.getInstance().getErrorCount() != 0)
            throw new ParserException("TypeEvaluator: Linker errors.");

        // check expression types and evaluate constant expressions
        ExpressionEvaluator exprEval = new ExpressionEvaluator();
        exprEval.setContext(context);
        exprEval.pushScope(globals);
        exprEval.root(rootNode);
        if (context.getErrorCount() != 0)
            throw new ParserException("ExpressionEvaluator: Parser errors.");
    }

    public void emitDatascript() throws Exception {
        if (rootNode == null)
            return;

        for (Extension extension : extensions) {
            extension.generate(emitter, rootNode);
        }
    }

    private void parseImportedPackages(AST unitNode) throws Exception {
        AST node = unitNode.getFirstChild();
        if (node.getType() == DataScriptParserTokenTypes.PACKAGE) {
            while (true) {
                node = node.getNextSibling();
                if (node == null || node.getType() != DataScriptParserTokenTypes.IMPORT)
                    break;

                String fileName = getPackageFile(node);
                if (!allPackageFiles.contains(fileName)) {
                    allPackageFiles.add(fileName);
                    context.setFileName(fileName);
                    AST unitRoot = (TokenAST) parsePackage();
                    if (unitRoot != null) {
                        rootNode.addChild(unitRoot);
                        parseImportedPackages(unitRoot);
                    }
                }
            }
        }
    }

    public static String getPackageFile(AST node) {
        AST sibling = node.getFirstChild();
        String fileName = sibling.getText();
        File file = new File(fileName);
        while (true) {
            sibling = sibling.getNextSibling();
            if (sibling == null)
                break;

            file = new File(file, sibling.getText());
        }
        return file.getPath() + ".ds";
    }

    private AST parsePackage() throws Exception {
        String fileName = ToolContext.getFullName();
        System.out.println("Parsing " + fileName);

        // set up lexer, parser and token buffer
        try {
            FileInputStream is = new FileInputStream(fileName);
            DataScriptLexer lexer = new DataScriptLexer(is);
            lexer.setFilename(fileName);
            lexer.setTokenObjectClass("datascript.antlr.util.FileNameToken");
            TokenStreamHiddenTokenFilter filter = new TokenStreamHiddenTokenFilter(lexer);
            filter.discard(DataScriptParserTokenTypes.WS);
            filter.discard(DataScriptParserTokenTypes.COMMENT);
            filter.hide(DataScriptParserTokenTypes.DOC);
            parser = new DataScriptParser(filter);
        } catch (java.io.FileNotFoundException fnfe) {
            ToolContext.logError((parser == null) ? null : (TokenAST) parser.getAST(), fnfe.getMessage());
        }

        if (parser == null)
            return null;
        parser.setContext(context);

        // must call this to see file name in error messages
        parser.setFilename(fileName);

        // use custom node class containing line information
        parser.setASTNodeClass("datascript.antlr.util.TokenAST");

        // parse file and get root node of syntax tree
        parser.translationUnit();
        AST retVal = parser.getAST();
        if (context.getErrorCount() != 0 || retVal == null)
            throw new ParserException("DataScriptParser: Parser errors.");

        String pkgName = ToolContext.getFileName();
        pkgName = pkgName.substring(0, pkgName.lastIndexOf(".ds"));
        TokenAST node = (TokenAST) retVal.getFirstChild();
        if (node.getType() != DataScriptParserTokenTypes.PACKAGE || node.getText().equals(pkgName))
            ToolContext.logWarning(node, "filename and package name do not match!");
        return retVal;
    }

    private void parseInstance() throws Exception {
        //FileBitStreamReader reader = new FileBitStreamReader(instanceFileName);
        LineCreator lineCreator = new LineCreator();
        byte[] blob = lineCreator.getLines(10000, 5);
        for (int i = 0; i < 100; i++) {
            System.gc();
            ByteArrayBitStreamReader reader = new ByteArrayBitStreamReader(blob);
            AstDataScriptInstanceParser parser = new AstDataScriptInstanceParser(reader);
            LineGeometriesInstanceHandler handler = new LineGeometriesInstanceHandler();
            parser.setInstanceHandler(handler);
            //parser.setInstanceHandler(new EchoingInstanceHandler());
            long start = System.currentTimeMillis();
            parser.parse(typeName);
            long stop = System.currentTimeMillis();
            System.out.println(
                    "Building application structure from instance parser events: " + (stop - start) + " ms");
            reader.setBitPosition(0);

            ByteArrayBitStreamReader reader2 = new ByteArrayBitStreamReader(blob);
            start = System.currentTimeMillis();
            LineGeometries geometries = new LineGeometries(reader2);
            stop = System.currentTimeMillis();
            System.out.println("Building DataScript object tree: " + (stop - start) + " ms");

            start = System.currentTimeMillis();
            handler.decode(geometries);
            stop = System.currentTimeMillis();
            System.out.println("Building application structure from object tree: " + (stop - start) + " ms");

            start = System.currentTimeMillis();
            handler.decodeManually(blob);
            stop = System.currentTimeMillis();
            System.out.println("Building application structure by manual decoding: " + (stop - start) + " ms");
            System.out.println();
        }
    }

    private void printServices() {
        Iterator<Extension> it = ServiceRegistry.lookupProviders(Extension.class);
        while (it.hasNext()) {
            Extension ext = it.next();
            System.out.println(ext.getClass().getName());
        }
    }

    /******** Implementation of Parameters interface ******* */

    public String getVersion() {
        return VERSION;
    }

    public boolean getCheckSyntax() {
        return checkSyntax;
    }

    public String getPathName() {
        return srcPathName;
    }

    public String getOutPathName() {
        return outPathName;
    }

    @Override
    public String getDocPathName() {
        return docPathName;
    }

    public String getFileName() {
        return fileName;
    }

    public DataScriptParser getParser() {
        return parser;
    }

    public boolean argumentExists(String key) {
        return cli.hasOption(key);
    }

    public String getCommandLineArg(String key) {
        if (!cli.hasOption(key))
            throw new IllegalArgumentException("illegal command line argument " + key);
        return cli.getOptionValue(key);
    }

    /******** End of Parameters interface ******* */

    public static void main(String[] args) {
        System.out.println(VERSION);
        DataScriptInstanceTool dsTool = new DataScriptInstanceTool();
        dsTool.parseArguments(args);
        try {
            dsTool.prepareExtensions(args);
            if (!dsTool.checkArguments() || dsTool.cli.hasOption('h')) {
                org.apache.commons.cli.HelpFormatter hf = new org.apache.commons.cli.HelpFormatter();
                //hf.printHelp("rds <extension options> [-c] [-ext \"pathname to extensions\"] [-out \"pathname for output\"] [-src \"pathname\"] \"filename\"", dsTool.rdsOptions);
                hf.printHelp("rds <options> \"filename\"", "options are:", dsTool.rdsOptions,
                        "\t\"filename\"    main DataScript source file", false);
            } else {
                dsTool.printServices();
                dsTool.parseDatascript();
                dsTool.parseInstance();

            }
        } catch (DataScriptException exc) {
            System.err.println(exc);
        } catch (TokenStreamRecognitionException exc) {
            System.err.println(exc);
        } catch (Exception exc) {
            exc.printStackTrace();
        }
        System.out.println("done.");
    }

}