AutumnParser.java
package autumn.lang.compiler;
import autumn.lang.compiler.ast.nodes.Module;
import autumn.lang.compiler.errors.IErrorReporter;
import com.google.common.base.Preconditions;
import com.mackenziehigh.autumn.lang.compiler.parser.AstBuilder;
import com.mackenziehigh.autumn.lang.compiler.parser.Parser;
import com.mackenziehigh.autumn.lang.compiler.parser.Utils;
import com.mackenziehigh.autumn.resources.Finished;
import com.mackenziehigh.snowflake.LinesAndColumns;
import com.mackenziehigh.snowflake.NewlineStyles;
import com.mackenziehigh.snowflake.ParserOutput;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
/**
* An instance of this class is a parser that can parse an Autumn module.
*
* @author Mackenzie High
*/
@Finished("2014/08/19")
public final class AutumnParser
{
/**
* This object is used to report syntax-errors.
*/
private final IErrorReporter reporter;
/**
* Constructor.
*
* @param reporter is the error-reporter to use in order to report any syntax errors.
* @throws NullPointerException if reporter is null.
*/
public AutumnParser(final IErrorReporter reporter)
{
Preconditions.checkNotNull(reporter);
this.reporter = reporter;
}
/**
* This method parses a string of Autumn source code that represents a single module.
*
* <p>
* If a syntax-error is found, then the error-reporter will be used to report the error.
* </p>
*
* @param code is the source-code itself.
* @param file denotes the location of the module, if error reporting occurs.
* @throws NullPointerException if code is null.
* @throws NullPointerException if file is null.
* @return a module created via parsing, or null, if parsing fails.
*/
public Module parse(final String code,
final URL file)
{
Preconditions.checkNotNull(code);
Preconditions.checkNotNull(file);
// Callers should not be using multiple threads to invoke this parser.
// However, this will provide some extra safety, just in case.
// Some of the code that is used to create an AST is not thread-safe.
synchronized (AutumnParser.class)
{
// The source file will be attached to each AST node.
Utils.source_file = file;
// Create the real parser.
final Parser parser = new Parser();
// Parse the source-code.
final ParserOutput output = parser.parse(code);
// If a syntax-error was detected, then report it.
if (!output.success())
{
// Detect the style of newline used within the code.
// This varies based on the platform (Windows, Linux, etc) on which the code was created.
// Code may have been created on different platforms.
// So, we will guess the newline style based on the souce-code.
// This method is more reliable than simply using the default newline style.
final NewlineStyles newline = NewlineStyles.fromGuess(code, NewlineStyles.fromSystem());
// Compute the line-numbers and column-numbers for each character in the input.
final LinesAndColumns finder = new LinesAndColumns(code.toCharArray(), newline);
// Get the line-number of where the syntax-error is located.
final int line = finder.lineNumbers()[output.lengthOfConsumption()];
// Get the column-number of where the syntax-error is located.
final int column = finder.columnNumbers()[output.lengthOfConsumption()];
// Issue the syntax-error.
reporter.reportSyntaxError(file, line, column);
// No Abstract-Syntax-Tree can be returned, because none could be created.
return null;
}
// Convert the parse-tree to an abstract-syntax-tree.
final Module module = AstBuilder.build(output.parseTree());
return module;
}
}
/**
* This method parses a string of Autumn source code that represents a single module.
*
* <p>
* If a syntax-error is found, then the error-reporter will be used to report the error.
* </p>
*
* @param code is the source-code itself.
* @param file denotes the location of the module, if error reporting occurs.
* @return a module created via parsing, or null, if parsing fails.
* @throws NullPointerException if code is null.
* @throws NullPointerException if file is null.
* @throws IllegalArgumentException if the file cannot be converted to a URL.
*/
public Module parse(final String code,
final File file)
{
Preconditions.checkNotNull(code);
Preconditions.checkNotNull(file);
try
{
final URL url = file.toURI().toURL();
final Module module = parse(code, url);
return module;
}
catch (MalformedURLException ex)
{
throw new IllegalArgumentException("Bad URL", ex);
}
}
}