org.netbeans.util.source.minify.MinifyUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.netbeans.util.source.minify.MinifyUtil.java

Source

/**
 * Copyright [2013] Gaurav Gupta
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.netbeans.util.source.minify;

import com.googlecode.htmlcompressor.compressor.HtmlCompressor;
import com.googlecode.htmlcompressor.compressor.XmlCompressor;
import com.yahoo.platform.yui.compressor.CssCompressor;
import com.yahoo.platform.yui.compressor.JavaScriptCompressor;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.mozilla.javascript.ErrorReporter;
import org.mozilla.javascript.EvaluatorException;
import org.netbeans.minify.ui.MinifyProperty;
import org.openide.filesystems.FileObject;
import org.openide.util.Exceptions;

public class MinifyUtil {

    MinifyResult minify(FileObject parentFile, MinifyProperty minifyProperty) {
        int directory = 0, cssFile = 0, jsFile = 0, htmlFile = 0, xmlFile = 0, jsonFile = 0;
        MinifyResult minifyResult = new MinifyResult();
        //        InputOutput io = IOProvider.getDefault().getIO(Bundle.CTL_Minify(), false);
        for (FileObject file : parentFile.getChildren()) {
            if (file.isFolder()) {
                directory++;
                MinifyResult preMinifyResult = minify(file, minifyProperty);
                directory = directory + preMinifyResult.getDirectories();
                cssFile = cssFile + preMinifyResult.getCssFiles();
                jsFile = jsFile + preMinifyResult.getJsFiles();
                htmlFile = htmlFile + preMinifyResult.getHtmlFiles();
                xmlFile = xmlFile + preMinifyResult.getXmlFiles();
                jsonFile = jsonFile + preMinifyResult.getJsonFiles();
                minifyResult.setInputJsFilesSize(
                        minifyResult.getInputJsFilesSize() + preMinifyResult.getInputJsFilesSize());
                minifyResult.setOutputJsFilesSize(
                        minifyResult.getOutputJsFilesSize() + preMinifyResult.getOutputJsFilesSize());
                minifyResult.setInputCssFilesSize(
                        minifyResult.getInputCssFilesSize() + preMinifyResult.getInputCssFilesSize());
                minifyResult.setOutputCssFilesSize(
                        minifyResult.getOutputCssFilesSize() + preMinifyResult.getOutputCssFilesSize());
                minifyResult.setInputHtmlFilesSize(
                        minifyResult.getInputHtmlFilesSize() + preMinifyResult.getInputHtmlFilesSize());
                minifyResult.setOutputHtmlFilesSize(
                        minifyResult.getOutputHtmlFilesSize() + preMinifyResult.getOutputHtmlFilesSize());
                minifyResult.setInputXmlFilesSize(
                        minifyResult.getInputXmlFilesSize() + preMinifyResult.getInputXmlFilesSize());
                minifyResult.setOutputXmlFilesSize(
                        minifyResult.getOutputXmlFilesSize() + preMinifyResult.getOutputXmlFilesSize());
                minifyResult.setInputJsonFilesSize(
                        minifyResult.getInputJsonFilesSize() + preMinifyResult.getInputJsonFilesSize());
                minifyResult.setOutputJsonFilesSize(
                        minifyResult.getOutputJsonFilesSize() + preMinifyResult.getOutputJsonFilesSize());

            } else if (file.getExt().equalsIgnoreCase("js") && minifyProperty.isBuildJSMinify()) {
                jsFile++;
                try {
                    Boolean allow = true;
                    String inputFilePath = file.getPath();
                    String outputFilePath;

                    if (minifyProperty.isSkipPreExtensionJS() && minifyProperty.isBuildJSMinify()
                            && minifyProperty.isNewJSFile()) {
                        if (minifyProperty.getPreExtensionJS() != null
                                && !minifyProperty.getPreExtensionJS().trim().isEmpty()
                                && file.getName().matches(".*" + Pattern.quote(
                                        minifyProperty.getSeparatorJS() + minifyProperty.getPreExtensionJS()))) {
                            allow = false;
                        }
                    }
                    if (allow) {
                        if (minifyProperty.isNewJSFile() && minifyProperty.getPreExtensionJS() != null
                                && !minifyProperty.getPreExtensionJS().trim().isEmpty()) {
                            outputFilePath = file.getParent().getPath() + File.separator + file.getName()
                                    + minifyProperty.getSeparatorJS() + minifyProperty.getPreExtensionJS() + "."
                                    + file.getExt();
                        } else {
                            outputFilePath = inputFilePath;
                        }

                        MinifyFileResult minifyFileResult = compressJavaScript(inputFilePath, outputFilePath,
                                minifyProperty);
                        minifyResult.setInputJsFilesSize(
                                minifyResult.getInputJsFilesSize() + minifyFileResult.getInputFileSize());
                        minifyResult.setOutputJsFilesSize(
                                minifyResult.getOutputJsFilesSize() + minifyFileResult.getOutputFileSize());
                    }
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            } else if (file.getExt().equalsIgnoreCase("css") && minifyProperty.isBuildCSSMinify()) {
                cssFile++;
                try {
                    Boolean allow = true;
                    String inputFilePath = file.getPath();
                    String outputFilePath;

                    if (minifyProperty.isSkipPreExtensionCSS() && minifyProperty.isBuildCSSMinify()
                            && minifyProperty.isNewCSSFile()) {
                        // String postFix = file.getName().substring(file.getName().lastIndexOf(minifyProperty.getSeparatorCSS()) + 1, file.getName().length());
                        if (minifyProperty.getPreExtensionCSS() != null
                                && !minifyProperty.getPreExtensionCSS().trim().isEmpty()
                                && file.getName().matches(".*" + Pattern.quote(
                                        minifyProperty.getSeparatorCSS() + minifyProperty.getPreExtensionCSS()))) {
                            allow = false;
                        }
                    }
                    if (allow) {
                        if (minifyProperty.isNewCSSFile() && minifyProperty.getPreExtensionCSS() != null
                                && !minifyProperty.getPreExtensionCSS().trim().isEmpty()) {
                            outputFilePath = file.getParent().getPath() + File.separator + file.getName()
                                    + minifyProperty.getSeparatorCSS() + minifyProperty.getPreExtensionCSS() + "."
                                    + file.getExt();
                        } else {
                            outputFilePath = inputFilePath;
                        }

                        MinifyFileResult minifyFileResult = compressCss(inputFilePath, outputFilePath,
                                minifyProperty);
                        minifyResult.setInputCssFilesSize(
                                minifyResult.getInputCssFilesSize() + minifyFileResult.getInputFileSize());
                        minifyResult.setOutputCssFilesSize(
                                minifyResult.getOutputCssFilesSize() + minifyFileResult.getOutputFileSize());
                    }
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            } else if (file.getExt().equalsIgnoreCase("html") && minifyProperty.isBuildHTMLMinify()) {
                htmlFile++;
                try {
                    Boolean allow = true;
                    String inputFilePath = file.getPath();
                    String outputFilePath;

                    if (minifyProperty.isSkipPreExtensionHTML() && minifyProperty.isBuildHTMLMinify()
                            && minifyProperty.isNewHTMLFile()) {
                        // String postFix = file.getName().substring(file.getName().lastIndexOf(minifyProperty.getSeparatorHTML()) + 1, file.getName().length());
                        if (minifyProperty.getPreExtensionHTML() != null
                                && !minifyProperty.getPreExtensionHTML().trim().isEmpty()
                                && file.getName().matches(".*" + Pattern.quote(minifyProperty.getSeparatorHTML()
                                        + minifyProperty.getPreExtensionHTML()))) {
                            allow = false;
                        }
                    }
                    if (allow) {
                        if (minifyProperty.isNewHTMLFile() && minifyProperty.getPreExtensionHTML() != null
                                && !minifyProperty.getPreExtensionHTML().trim().isEmpty()) {
                            outputFilePath = file.getParent().getPath() + File.separator + file.getName()
                                    + minifyProperty.getSeparatorHTML() + minifyProperty.getPreExtensionHTML() + "."
                                    + file.getExt();
                        } else {
                            outputFilePath = inputFilePath;
                        }

                        MinifyFileResult minifyFileResult = compressHtml(inputFilePath, outputFilePath,
                                minifyProperty);
                        minifyResult.setInputHtmlFilesSize(
                                minifyResult.getInputHtmlFilesSize() + minifyFileResult.getInputFileSize());
                        minifyResult.setOutputHtmlFilesSize(
                                minifyResult.getOutputHtmlFilesSize() + minifyFileResult.getOutputFileSize());
                    }
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            } else if (file.getExt().equalsIgnoreCase("xml") && minifyProperty.isBuildXMLMinify()) {
                xmlFile++;
                try {
                    Boolean allow = true;
                    String inputFilePath = file.getPath();
                    String outputFilePath;

                    if (minifyProperty.isSkipPreExtensionXML() && minifyProperty.isBuildXMLMinify()
                            && minifyProperty.isNewXMLFile()) {
                        // String postFix = file.getName().substring(file.getName().lastIndexOf(minifyProperty.getSeparatorXML()) + 1, file.getName().length());
                        if (minifyProperty.getPreExtensionXML() != null
                                && !minifyProperty.getPreExtensionXML().trim().isEmpty()
                                && file.getName().matches(".*" + Pattern.quote(
                                        minifyProperty.getSeparatorXML() + minifyProperty.getPreExtensionXML()))) {
                            allow = false;
                        }
                    }
                    if (allow) {
                        if (minifyProperty.isNewXMLFile() && minifyProperty.getPreExtensionXML() != null
                                && !minifyProperty.getPreExtensionXML().trim().isEmpty()) {
                            outputFilePath = file.getParent().getPath() + File.separator + file.getName()
                                    + minifyProperty.getSeparatorXML() + minifyProperty.getPreExtensionXML() + "."
                                    + file.getExt();
                        } else {
                            outputFilePath = inputFilePath;
                        }

                        MinifyFileResult minifyFileResult = compressXml(inputFilePath, outputFilePath,
                                minifyProperty);
                        minifyResult.setInputXmlFilesSize(
                                minifyResult.getInputXmlFilesSize() + minifyFileResult.getInputFileSize());
                        minifyResult.setOutputXmlFilesSize(
                                minifyResult.getOutputXmlFilesSize() + minifyFileResult.getOutputFileSize());
                    }
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            } else if (file.getExt().equalsIgnoreCase("json") && minifyProperty.isBuildJSONMinify()) {
                jsonFile++;
                try {
                    Boolean allow = true;
                    String inputFilePath = file.getPath();
                    String outputFilePath;

                    if (minifyProperty.isSkipPreExtensionJSON() && minifyProperty.isBuildJSONMinify()
                            && minifyProperty.isNewJSONFile()) {
                        // String postFix = file.getName().substring(file.getName().lastIndexOf(minifyProperty.getSeparatorJSON()) + 1, file.getName().length());
                        if (minifyProperty.getPreExtensionJSON() != null
                                && !minifyProperty.getPreExtensionJSON().trim().isEmpty()
                                && file.getName().matches(".*" + Pattern.quote(minifyProperty.getSeparatorJSON()
                                        + minifyProperty.getPreExtensionJSON()))) {
                            allow = false;
                        }
                    }
                    if (allow) {
                        if (minifyProperty.isNewJSONFile() && minifyProperty.getPreExtensionJSON() != null
                                && !minifyProperty.getPreExtensionJSON().trim().isEmpty()) {
                            outputFilePath = file.getParent().getPath() + File.separator + file.getName()
                                    + minifyProperty.getSeparatorJSON() + minifyProperty.getPreExtensionJSON() + "."
                                    + file.getExt();
                        } else {
                            outputFilePath = inputFilePath;
                        }

                        MinifyFileResult minifyFileResult = compressJson(inputFilePath, outputFilePath,
                                minifyProperty);
                        minifyResult.setInputJsonFilesSize(
                                minifyResult.getInputJsonFilesSize() + minifyFileResult.getInputFileSize());
                        minifyResult.setOutputJsonFilesSize(
                                minifyResult.getOutputJsonFilesSize() + minifyFileResult.getOutputFileSize());
                    }
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            } else {
                //io.getOut().println("Invalid File: " + file.getPath());
            }
        }

        minifyResult.setDirectories(directory);
        minifyResult.setCssFiles(cssFile);
        minifyResult.setJsFiles(jsFile);
        minifyResult.setHtmlFiles(htmlFile);
        minifyResult.setXmlFiles(xmlFile);
        minifyResult.setJsonFiles(jsonFile);
        return minifyResult;
    }

    public MinifyFileResult compressJavaScript(String inputFilename, String outputFilename,
            MinifyProperty minifyProperty) throws IOException {
        Reader in = null;
        Writer out = null;
        MinifyFileResult minifyFileResult = new MinifyFileResult();
        try {
            File inputFile = new File(inputFilename);
            File outputFile = new File(outputFilename);
            in = new InputStreamReader(new FileInputStream(inputFile), minifyProperty.getCharset());
            minifyFileResult.setInputFileSize(inputFile.length());

            JavaScriptCompressor compressor = new JavaScriptCompressor(in,
                    new MinifyUtil.CompressorErrorReporter());
            in.close();
            in = null;

            out = new OutputStreamWriter(new FileOutputStream(outputFile), minifyProperty.getCharset());
            compressor.compress(out, minifyProperty.getLineBreakPosition(), minifyProperty.isJsObfuscate(),
                    minifyProperty.getVerbose(), minifyProperty.isPreserveSemicolon(),
                    minifyProperty.getDisableOptimizations());
            out.flush();
            minifyFileResult.setOutputFileSize(outputFile.length());
            if (minifyProperty.isAppendLogToFile()) {
                out.append("\n/*Size: " + minifyFileResult.getInputFileSize() + "->"
                        + minifyFileResult.getOutputFileSize() + "Bytes " + "\n Saved "
                        + minifyFileResult.getSavedPercentage() + "%*/");
            }
            out.flush();

        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
        return minifyFileResult;
    }

    public void compressJavaScriptInternal(Reader in, Writer out, MinifyProperty minifyProperty)
            throws IOException {
        try {
            JavaScriptCompressor compressor = new JavaScriptCompressor(in,
                    new MinifyUtil.CompressorErrorReporter());
            in.close();
            in = null;
            compressor.compress(out, minifyProperty.getLineBreakPosition(), minifyProperty.isJsObfuscate(),
                    minifyProperty.getVerbose(), minifyProperty.isPreserveSemicolon(),
                    minifyProperty.getDisableOptimizations());
            out.flush();
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }

    public MinifyFileResult compressCss(String inputFilename, String outputFilename, MinifyProperty minifyProperty)
            throws IOException {
        Reader in = null;
        Writer out = null;
        MinifyFileResult minifyFileResult = new MinifyFileResult();
        try {
            File inputFile = new File(inputFilename);
            File outputFile = new File(outputFilename);
            in = new InputStreamReader(new FileInputStream(inputFile), minifyProperty.getCharset());
            minifyFileResult.setInputFileSize(inputFile.length());

            CssCompressor compressor = new CssCompressor(in);
            in.close();
            in = null;

            out = new OutputStreamWriter(new FileOutputStream(outputFile), minifyProperty.getCharset());
            compressor.compress(out, minifyProperty.getLineBreakPosition());
            out.flush();
            minifyFileResult.setOutputFileSize(outputFile.length());
            if (minifyProperty.isAppendLogToFile()) {
                out.append("\n/*Size: " + minifyFileResult.getInputFileSize() + "->"
                        + minifyFileResult.getOutputFileSize() + "Bytes " + "\n Saved "
                        + minifyFileResult.getSavedPercentage() + "%*/");
            }
            out.flush();

        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
        return minifyFileResult;
    }

    public void compressCssInternal(Reader in, Writer out, MinifyProperty minifyProperty) throws IOException {
        try {
            CssCompressor compressor = new CssCompressor(in);
            in.close();
            in = null;
            compressor.compress(out, minifyProperty.getLineBreakPosition());
            out.flush();
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }

    public MinifyFileResult compressHtml(String inputFilename, String outputFilename, MinifyProperty minifyProperty)
            throws IOException {
        InputStreamReader in = null;
        Writer out = null;
        MinifyFileResult minifyFileResult = new MinifyFileResult();
        try {
            File inputFile = new File(inputFilename);
            File outputFile = new File(outputFilename);
            in = new InputStreamReader(new FileInputStream(inputFile), minifyProperty.getCharset());
            minifyFileResult.setInputFileSize(inputFile.length());

            HtmlCompressor compressor = new HtmlCompressor();
            compressor.setRemoveIntertagSpaces(true);
            compressor.setCompressCss(minifyProperty.isBuildInternalCSSMinify()); //compress inline css
            compressor.setCompressJavaScript(minifyProperty.isBuildInternalJSMinify()); //compress inline javascript
            compressor.setYuiJsNoMunge(!minifyProperty.isJsObfuscate());
            //            compressor.setRemoveQuotes(true); //false may in feature             //removes unnecessary tag attribute quotes
            //compressor.setSimpleDoctype(true);   //false may in feature          //simplify existing doctype
            //compressor.setRemoveComments(true); //false may in feature           //if false keeps HTML comments (default is true)
            //compressor.setSimpleBooleanAttributes(true);  //false may in feature  //remove values from boolean tag attributes
            //compressor.setPreserveLineBreaks(true);        //preserves original line breaks

            String output = compressor.compress(fromStream(in));//out, minifyProperty.getLineBreakPosition());

            in.close();
            in = null;

            out = new OutputStreamWriter(new FileOutputStream(outputFile), minifyProperty.getCharset());
            out.write(output);

            out.flush();
            minifyFileResult.setOutputFileSize(outputFile.length());
            if (minifyProperty.isAppendLogToFile()) {
                out.append("\n<!--Size: " + minifyFileResult.getInputFileSize() + "=>"
                        + minifyFileResult.getOutputFileSize() + "Bytes " + "\n Saved "
                        + minifyFileResult.getSavedPercentage() + "%-->");
            }
            out.flush();

        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
        return minifyFileResult;
    }

    public void compressHtmlInternal(Reader in, Writer out, MinifyProperty minifyProperty) throws IOException {
        try {
            HtmlCompressor compressor = new HtmlCompressor();
            compressor.setRemoveIntertagSpaces(true);
            compressor.setCompressCss(minifyProperty.isBuildInternalCSSMinify()); //compress inline css
            compressor.setCompressJavaScript(minifyProperty.isBuildInternalJSMinify());
            compressor.setYuiJsNoMunge(!minifyProperty.isJsObfuscate());
            String output = compressor.compress(fromStream(in));//out, minifyProperty.getLineBreakPosition());
            in.close();
            in = null;
            out.write(output);
            out.flush();
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }

    public MinifyFileResult compressXml(String inputFilename, String outputFilename, MinifyProperty minifyProperty)
            throws IOException {
        InputStreamReader in = null;
        Writer out = null;
        MinifyFileResult minifyFileResult = new MinifyFileResult();
        try {
            File inputFile = new File(inputFilename);
            File outputFile = new File(outputFilename);
            in = new InputStreamReader(new FileInputStream(inputFile), minifyProperty.getCharset());
            minifyFileResult.setInputFileSize(inputFile.length());

            XmlCompressor compressor = new XmlCompressor();
            compressor.setRemoveIntertagSpaces(true);
            compressor.setRemoveComments(true);
            compressor.setEnabled(true);

            String output = compressor.compress(fromStream(in));//out, minifyProperty.getLineBreakPosition());

            in.close();
            in = null;

            out = new OutputStreamWriter(new FileOutputStream(outputFile), minifyProperty.getCharset());
            out.write(output);

            out.flush();
            minifyFileResult.setOutputFileSize(outputFile.length());
            if (minifyProperty.isAppendLogToFile()) {
                out.append("\n<!--Size: " + minifyFileResult.getInputFileSize() + "=>"
                        + minifyFileResult.getOutputFileSize() + "Bytes " + "\n Saved "
                        + minifyFileResult.getSavedPercentage() + "%-->");
            }
            out.flush();

        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
        return minifyFileResult;
    }

    public void compressXmlInternal(Reader in, Writer out, MinifyProperty minifyProperty) throws IOException {
        try {
            XmlCompressor compressor = new XmlCompressor();
            compressor.setRemoveIntertagSpaces(true);
            compressor.setRemoveComments(true);
            compressor.setEnabled(true);
            String output = compressor.compress(fromStream(in));//out, minifyProperty.getLineBreakPosition());
            in.close();
            in = null;
            out.write(output);
            out.flush();
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }

    public MinifyFileResult compressJson(String inputFilename, String outputFilename, MinifyProperty minifyProperty)
            throws IOException {
        InputStreamReader in = null;
        Writer out = null;
        MinifyFileResult minifyFileResult = new MinifyFileResult();
        try {
            File inputFile = new File(inputFilename);
            File outputFile = new File(outputFilename);
            in = new InputStreamReader(new FileInputStream(inputFile), minifyProperty.getCharset());
            minifyFileResult.setInputFileSize(inputFile.length());

            JSONMinifyUtil compressor = new JSONMinifyUtil();
            String output = compressor.minify(fromStream(in));

            in.close();
            in = null;

            out = new OutputStreamWriter(new FileOutputStream(outputFile), minifyProperty.getCharset());
            out.write(output);

            out.flush();
            minifyFileResult.setOutputFileSize(outputFile.length());
            if (minifyProperty.isAppendLogToFile()) {
                out.append("\n<!--Size: " + minifyFileResult.getInputFileSize() + "=>"
                        + minifyFileResult.getOutputFileSize() + "Bytes " + "\n Saved "
                        + minifyFileResult.getSavedPercentage() + "%-->");
            }
            out.flush();

        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
        return minifyFileResult;
    }

    public void compressJsonInternal(Reader in, Writer out, MinifyProperty minifyProperty) throws IOException {
        try {
            JSONMinifyUtil compressor = new JSONMinifyUtil();
            String output = compressor.minify(fromStream(in));
            in.close();
            in = null;
            out.write(output);
            out.flush();
        } finally {
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(out);
        }
    }

    public static String fromStream(Reader in) throws IOException {
        StringBuffer srcsb = new StringBuffer();
        int c;
        while ((c = in.read()) != -1) {
            srcsb.append((char) c);
        }

        return srcsb.toString();
    }

    /* Error Reporter */
    private static final Logger logger = Logger.getLogger(MinifyUtil.class.getName());

    private static class CompressorErrorReporter implements ErrorReporter {

        @Override
        public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) {
            if (line < 0) {
                logger.log(Level.WARNING, message);
            } else {
                logger.log(Level.WARNING, line + ':' + lineOffset + ':' + message);
            }
        }

        @Override
        public void error(String message, String sourceName, int line, String lineSource, int lineOffset) {
            if (line < 0) {
                logger.log(Level.SEVERE, message);
            } else {
                logger.log(Level.SEVERE, line + ':' + lineOffset + ':' + message);
            }
        }

        @Override
        public EvaluatorException runtimeError(String message, String sourceName, int line, String lineSource,
                int lineOffset) {
            error(message, sourceName, line, lineSource, lineOffset);
            return new EvaluatorException(message);
        }
    }
}