package de.skuzzle.polly.core.parser.ast.declarations; import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; import java.io.UnsupportedEncodingException; import de.skuzzle.polly.core.parser.InputParser; import de.skuzzle.polly.core.parser.ParseException; import de.skuzzle.polly.core.parser.ast.expressions.Assignment; import de.skuzzle.polly.core.parser.ast.expressions.Expression; import de.skuzzle.polly.core.parser.ast.visitor.ASTTraversalException; import de.skuzzle.polly.core.parser.ast.visitor.ExecutionVisitor; import de.skuzzle.polly.core.parser.ast.visitor.resolving.TypeResolver; import de.skuzzle.polly.core.parser.problems.SimpleProblemReporter; /** * Class to read assignments from a file. The assignments must be valid polly statements * and separated by lines. Any empty line or line that starts with a '#' will be skipped. * * @author Simon Taddiken */ public class DeclarationReader implements Closeable { /** * Parser subclass that changes visibility of the parseExpr method. This is used to * parse a single assignment from file. * * @author Simon Taddiken */ private final class DeclarationParser extends InputParser { public DeclarationParser(String input, String charset) throws UnsupportedEncodingException { super(input, new SimpleProblemReporter()); } @Override public Expression parseAssignment() throws ParseException { return super.parseAssignment(); } } private final String charset; private final LineNumberReader reader; private final File file; private final ExecutionVisitor executor; private final Namespace nspace; /** * Creates a new DeclarationReader. * * @param file Input file to read the declarations from. * @param charset Encoding name of that file. * @param nspace The namespace where the read declarations are stored. * @throws FileNotFoundException If <code>file</code> did not exist. */ public DeclarationReader(File file, String charset, Namespace nspace) throws FileNotFoundException { this.charset = charset; this.file = file; this.reader = new LineNumberReader(new FileReader(file)); this.nspace = nspace; this.executor = new ExecutionVisitor(nspace, nspace, new SimpleProblemReporter()); } /** * Reads all declarations from the file and stores them in the namespace. * * @throws IOException If an IO error occurs. * @see #readDeclaration */ public void readAll() throws IOException { while(this.readDeclaration()); } /** * <p>Reads the next declaration from the declaration file and stores it to the * namespace that this class was created with. If the read declaration is * invalid, it will be skipped. In this case, this method might return * <code>true</code> anyway if there are more declarations to read.</p> * * @return <code>true</code> if more declarations are to be read, <code>false</code> * if no more declarations are available. * @throws IOException If an IO error occurs. */ public boolean readDeclaration() throws IOException { String line = this.reader.readLine(); if (line == null) { return false; } else if (line.equals("") || line.startsWith("#")) { //$NON-NLS-1$ //$NON-NLS-2$ // line to be skipped return true; } final DeclarationParser p = new DeclarationParser(line, this.charset); try { final Expression exp = p.parseAssignment(); if (!(exp instanceof Assignment)) { return true; } final Assignment assign = (Assignment) exp; TypeResolver.resolveAST(assign, this.nspace, new SimpleProblemReporter()); assign.visit(this.executor); return true; } catch (ASTTraversalException e) { // skip this delcaration because it was invalid. return true; } catch (Exception e) { throw new IOException("In file: " + this.file.getName() + ", in line: " + this.reader.getLineNumber() + ": " + e.getMessage(), e); } } @Override public void close() throws IOException { if (this.reader != null) { this.reader.close(); } } }