All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.beezle.mork.mapping.Mapper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 1&1 Internet AG, http://www.1and1.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */

package net.sf.beezle.mork.mapping;

import net.sf.beezle.mork.parser.Parser;
import net.sf.beezle.mork.scanner.Position;
import net.sf.beezle.mork.semantics.Node;
import net.sf.beezle.mork.semantics.Oag;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Maps streams into Objects by scanning. Implements the analyzing parts a compiler or any other text processing
 * program: scanner, parser and attribution. Mappers don't store symbol tables because they would only be necessary
 * for visualization.
 *
 * Technically, a Mapper is a translated Mapping.
 */
public class Mapper implements Serializable {
    private final String name;
    private Parser parser;  // null: not loaded
    private Oag oag;  // undefined if not loaded
    private PrintStream logParsing;
    private PrintStream logAttribution;
    private Object environment;  // default environment is null

    /** never null */
    private ErrorHandler errorHandler;

    //--

    /** Creates a mapper with the specified name. **/
    public Mapper(String name) {
        this(name, null, null);
    }

    /**
     * Create a mapper with the specified parser and semantics. This constructor is used
     * my Mork when generating a mapper, applications will usually use Mapper(String).
     */
    public Mapper(String name, Parser parser, Oag oag) {
        this(name, parser, oag, PrintStreamErrorHandler.STDERR);
    }

    public Mapper(String name, Parser parser, Oag oag, ErrorHandler errorHandler) {
        if (errorHandler == null) {
            throw new IllegalArgumentException();
        }
        this.name = name;
        this.parser = parser;
        this.oag = oag;
        this.errorHandler = errorHandler;
        this.logParsing = null;
        this.logAttribution = null;
    }

    /**
     * Creates a new mapper instance.
     * Shares common data (esp. scanner and parser table with this instance.
     */
    public Mapper newInstance() {
        Mapper mapper;

        mapper = new Mapper(name, parser.newInstance(), oag.newInstance());
        mapper.setLogging(logParsing, logAttribution);
        return mapper;
    }

    /**
     * 

Loads the mapper tables if not already done so. This method is usually invoked implicity * by the various run methods. Don't call load explicitly unless * you want to force loading of mapper tables.

* *

I tried to load the mapper from a background Thread started in the constructor. But * the overall performance (of the jp example) was worse, probably because class loading * is to fast (and out-performes the threading overhead). * * @throws IllegalStateException to indicate a class loading problem */ public void load() { ClassLoader loader; Class c; Method m; Object[] tables; if (isLoaded()) { return; } loader = Mapper.class.getClassLoader(); try { c = loader.loadClass(name); } catch (ClassNotFoundException e) { throw new IllegalStateException(e.getMessage(), e); } try { m = c.getMethod("load", new Class[]{}); } catch (NoSuchMethodException e) { throw new IllegalStateException(e.getMessage(), e); } try { tables = (Object[]) m.invoke(null, new Object[] {}); } catch (InvocationTargetException e) { throw new IllegalStateException(e.getTargetException().getMessage(), e); } catch (IllegalAccessException e) { throw new IllegalStateException(e.getMessage(), e); } parser = (Parser) tables[0]; oag = (Oag) tables[1]; } /** * Returns true if the mapper tables have already been loaded. */ public boolean isLoaded() { return parser != null; } /** * Defines the handler to report errors to. * * @param errorHandler may be null */ public void setErrorHandler(ErrorHandler errorHandler) { if (errorHandler == null) { throw new IllegalArgumentException(); } this.errorHandler = errorHandler; } /** * Defines the environment object of the mapper. To access the environment object * from your mapper file use YourSymbols : [env];. The default environment * object is this. * * @param environment may be null */ public void setEnvironment(Object environment) { this.environment = environment; } public void setLogging(PrintStream logParsing, PrintStream logAttribution) { this.logParsing = logParsing; this.logAttribution = logAttribution; } public Parser getParser() { load(); return parser; } public Oag getSemantics() { load(); return oag; } //-- running the mapper public Object[] run(String fileName) { return run(new File(fileName)); } public Object[] run(net.sf.beezle.sushi.fs.Node node) { try { return run(node.toString(), node.createReader()); } catch (IOException e) { errorHandler.ioError(node.toString(), "cannot open stream", e); return null; } } public Object[] run(File file) { try { return run(file.toURI().toURL().toString(), new FileReader(file)); } catch (MalformedURLException e) { System.err.println("malformed file name: " + file); return null; } catch (FileNotFoundException e) { errorHandler.ioError(file.toString(), "file not found", e); return null; } } public Object[] run(String context, Reader src) { return run(new Position(context), src); } /** * Reads an stream, creates the syntax tree, computes the attributes and returns * the attributes of the start symbol. Main functionality of this class, all other * run methods use it. Reports errors to the registered errorHander; * if there is no errorHandler defined, this method defines a PrintStreamErrorHandler * for System.err. * * @param src when the method returns, src is always closed. * @return null if error an error has been reported to the error handler */ public Object[] run(Position position, Reader src) { Node node; load(); oag.setEnvironment(environment); oag.setLogging(logAttribution); parser.setErrorHandler(errorHandler); // casting is ok: the Treebuilder used in a mapper always creates Nodes node = (Node) parser.run(position, src, oag, logParsing); try { src.close(); } catch (IOException e) { // nothing I can do - a follow-up problem of a previous io exception } if (node == null) { return null; } else { return node.attrs; } } /** * Read-eval-print loop. Loop terminates if the specified end string is * entered. This method is handy to test mappers interactively. * TODO: should print all attributes returned by the mapper, * but currently, this would also print transport attributes. * * @param prompt prompt string. * @param end string to terminal real-eval-print loop; null specifies * that the loop will not be terminated. */ public void repl(String prompt, String end) { BufferedReader input; String line; Object[] result; input = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.print(prompt); try { line = input.readLine(); } catch (IOException e) { System.out.println("io error: " + e.toString()); return; } if (line == null) { // EOF (ctrl-d on unix, ctrl-c on windows) return; } if (line.equals(end)) { return; } result = run("", new StringReader(line)); if ((result != null) && (result.length > 0)) { System.out.println(result[0]); } } } @Override public String toString() { StringBuilder buf; buf = new StringBuilder(); buf.append("Parser:\n"); buf.append(parser.toString()); buf.append("Semantics:\n"); buf.append(oag.toString()); return buf.toString(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy