/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.core.ast.nodes;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.jface.text.Document;
import org.eclipse.php.core.PHPVersion;
import org.eclipse.php.core.project.ProjectOptions;
import org.eclipse.php.internal.core.ast.util.Util;
import java_cup.runtime.Scanner;
import java_cup.runtime.Symbol;
import java_cup.runtime.lr_parser;
/**
* A PHP language parser for creating abstract syntax trees (ASTs).
* <p>
* Example: Create basic AST from source string
*
* <pre>
* String source = ...;
* Program program = ASTParser.parse(source);
* </pre>
*/
public class ASTParser {
/**
* THREAD SAFE AST PARSER STARTS HERE
*/
private final AST ast;
private final ISourceModule sourceModule;
private ASTParser(Reader reader, PHPVersion phpVersion, boolean useASPTags, boolean useShortTags)
throws IOException {
this(reader, phpVersion, useASPTags, useShortTags, null);
}
private ASTParser(Reader reader, PHPVersion phpVersion, boolean useASPTags, boolean useShortTags,
ISourceModule sourceModule) throws IOException {
this.sourceModule = sourceModule;
this.ast = new AST(reader, phpVersion, useASPTags, useShortTags);
this.ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
// set resolve binding property and the binding resolver
if (sourceModule != null) {
this.ast.setFlag(AST.RESOLVED_BINDINGS);
// try {
this.ast.setBindingResolver(new DefaultBindingResolver(sourceModule, sourceModule.getOwner()));
// } catch (ModelException e) {
// throw new IOException("ModelException " + e.getMessage());
// }
}
}
/**
* Factory methods for ASTParser
*/
public static ASTParser newParser(PHPVersion version, boolean useShortTags) {
try {
return new ASTParser(new StringReader(""), version, false, //$NON-NLS-1$
useShortTags);
} catch (IOException e) {
assert false;
// Since we use empty reader we cannot have an IOException here
return null;
}
}
/**
* Factory methods for ASTParser
*/
public static ASTParser newParser(PHPVersion version) {
return newParser(version, true);
}
/**
* Factory methods for ASTParser
*/
public static ASTParser newParser(ISourceModule sourceModule) {
PHPVersion phpVersion = ProjectOptions.getPHPVersion(sourceModule.getScriptProject().getProject());
return newParser(phpVersion, sourceModule);
}
public static ASTParser newParser(PHPVersion version, ISourceModule sourceModule) {
if (sourceModule == null) {
throw new IllegalStateException("ASTParser - Can't parser with null ISourceModule"); //$NON-NLS-1$
}
try {
final ASTParser parser = new ASTParser(new StringReader(""), //$NON-NLS-1$
version, false, ProjectOptions.useShortTags(sourceModule.getScriptProject().getProject()),
sourceModule);
parser.setSource(sourceModule.getSourceAsCharArray());
return parser;
} catch (IOException e) {
return null;
} catch (ModelException e) {
return null;
}
}
public static ASTParser newParser(Reader reader, PHPVersion version, boolean useShortTags) throws IOException {
return new ASTParser(reader, version, false, useShortTags);
}
public static ASTParser newParser(Reader reader, PHPVersion version, boolean useASPTags, boolean useShortTags)
throws IOException {
return new ASTParser(reader, version, useASPTags, useShortTags);
}
public static ASTParser newParser(Reader reader, PHPVersion version, boolean useASPTags, ISourceModule sourceModule)
throws IOException {
return new ASTParser(reader, version, useASPTags,
ProjectOptions.useShortTags(sourceModule.getScriptProject().getProject()), sourceModule);
}
/**
* Set the raw source that will be used on parsing
*
* @throws IOException
*/
public void setSource(char[] source) throws IOException {
final CharArrayReader charArrayReader = new CharArrayReader(source);
setSource(charArrayReader);
}
/**
* Set source of the parser
*
* @throws IOException
*/
public void setSource(Reader source) throws IOException {
this.ast.setSource(source);
}
/**
* Set the source from source module
*
* @throws IOException
* @throws ModelException
*/
public void setSource(ISourceModule sourceModule) throws IOException, ModelException {
this.ast.setSource(new CharArrayReader(sourceModule.getSourceAsCharArray()));
}
/**
* This operation creates an abstract syntax tree for the given AST Factory
*
* @param progressMonitor
* @return Program that represents the equivalent AST, null if AST couldn't
* be built
* @throws Exception
* - for exception occurs on the parsing step
*/
public Program createAST(IProgressMonitor progressMonitor) throws Exception {
if (progressMonitor == null) {
progressMonitor = new NullProgressMonitor();
}
progressMonitor.beginTask("Creating Abstract Syntax Tree for source...", //$NON-NLS-1$
3);
final Scanner lexer = this.ast.lexer();
final lr_parser phpParser = this.ast.parser();
progressMonitor.worked(1);
phpParser.setScanner(lexer);
progressMonitor.worked(2);
final Symbol symbol = phpParser.parse();
progressMonitor.done();
if (symbol == null || !(symbol.value instanceof Program)) {
return null;
}
Program p = (Program) symbol.value;
AST ast = p.getAST();
p.setSourceModule(sourceModule);
if (sourceModule != null)
p.setLineEndTable(Util.lineEndTable(new Document(sourceModule.getSource())));
// now reset the ast default node flag back to differntate between
// original nodes
ast.setDefaultNodeFlag(0);
// Set the original modification count to the count after the creation
// of the Program.
// This is important to allow the AST rewriting.
ast.setOriginalModificationCount(ast.modificationCount());
return p;
}
}