nodes.functions.Statements Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsyntaxtree Show documentation
Show all versions of jsyntaxtree Show documentation
Syntax tree representation of the JASS language
The newest version!
package nodes.functions;
import interfaces.IFunctionRenameable;
import interfaces.IMergable;
import interfaces.IVariableRenameable;
import nodes.AbstractNode;
import nodes.AbstractStatement;
import exception.ParsingException;
import tree.TreeContext;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;
/**
* Represents a block of one or more generic statements
*/
public final class Statements extends AbstractNode implements IMergable, IFunctionRenameable, IVariableRenameable {
private List statements;
/**
* Sets up any class-level variables before
* performing the node reading.
*/
@Override
protected final void setupVariables() {
this.statements = new ArrayList<>();
}
/**
* Sets up this node with a scanner to receive words.
*
* @param inputScanner Scanner containing JASS code
*/
public Statements(Scanner inputScanner, TreeContext context) {
super(inputScanner, context);
}
public Statements(List statements, TreeContext context) {
super(context);
this.statements = new ArrayList<>();
this.statements.addAll(statements);
}
/**
* Renames the variable and all uses of this variable.
*
* @param oldVariableName Existing variable name
* @param newVariableName Desired variable name
*/
@Override
public final void renameVariable(String oldVariableName, String newVariableName) {
for (AbstractStatement statement : statements) {
statement.renameVariable(oldVariableName, newVariableName);
}
}
/**
* Converts the given function name into an inline function.
* Replaces usages of function
*
* @param functionName Function name to replace
* @param newText Function text to replace with
* @return Replaced statements
*/
public final Statements inline(String functionName, String newText) {
List newStatements = new ArrayList<>();
for (AbstractStatement statement : statements) {
newStatements.add((AbstractStatement) statement.inline(functionName, newText));
}
return new Statements(newStatements, context);
}
/**
* Renames a function and uses to a new name
*
* @param oldFunctionName Existing function name
* @param newFunctionName Desired function name
*/
@Override
public final void renameFunction(String oldFunctionName, String newFunctionName) {
for (AbstractStatement statement : statements) {
statement.renameFunction(oldFunctionName, newFunctionName);
}
}
/**
* Converts this node back to its original form.
* Indentation is not added.
*
* @return Original form of this node (code or string)
*/
@Override
public final String toString() {
StringBuilder built = new StringBuilder();
for (AbstractStatement statement : statements) {
built.append(statement.toString()).append("\n");
}
if (built.length() > 0) {
built.setLength(built.length() - 1);
}
return built.toString();
}
/**
* Converts this node back to its original form.
*
* @param indentationLevel Current indentation level
* @return Original form of this node (code or string) with indentation
*/
@Override
public String toFormattedString(int indentationLevel) {
StringBuilder built = new StringBuilder();
for (AbstractStatement statement : statements) {
built.append(statement.toFormattedString(indentationLevel)).append("\n");
}
if (built.length() > 0) {
built.setLength(built.length() - 1);
}
return built.toString();
}
/**
* Parse the JASS code contained in the Scanner into a model object
*/
@Override
protected final void readNode() {
boolean readingLocals = true; // set to false when any line other than locals is discovered
while (hasNextLine()) {
String line = readLine();
// Determine what type of method to read and then read it
if (line.startsWith("call ")) {
// Call statements are a single line
CallStatement statement = new CallStatement(new Scanner(line), context);
statements.add(statement);
readingLocals = false;
} else if (line.startsWith("set ")) {
// Set statements are a single line
SetStatement statement = new SetStatement(new Scanner(line), context);
statements.add(statement);
readingLocals = false;
} else if (line.startsWith("local ")) {
// Local statements are a single line AND must come at the start of the file
if (readingLocals) {
LocalStatement statement = new LocalStatement(new Scanner(line), context);
statements.add(statement);
} else {
throw new ParsingException("Locals section out of place: " + line);
}
} else if (line.startsWith("if ")) {
// If statements contain inner blocks of code
readIfStatement(line);
readingLocals = false;
} else if (line.startsWith("loop")) {
// Loop statements contain inner blocks of code
readLoopStatememt(line);
readingLocals = false;
} else if (line.startsWith("exitwhen ")) {
// Exitwhen statements exist on their own but will only be found inside loops
ExitWhenStatement statement = new ExitWhenStatement(new Scanner(line), context);
statements.add(statement);
readingLocals = false;
} else if (line.startsWith("return")) {
// There can be multiple returns in a single function.
ReturnStatement statement = new ReturnStatement(new Scanner(line), context);
statements.add(statement);
readingLocals = false;
} else {
if (!line.isEmpty()) {
throw new ParsingException("Unrecognized line in statement: " + line);
}
}
}
}
/**
* Reads from if -> endif and parses it as an IfStatement
*
* @param firstLine First line that triggered this if reading
*/
private final void readIfStatement(String firstLine) {
StringBuilder fullStatement = new StringBuilder();
fullStatement.append(firstLine).append("\n");
String newLine = "";
int ifLevel = 0;
boolean exit = false;
while (!exit) {
newLine = readLine();
fullStatement.append(newLine).append("\n");
if (newLine.startsWith("if ")) {
ifLevel++;
} else if (newLine.startsWith("endif")) {
if (ifLevel == 0) {
exit = true;
}
ifLevel--;
}
}
IfStatement ifStatement = new IfStatement(new Scanner(fullStatement.toString()), context);
statements.add(ifStatement);
}
/**
* Reads from loop -> endloop and parses it as an LoopStatement
*
* @param firstLine First line that triggered this loop reading
*/
private final void readLoopStatememt(String firstLine) {
StringBuilder fullStatement = new StringBuilder();
fullStatement.append(firstLine).append("\n");
String newLine = "";
int loopLevel = 1;
boolean exit = false;
while (!exit) {
newLine = readLine();
if (newLine.startsWith("loop")) {
loopLevel++;
} else if (newLine.startsWith("endloop")) {
loopLevel--;
if (loopLevel == 0) {
exit = true;
}
}
fullStatement.append(newLine).append("\n");
}
if (fullStatement.length() > 0) {
fullStatement.setLength(fullStatement.length() - 1);
}
LoopStatement loopStatement = new LoopStatement(new Scanner(fullStatement.toString()), context);
statements.add(loopStatement);
}
public boolean usesAsFunction(String functionName) {
List statements = getStatements();
for (AbstractStatement statement : statements) {
if (statement.usesAsFunction(functionName)) {
return true;
}
}
return false;
}
public final List getStatements() {
return Collections.unmodifiableList(statements);
}
public final List getCallStatements() {
List statementsList = new ArrayList<>();
for (AbstractStatement statement : statements) {
if (statement instanceof CallStatement) {
statementsList.add((CallStatement) statement);
}
}
return statementsList;
}
public final List getLoopStatements() {
List statementsList = new ArrayList<>();
for (AbstractStatement statement : statements) {
if (statement instanceof LoopStatement) {
statementsList.add((LoopStatement) statement);
}
}
return statementsList;
}
public final List getIfStatements() {
List statementsList = new ArrayList<>();
for (AbstractStatement statement : statements) {
if (statement instanceof IfStatement) {
statementsList.add((IfStatement) statement);
}
}
return statementsList;
}
public final List getSetStatements() {
List statementsList = new ArrayList<>();
for (AbstractStatement statement : statements) {
if (statement instanceof SetStatement) {
statementsList.add((SetStatement) statement);
}
}
return statementsList;
}
public final List getLocalStatements() {
List statementsList = new ArrayList<>();
for (AbstractStatement statement : statements) {
if (statement instanceof LocalStatement) {
statementsList.add((LocalStatement) statement);
}
}
return statementsList;
}
public final List getExitWhenStatements() {
List statementsList = new ArrayList<>();
for (AbstractStatement statement : statements) {
if (statement instanceof ExitWhenStatement) {
statementsList.add((ExitWhenStatement) statement);
}
}
return statementsList;
}
public final List getReturnStatements() {
List statementsList = new ArrayList<>();
for (AbstractStatement statement : statements) {
if (statement instanceof ReturnStatement) {
statementsList.add((ReturnStatement) statement);
}
}
return statementsList;
}
/**
* Combines this AST Node with another and then checks
* for errors. Gracefully handles function main.
*
* @param other Other AST node to combine
*/
@Override
public final void merge(AbstractNode other) {
Statements otherStatements = (Statements) other;
List newStatements = new ArrayList<>();
newStatements.addAll(this.getLocalStatements());
newStatements.addAll(otherStatements.getLocalStatements());
for (AbstractStatement statement : statements) {
if (!(statement instanceof LocalStatement)) {
newStatements.add(statement);
}
}
for (AbstractStatement statement : otherStatements.statements) {
if (!(statement instanceof LocalStatement)) {
newStatements.add(statement);
}
}
this.statements = newStatements;
}
public final List getArguments() {
List arguments = new ArrayList<>();
for(AbstractStatement statement : getStatements()) {
arguments.addAll(statement.getArguments());
}
return arguments;
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != getClass()) {
return false;
}
Statements other = (Statements) obj;
return this.toString().equals(other.toString());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy