| summaryrefslogtreecommitdiff |
diff options
7 files changed, 315 insertions, 18 deletions
diff --git a/src/core/src/tonkadur/fate/v1/error/UnknownDictionaryFieldException.java b/src/core/src/tonkadur/fate/v1/error/UnknownDictionaryFieldException.java index dd3e67d..aa1ff70 100644 --- a/src/core/src/tonkadur/fate/v1/error/UnknownDictionaryFieldException.java +++ b/src/core/src/tonkadur/fate/v1/error/UnknownDictionaryFieldException.java @@ -47,14 +47,13 @@ public class UnknownDictionaryFieldException extends ParsingError sb.append(field_name); sb.append("' for dictionary type '"); sb.append(dict.get_name()); - sb.append("' at "); - sb.append(origin.get_location().toString()); - sb.append("."); + sb.append("'."); sb.append(System.lineSeparator()); sb.append("Available fields are:"); for (final Map.Entry<String, Type> field: dict.get_fields()) { + sb.append(System.lineSeparator()); sb.append("- "); sb.append(field.getKey()); sb.append(": "); diff --git a/src/core/src/tonkadur/fate/v1/error/UnknownVariableScopeException.java b/src/core/src/tonkadur/fate/v1/error/UnknownVariableScopeException.java new file mode 100644 index 0000000..129a789 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/error/UnknownVariableScopeException.java @@ -0,0 +1,55 @@ +package tonkadur.fate.v1.error; + +import tonkadur.error.ErrorLevel; + +import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +import tonkadur.fate.v1.lang.VariableScope; + +public class UnknownVariableScopeException extends ParsingError +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final String name; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + public UnknownVariableScopeException + ( + final Origin origin, + final String name + ) + { + super(ErrorLevel.ERROR, ErrorCategory.INVALID_USE, origin); + this.name = name; + } + + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append(origin.toString()); + sb.append(" "); + sb.append(error_category.toString()); + sb.append(System.lineSeparator()); + + sb.append("Unknown variable scope '"); + sb.append(name); + sb.append("'."); + sb.append(System.lineSeparator()); + sb.append("Available fields are:"); + + for (final String scope: VariableScope.get_available_scopes()) + { + sb.append(System.lineSeparator()); + sb.append("- "); + sb.append(scope); + } + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/Event.java b/src/core/src/tonkadur/fate/v1/lang/Event.java index b917ebf..d762c71 100644 --- a/src/core/src/tonkadur/fate/v1/lang/Event.java +++ b/src/core/src/tonkadur/fate/v1/lang/Event.java @@ -127,7 +127,7 @@ public class Event extends DeclaredEntity protected Boolean lambda (final Type a, final Type b) { return - new Boolean(a.is_incompatible_with_declaration(b)); + new Boolean(a.can_be_used_as(b)); } }.merge(signature, e.signature) ); @@ -171,8 +171,4 @@ public class Event extends DeclaredEntity return sb.toString(); } - - /***************************************************************************/ - /**** PROTECTED ************************************************************/ - /***************************************************************************/ } diff --git a/src/core/src/tonkadur/fate/v1/lang/Variable.java b/src/core/src/tonkadur/fate/v1/lang/Variable.java new file mode 100644 index 0000000..3e17d61 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/Variable.java @@ -0,0 +1,136 @@ +package tonkadur.fate.v1.lang; + +import java.util.ArrayList; +import java.util.List; + +import tonkadur.functional.Merge; + +import tonkadur.parser.Context; +import tonkadur.parser.Location; +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.lang.meta.DeclaredEntity; + +public class Variable extends DeclaredEntity +{ + protected static final Variable ANY; + + static + { + ANY = + new Variable + ( + new Origin(new Context(""), Location.BASE_LANGUAGE), + VariableScope.ANY, + Type.ANY, + /* + * Use of a space necessary to avoid conflicting with a user created + * type. + */ + "undetermined variable" + ); + } + + public static Variable value_on_missing () + { + return ANY; + } + + @Override + public /* static */ String get_type_name () + { + return "Variable"; + } + + + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final VariableScope scope; + protected final Type type; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + + /**** Constructors *********************************************************/ + public Variable + ( + final Origin origin, + final VariableScope scope, + final Type type, + final String name + ) + { + super(origin, name); + + this.scope = scope; + this.type = type; + } + + /**** Accessors ************************************************************/ + public Type get_type () + { + return type; + } + + @Override + public DeclaredEntity generate_comparable_to (final DeclaredEntity de) + { + final VariableScope new_scope; + final Type new_type; + final Variable v; + + if (!(de instanceof Variable)) + { + return ANY; + } + + v = (Variable) de; + + new_scope = scope.generate_compatible_with(v.scope); + new_type = (Type) type.generate_comparable_to(v.type); + + return new Variable(origin, new_scope, new_type, name); + } + + /**** Misc. ****************************************************************/ + @Override + public boolean is_incompatible_with_declaration (final DeclaredEntity de) + { + if (de instanceof Variable) + { + final Variable v; + + v = (Variable) de; + + return + ( + (!scope.equals(v.scope)) + || !type.can_be_used_as(v.type) + ); + } + + return true; + } + + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("("); + sb.append(scope.toString()); + sb.append(" "); + sb.append(type.get_name()); + sb.append(" Variable "); + sb.append(name); + sb.append(")"); + + return sb.toString(); + } + + /***************************************************************************/ + /**** PROTECTED ************************************************************/ + /***************************************************************************/ +} diff --git a/src/core/src/tonkadur/fate/v1/lang/VariableScope.java b/src/core/src/tonkadur/fate/v1/lang/VariableScope.java new file mode 100644 index 0000000..7f42fa6 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/VariableScope.java @@ -0,0 +1,88 @@ +package tonkadur.fate.v1.lang; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.HashSet; + +/* + * Yes, it *could* have been an enum. Except that you can't extend enums, making + * them inadequate for anything that has even the slightest chance of needing to + * be extended at some point in the future. In other words, they're inadequate + * for anything but very rare corner cases (days in week, for example). + * Tonkadur wants extension support, ergo, no enums in Tonkadur. + * + * The use of a collection to decode them stems from the same reason (can't + * override static methods). + */ +public class VariableScope +{ + public static final VariableScope ANY; + + protected static final Map<String, VariableScope> from_name; + public static final VariableScope LOCAL; + public static final VariableScope GLOBAL; + + static + { + from_name = new HashMap<String, VariableScope>(); + + ANY = new VariableScope("unknown scope", null); + GLOBAL = new VariableScope("global", null); + LOCAL = new VariableScope("local", GLOBAL); + } + + public static VariableScope value_of (final String string) + { + return from_name.get(string); + } + + public static Set<String> get_available_scopes () + { + return from_name.keySet(); + } + + protected final String name; + protected final Set<VariableScope> more_restrictive_than; + + protected VariableScope (final String name, final VariableScope parent) + { + this.name = name; + + more_restrictive_than = new HashSet<VariableScope>(); + + if (parent != null) + { + more_restrictive_than.addAll(parent.more_restrictive_than); + more_restrictive_than.add(parent); + } + + from_name.put(name, this); + } + + public VariableScope generate_compatible_with (final VariableScope other) + { + if (other.equals(this)) + { + return this; + } + + if (other.more_restrictive_than.contains(this)) + { + if (this.more_restrictive_than.contains(other)) + { + return ANY; + } + + return other; + } + + return this; + } + + @Override + public String toString () + { + return name; + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/World.java b/src/core/src/tonkadur/fate/v1/lang/World.java index 43feb5f..8419b06 100644 --- a/src/core/src/tonkadur/fate/v1/lang/World.java +++ b/src/core/src/tonkadur/fate/v1/lang/World.java @@ -21,7 +21,7 @@ public class World // protected final DeclarationCollection<Sequence> sequences; // protected final DeclarationCollection<TextEffect> text_effects; protected final DeclarationCollection<Type> type_collection; -// protected final DeclarationCollection<Variable> variables; + protected final DeclarationCollection<Variable> variable_collection; /***************************************************************************/ /**** PUBLIC ***************************************************************/ @@ -39,7 +39,8 @@ public class World //text_effects = new DeclarationCollection<TextEffect>(); type_collection = new DeclarationCollection<Type>(Type.value_on_missing()); - //variables = new DeclarationCollection<Variable>(); + variable_collection = + new DeclarationCollection<Variable>(Variable.value_on_missing()); add_base_types(); } @@ -61,16 +62,21 @@ public class World loaded_files.add(name); } - public DeclarationCollection<Type> types() + public DeclarationCollection<Type> types () { return type_collection; } - public DeclarationCollection<Event> events() + public DeclarationCollection<Event> events () { return event_collection; } + public DeclarationCollection<Variable> variables () + { + return variable_collection; + } + /**** Misc. ****************************************************************/ @Override public String toString () @@ -103,6 +109,12 @@ public class World sb.append(System.lineSeparator()); sb.append(System.lineSeparator()); + sb.append("Variable: "); + sb.append(System.lineSeparator()); + sb.append(variable_collection.toString()); + sb.append(System.lineSeparator()); + sb.append(System.lineSeparator()); + sb.append(")"); return sb.toString(); diff --git a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 index 27ff773..9d30b0f 100644 --- a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 +++ b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 @@ -9,11 +9,13 @@ options { package tonkadur.fate.v1.parser; - import tonkadur.error.Error; + import tonkadur.error.ErrorManager; import tonkadur.parser.Context; import tonkadur.parser.Origin; + import tonkadur.fate.v1.error.UnknownVariableScopeException; + import tonkadur.fate.v1.lang.*; import tonkadur.fate.v1.lang.meta.*; } @@ -71,11 +73,10 @@ first_level_fate_instr: | DECLARE_VARIABLE_KW scope=WORD WS+ type=WORD WS+ name=WORD R_PAREN { - /* final Origin start_origin, scope_origin, type_origin; - final VariableScope variable_scope; final Type variable_type; final Variable new_variable; + VariableScope variable_scope; start_origin = CONTEXT.get_origin_at @@ -98,8 +99,19 @@ first_level_fate_instr: ($type.getCharPositionInLine()) ); - variable_scope = VariableScope.value_of(scope_origin, ($scope.text)); - variable_type = WORLD.types().get(($type.text)); + variable_scope = VariableScope.value_of(($scope.text)); + + if (variable_scope == null) + { + ErrorManager.handle + ( + new UnknownVariableScopeException(scope_origin, ($scope.text)) + ); + + variable_scope = VariableScope.ANY; + } + + variable_type = WORLD.types().get(type_origin, ($type.text)); new_variable = new Variable ( @@ -110,7 +122,6 @@ first_level_fate_instr: ); WORLD.variables().add(new_variable); - */ } | DECLARE_TEXT_EFFECT_KW params=word_list name=WORD R_PAREN |


