nodes.j.Script 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.j;
import interfaces.IFunctionRenameable;
import interfaces.IMergable;
import interfaces.IVariableRenameable;
import nodes.AbstractFunction;
import nodes.AbstractNode;
import exception.ParsingException;
import nodes.functions.Argument;
import nodes.functions.TypeDeclaration;
import nodes.vjass.Library;
import nodes.vjass.Scope;
import nodes.vjass.Struct;
import tree.TreeContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* Represents a .j file with a globals/functions section.
*/
public final class Script extends AbstractNode implements IMergable, IFunctionRenameable, IVariableRenameable {
private GlobalsSection globalsSection;
private FunctionsSection functionsSection;
private List types;
private List libraries;
private List scopes;
private List structs;
/**
* Sets up this node with a scanner to receive words.
*
* @param inputScanner Scanner containing JASS code
*/
public Script(Scanner inputScanner, TreeContext context) {
super(inputScanner, context);
}
public Script(GlobalsSection globalsSection, FunctionsSection functionsSection, List types, TreeContext context) {
super(context);
this.globalsSection = globalsSection;
this.functionsSection = functionsSection;
this.types = types;
}
/**
* 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 returnValue = new StringBuilder();
if(globalsSection != null) {
returnValue.append(globalsSection.toString());
returnValue.append("\n");
}
if(functionsSection != null) {
returnValue.append(functionsSection.toString());
returnValue.append("\n");
}
if(libraries != null && libraries.size() > 0) {
for(Library library : libraries) {
returnValue.append(library.toString());
returnValue.append("\n");
}
}
if(scopes != null && scopes.size() > 0) {
for(Scope scope : scopes) {
returnValue.append(scope.toString());
returnValue.append("\n");
}
}
if(structs != null && structs.size() > 0) {
for(Struct struct : structs) {
returnValue.append(struct.toString());
returnValue.append("\n");
}
}
removeFinalCharacter(returnValue);
return returnValue.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 builder = new StringBuilder();
if(globalsSection != null) {
builder.append(globalsSection.toFormattedString(indentationLevel + 1));
builder.append("\n");
}
if(functionsSection != null) {
builder.append(functionsSection.toFormattedString(indentationLevel + 1));
builder.append("\n");
}
if(libraries != null && libraries.size() > 0) {
for(Library library : libraries) {
builder.append(library.toFormattedString(indentationLevel + 1));
builder.append("\n");
}
}
if(scopes != null && scopes.size() > 0) {
for(Scope scope : scopes) {
builder.append(scope.toFormattedString(indentationLevel + 1));
builder.append("\n");
}
}
if(structs != null && structs.size() > 0) {
for(Struct struct : structs) {
builder.append(struct.toFormattedString(indentationLevel + 1));
builder.append("\n");
}
}
removeFinalCharacter(builder);
return builder.toString();
}
/**
* Parse the JASS code contained in the Scanner into a model object
*/
@Override
protected final void readNode() {
boolean readingGlobals = false; // set to true when "globals" is discovered
boolean readingFunctions = true; // set to true when "endglobals" is discovered
StringBuilder currentAccumulatedString = new StringBuilder(); // contains either the globals or endglobal section
boolean readingLibrary = false;
boolean readingScope = false;
boolean readingStruct = false;
while(hasNextLine()) {
String line = readLine();
if(line.equals("globals") && !readingLibrary && !readingScope && !readingStruct) {
// Read the entire script until endglobals
if (!readingGlobals) {
readingGlobals = true;
readingFunctions = false;
currentAccumulatedString.append(line).append("\n");
} else {
throw new ParsingException("Nested globals section not supported: " + line);
}
} else if(line.startsWith("type") && !readingLibrary && !readingScope && !readingStruct) {
if(types == null) {
types = new ArrayList<>();
}
TypeDeclaration typeDeclaration = new TypeDeclaration(new Scanner(line), context);
types.add(typeDeclaration);
} else if(line.equals("endglobals") && !readingLibrary && !readingScope && !readingStruct) {
// Read the entire script until EOF
if (readingFunctions) {
throw new ParsingException("Globals in functions section not supported: " + line);
}
if (readingGlobals) {
readingGlobals = false;
currentAccumulatedString.append(line);
// Parse the globals before resetting
this.globalsSection = new GlobalsSection(new Scanner(currentAccumulatedString.toString()), context);
currentAccumulatedString = new StringBuilder();
readingFunctions = true;
} else {
throw new ParsingException("Found endglobals before globals: " + line);
}
} else if(line.startsWith("library")) {
if(currentAccumulatedString.length() > 0) {
saveData(readingFunctions, currentAccumulatedString, readingLibrary, readingScope, readingStruct);
}
readingLibrary = true;
readingFunctions = false;
currentAccumulatedString.append(line).append("\n");
} else if(line.startsWith("endlibrary")) {
if (libraries == null) {
libraries = new ArrayList<>();
}
currentAccumulatedString.append(line);
libraries.add(new Library(new Scanner(currentAccumulatedString.toString()), context));
currentAccumulatedString.setLength(0);
readingLibrary = false;
} else if(line.startsWith("scope")) {
if(currentAccumulatedString.length() > 0) {
saveData(readingFunctions, currentAccumulatedString, readingLibrary, readingScope, readingStruct);
}
readingScope = true;
readingFunctions = false;
currentAccumulatedString.append(line).append("\n");
} else if(line.startsWith("endscope")) {
if (scopes == null) {
scopes = new ArrayList<>();
}
currentAccumulatedString.append(line);
scopes.add(new Scope(new Scanner(currentAccumulatedString.toString()), context));
currentAccumulatedString.setLength(0);
readingScope = false;
} else if(line.startsWith("struct")) {
if(currentAccumulatedString.length() > 0) {
saveData(readingFunctions, currentAccumulatedString, readingLibrary, readingScope, readingStruct);
}
readingStruct = true;
readingFunctions = false;
currentAccumulatedString.append(line).append("\n");
} else if(line.startsWith("endstruct")) {
if (structs == null) {
structs = new ArrayList<>();
}
currentAccumulatedString.append(line);
structs.add(new Struct(new Scanner(currentAccumulatedString.toString()), context));
currentAccumulatedString.setLength(0);
readingStruct = false;
} else {
currentAccumulatedString.append(line).append("\n");
}
}
saveData(readingFunctions, currentAccumulatedString, readingLibrary, readingScope, readingStruct);
}
private void saveData(boolean readingFunctions, StringBuilder currentAccumulatedString, boolean readingLibrary, boolean readingScope, boolean readingStruct) {
if (readingFunctions) {
// Finally parse the Functions
this.functionsSection = new FunctionsSection(new Scanner(currentAccumulatedString.toString()), context);
}
if (readingLibrary && currentAccumulatedString.length() > 0) {
if (libraries == null) {
libraries = new ArrayList<>();
}
libraries.add(new Library(new Scanner(currentAccumulatedString.toString()), context));
}
if (readingScope && currentAccumulatedString.length() > 0) {
if (scopes == null) {
scopes = new ArrayList<>();
}
scopes.add(new Scope(new Scanner(currentAccumulatedString.toString()), context));
}
if (readingStruct && currentAccumulatedString.length() > 0) {
if (structs == null) {
structs = new ArrayList<>();
}
structs.add(new Struct(new Scanner(currentAccumulatedString.toString()), context));
}
currentAccumulatedString.setLength(0);
}
/**
* 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) {
globalsSection.renameVariable(oldVariableName, newVariableName);
functionsSection.renameVariable(oldVariableName, newVariableName);
}
/**
* 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) {
functionsSection.renameFunction(oldFunctionName, newFunctionName);
}
public final GlobalsSection getGlobalsSection() {
return globalsSection;
}
public final FunctionsSection getFunctionsSection() {
return functionsSection;
}
/**
* 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) {
Script otherScript = (Script)other;
this.globalsSection.merge(otherScript.globalsSection);
this.functionsSection.merge(otherScript.functionsSection);
}
public final List getArguments() {
List baseArguments = new ArrayList<>();
List finalArguments = new ArrayList<>();
for(Variable variable : globalsSection.getGlobalVariables()) {
baseArguments.add(variable.getInitialValue());
}
for(AbstractFunction function : functionsSection.getFunctions()) {
baseArguments.addAll(function.getArguments());
}
for(Argument argument : baseArguments) {
if(argument != null) {
finalArguments.addAll(argument.getArguments());
}
}
return finalArguments;
}
public List getTypes() {
return types;
}
public void addFunctionMain() {
if(functionsSection == null) {
functionsSection = new FunctionsSection(new Scanner("function main takes nothing returns nothing\nendfunction"), new TreeContext());
} else {
functionsSection.addFunctionMain();
}
}
@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;
}
Script other = (Script) obj;
return this.toString().equals(other.toString());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy