summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/Makefile6
-rw-r--r--src/core/src/tonkadur/fate/v1/error/ContextCycleException.java47
-rw-r--r--src/core/src/tonkadur/fate/v1/error/InputException.java40
-rw-r--r--src/core/src/tonkadur/fate/v1/error/TypeAlreadyDeclaredException.java10
-rw-r--r--src/core/src/tonkadur/fate/v1/parser/Context.java126
-rw-r--r--src/core/src/tonkadur/fate/v1/parser/FateLexer.g45
-rw-r--r--src/core/src/tonkadur/fate/v1/parser/FateParser.g464
-rw-r--r--src/core/src/tonkadur/fate/v1/parser/Location.java114
-rw-r--r--src/core/src/tonkadur/fate/v1/parser/Origin.java33
9 files changed, 401 insertions, 44 deletions
diff --git a/src/core/Makefile b/src/core/Makefile
index 178f01b..ffca63b 100644
--- a/src/core/Makefile
+++ b/src/core/Makefile
@@ -80,11 +80,9 @@ clean:
rm -rf $(BIN_DIR)/*
rm -rf $(TARGET) $(STANDALONE)
-$(SRC_DIR)/tonkadur/parser/LangParser.java: $(ANTLR_SOURCES)
-
# Pattern rules can be used to generate multiple target in a single action.
-LangLexer%java LangParser%java: $(ANTLR_SOURCES)
- $(JAVA) -jar $(ANTLR_JAR) -lib $(SRC_DIR)/tonkadur/parser/ $^
+%Lexer.java %Parser.java: $(ANTLR_SOURCES)
+ $(JAVA) -jar $(ANTLR_JAR) -lib $(dir $@) $^
$(CLASSES): $(BIN_DIR)/%.class: $(SRC_DIR)/%.java $(BIN_DIR)
$(JAVAC) -cp $(CLASSPATH) -d $(BIN_DIR) $<
diff --git a/src/core/src/tonkadur/fate/v1/error/ContextCycleException.java b/src/core/src/tonkadur/fate/v1/error/ContextCycleException.java
new file mode 100644
index 0000000..c5a2434
--- /dev/null
+++ b/src/core/src/tonkadur/fate/v1/error/ContextCycleException.java
@@ -0,0 +1,47 @@
+package tonkadur.fate.v1.error;
+
+import tonkadur.fate.v1.parser.Location;
+import tonkadur.fate.v1.parser.Origin;
+
+public class ContextCycleException extends InputException
+{
+ /***************************************************************************/
+ /**** MEMBERS **************************************************************/
+ /***************************************************************************/
+ /*
+ * Using a Location instead of an Origin here, because the file refers to
+ * something in 'origin' anyway.
+ */
+ protected final Location original_require_location;
+ protected final String filename;
+
+ /***************************************************************************/
+ /**** PUBLIC ***************************************************************/
+ /***************************************************************************/
+ public ContextCycleException
+ (
+ final Location original_require_location,
+ final String filename
+ )
+ {
+ this.original_require_location = original_require_location;
+ this.filename = filename;
+ }
+
+ @Override
+ public String toString ()
+ {
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append(origin.get_context().toString());
+ sb.append("Cyclic dependency for file '");
+ sb.append(filename);
+ sb.append("' required at ");
+ sb.append(origin.get_location().toString());
+ sb.append(" when it was already required at ");
+ sb.append(original_require_location.toString());
+ sb.append(".");
+
+ return sb.toString();
+ }
+}
diff --git a/src/core/src/tonkadur/fate/v1/error/InputException.java b/src/core/src/tonkadur/fate/v1/error/InputException.java
index d2921cb..71b1878 100644
--- a/src/core/src/tonkadur/fate/v1/error/InputException.java
+++ b/src/core/src/tonkadur/fate/v1/error/InputException.java
@@ -1,5 +1,8 @@
package tonkadur.fate.v1.error;
+import tonkadur.fate.v1.parser.Context;
+import tonkadur.fate.v1.parser.Origin;
+
abstract class InputException extends Throwable
{
/***************************************************************************/
@@ -10,43 +13,28 @@ abstract class InputException extends Throwable
/***************************************************************************/
/**** MEMBERS **************************************************************/
/***************************************************************************/
- protected String filename = "";
- protected int line = -1;
- protected int column = -1;
+ protected Origin origin;
/***************************************************************************/
/**** PUBLIC ***************************************************************/
/***************************************************************************/
- public InputException set_location
+ public void set_origin (final Origin origin)
+ {
+ this.origin = origin;
+ }
+
+ public void set_origin
(
- final String filename,
+ final Context context,
final int line,
final int column
)
{
- this.filename = filename;
- this.line = line;
- this.column = column;
-
- return this;
- }
-
- public String get_location ()
- {
- final StringBuilder sb = new StringBuilder();
-
- sb.append(filename);
- sb.append(":");
- sb.append(line);
- sb.append(",");
- sb.append(column);
-
- return sb.toString();
+ origin = context.get_origin_at(line, column);
}
- @Override
- public String toString ()
+ public Origin get_origin ()
{
- return get_location();
+ return origin;
}
}
diff --git a/src/core/src/tonkadur/fate/v1/error/TypeAlreadyDeclaredException.java b/src/core/src/tonkadur/fate/v1/error/TypeAlreadyDeclaredException.java
index 673a3bd..b028127 100644
--- a/src/core/src/tonkadur/fate/v1/error/TypeAlreadyDeclaredException.java
+++ b/src/core/src/tonkadur/fate/v1/error/TypeAlreadyDeclaredException.java
@@ -22,11 +22,13 @@ public class TypeAlreadyDeclaredException extends InputException
{
final StringBuilder sb = new StringBuilder();
- sb.append(super.toString());
- sb.append(" Type '");
+ sb.append(origin.get_context().toString());
+ sb.append("Declaration for type '");
sb.append(original_type.get_name());
- sb.append("' already declared in ");
- sb.append(original_type.get_source().toString());
+ sb.append("' at ");
+ sb.append(origin.get_location().toString());
+ sb.append(" when it was already declared at ");
+ sb.append(original_type.get_origin().get_location().toString());
sb.append(".");
return sb.toString();
diff --git a/src/core/src/tonkadur/fate/v1/parser/Context.java b/src/core/src/tonkadur/fate/v1/parser/Context.java
new file mode 100644
index 0000000..3ad958d
--- /dev/null
+++ b/src/core/src/tonkadur/fate/v1/parser/Context.java
@@ -0,0 +1,126 @@
+package tonkadur.fate.v1.parser;
+
+import java.util.Stack;
+
+import tonkadur.fate.v1.error.ContextCycleException;
+
+public class Context
+{
+ /***************************************************************************/
+ /**** MEMBERS **************************************************************/
+ /***************************************************************************/
+ protected final boolean locked;
+ protected final Stack<Location> source;
+ protected String current_file;
+
+ /***************************************************************************/
+ /**** PUBLIC ***************************************************************/
+ /***************************************************************************/
+
+ /**** Constructors *********************************************************/
+ public Context (final String filename)
+ {
+ locked = false;
+ source = new Stack<Location>();
+ current_file = filename;
+ }
+
+ /**** Accessors ************************************************************/
+ public void push (final Location location, final String new_file)
+ throws ContextCycleException
+ {
+ throw_exception_on_cycle(new_file);
+
+ current_file = new_file;
+
+ source.push(location);
+ }
+
+ public void pop ()
+ {
+ current_file = source.peek().get_filename();
+ source.pop();
+ }
+
+ /**** Utils ****************************************************************/
+ public Origin get_origin_at (final int line, final int column)
+ {
+ return new Origin(this, new Location(current_file, line, column));
+ }
+
+ /**** Misc. ****************************************************************/
+ @Override
+ public String toString ()
+ {
+ final StringBuilder sb = new StringBuilder();
+
+ /*
+ * That's in FIFO order, as we want it to be, due to arguable design
+ * decisions in Java.
+ */
+ for (final Location location: source)
+ {
+ sb.append("Require at ");
+ sb.append(location.toString());
+ sb.append(" led to");
+ sb.append(System.lineSeparator());
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals (final Object o)
+ {
+ if (o instanceof Context)
+ {
+ final Context b;
+
+ b = (Context) o;
+
+ return
+ (
+ (source.equals(b.source))
+ && (current_file.equals (b.current_file))
+ );
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode ()
+ {
+ return (source.hashCode() + current_file.hashCode());
+ }
+
+ /***************************************************************************/
+ /**** PROTECTED ************************************************************/
+ /***************************************************************************/
+ protected void throw_exception_on_cycle (final String new_file)
+ throws ContextCycleException
+ {
+ Location previous_import;
+
+ previous_import = null;
+
+ /*
+ * That's in FIFO order, as we want it to be, due to arguable design
+ * decisions in Java.
+ */
+ for (final Location location: source)
+ {
+ if (location.get_filename().equals(new_file))
+ {
+ throw new ContextCycleException(previous_import, new_file);
+ }
+
+ previous_import = location;
+ }
+
+ if (current_file.equals(new_file))
+ {
+ throw new ContextCycleException(previous_import, new_file);
+ }
+ }
+}
diff --git a/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 b/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4
index 80fe1fd..3671a4f 100644
--- a/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4
+++ b/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4
@@ -5,8 +5,6 @@ lexer grammar FateLexer;
package tonkadur.fate.v1.parser;
}
-
-
fragment SEP: [ \t\r\n]+;
WS: SEP;
@@ -53,6 +51,9 @@ PARAMETER_KW: L_PAREN 'parameter' WS*;
PLUS_KW: L_PAREN 'plus' WS*;
POWER_KW: L_PAREN 'power' WS*;
RANDOM_KW: L_PAREN 'random' WS*;
+DECLARE_TEXT_EFFECT_KW: L_PAREN 'declare_text_effect' WS*;
+PLAYER_CHOICE_KW: L_PAREN 'player_choice' WS*;
+CAST_KW: L_PAREN 'cast' WS*;
REMOVE_ALL_KW: L_PAREN 'remove_all' WS*;
REMOVE_ONE_KW: L_PAREN 'remove_one' WS*;
REQUIRE_KW: L_PAREN 'require' WS*;
diff --git a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4
index c0be842..408d71d 100644
--- a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4
+++ b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4
@@ -123,25 +123,67 @@ general_fate_instr:
{
}
- | NEWLINE_KW
+ | IF_ELSE_KW value WS+ general_fate_instr WS+ general_fate_instr R_PAREN
+ {
+ }
+
+ | COND_KW instr_cond_list R_PAREN
+ {
+ }
+
+ | PLAYER_CHOICE_KW player_choice* R_PAREN
+ {
+ }
+
+ | text+
+ {
+ }
+;
+
+instr_cond_list:
+ (L_PAREN value WS+ general_fate_instr R_PAREN)+
+ {
+ }
+;
+
+player_choice:
+ L_PAREN L_PAREN text+ R_PAREN WS+ general_fate_instr R_PAREN
+ {
+ }
+
+ | IF_KW value WS+ player_choice R_PAREN
+ {
+ }
+
+ | IF_ELSE_KW value WS+ player_choice WS+ player_choice R_PAREN
{
}
- | text
+ | COND_KW player_choice_cond_list R_PAREN
+ {
+ }
+;
+
+player_choice_cond_list:
+ (L_PAREN value WS+ player_choice R_PAREN)+
{
}
;
text:
- sentence text*
+ sentence
{
}
- | (ENABLE_TEXT_PARAMETER_KW WORD WS+ text R_PAREN) text*
+ | ENABLE_TEXT_PARAMETER_KW WORD WS+ text+ R_PAREN
{
}
- | non_text_value text*
+ | NEWLINE_KW
+ {
+ }
+
+ | non_text_value
{
}
;
@@ -289,7 +331,7 @@ value:
;
non_text_value:
- | IF_ELSE_KW value WS+ value WS+ value R_PAREN
+ IF_ELSE_KW value WS+ value WS+ value R_PAREN
{
}
@@ -305,6 +347,10 @@ non_text_value:
{
}
+ | CAST_KW WORD WORD value R_PAREN
+ {
+ }
+
| value_reference
{
}
@@ -325,13 +371,15 @@ value_reference:
;
value_cond_list:
- (L_PAREN value WS value R_PAREN)+
+ (L_PAREN value WS+ value R_PAREN)+
{
}
;
value_list:
- value*
+ value* (WS+ value)*
{
}
;
+
+
diff --git a/src/core/src/tonkadur/fate/v1/parser/Location.java b/src/core/src/tonkadur/fate/v1/parser/Location.java
new file mode 100644
index 0000000..98f407d
--- /dev/null
+++ b/src/core/src/tonkadur/fate/v1/parser/Location.java
@@ -0,0 +1,114 @@
+package tonkadur.fate.v1.parser;
+
+public class Location
+{
+ /***************************************************************************/
+ /**** STATIC MEMBERS *******************************************************/
+ /***************************************************************************/
+ public static final Location BASE_LANGUAGE;
+
+ static
+ {
+ BASE_LANGUAGE = new Location(true, "", -1, -1);
+ }
+
+ /***************************************************************************/
+ /**** MEMBERS **************************************************************/
+ /***************************************************************************/
+ protected final boolean is_base_language;
+ protected final String filename;
+ protected final int line;
+ protected final int column;
+
+ /***************************************************************************/
+ /**** PROTECTED ************************************************************/
+ /***************************************************************************/
+ protected Location
+ (
+ final boolean is_base_language,
+ final String filename,
+ final int line,
+ final int column
+ )
+ {
+ this.is_base_language = is_base_language;
+ this.filename = filename;
+ this.line = line;
+ this.column = column;
+ }
+
+ /***************************************************************************/
+ /**** PUBLIC ***************************************************************/
+ /***************************************************************************/
+
+ /**** Constructors *********************************************************/
+ public Location
+ (
+ final String filename,
+ final int line,
+ final int column
+ )
+ {
+ this.is_base_language = false;
+ this.filename = filename;
+ this.line = line;
+ this.column = column;
+ }
+
+ /**** Accessors ************************************************************/
+ public String get_filename ()
+ {
+ return filename;
+ }
+
+ public int get_line ()
+ {
+ return line;
+ }
+
+ public int get_column ()
+ {
+ return line;
+ }
+
+ /**** Misc. ****************************************************************/
+ @Override
+ public String toString ()
+ {
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append(filename);
+ sb.append(":");
+ sb.append(line);
+ sb.append(",");
+ sb.append(column);
+
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals (final Object o)
+ {
+ if (o instanceof Location)
+ {
+ final Location b;
+
+ b = (Location) o;
+
+ return
+ (
+ (filename.equals(b.filename))
+ && (line == b.line)
+ && (column == b.column)
+ );
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode ()
+ {
+ return (filename.hashCode() + line + column);
+ }
+}
diff --git a/src/core/src/tonkadur/fate/v1/parser/Origin.java b/src/core/src/tonkadur/fate/v1/parser/Origin.java
new file mode 100644
index 0000000..cd4b784
--- /dev/null
+++ b/src/core/src/tonkadur/fate/v1/parser/Origin.java
@@ -0,0 +1,33 @@
+package tonkadur.fate.v1.parser;
+
+public class Origin
+{
+ /***************************************************************************/
+ /**** MEMBERS **************************************************************/
+ /***************************************************************************/
+ protected final Context context;
+ protected final Location location;
+
+ /***************************************************************************/
+ /**** PUBLIC ***************************************************************/
+ /***************************************************************************/
+ public Origin
+ (
+ final Context context,
+ final Location location
+ )
+ {
+ this.context = context;
+ this.location = location;
+ }
+
+ public Context get_context ()
+ {
+ return context;
+ }
+
+ public Location get_location ()
+ {
+ return location;
+ }
+}