First draft of a jass parser for some configurable ui tests

This commit is contained in:
Retera 2020-06-26 23:54:42 -04:00
parent 55dfe10034
commit 1c084e9695
52 changed files with 1275 additions and 195 deletions

View File

@ -32,7 +32,7 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvider {
private static final boolean SPIN = false;
private static final boolean ADVANCE_ANIMS = true;
private static final boolean ADVANCE_ANIMS = false;
private DataSource codebase;
private ModelViewer viewer;
private MdxModel model;
@ -69,12 +69,12 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
this.viewer.enableAudio();
final Scene scene = this.viewer.addWorldScene();
scene.enableAudio();
// scene.enableAudio();
this.cameraManager = new CameraManager();
this.cameraManager.setupCamera(scene);
this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3d\\MainMenu3d.mdx",
this.mainModel = (MdxModel) this.viewer.load("Doodads\\Cinematic\\ArthasIllidanFight\\ArthasIllidanFight.mdx",
// this.mainModel = (MdxModel) this.viewer.load("Abilities\\Spells\\Orc\\FeralSpirit\\feralspirittarget.mdx",
new PathSolver() {
@Override
@ -90,28 +90,15 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
// System.out.println(Arrays.toString(evt.keyFrames));
// System.out.println(evt.name);
this.modelCamera = this.mainModel.cameras.get(0);
this.mainInstance = (MdxComplexInstance) this.mainModel.addInstance(0);
this.mainInstance.setScene(scene);
int animIndex = 0;
for (final Sequence s : this.mainModel.getSequences()) {
if (s.getName().toLowerCase().startsWith("stand")) {
animIndex = this.mainModel.getSequences().indexOf(s);
break;
}
}
final int animIndex = 1;
this.modelCamera = this.mainModel.cameras.get(animIndex);
this.mainInstance.setSequence(animIndex);
this.mainInstance.setSequenceLoopMode(0);
final Music music = Gdx.audio
.newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\MainScreen.mp3"));
music.setVolume(0.2f);
music.setLooping(true);
music.play();
this.mainInstance.setSequenceLoopMode(4);
// acolytesHarvestingSceneJoke2(scene);
@ -365,6 +352,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
private com.etheller.warsmash.viewer5.handlers.mdx.Camera modelCamera;
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
private boolean firstFrame = true;
@Override
public void render() {
@ -375,6 +363,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
this.cameraManager.horizontalAngle = 0;
}
}
this.modelCamera = this.mainModel.cameras.get(this.mainInstance.sequence);
this.cameraManager.updateCamera();
this.viewer.updateAndRender();
@ -390,7 +379,17 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
}
if (ADVANCE_ANIMS && this.mainInstance.sequenceEnded) {
this.mainInstance.setSequence((this.mainInstance.sequence + 1) % this.mainModel.getSequences().size());
final int sequence = (this.mainInstance.sequence + 1) % this.mainModel.getSequences().size();
this.mainInstance.setSequence(sequence);
this.mainInstance.frame += (int) (Gdx.graphics.getRawDeltaTime() * 1000);
}
if (this.firstFrame) {
final Music music = Gdx.audio.newMusic(new DataSourceFileHandle(this.viewer.dataSource,
"Sound\\Ambient\\DoodadEffects\\FinalCinematic.mp3"));
music.setVolume(0.2f);
music.setLooping(true);
music.play();
this.firstFrame = false;
}
}

View File

@ -14,6 +14,7 @@ import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.GL30;
@ -37,10 +38,8 @@ import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.datasources.DataSourceDescriptor;
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.parsers.jass.Jass2;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.util.DataSourceFileHandle;
import com.etheller.warsmash.util.ImageUtils;
import com.etheller.warsmash.util.WarsmashConstants;
@ -120,6 +119,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
System.err.println("Renderer: " + renderer);
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor("E:\\Backups\\Warcraft\\Data\\127");
final FolderDataSourceDescriptor smashmpq = new FolderDataSourceDescriptor("..\\..\\resources");
// final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor(
// "D:\\NEEDS_ORGANIZING\\MPQBuild\\War3.mpq\\war3.mpq");
// final FolderDataSourceDescriptor war3xLocalmpq = new FolderDataSourceDescriptor(
@ -128,9 +128,8 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
// "E:\\Games\\Warcraft III Patch 1.31 Rebirth");
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor("E:\\Backups\\Warsmash\\Data");
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
this.codebase = new CompoundDataSourceDescriptor(
Arrays.<DataSourceDescriptor>asList(war3mpq, /* war3xLocalmpq, */ testingFolder, currentFolder))
.createDataSource();
this.codebase = new CompoundDataSourceDescriptor(Arrays.<DataSourceDescriptor>asList(war3mpq, smashmpq,
/* war3xLocalmpq, */ testingFolder, currentFolder)).createDataSource();
this.viewer = new War3MapViewer(this.codebase, this);
this.viewer.worldScene.enableAudio();
@ -232,11 +231,11 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
Gdx.input.setInputProcessor(this);
// final Music music = Gdx.audio
// .newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\DarkAgents.mp3"));
// music.setVolume(0.2f);
// music.setLooping(true);
// music.play();
final Music music = Gdx.audio
.newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\DarkAgents.mp3"));
music.setVolume(0.2f);
music.setLooping(true);
music.play();
this.minimap = new Rectangle(18.75f, 13.75f, 278.75f, 276.25f);
final float worldWidth = (this.viewer.terrain.columns - 1);
@ -255,32 +254,12 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.shapeRenderer = new ShapeRenderer();
this.talentTreeWindow = new Rectangle(100, 300, 1400, 800);
final Element skin = GameUI.loadSkin(this.viewer.dataSource, "Human");
this.gameUI = new GameUI(this.viewer.dataSource, skin, this.uiViewport);
String timeIndicatorPath = skin.getField("TimeOfDayIndicator");
if (!this.viewer.dataSource.has(timeIndicatorPath)) {
final int lastDotIndex = timeIndicatorPath.lastIndexOf('.');
if (lastDotIndex >= 0) {
timeIndicatorPath = timeIndicatorPath.substring(0, lastDotIndex);
Jass2.loadJUI(this.codebase, this.uiViewport, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
WarsmashGdxMapGame.this.gameUI = rootFrame;
}
timeIndicatorPath += ".mdx";
}
this.timeIndicator = (MdxModel) this.viewer.load(timeIndicatorPath, this.viewer.mapPathSolver,
this.viewer.solverParams);
final MdxComplexInstance timeIndicatorInstance = (MdxComplexInstance) this.timeIndicator.addInstance();
timeIndicatorInstance.setScene(this.uiScene);
timeIndicatorInstance.setSequence(0);
timeIndicatorInstance.setSequenceLoopMode(2);
try {
this.gameUI.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
}
catch (final IOException e) {
throw new RuntimeException(e);
}
this.gameUI.createSimpleFrame("ConsoleUI", this.gameUI, 0);
final UIFrame resourceBarFrame = this.gameUI.createSimpleFrame("ResourceBarFrame", this.gameUI, 0);
resourceBarFrame.addAnchor(new AnchorDefinition(FramePoint.TOPRIGHT, 0, 0));
this.gameUI.positionBounds(this.uiViewport);
}, "Scripts\\common.jui", "Scripts\\melee.jui");
}
@Override

View File

@ -0,0 +1,172 @@
package com.etheller.warsmash.parsers.jass;
import java.io.IOException;
import java.util.List;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.interpreter.JassLexer;
import com.etheller.interpreter.JassParser;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.StringJassValue;
import com.etheller.interpreter.ast.value.visitor.IntegerJassValueVisitor;
import com.etheller.interpreter.ast.value.visitor.ObjectJassValueVisitor;
import com.etheller.interpreter.ast.value.visitor.RealJassValueVisitor;
import com.etheller.interpreter.ast.value.visitor.StringJassValueVisitor;
import com.etheller.interpreter.ast.visitors.JassProgramVisitor;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.units.Element;
public class Jass2 {
public static final boolean REPORT_SYNTAX_ERRORS = true;
public static JUIEnvironment loadJUI(final DataSource dataSource, final Viewport uiViewport,
final RootFrameListener rootFrameListener, final String... files) {
final JassProgramVisitor jassProgramVisitor = new JassProgramVisitor();
final JUIEnvironment environment = new JUIEnvironment(jassProgramVisitor, dataSource, uiViewport,
rootFrameListener);
for (final String jassFile : files) {
try {
JassLexer lexer;
try {
lexer = new JassLexer(CharStreams.fromStream(dataSource.getResourceAsStream(jassFile)));
}
catch (final IOException e) {
throw new RuntimeException(e);
}
final JassParser parser = new JassParser(new CommonTokenStream(lexer));
// parser.removeErrorListener(ConsoleErrorListener.INSTANCE);
parser.addErrorListener(new BaseErrorListener() {
@Override
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol,
final int line, final int charPositionInLine, final String msg,
final RecognitionException e) {
if (!REPORT_SYNTAX_ERRORS) {
return;
}
final String sourceName = String.format("%s:%d:%d: ", jassFile, line, charPositionInLine);
System.err.println(sourceName + "line " + line + ":" + charPositionInLine + " " + msg);
}
});
jassProgramVisitor.visit(parser.program());
}
catch (final Exception e) {
e.printStackTrace();
}
}
jassProgramVisitor.getJassNativeManager().checkUnregisteredNatives();
return environment;
}
public static interface RootFrameListener {
void onCreate(GameUI rootFrame);
}
private static final class JUIEnvironment {
private GameUI gameUI;
private Element skin;
public JUIEnvironment(final JassProgramVisitor jassProgramVisitor, final DataSource dataSource,
final Viewport uiViewport, final RootFrameListener rootFrameListener) {
jassProgramVisitor.getJassNativeManager().createNative("LogError", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final String stringValue = arguments.get(0).visit(StringJassValueVisitor.getInstance());
System.err.println(stringValue);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("ConvertFramePointType", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final int value = arguments.get(0).visit(IntegerJassValueVisitor.getInstance());
return new HandleJassValue(jassProgramVisitor.getGlobals().framePointType,
FramePoint.values()[value]);
}
});
jassProgramVisitor.getJassNativeManager().createNative("CreateRootFrame", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final String skinArg = arguments.get(0).visit(StringJassValueVisitor.getInstance());
final Element skin = GameUI.loadSkin(dataSource, skinArg);
final GameUI gameUI = new GameUI(dataSource, skin, uiViewport);
JUIEnvironment.this.gameUI = gameUI;
JUIEnvironment.this.skin = skin;
rootFrameListener.onCreate(gameUI);
return new HandleJassValue(jassProgramVisitor.getGlobals().frameHandleType, gameUI);
}
});
jassProgramVisitor.getJassNativeManager().createNative("LoadTOCFile", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final String tocFileName = arguments.get(0).visit(StringJassValueVisitor.getInstance());
try {
JUIEnvironment.this.gameUI.loadTOCFile(tocFileName);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
return BooleanJassValue.TRUE;
}
});
jassProgramVisitor.getJassNativeManager().createNative("CreateSimpleFrame", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final String templateName = arguments.get(0).visit(StringJassValueVisitor.getInstance());
final UIFrame ownerFrame = arguments.get(1).visit(ObjectJassValueVisitor.<UIFrame>getInstance());
final int createContext = arguments.get(2).visit(IntegerJassValueVisitor.getInstance());
final UIFrame simpleFrame = JUIEnvironment.this.gameUI.createSimpleFrame(templateName, ownerFrame,
createContext);
return new HandleJassValue(jassProgramVisitor.getGlobals().frameHandleType, simpleFrame);
}
});
jassProgramVisitor.getJassNativeManager().createNative("FrameSetAbsPoint", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final UIFrame frame = arguments.get(0).visit(ObjectJassValueVisitor.<UIFrame>getInstance());
final FramePoint framePoint = arguments.get(1)
.visit(ObjectJassValueVisitor.<FramePoint>getInstance());
final double x = arguments.get(2).visit(RealJassValueVisitor.getInstance());
final double y = arguments.get(3).visit(RealJassValueVisitor.getInstance());
frame.addAnchor(new AnchorDefinition(framePoint, GameUI.convertX(uiViewport, (float) x),
GameUI.convertY(uiViewport, (float) y)));
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("FramePositionBounds", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final UIFrame frame = arguments.get(0).visit(ObjectJassValueVisitor.<UIFrame>getInstance());
frame.positionBounds(uiViewport);
return null;
}
});
jassProgramVisitor.getJassNativeManager().createNative("SkinGetField", new JassFunction() {
@Override
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
final String fieldName = arguments.get(0).visit(StringJassValueVisitor.getInstance());
return new StringJassValue(JUIEnvironment.this.skin.getField(fieldName));
}
});
}
}
}

View File

@ -283,7 +283,7 @@ public class ModelViewer {
}
public void update() {
final float dt = this.frameTime * 0.001f;
final float dt = Gdx.graphics.getRawDeltaTime();// this.frameTime * 0.001f;
this.frame += 1;

View File

@ -55,6 +55,8 @@ public abstract class RawOpenGLTextureResource extends Texture {
@Override
public void internalBind() {
this.viewer.gl.glBindTexture(this.target, this.handle);
this.viewer.gl.glTexParameteri(this.target, GL20.GL_TEXTURE_WRAP_S, this.wrapS);
this.viewer.gl.glTexParameteri(this.target, GL20.GL_TEXTURE_WRAP_T, this.wrapT);
}
@Override
@ -81,19 +83,12 @@ public abstract class RawOpenGLTextureResource extends Texture {
public void setWrapS(final boolean wrapS) {
this.wrapS = wrapS ? GL20.GL_REPEAT : GL20.GL_CLAMP_TO_EDGE;
final GL20 gl = this.viewer.gl;
gl.glBindTexture(this.target, this.handle);
gl.glTexParameteri(this.target, GL20.GL_TEXTURE_WRAP_S, this.wrapS);
}
@Override
public void setWrapT(final boolean wrapT) {
this.wrapT = wrapT ? GL20.GL_REPEAT : GL20.GL_CLAMP_TO_EDGE;
final GL20 gl = this.viewer.gl;
gl.glBindTexture(this.target, this.handle);
gl.glTexParameteri(this.target, GL20.GL_TEXTURE_WRAP_T, this.wrapT);
}
public void update(final BufferedImage image) {

View File

@ -522,7 +522,7 @@ public class MdxComplexInstance extends ModelInstance {
if (sequenceId != -1) {
final Sequence sequence = model.sequences.get(sequenceId);
final long[] interval = sequence.getInterval();
final int frameTime = model.viewer.frameTime;
final int frameTime = (int) (dt * 1000);
this.frame += frameTime;
this.counter += frameTime;
@ -534,6 +534,16 @@ public class MdxComplexInstance extends ModelInstance {
this.resetEventEmitters();
}
else if (this.sequenceLoopMode == 4) { // faux queued animation mode
final int framesPast = this.frame - (int) interval[1];
final List<Sequence> sequences = model.sequences;
this.sequence = (this.sequence + 1) % sequences.size();
this.frame = (int) sequences.get(this.sequence).getInterval()[0] + framesPast; // TODO not cast
this.sequenceEnded = false;
this.resetEventEmitters();
this.forced = true;
}
else {
this.frame = (int) interval[1]; // TODO not cast
this.counter -= frameTime;

View File

@ -156,14 +156,12 @@ public class MdxModel extends com.etheller.warsmash.viewer5.Model<MdxHandler> {
final Texture viewerTexture = (Texture) viewer.load(path, pathSolver, solverParams);
// When the texture will load, it will apply its wrap modes.
if (!viewerTexture.loaded) {
if ((flags & 0x1) != 0) {
viewerTexture.setWrapS(true);
}
if ((flags & 0x1) != 0) {
viewerTexture.setWrapS(true);
}
if ((flags & 0x2) != 0) {
viewerTexture.setWrapT(true);
}
if ((flags & 0x2) != 0) {
viewerTexture.setWrapT(true);
}
this.replaceables.add(replaceableId);

View File

@ -7,7 +7,7 @@ import org.lwjgl.opengl.GL33;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.etheller.warsmash.WarsmashGdxMapGame;
import com.etheller.warsmash.WarsmashGdxGame;
import com.etheller.warsmash.viewer5.gl.ANGLEInstancedArrays;
import com.etheller.warsmash.viewer5.gl.DynamicShadowExtension;
import com.etheller.warsmash.viewer5.gl.Extensions;
@ -62,6 +62,6 @@ public class DesktopLauncher {
// final DisplayMode desktopDisplayMode = LwjglApplicationConfiguration.getDesktopDisplayMode();
// config.width = desktopDisplayMode.width;
// config.height = desktopDisplayMode.height;
new LwjglApplication(new WarsmashGdxMapGame(), config);
new LwjglApplication(new WarsmashGdxGame(), config);
}
}

View File

@ -26,13 +26,13 @@ type :
|
ID ARRAY # ArrayType
|
'nothing' # NothingType
NOTHING # NothingType
;
global :
type ID newlines # BasicGlobal
CONSTANT? type ID newlines # BasicGlobal
|
type ID assignTail newlines # DefinitionGlobal
CONSTANT? type ID assignTail newlines # DefinitionGlobal
;
assignTail:
@ -58,18 +58,20 @@ expression:
functionExpression # FunctionCallExpression
|
'(' expression ')' # ParentheticalExpression
|
NOT expression # NotExpression
;
functionExpression:
ID '(' argsList ')'
|
ID '(' ')'
;
argsList:
expression # SingleArgument
|
expression ',' argsList # ListArgument
|
#EmptyArgument
;
//#booleanExpression:
@ -84,6 +86,16 @@ statement:
SET ID '[' expression ']' EQUALS expression newlines # ArrayedAssignmentStatement
|
RETURN expression newlines # ReturnStatement
|
IF ifStatementPartial # IfStatement
;
ifStatementPartial:
expression THEN newlines statements ENDIF newlines # SimpleIfStatement
|
expression THEN newlines statements ELSE newlines statements ENDIF newlines # IfElseStatement
|
expression THEN newlines statements ELSEIF ifStatementPartial # IfElseIfStatement
;
param:
@ -94,7 +106,7 @@ paramList:
|
param ',' paramList # ListParameter
|
'nothing' # NothingParameter
NOTHING # NothingParameter
;
globalsBlock :
@ -105,7 +117,7 @@ typeDefinitionBlock :
;
nativeBlock:
NATIVE ID TAKES paramList RETURNS type newlines
CONSTANT? NATIVE ID TAKES paramList RETURNS type newlines
;
block:
@ -115,20 +127,30 @@ block:
;
functionBlock:
FUNCTION ID TAKES paramList RETURNS type newlines (statement)* ENDFUNCTION newlines
FUNCTION ID TAKES paramList RETURNS type newlines statements ENDFUNCTION newlines
;
statements:
(statement)*
;
newlines:
NEWLINES
pnewlines
|
EOF;
newlines_opt:
NEWLINES
pnewlines
|
EOF
|
;
pnewlines:
NEWLINE
|
NEWLINE newlines
;
EQUALS : '=';
@ -142,6 +164,7 @@ FUNCTION : 'function' ; // function
TAKES : 'takes' ; // takes
RETURNS : 'returns' ;
ENDFUNCTION : 'endfunction' ; // endfunction
NOTHING : 'nothing' ;
CALL : 'call' ;
SET : 'set' ;
@ -153,6 +176,13 @@ TYPE : 'type';
EXTENDS : 'extends';
IF : 'if';
THEN : 'then';
ELSE : 'else';
ENDIF : 'endif';
ELSEIF : 'elseif';
CONSTANT : 'constant';
STRING_LITERAL : ('"'.*?'"');
INTEGER : [0]|([1-9][0-9]*) ;
@ -161,9 +191,10 @@ NULL : 'null' ;
TRUE : 'true' ;
FALSE : 'false' ;
NOT : 'not';
ID : ([a-zA-Z_][a-zA-Z_0-9]*) ; // match identifiers
WS : [ \t]+ -> skip ; // skip spaces, tabs
NEWLINES : NEWLINE+;
fragment NEWLINE : '\r' '\n' | '\n' | '\r' | ('//'.*?'\n');
NEWLINE : '//'.*?'\r\n' | '//'.*?'\n' | '//'.*?'\r' | '\r' '\n' | '\n' | '\r';

View File

@ -13,17 +13,18 @@ public class Assignable {
}
public void setValue(final JassValue value) {
if (value.visit(JassTypeGettingValueVisitor.getInstance()) != type) {
throw new RuntimeException("Incompatible types");
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
if (!this.type.isAssignableFrom(valueType)) {
throw new RuntimeException("Incompatible types " + valueType.getName() + " != " + this.type.getName());
}
this.value = value;
}
public JassValue getValue() {
return value;
return this.value;
}
public JassType getType() {
return type;
return this.type;
}
}

View File

@ -0,0 +1,20 @@
package com.etheller.interpreter.ast.expression;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.BooleanJassValueVisitor;
import com.etheller.interpreter.ast.value.visitor.NotJassValueVisitor;
public class NotJassExpression implements JassExpression {
private final JassExpression expression;
public NotJassExpression(final JassExpression expression) {
this.expression = expression;
}
@Override
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope) {
return this.expression.evaluate(globalScope, localScope).visit(NotJassValueVisitor.getInstance());
}
}

View File

@ -6,6 +6,7 @@ import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassType;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.JassTypeGettingValueVisitor;
/**
* Not a native
@ -24,15 +25,19 @@ public abstract class AbstractJassFunction implements JassFunction {
@Override
public final JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
if (arguments.size() != parameters.size()) {
if (arguments.size() != this.parameters.size()) {
throw new RuntimeException("Invalid number of arguments passed to function");
}
final LocalScope localScope = new LocalScope();
for (int i = 0; i < parameters.size(); i++) {
final JassParameter parameter = parameters.get(i);
for (int i = 0; i < this.parameters.size(); i++) {
final JassParameter parameter = this.parameters.get(i);
final JassValue argument = arguments.get(i);
if (!parameter.matchesType(argument)) {
throw new RuntimeException("Invalid type for specified argument");
System.err.println(
parameter.getType() + " != " + argument.visit(JassTypeGettingValueVisitor.getInstance()));
throw new RuntimeException(
"Invalid type " + argument.visit(JassTypeGettingValueVisitor.getInstance()).getName()
+ " for specified argument " + parameter.getType().getName());
}
localScope.createLocal(parameter.getIdentifier(), parameter.getType(), argument);
}

View File

@ -17,6 +17,10 @@ public class JassNativeManager {
this.nameToNativeCode = new HashMap<>();
}
public void createNative(final String name, final JassFunction nativeCode) {
this.nameToNativeCode.put(name, nativeCode);
}
public void registerNativeCode(final String name, final List<JassParameter> parameters, final JassType returnType,
final GlobalScope globals) {
if (this.registeredNativeNames.contains(name)) {

View File

@ -14,14 +14,15 @@ public class JassParameter {
}
public String getIdentifier() {
return identifier;
return this.identifier;
}
public JassType getType() {
return type;
return this.type;
}
public boolean matchesType(final JassValue value) {
return type == value.visit(JassTypeGettingValueVisitor.getInstance());
final JassType valueType = value.visit(JassTypeGettingValueVisitor.getInstance());
return this.type.isAssignableFrom(valueType);
}
}

View File

@ -7,34 +7,74 @@ import com.etheller.interpreter.ast.Assignable;
import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.value.ArrayJassType;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.JassType;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.PrimitiveJassType;
import com.etheller.interpreter.ast.value.visitor.ArrayPrimitiveTypeVisitor;
import com.etheller.interpreter.ast.value.visitor.HandleJassTypeVisitor;
import com.etheller.interpreter.ast.value.visitor.HandleTypeSuperTypeLoadingVisitor;
public final class GlobalScope {
private final Map<String, Assignable> globals = new HashMap<>();
private final Map<String, JassFunction> functions = new HashMap<>();
private final Map<String, JassType> types = new HashMap<>();
private final HandleTypeSuperTypeLoadingVisitor handleTypeSuperTypeLoadingVisitor = new HandleTypeSuperTypeLoadingVisitor();
public final HandleJassType handleType;
public final HandleJassType frameHandleType;
public final HandleJassType framePointType;
private static int lineNumber;
public GlobalScope() {
this.handleType = registerHandleType("handle");// the handle type
this.frameHandleType = registerHandleType("framehandle");
this.framePointType = registerHandleType("framepointtype");
registerPrimitiveType(JassType.BOOLEAN);
registerPrimitiveType(JassType.INTEGER);
registerPrimitiveType(JassType.CODE);
registerPrimitiveType(JassType.NOTHING);
registerPrimitiveType(JassType.REAL);
registerPrimitiveType(JassType.STRING);
}
public static void setLineNumber(final int lineNo) {
lineNumber = lineNo;
}
public static int getLineNumber() {
return lineNumber;
}
private HandleJassType registerHandleType(final String name) {
final HandleJassType handleJassType = new HandleJassType(null, name);
this.types.put(name, handleJassType);
return handleJassType;
}
private void registerPrimitiveType(final PrimitiveJassType type) {
this.types.put(type.getName(), type);
}
public void createGlobalArray(final String name, final JassType type) {
final Assignable assignable = new Assignable(type);
assignable.setValue(new ArrayJassValue((ArrayJassType) type)); // TODO less bad code
globals.put(name, assignable);
this.globals.put(name, assignable);
}
public void createGlobal(final String name, final JassType type) {
globals.put(name, new Assignable(type));
this.globals.put(name, new Assignable(type));
}
public void createGlobal(final String name, final JassType type, final JassValue value) {
final Assignable assignable = new Assignable(type);
assignable.setValue(value);
globals.put(name, assignable);
this.globals.put(name, assignable);
}
public void setGlobal(final String name, final JassValue value) {
final Assignable assignable = globals.get(name);
final Assignable assignable = this.globals.get(name);
if (assignable == null) {
throw new RuntimeException("Undefined global: " + name);
}
@ -45,7 +85,7 @@ public final class GlobalScope {
}
public JassValue getGlobal(final String name) {
final Assignable global = globals.get(name);
final Assignable global = this.globals.get(name);
if (global == null) {
throw new RuntimeException("Undefined global: " + name);
}
@ -53,42 +93,51 @@ public final class GlobalScope {
}
public Assignable getAssignableGlobal(final String name) {
return globals.get(name);
return this.globals.get(name);
}
public void defineFunction(final String name, final JassFunction function) {
functions.put(name, function);
this.functions.put(name, function);
}
public JassFunction getFunctionByName(final String name) {
return functions.get(name);
return this.functions.get(name);
}
public PrimitiveJassType parseType(final String text) {
if (text.equals("string")) {
return JassType.STRING;
} else if (text.equals("integer")) {
return JassType.INTEGER;
} else if (text.equals("boolean")) {
return JassType.BOOLEAN;
} else if (text.equals("real")) {
return JassType.REAL;
} else if (text.equals("code")) {
return JassType.CODE;
} else if (text.equals("nothing")) {
return JassType.NOTHING;
} else {
public JassType parseType(final String text) {
final JassType type = this.types.get(text);
if (type != null) {
return type;
}
else {
throw new RuntimeException("Unknown type: " + text);
}
}
public JassType parseArrayType(final String primitiveTypeName) {
final String arrayTypeName = primitiveTypeName + " array";
JassType arrayType = types.get(arrayTypeName);
JassType arrayType = this.types.get(arrayTypeName);
if (arrayType == null) {
arrayType = new ArrayJassType(parseType(primitiveTypeName));
types.put(arrayTypeName, arrayType);
this.types.put(arrayTypeName, arrayType);
}
return arrayType;
}
public void loadTypeDefinition(final String type, final String supertype) {
final JassType superType = this.types.get(supertype);
if (superType != null) {
final HandleJassType handleSuperType = superType.visit(HandleJassTypeVisitor.getInstance());
if (handleSuperType != null) {
final JassType jassType = this.types.get(type);
jassType.visit(this.handleTypeSuperTypeLoadingVisitor.reset(handleSuperType));
}
else {
throw new RuntimeException("type " + type + " cannot extend primitive type " + supertype);
}
}
else {
throw new RuntimeException("type " + type + " cannot extend unknown type " + supertype);
}
}
}

View File

@ -11,17 +11,17 @@ public final class LocalScope {
private final Map<String, Assignable> locals = new HashMap<>();
public void createLocal(final String name, final JassType type) {
locals.put(name, new Assignable(type));
this.locals.put(name, new Assignable(type));
}
public void createLocal(final String name, final JassType type, final JassValue value) {
final Assignable assignable = new Assignable(type);
assignable.setValue(value);
locals.put(name, assignable);
this.locals.put(name, assignable);
}
public void setLocal(final String name, final JassValue value) {
final Assignable assignable = locals.get(name);
final Assignable assignable = this.locals.get(name);
if (assignable == null) {
throw new RuntimeException("Undefined local variable: " + name);
}
@ -29,7 +29,7 @@ public final class LocalScope {
}
public JassValue getLocal(final String name) {
final Assignable local = locals.get(name);
final Assignable local = this.locals.get(name);
if (local == null) {
throw new RuntimeException("Undefined local variable: " + name);
}
@ -37,6 +37,6 @@ public final class LocalScope {
}
public Assignable getAssignableLocal(final String name) {
return locals.get(name);
return this.locals.get(name);
}
}

View File

@ -13,9 +13,11 @@ public class JassArrayedAssignmentStatement implements JassStatement {
private final String identifier;
private final JassExpression indexExpression;
private final JassExpression expression;
private final int lineNo;
public JassArrayedAssignmentStatement(final String identifier, final JassExpression indexExpression,
final JassExpression expression) {
public JassArrayedAssignmentStatement(final int lineNo, final String identifier,
final JassExpression indexExpression, final JassExpression expression) {
this.lineNo = lineNo;
this.identifier = identifier;
this.indexExpression = indexExpression;
this.expression = expression;
@ -23,10 +25,11 @@ public class JassArrayedAssignmentStatement implements JassStatement {
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
Assignable variable = localScope.getAssignableLocal(identifier);
final JassValue index = indexExpression.evaluate(globalScope, localScope);
globalScope.setLineNumber(this.lineNo);
Assignable variable = localScope.getAssignableLocal(this.identifier);
final JassValue index = this.indexExpression.evaluate(globalScope, localScope);
if (variable == null) {
variable = globalScope.getAssignableGlobal(identifier);
variable = globalScope.getAssignableGlobal(this.identifier);
}
if (variable.getValue() == null) {
throw new RuntimeException("Unable to assign uninitialized array");
@ -34,8 +37,9 @@ public class JassArrayedAssignmentStatement implements JassStatement {
final ArrayJassValue arrayValue = variable.getValue().visit(ArrayJassValueVisitor.getInstance());
if (arrayValue != null) {
arrayValue.set(index.visit(IntegerJassValueVisitor.getInstance()),
expression.evaluate(globalScope, localScope));
} else {
this.expression.evaluate(globalScope, localScope));
}
else {
throw new RuntimeException("Not an array");
}
return null;

View File

@ -10,22 +10,25 @@ import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassValue;
public class JassCallStatement implements JassStatement {
private final int lineNo;
private final String functionName;
private final List<JassExpression> arguments;
public JassCallStatement(final String functionName, final List<JassExpression> arguments) {
public JassCallStatement(final int lineNo, final String functionName, final List<JassExpression> arguments) {
this.lineNo = lineNo;
this.functionName = functionName;
this.arguments = arguments;
}
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
final JassFunction functionByName = globalScope.getFunctionByName(functionName);
globalScope.setLineNumber(this.lineNo);
final JassFunction functionByName = globalScope.getFunctionByName(this.functionName);
if (functionByName == null) {
throw new RuntimeException("Undefined function: " + functionName);
throw new RuntimeException("Undefined function: " + this.functionName);
}
final List<JassValue> evaluatedExpressions = new ArrayList<>();
for (final JassExpression expr : arguments) {
for (final JassExpression expr : this.arguments) {
final JassValue evaluatedExpression = expr.evaluate(globalScope, localScope);
evaluatedExpressions.add(evaluatedExpression);
}

View File

@ -0,0 +1,42 @@
package com.etheller.interpreter.ast.statement;
import java.util.List;
import com.etheller.interpreter.ast.expression.JassExpression;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.BooleanJassValueVisitor;
public class JassIfElseIfStatement implements JassStatement {
private final int lineNo;
private final JassExpression condition;
private final List<JassStatement> thenStatements;
private final JassStatement elseifTail;
public JassIfElseIfStatement(final int lineNo, final JassExpression condition,
final List<JassStatement> thenStatements, final JassStatement elseifTail) {
this.lineNo = lineNo;
this.condition = condition;
this.thenStatements = thenStatements;
this.elseifTail = elseifTail;
}
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
globalScope.setLineNumber(this.lineNo);
if (this.condition.evaluate(globalScope, localScope).visit(BooleanJassValueVisitor.getInstance())) {
for (final JassStatement statement : this.thenStatements) {
final JassValue returnValue = statement.execute(globalScope, localScope);
if (returnValue != null) {
return returnValue;
}
}
}
else {
return this.elseifTail.execute(globalScope, localScope);
}
return null;
}
}

View File

@ -0,0 +1,47 @@
package com.etheller.interpreter.ast.statement;
import java.util.List;
import com.etheller.interpreter.ast.expression.JassExpression;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.BooleanJassValueVisitor;
public class JassIfElseStatement implements JassStatement {
private final int lineNo;
private final JassExpression condition;
private final List<JassStatement> thenStatements;
private final List<JassStatement> elseStatements;
public JassIfElseStatement(final int lineNo, final JassExpression condition,
final List<JassStatement> thenStatements, final List<JassStatement> elseStatements) {
this.lineNo = lineNo;
this.condition = condition;
this.thenStatements = thenStatements;
this.elseStatements = elseStatements;
}
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
globalScope.setLineNumber(this.lineNo);
if (this.condition.evaluate(globalScope, localScope).visit(BooleanJassValueVisitor.getInstance())) {
for (final JassStatement statement : this.thenStatements) {
final JassValue returnValue = statement.execute(globalScope, localScope);
if (returnValue != null) {
return returnValue;
}
}
}
else {
for (final JassStatement statement : this.elseStatements) {
final JassValue returnValue = statement.execute(globalScope, localScope);
if (returnValue != null) {
return returnValue;
}
}
}
return null;
}
}

View File

@ -0,0 +1,44 @@
package com.etheller.interpreter.ast.statement;
import java.util.List;
import com.etheller.interpreter.ast.expression.JassExpression;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.visitor.BooleanJassValueVisitor;
public class JassIfStatement implements JassStatement {
private final int lineNo;
private final JassExpression condition;
private final List<JassStatement> thenStatements;
public JassIfStatement(final int lineNo, final JassExpression condition, final List<JassStatement> thenStatements) {
this.lineNo = lineNo;
this.condition = condition;
this.thenStatements = thenStatements;
}
public JassExpression getCondition() {
return this.condition;
}
public List<JassStatement> getThenStatements() {
return this.thenStatements;
}
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
globalScope.setLineNumber(this.lineNo);
if (this.condition.evaluate(globalScope, localScope).visit(BooleanJassValueVisitor.getInstance())) {
for (final JassStatement statement : this.thenStatements) {
final JassValue returnValue = statement.execute(globalScope, localScope);
if (returnValue != null) {
return returnValue;
}
}
}
return null;
}
}

View File

@ -6,15 +6,18 @@ import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassValue;
public class JassReturnStatement implements JassStatement {
private final int lineNo;
private final JassExpression expression;
public JassReturnStatement(final JassExpression expression) {
public JassReturnStatement(final int lineNo, final JassExpression expression) {
this.lineNo = lineNo;
this.expression = expression;
}
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
return expression.evaluate(globalScope, localScope);
globalScope.setLineNumber(this.lineNo);
return this.expression.evaluate(globalScope, localScope);
}
}

View File

@ -7,21 +7,25 @@ import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassValue;
public class JassSetStatement implements JassStatement {
private final int lineNo;
private final String identifier;
private final JassExpression expression;
public JassSetStatement(final String identifier, final JassExpression expression) {
public JassSetStatement(final int lineNo, final String identifier, final JassExpression expression) {
this.lineNo = lineNo;
this.identifier = identifier;
this.expression = expression;
}
@Override
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
final Assignable local = localScope.getAssignableLocal(identifier);
globalScope.setLineNumber(this.lineNo);
final Assignable local = localScope.getAssignableLocal(this.identifier);
if (local != null) {
local.setValue(expression.evaluate(globalScope, localScope));
} else {
globalScope.setGlobal(identifier, expression.evaluate(globalScope, localScope));
local.setValue(this.expression.evaluate(globalScope, localScope));
}
else {
globalScope.setGlobal(this.identifier, this.expression.evaluate(globalScope, localScope));
}
return null;
}

View File

@ -1,14 +1,26 @@
package com.etheller.interpreter.ast.value;
public class ArrayJassType implements JassType {
private final PrimitiveJassType primitiveType;
private final JassType primitiveType;
private final String name;
public ArrayJassType(final PrimitiveJassType primitiveType) {
public ArrayJassType(final JassType primitiveType) {
this.primitiveType = primitiveType;
this.name = primitiveType.getName() + " array";
}
public PrimitiveJassType getPrimitiveType() {
return primitiveType;
@Override
public boolean isAssignableFrom(final JassType value) {
return value == this;
}
public JassType getPrimitiveType() {
return this.primitiveType;
}
@Override
public String getName() {
return this.name;
}
@Override

View File

@ -1,6 +1,9 @@
package com.etheller.interpreter.ast.value;
public class BooleanJassValue implements JassValue {
public static final BooleanJassValue TRUE = new BooleanJassValue(true);
public static final BooleanJassValue FALSE = new BooleanJassValue(false);
private final boolean value;
public BooleanJassValue(final boolean value) {
@ -8,11 +11,20 @@ public class BooleanJassValue implements JassValue {
}
public boolean getValue() {
return value;
return this.value;
}
@Override
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
return visitor.accept(this);
}
public static BooleanJassValue inverse(final BooleanJassValue value) {
if (value.value) {
return FALSE;
}
else {
return TRUE;
}
}
}

View File

@ -0,0 +1,43 @@
package com.etheller.interpreter.ast.value;
import com.etheller.interpreter.ast.value.visitor.SuperTypeVisitor;
public class HandleJassType implements JassType {
private HandleJassType superType;
private final String name;
public HandleJassType(final HandleJassType superType, final String name) {
this.superType = superType;
this.name = name;
}
@Override
public boolean isAssignableFrom(JassType valueType) {
while (valueType != null) {
if (this == valueType) {
return true;
}
valueType = valueType.visit(SuperTypeVisitor.getInstance());
}
return false;
}
@Override
public String getName() {
return this.name;
}
public HandleJassType getSuperType() {
return this.superType;
}
public void setSuperType(final HandleJassType superType) {
this.superType = superType;
}
@Override
public <TYPE> TYPE visit(final JassTypeVisitor<TYPE> visitor) {
return visitor.accept(this);
}
}

View File

@ -0,0 +1,25 @@
package com.etheller.interpreter.ast.value;
public class HandleJassValue implements JassValue {
private final HandleJassType type;
private final Object javaValue;
public HandleJassValue(final HandleJassType type, final Object javaValue) {
this.type = type;
this.javaValue = javaValue;
}
public HandleJassType getType() {
return this.type;
}
public Object getJavaValue() {
return this.javaValue;
}
@Override
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
return visitor.accept(this);
}
}

View File

@ -3,10 +3,14 @@ package com.etheller.interpreter.ast.value;
public interface JassType {
<TYPE> TYPE visit(JassTypeVisitor<TYPE> visitor);
String getName(); // used for error messages
boolean isAssignableFrom(JassType value);
public static final PrimitiveJassType INTEGER = new PrimitiveJassType("integer");
public static final PrimitiveJassType STRING = new PrimitiveJassType("string");
public static final PrimitiveJassType CODE = new PrimitiveJassType("code");
public static final PrimitiveJassType REAL = new PrimitiveJassType("real");
public static final PrimitiveJassType REAL = new RealJassType("real");
public static final PrimitiveJassType BOOLEAN = new PrimitiveJassType("boolean");
public static final PrimitiveJassType NOTHING = new PrimitiveJassType("nothing");
}

View File

@ -4,4 +4,6 @@ public interface JassTypeVisitor<TYPE> {
TYPE accept(PrimitiveJassType primitiveType);
TYPE accept(ArrayJassType arrayType);
TYPE accept(HandleJassType type);
}

View File

@ -12,4 +12,6 @@ public interface JassValueVisitor<TYPE> {
TYPE accept(CodeJassValue value);
TYPE accept(ArrayJassValue value);
TYPE accept(HandleJassValue value);
}

View File

@ -7,8 +7,14 @@ public class PrimitiveJassType implements JassType {
this.name = name;
}
@Override
public boolean isAssignableFrom(final JassType value) {
return value == this;
}
@Override
public String getName() {
return name;
return this.name;
}
@Override

View File

@ -0,0 +1,16 @@
package com.etheller.interpreter.ast.value;
public class RealJassType extends PrimitiveJassType {
public RealJassType(final String name) {
super(name);
}
@Override
public boolean isAssignableFrom(final JassType value) {
if (value == JassType.INTEGER) {
return true;
}
return super.isAssignableFrom(value);
}
}

View File

@ -3,6 +3,7 @@ package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
@ -45,4 +46,9 @@ public class ArrayJassValueVisitor implements JassValueVisitor<ArrayJassValue> {
return value;
}
@Override
public ArrayJassValue accept(final HandleJassValue value) {
return null;
}
}

View File

@ -1,10 +1,12 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassType;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.JassType;
import com.etheller.interpreter.ast.value.JassTypeVisitor;
import com.etheller.interpreter.ast.value.PrimitiveJassType;
public class ArrayPrimitiveTypeVisitor implements JassTypeVisitor<PrimitiveJassType> {
public class ArrayPrimitiveTypeVisitor implements JassTypeVisitor<JassType> {
private static final ArrayPrimitiveTypeVisitor INSTANCE = new ArrayPrimitiveTypeVisitor();
public static ArrayPrimitiveTypeVisitor getInstance() {
@ -12,13 +14,18 @@ public class ArrayPrimitiveTypeVisitor implements JassTypeVisitor<PrimitiveJassT
}
@Override
public PrimitiveJassType accept(final PrimitiveJassType primitiveType) {
public JassType accept(final PrimitiveJassType primitiveType) {
return null;
}
@Override
public PrimitiveJassType accept(final ArrayJassType arrayType) {
public JassType accept(final ArrayJassType arrayType) {
return arrayType.getPrimitiveType();
}
@Override
public JassType accept(final HandleJassType type) {
return null;
}
}

View File

@ -0,0 +1,54 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
import com.etheller.interpreter.ast.value.StringJassValue;
public class BooleanJassValueVisitor implements JassValueVisitor<Boolean> {
private static final BooleanJassValueVisitor INSTANCE = new BooleanJassValueVisitor();
public static BooleanJassValueVisitor getInstance() {
return INSTANCE;
}
@Override
public Boolean accept(final IntegerJassValue value) {
throw new IllegalStateException("Unable to convert " + value + " to boolean");
}
@Override
public Boolean accept(final RealJassValue value) {
throw new IllegalStateException("Unable to convert " + value + " to boolean");
}
@Override
public Boolean accept(final BooleanJassValue value) {
return value.getValue();
}
@Override
public Boolean accept(final StringJassValue value) {
throw new IllegalStateException("Unable to convert " + value + " to boolean");
}
@Override
public Boolean accept(final CodeJassValue value) {
throw new IllegalStateException("Unable to convert " + value + " to boolean");
}
@Override
public Boolean accept(final ArrayJassValue value) {
throw new IllegalStateException("Unable to convert " + value + " to boolean");
}
@Override
public Boolean accept(final HandleJassValue value) {
throw new IllegalStateException("Unable to convert " + value + " to boolean");
}
}

View File

@ -0,0 +1,30 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassType;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.JassTypeVisitor;
import com.etheller.interpreter.ast.value.PrimitiveJassType;
public class HandleJassTypeVisitor implements JassTypeVisitor<HandleJassType> {
private static final HandleJassTypeVisitor INSTANCE = new HandleJassTypeVisitor();
public static HandleJassTypeVisitor getInstance() {
return INSTANCE;
}
@Override
public HandleJassType accept(final PrimitiveJassType primitiveType) {
return null;
}
@Override
public HandleJassType accept(final ArrayJassType arrayType) {
return null;
}
@Override
public HandleJassType accept(final HandleJassType type) {
return type;
}
}

View File

@ -0,0 +1,32 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassType;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.JassTypeVisitor;
import com.etheller.interpreter.ast.value.PrimitiveJassType;
public class HandleTypeSuperTypeLoadingVisitor implements JassTypeVisitor<Void> {
private HandleJassType superType;
public HandleTypeSuperTypeLoadingVisitor reset(final HandleJassType superType) {
this.superType = superType;
return this;
}
@Override
public Void accept(final PrimitiveJassType primitiveType) {
return null;
}
@Override
public Void accept(final ArrayJassType arrayType) {
return null;
}
@Override
public Void accept(final HandleJassType type) {
type.setSuperType(this.superType);
return null;
}
}

View File

@ -3,6 +3,7 @@ package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
@ -45,4 +46,9 @@ public class IntegerJassValueVisitor implements JassValueVisitor<Integer> {
return 0;
}
@Override
public Integer accept(final HandleJassValue value) {
return 0;
}
}

View File

@ -4,6 +4,7 @@ import com.etheller.interpreter.ast.function.JassFunction;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
@ -46,4 +47,9 @@ public class JassFunctionJassValueVisitor implements JassValueVisitor<JassFuncti
return null;
}
@Override
public JassFunction accept(final HandleJassValue value) {
return null;
}
}

View File

@ -3,6 +3,7 @@ package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassType;
import com.etheller.interpreter.ast.value.JassValueVisitor;
@ -46,4 +47,9 @@ public class JassTypeGettingValueVisitor implements JassValueVisitor<JassType> {
return value.getType();
}
@Override
public JassType accept(final HandleJassValue value) {
return value.getType();
}
}

View File

@ -0,0 +1,56 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
import com.etheller.interpreter.ast.value.StringJassValue;
public class NotJassValueVisitor implements JassValueVisitor<JassValue> {
private static final NotJassValueVisitor INSTANCE = new NotJassValueVisitor();
public static NotJassValueVisitor getInstance() {
return INSTANCE;
}
@Override
public JassValue accept(final IntegerJassValue value) {
throw new IllegalStateException("Unable to apply not keyword to a variable of type integer");
}
@Override
public JassValue accept(final RealJassValue value) {
throw new IllegalStateException("Unable to apply not keyword to a variable of type real");
}
@Override
public JassValue accept(final BooleanJassValue value) {
return BooleanJassValue.inverse(value);
}
@Override
public JassValue accept(final StringJassValue value) {
throw new IllegalStateException("Unable to apply not keyword to a variable of type string");
}
@Override
public JassValue accept(final CodeJassValue value) {
throw new IllegalStateException("Unable to apply not keyword to a variable of type code");
}
@Override
public JassValue accept(final ArrayJassValue value) {
throw new IllegalStateException("Unable to apply not keyword to a variable of an array type");
}
@Override
public JassValue accept(final HandleJassValue value) {
throw new IllegalStateException(
"Unable to apply not keyword to a variable of type " + value.getType().getName());
}
}

View File

@ -0,0 +1,54 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
import com.etheller.interpreter.ast.value.StringJassValue;
public class ObjectJassValueVisitor<T> implements JassValueVisitor<T> {
private static final ObjectJassValueVisitor<?> INSTANCE = new ObjectJassValueVisitor();
public static <V> ObjectJassValueVisitor<V> getInstance() {
return (ObjectJassValueVisitor<V>) INSTANCE;
}
@Override
public T accept(final IntegerJassValue value) {
return null;
}
@Override
public T accept(final RealJassValue value) {
return null;
}
@Override
public T accept(final BooleanJassValue value) {
return null;
}
@Override
public T accept(final StringJassValue value) {
return null;
}
@Override
public T accept(final CodeJassValue value) {
return null;
}
@Override
public T accept(final ArrayJassValue value) {
return null;
}
@Override
public T accept(final HandleJassValue value) {
return (T) value.getJavaValue();
}
}

View File

@ -0,0 +1,54 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
import com.etheller.interpreter.ast.value.StringJassValue;
public class RealJassValueVisitor implements JassValueVisitor<Double> {
private static final RealJassValueVisitor INSTANCE = new RealJassValueVisitor();
public static RealJassValueVisitor getInstance() {
return INSTANCE;
}
@Override
public Double accept(final IntegerJassValue value) {
return Double.valueOf(value.getValue());
}
@Override
public Double accept(final RealJassValue value) {
return value.getValue();
}
@Override
public Double accept(final BooleanJassValue value) {
return 0.0;
}
@Override
public Double accept(final StringJassValue value) {
return 0.0;
}
@Override
public Double accept(final CodeJassValue value) {
return 0.0;
}
@Override
public Double accept(final ArrayJassValue value) {
return 0.0;
}
@Override
public Double accept(final HandleJassValue value) {
return 0.0;
}
}

View File

@ -3,6 +3,7 @@ package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassValue;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.CodeJassValue;
import com.etheller.interpreter.ast.value.HandleJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
import com.etheller.interpreter.ast.value.JassValueVisitor;
import com.etheller.interpreter.ast.value.RealJassValue;
@ -45,4 +46,9 @@ public class StringJassValueVisitor implements JassValueVisitor<String> {
return null;
}
@Override
public String accept(final HandleJassValue value) {
return null;
}
}

View File

@ -0,0 +1,30 @@
package com.etheller.interpreter.ast.value.visitor;
import com.etheller.interpreter.ast.value.ArrayJassType;
import com.etheller.interpreter.ast.value.HandleJassType;
import com.etheller.interpreter.ast.value.JassTypeVisitor;
import com.etheller.interpreter.ast.value.PrimitiveJassType;
public class SuperTypeVisitor implements JassTypeVisitor<HandleJassType> {
private static final SuperTypeVisitor INSTANCE = new SuperTypeVisitor();
public static SuperTypeVisitor getInstance() {
return INSTANCE;
}
@Override
public HandleJassType accept(final PrimitiveJassType primitiveType) {
return null;
}
@Override
public HandleJassType accept(final ArrayJassType arrayType) {
return null;
}
@Override
public HandleJassType accept(final HandleJassType type) {
return type.getSuperType();
}
}

View File

@ -1,11 +1,9 @@
package com.etheller.interpreter.ast.visitors;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import com.etheller.interpreter.JassBaseVisitor;
import com.etheller.interpreter.JassParser.EmptyArgumentContext;
import com.etheller.interpreter.JassParser.ListArgumentContext;
import com.etheller.interpreter.JassParser.SingleArgumentContext;
import com.etheller.interpreter.ast.expression.JassExpression;
@ -20,19 +18,14 @@ public class JassArgumentsVisitor extends JassBaseVisitor<List<JassExpression>>
@Override
public List<JassExpression> visitSingleArgument(final SingleArgumentContext ctx) {
final List<JassExpression> list = new LinkedList<>();
list.add(argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
list.add(this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
return list;
}
@Override
public List<JassExpression> visitListArgument(final ListArgumentContext ctx) {
final List<JassExpression> list = visit(ctx.argsList());
list.add(0, argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
list.add(0, this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
return list;
}
@Override
public List<JassExpression> visitEmptyArgument(final EmptyArgumentContext ctx) {
return Collections.EMPTY_LIST;
}
}

View File

@ -1,11 +1,16 @@
package com.etheller.interpreter.ast.visitors;
import java.util.Collections;
import java.util.List;
import com.etheller.interpreter.JassBaseVisitor;
import com.etheller.interpreter.JassParser.ArgsListContext;
import com.etheller.interpreter.JassParser.ArrayReferenceExpressionContext;
import com.etheller.interpreter.JassParser.FalseExpressionContext;
import com.etheller.interpreter.JassParser.FunctionCallExpressionContext;
import com.etheller.interpreter.JassParser.FunctionReferenceExpressionContext;
import com.etheller.interpreter.JassParser.IntegerLiteralExpressionContext;
import com.etheller.interpreter.JassParser.NotExpressionContext;
import com.etheller.interpreter.JassParser.ParentheticalExpressionContext;
import com.etheller.interpreter.JassParser.ReferenceExpressionContext;
import com.etheller.interpreter.JassParser.StringLiteralExpressionContext;
@ -15,6 +20,7 @@ import com.etheller.interpreter.ast.expression.FunctionCallJassExpression;
import com.etheller.interpreter.ast.expression.FunctionReferenceJassExpression;
import com.etheller.interpreter.ast.expression.JassExpression;
import com.etheller.interpreter.ast.expression.LiteralJassExpression;
import com.etheller.interpreter.ast.expression.NotJassExpression;
import com.etheller.interpreter.ast.expression.ReferenceJassExpression;
import com.etheller.interpreter.ast.value.BooleanJassValue;
import com.etheller.interpreter.ast.value.IntegerJassValue;
@ -61,17 +67,24 @@ public class JassExpressionVisitor extends JassBaseVisitor<JassExpression> {
@Override
public JassExpression visitFalseExpression(final FalseExpressionContext ctx) {
return new LiteralJassExpression(new BooleanJassValue(false));
return new LiteralJassExpression(BooleanJassValue.FALSE);
}
@Override
public JassExpression visitTrueExpression(final TrueExpressionContext ctx) {
return new LiteralJassExpression(new BooleanJassValue(true));
return new LiteralJassExpression(BooleanJassValue.TRUE);
}
@Override
public JassExpression visitNotExpression(final NotExpressionContext ctx) {
return new NotJassExpression(visit(ctx.expression()));
}
@Override
public JassExpression visitFunctionCallExpression(final FunctionCallExpressionContext ctx) {
return new FunctionCallJassExpression(ctx.functionExpression().ID().getText(),
argumentExpressionHandler.argumentsVisitor.visit(ctx.functionExpression().argsList()));
final ArgsListContext argsList = ctx.functionExpression().argsList();
final List<JassExpression> arguments = argsList == null ? Collections.<JassExpression>emptyList()
: this.argumentExpressionHandler.argumentsVisitor.visit(argsList);
return new FunctionCallJassExpression(ctx.functionExpression().ID().getText(), arguments);
}
}

View File

@ -6,7 +6,6 @@ import com.etheller.interpreter.JassParser.DefinitionGlobalContext;
import com.etheller.interpreter.ast.scope.GlobalScope;
import com.etheller.interpreter.ast.scope.LocalScope;
import com.etheller.interpreter.ast.value.JassType;
import com.etheller.interpreter.ast.value.PrimitiveJassType;
import com.etheller.interpreter.ast.value.visitor.ArrayPrimitiveTypeVisitor;
public class JassGlobalsVisitor extends JassBaseVisitor<Void> {
@ -24,25 +23,27 @@ public class JassGlobalsVisitor extends JassBaseVisitor<Void> {
@Override
public Void visitBasicGlobal(final BasicGlobalContext ctx) {
final JassType type = jassTypeVisitor.visit(ctx.type());
final PrimitiveJassType arrayPrimType = type.visit(ArrayPrimitiveTypeVisitor.getInstance());
final JassType type = this.jassTypeVisitor.visit(ctx.type());
final JassType arrayPrimType = type.visit(ArrayPrimitiveTypeVisitor.getInstance());
if (arrayPrimType != null) {
globals.createGlobalArray(ctx.ID().getText(), type);
} else {
globals.createGlobal(ctx.ID().getText(), type);
this.globals.createGlobalArray(ctx.ID().getText(), type);
}
else {
this.globals.createGlobal(ctx.ID().getText(), type);
}
return null;
}
@Override
public Void visitDefinitionGlobal(final DefinitionGlobalContext ctx) {
final JassType type = jassTypeVisitor.visit(ctx.type());
final PrimitiveJassType arrayPrimType = type.visit(ArrayPrimitiveTypeVisitor.getInstance());
final JassType type = this.jassTypeVisitor.visit(ctx.type());
final JassType arrayPrimType = type.visit(ArrayPrimitiveTypeVisitor.getInstance());
if (arrayPrimType != null) {
globals.createGlobalArray(ctx.ID().getText(), type);
} else {
globals.createGlobal(ctx.ID().getText(), type,
jassExpressionVisitor.visit(ctx.assignTail().expression()).evaluate(globals, EMPTY_LOCAL_SCOPE));
this.globals.createGlobalArray(ctx.ID().getText(), type);
}
else {
this.globals.createGlobal(ctx.ID().getText(), type, this.jassExpressionVisitor
.visit(ctx.assignTail().expression()).evaluate(this.globals, EMPTY_LOCAL_SCOPE));
}
return null;
}

View File

@ -2,9 +2,7 @@ package com.etheller.interpreter.ast.visitors;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.etheller.interpreter.JassBaseVisitor;
import com.etheller.interpreter.JassParser.BlockContext;
@ -22,7 +20,6 @@ import com.etheller.interpreter.ast.statement.JassStatement;
public class JassProgramVisitor extends JassBaseVisitor<Void> {
private final GlobalScope globals = new GlobalScope();
private final JassNativeManager jassNativeManager = new JassNativeManager();
private final Map<String, String> typeToSuperType = new HashMap<>();
private final JassTypeVisitor jassTypeVisitor = new JassTypeVisitor(this.globals);
private final ArgumentExpressionHandler argumentExpressionHandler = new ArgumentExpressionHandler();
private final JassExpressionVisitor jassExpressionVisitor = new JassExpressionVisitor(
@ -45,24 +42,39 @@ public class JassProgramVisitor extends JassBaseVisitor<Void> {
}
}
else if (ctx.nativeBlock() != null) {
this.jassNativeManager.registerNativeCode(ctx.nativeBlock().ID().getText(),
final String text = ctx.nativeBlock().ID().getText();
System.out.println("Registering native: " + text);
this.jassNativeManager.registerNativeCode(text,
this.jassParametersVisitor.visit(ctx.nativeBlock().paramList()),
this.jassTypeVisitor.visit(ctx.nativeBlock().type()), this.globals);
}
return null;
}
@Override
public Void visitFunctionBlock(final FunctionBlockContext ctx) {
final List<JassStatement> statements = new ArrayList<>();
for (final StatementContext statementContext : ctx.statements().statement()) {
statements.add(this.jassStatementVisitor.visit(statementContext));
}
final UserJassFunction userJassFunction = new UserJassFunction(statements,
this.jassParametersVisitor.visit(ctx.paramList()), this.jassTypeVisitor.visit(ctx.type()));
this.globals.defineFunction(ctx.ID().getText(), userJassFunction);
return null;
}
@Override
public Void visitProgram(final ProgramContext ctx) {
for (final TypeDefinitionContext typeDefinitionContext : ctx.typeDefinitionBlock().typeDefinition()) {
this.typeToSuperType.put(typeDefinitionContext.ID(0).getText(), typeDefinitionContext.ID(1).getText());
this.globals.loadTypeDefinition(typeDefinitionContext.ID(0).getText(),
typeDefinitionContext.ID(1).getText());
}
for (final BlockContext blockContext : ctx.block()) {
visit(blockContext);
}
for (final FunctionBlockContext functionBlockContext : ctx.functionBlock()) {
final List<JassStatement> statements = new ArrayList<>();
for (final StatementContext statementContext : functionBlockContext.statement()) {
for (final StatementContext statementContext : functionBlockContext.statements().statement()) {
statements.add(this.jassStatementVisitor.visit(statementContext));
}
final UserJassFunction userJassFunction = new UserJassFunction(statements,
@ -72,7 +84,12 @@ public class JassProgramVisitor extends JassBaseVisitor<Void> {
}
final JassFunction mainFunction = this.globals.getFunctionByName("main");
if (mainFunction != null) {
mainFunction.call(Collections.EMPTY_LIST, this.globals);
try {
mainFunction.call(Collections.EMPTY_LIST, this.globals);
}
catch (final Exception exc) {
throw new RuntimeException("Exception on Line " + GlobalScope.getLineNumber(), exc);
}
}
return null;
}

View File

@ -1,12 +1,22 @@
package com.etheller.interpreter.ast.visitors;
import java.util.ArrayList;
import java.util.List;
import com.etheller.interpreter.JassBaseVisitor;
import com.etheller.interpreter.JassParser.ArrayedAssignmentStatementContext;
import com.etheller.interpreter.JassParser.CallStatementContext;
import com.etheller.interpreter.JassParser.IfElseIfStatementContext;
import com.etheller.interpreter.JassParser.IfElseStatementContext;
import com.etheller.interpreter.JassParser.ReturnStatementContext;
import com.etheller.interpreter.JassParser.SetStatementContext;
import com.etheller.interpreter.JassParser.SimpleIfStatementContext;
import com.etheller.interpreter.JassParser.StatementContext;
import com.etheller.interpreter.ast.statement.JassArrayedAssignmentStatement;
import com.etheller.interpreter.ast.statement.JassCallStatement;
import com.etheller.interpreter.ast.statement.JassIfElseIfStatement;
import com.etheller.interpreter.ast.statement.JassIfElseStatement;
import com.etheller.interpreter.ast.statement.JassIfStatement;
import com.etheller.interpreter.ast.statement.JassReturnStatement;
import com.etheller.interpreter.ast.statement.JassSetStatement;
import com.etheller.interpreter.ast.statement.JassStatement;
@ -20,25 +30,62 @@ public class JassStatementVisitor extends JassBaseVisitor<JassStatement> {
@Override
public JassStatement visitCallStatement(final CallStatementContext ctx) {
return new JassCallStatement(ctx.functionExpression().ID().getText(),
argumentExpressionHandler.argumentsVisitor.visit(ctx.functionExpression().argsList()));
return new JassCallStatement(ctx.getStart().getLine(), ctx.functionExpression().ID().getText(),
this.argumentExpressionHandler.argumentsVisitor.visit(ctx.functionExpression().argsList()));
}
@Override
public JassStatement visitSetStatement(final SetStatementContext ctx) {
return new JassSetStatement(ctx.ID().getText(),
argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
return new JassSetStatement(ctx.getStart().getLine(), ctx.ID().getText(),
this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
}
@Override
public JassStatement visitReturnStatement(final ReturnStatementContext ctx) {
return new JassReturnStatement(argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
return new JassReturnStatement(ctx.getStart().getLine(),
this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
}
@Override
public JassStatement visitIfElseIfStatement(final IfElseIfStatementContext ctx) {
final List<JassStatement> thenStatements = new ArrayList<>();
for (final StatementContext statementCtx : ctx.statements().statement()) {
thenStatements.add(visit(statementCtx));
}
final JassStatement elseIfTail = visit(ctx.ifStatementPartial());
return new JassIfElseIfStatement(ctx.getStart().getLine(),
this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression()), thenStatements, elseIfTail);
}
@Override
public JassStatement visitIfElseStatement(final IfElseStatementContext ctx) {
final List<JassStatement> thenStatements = new ArrayList<>();
for (final StatementContext statementCtx : ctx.statements(0).statement()) {
thenStatements.add(visit(statementCtx));
}
final List<JassStatement> elseStatements = new ArrayList<>();
for (final StatementContext statementCtx : ctx.statements(1).statement()) {
elseStatements.add(visit(statementCtx));
}
return new JassIfElseStatement(ctx.getStart().getLine(),
this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression()), thenStatements,
elseStatements);
}
@Override
public JassStatement visitSimpleIfStatement(final SimpleIfStatementContext ctx) {
final List<JassStatement> thenStatements = new ArrayList<>();
for (final StatementContext statementCtx : ctx.statements().statement()) {
thenStatements.add(visit(statementCtx));
}
return new JassIfStatement(ctx.getStart().getLine(),
this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression()), thenStatements);
}
@Override
public JassStatement visitArrayedAssignmentStatement(final ArrayedAssignmentStatementContext ctx) {
return new JassArrayedAssignmentStatement(ctx.ID().getText(),
argumentExpressionHandler.expressionVisitor.visit(ctx.expression(0)),
argumentExpressionHandler.expressionVisitor.visit(ctx.expression(1)));
return new JassArrayedAssignmentStatement(ctx.getStart().getLine(), ctx.ID().getText(),
this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression(0)),
this.argumentExpressionHandler.expressionVisitor.visit(ctx.expression(1)));
}
}

View File

@ -0,0 +1,94 @@
//============================================================================
// User Interface scripts for the Warsmash mod engine. This is
// an attempt to get these defined in an external import that
// a map can override. Unfortunately, although I would like for
// this to be a JASS file, it is not very consistent with the
// notion of the JASS2 VM to define UI, because handles are
// mostly network synced. So, we will assume the contents
// of this file are run in a special client-only JASS VM
// once I implement networking, so that this script will not
// cause a desync as it would if it was in the standard game
// JASS files. For that reason, it will have '.jui' extension
// to signify it runs in this modified JASS VM, instead of
// standard '.j' as used for JASS2 script files.
//
// Right now there is some duplicated code from common.j --
// maybe later on we will load that stuff first, then this
// one in the same variable space?
//
type framehandle extends handle
type framepointtype extends handle
native LogError takes string message returns nothing
constant native ConvertFramePointType takes integer i returns framepointtype
globals
//===================================================
// UI API constants
//===================================================
constant framepointtype FRAMEPOINT_TOPLEFT = ConvertFramePointType(0)
constant framepointtype FRAMEPOINT_TOP = ConvertFramePointType(1)
constant framepointtype FRAMEPOINT_TOPRIGHT = ConvertFramePointType(2)
constant framepointtype FRAMEPOINT_LEFT = ConvertFramePointType(3)
constant framepointtype FRAMEPOINT_CENTER = ConvertFramePointType(4)
constant framepointtype FRAMEPOINT_RIGHT = ConvertFramePointType(5)
constant framepointtype FRAMEPOINT_BOTTOMLEFT = ConvertFramePointType(6)
constant framepointtype FRAMEPOINT_BOTTOM = ConvertFramePointType(7)
constant framepointtype FRAMEPOINT_BOTTOMRIGHT = ConvertFramePointType(8)
endglobals
//===================================================
// UI API
//===================================================
// Loads an entry from the file "UI\war3skins.txt" and returns
// it as the current GAMEUI. The default possible
// strings are "Human", "Orc", "NightElf", and "Undead".
// Some UI FDF templates will use this information as
// the source for lookup strings as a means to change
// their style.
// Calling this more than once will probably crash the game,
// or something, so only call it once on startup.
native CreateRootFrame takes string skinName returns framehandle
// Loads the (T)able (O)f (C)ontents file.
// This must be a simple text document with each line
// having only a filepath of a .FDF frame template
// definition file to load. Unlike War3 engine,
// I do not require the file to include one extra
// blank line at the end.
//
// We typically call this first during UI setup, and
// only once for a given mod.
native LoadTOCFile takes string TOCFile returns framehandle
// Spawn a SIMPLEFRAME element that was defined in a FDF
// template onto the screen. The "name" field must match
// the name of a template to spawn, loaded with LoadTOCFile.
// The create context is pretty pointless, but I think
// they use it so that they have an integer tag on the
// "Attack 1" and "Attack 2" ui components. I was trying
// to keep parity with the FDF UI APIs from 1.31, imagine
// that.
native CreateSimpleFrame takes string name, framehandle owner, integer createContext returns framehandle
// Set the absolute point (often called Anchor) for the frame handle.
// See FDF template files for examples
native FrameSetAbsPoint takes framehandle frame, framepointtype point, real x, real y returns nothing
// Created for Warsmash engine, not a part of 1.31 UI apis,
// and at some point it might be removed. Basically
// this function will apply Anchors and SetPoints assigned
// to the frame handle and all its children and resolve where
// they should go onscreen. Generally in my experience,
// War3 will do this automatically in their FDF system.
native FramePositionBounds takes framehandle frame returns nothing
// Used to lookup fields in the Skin data, for example
// SkinGetField("TimeOfDayIndicator") will return the
// string "UI\\Console\\Human\\HumanUI-TimeIndicator.mdl"
// when the "Human" skin was loaded with CreateRootFrame
native SkinGetField takes string field returns string

View File

@ -0,0 +1,35 @@
globals
// Defaults for testing:
constant string SKIN = "Human"
// Major UI components
framehandle ROOT_FRAME
framehandle CONSOLE_UI
framehandle RESOURCE_BAR
endglobals
function main takes nothing returns nothing
// =================================
// Load skins and templates
// =================================
set ROOT_FRAME = CreateRootFrame(SKIN)
if not LoadTOCFile("UI\\FrameDef\\FrameDef.toc") then
call LogError("Unable to load FrameDef.toc")
endif
// =================================
// Load major UI components
// =================================
// Console UI is the background with the racial theme
set CONSOLE_UI = CreateSimpleFrame("ConsoleUI", ROOT_FRAME, 0)
// Resource bar is a 3 part bar with Gold, Lumber, and Food.
// Its template does not specify where to put it, so we must
// put it in the "TOPRIGHT" corner.
set RESOURCE_BAR = CreateSimpleFrame("ResourceBarFrame", CONSOLE_UI, 0)
call FrameSetAbsPoint(RESOURCE_BAR, FRAMEPOINT_TOPRIGHT, 0, 0)
// Assemble the UI and resolve the location of every component that
// has Anchors and SetPoints (maybe in future version this call
// wont be necessary!)
call FramePositionBounds(ROOT_FRAME)
endfunction