| summaryrefslogtreecommitdiff |
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2020-07-05 13:36:24 +0200 |
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2020-07-05 13:36:24 +0200 |
| commit | 1737cb747199beac1879aa0867423bd634113333 (patch) | |
| tree | 541f557f85e44f60eaa1176e3c619f2758549a10 | |
| parent | f6cd96ae24b458a5b4875f8e151758c11c45dbcd (diff) | |
Adds DictType, guards for SetType, hints.
7 files changed, 357 insertions, 31 deletions
diff --git a/src/core/src/tonkadur/fate/v1/error/IncompatibleDeclarationException.java b/src/core/src/tonkadur/fate/v1/error/IncompatibleDeclarationException.java index f1f1be6..ce8792a 100644 --- a/src/core/src/tonkadur/fate/v1/error/IncompatibleDeclarationException.java +++ b/src/core/src/tonkadur/fate/v1/error/IncompatibleDeclarationException.java @@ -14,6 +14,7 @@ public class IncompatibleDeclarationException extends ParsingError /***************************************************************************/ protected final DeclaredEntity new_declaration; protected final DeclaredEntity original_declaration; + protected final DeclaredEntity correction_hint; /***************************************************************************/ /**** PUBLIC ***************************************************************/ @@ -33,6 +34,26 @@ public class IncompatibleDeclarationException extends ParsingError this.new_declaration = new_declaration; this.original_declaration = original_declaration; + this.correction_hint = null; + } + + public IncompatibleDeclarationException + ( + final DeclaredEntity new_declaration, + final DeclaredEntity original_declaration, + final DeclaredEntity correction_hint + ) + { + super + ( + ErrorLevel.ERROR, + ErrorCategory.INCOMPATIBLE, + new_declaration.get_origin() + ); + + this.new_declaration = new_declaration; + this.original_declaration = original_declaration; + this.correction_hint = correction_hint; } @Override @@ -60,6 +81,14 @@ public class IncompatibleDeclarationException extends ParsingError sb.append(new_declaration.toString()); sb.append("."); + if (correction_hint != null) + { + sb.append(System.lineSeparator()); + sb.append("Recommended compatible declaration: "); + sb.append(correction_hint.toString()); + sb.append("."); + } + return sb.toString(); } } diff --git a/src/core/src/tonkadur/fate/v1/error/UnknownDictionaryFieldException.java b/src/core/src/tonkadur/fate/v1/error/UnknownDictionaryFieldException.java new file mode 100644 index 0000000..a624fb8 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/error/UnknownDictionaryFieldException.java @@ -0,0 +1,63 @@ +package tonkadur.fate.v1.error; + +import java.util.Map; + +import tonkadur.error.ErrorLevel; + +import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +import tonkadur.fate.v1.lang.DictType; +import tonkadur.fate.v1.lang.Type; + +public class UnknownDictionaryFieldException extends ParsingError +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final String field_name; + protected final DictType dict; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + public UnknownDictionaryFieldException + ( + final Origin origin, + final String field_name, + final DictType dict + ) + { + super(ErrorLevel.ERROR, ErrorCategory.INVALID_USE, origin); + this.field_name = field_name; + this.dict = dict; + } + + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append(origin.get_context().toString()); + sb.append(error_category.toString()); + sb.append(" Unknown field '"); + 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(System.lineSeparator()); + sb.append("Available fields are:"); + + for (final Map.Entry<String, Type> field: dict.get_fields()) + { + sb.append("- "); + sb.append(field.getKey()); + sb.append(": "); + sb.append(field.getValue().get_name()); + } + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/DictType.java b/src/core/src/tonkadur/fate/v1/lang/DictType.java new file mode 100644 index 0000000..0b1d138 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/DictType.java @@ -0,0 +1,178 @@ +package tonkadur.fate.v1.lang; + +import java.util.Map; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Set; + +import tonkadur.parser.Origin; + +import tonkadur.error.ErrorManager; + +import tonkadur.fate.v1.error.UnknownDictionaryFieldException; + +import tonkadur.fate.v1.lang.meta.DeclaredEntity; + +public class DictType extends Type +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final Map<String, Type> field_types; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + + /**** Constructors *********************************************************/ + public DictType + ( + final Origin origin, + final Map<String, Type> field_types, + final String name + ) + { + super(origin, Type.DICT, name); + + this.field_types = field_types; + } + + /**** Accessors ************************************************************/ + public Type get_field_type (final Origin call_origin, final String t) + throws UnknownDictionaryFieldException + { + final Type result; + + result = field_types.get(t); + + if (result == null) + { + ErrorManager.handle + ( + new UnknownDictionaryFieldException(call_origin, t, this) + ); + + return Type.ANY; + } + + return result; + } + + public Set<Map.Entry<String, Type>> get_fields () + { + return field_types.entrySet(); + } + + /**** Compatibility ********************************************************/ + @Override + public boolean can_be_used_as (final Type t) + { + if (t instanceof DictType) + { + final DictType dt; + + dt = (DictType) t; + + for (final Map.Entry<String, Type> own_field: get_fields()) + { + final Type dt_field_t; + + dt_field_t = dt.field_types.get(own_field.getKey()); + + if + ( + (dt_field_t == null) + || !(own_field.getValue().can_be_used_as(dt_field_t)) + ) + { + return false; + } + } + + return true; + + } + + return false; + } + + /* + * This is for the very special case where a type is used despite not being + * even a sub-type of the expected one. Using this rather expensive function, + * the most restrictive shared type will be returned. If no such type exists, + * the ANY time is returned. + */ + @Override + public DeclaredEntity generate_comparable_to (final DeclaredEntity de) + { + final Map<String, Type> result_field_types; + final Set<String> result_field_names; + final DictType dt; + + if (!(de instanceof DictType)) + { + return Type.ANY; + } + + dt = (DictType) de; + + result_field_names = new HashSet<String>(); + result_field_types = new HashMap<String, Type>(); + + result_field_names.addAll(field_types.keySet()); + result_field_names.addAll(dt.field_types.keySet()); + + for (final String field_name: result_field_names) + { + final Type this_type; + final Type other_type; + Type result_field_type; + + this_type = field_types.get(field_name); + other_type = dt.field_types.get(field_name); + + if (this_type == null) + { + result_field_type = other_type; + } + else if (other_type == null) + { + result_field_type = this_type; + } + else + { + result_field_type = + (Type) this_type.generate_comparable_to(other_type); + } + + result_field_types.put(field_name, result_field_type); + } + + return new DictType(get_origin(), result_field_types, name); + } + + + /**** Misc. ****************************************************************/ + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("(Dict "); + + for (final Map.Entry<String, Type> field: get_fields()) + { + sb.append(System.lineSeparator()); + sb.append("(field "); + sb.append(field.getKey()); + sb.append(" "); + sb.append(field.getValue().toString()); + sb.append(")"); + } + sb.append(System.lineSeparator()); + sb.append(")::"); + sb.append(name); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/Operator.java b/src/core/src/tonkadur/fate/v1/lang/Operator.java index f8fb8ff..9e2e522 100644 --- a/src/core/src/tonkadur/fate/v1/lang/Operator.java +++ b/src/core/src/tonkadur/fate/v1/lang/Operator.java @@ -1,8 +1,7 @@ package tonkadur.fate.v1.lang; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; +import java.util.Collections; +import java.util.Set; public enum Operator { @@ -11,12 +10,12 @@ public enum Operator TIMES("*", 0, Type.NUMBER_TYPES, null), DIVIDED("/", 0, Type.NUMBER_TYPES, null), POWER("^", 2, Type.NUMBER_TYPES, null), - RANDOM("rand", 2, (new Type[]{Type.INT}), null), + RANDOM("rand", 2, Collections.singleton(Type.INT), null), - AND("and", 0, (new Type[]{Type.BOOLEAN}), null), - OR("or", 0, (new Type[]{Type.BOOLEAN}), null), - NOT("not", 1, (new Type[]{Type.BOOLEAN}), null), - IMPLIES("implies", 1, (new Type[]{Type.BOOLEAN}), null), + AND("and", 0, Collections.singleton(Type.BOOLEAN), null), + OR("or", 0, Collections.singleton(Type.BOOLEAN), null), + NOT("not", 1, Collections.singleton(Type.BOOLEAN), null), + IMPLIES("implies", 1, Collections.singleton(Type.BOOLEAN), null), LOWER_THAN("<", 2, Type.NUMBER_TYPES, Type.BOOLEAN), LOWER_EQUAL_THAN("=<", 2, Type.NUMBER_TYPES, Type.BOOLEAN), @@ -25,26 +24,25 @@ public enum Operator final private String name; final private int arity; - final private Collection<Type> valid_input_types; + final private Set<Type> valid_input_types; final private Type output_type_transform; private Operator ( final String name, final int arity, - final Type[] valid_input_types, + final Set<Type> valid_input_types, final Type output_type_transform ) { this.name = name; this.arity = arity; - this.valid_input_types = - new HashSet<Type>(Arrays.asList(valid_input_types)); + this.valid_input_types = valid_input_types; this.output_type_transform = output_type_transform; } - public Collection<Type> get_allowed_base_types () + public Set<Type> get_allowed_base_types () { return valid_input_types; } diff --git a/src/core/src/tonkadur/fate/v1/lang/SetType.java b/src/core/src/tonkadur/fate/v1/lang/SetType.java index ccb5bf3..2b30139 100644 --- a/src/core/src/tonkadur/fate/v1/lang/SetType.java +++ b/src/core/src/tonkadur/fate/v1/lang/SetType.java @@ -1,9 +1,11 @@ package tonkadur.fate.v1.lang; -import java.util.Iterator; +import tonkadur.error.ErrorManager; import tonkadur.parser.Origin; +import tonkadur.fate.v1.error.InvalidTypeException; + import tonkadur.fate.v1.lang.meta.DeclaredEntity; public class SetType extends Type @@ -18,18 +20,31 @@ public class SetType extends Type /***************************************************************************/ /**** Constructors *********************************************************/ - public SetType + public static SetType build ( final Origin origin, final Type content_type, final String name ) + throws InvalidTypeException { - super(origin, Type.SET, name); + if (!Type.SET_COMPATIBLE_TYPES.contains(content_type.get_true_type())) + { + ErrorManager.handle + ( + new InvalidTypeException + ( + origin, + content_type, + Type.SET_COMPATIBLE_TYPES + ) + ); + } - this.content_type = content_type; + return new SetType(origin, content_type, name); } + /**** Accessors ************************************************************/ public Type get_content_type () { @@ -65,7 +80,7 @@ public class SetType extends Type return new SetType ( - de.get_origin(), + get_origin(), ( (Type) content_type.generate_comparable_to ( @@ -85,8 +100,26 @@ public class SetType extends Type sb.append("(Set "); sb.append(content_type.toString()); - sb.append(")"); + sb.append(")::"); + sb.append(name); return sb.toString(); } + + /***************************************************************************/ + /**** PROTECTED ************************************************************/ + /***************************************************************************/ + + /**** Constructors *********************************************************/ + protected SetType + ( + final Origin origin, + final Type content_type, + final String name + ) + { + super(origin, Type.SET, name); + + this.content_type = content_type; + } } diff --git a/src/core/src/tonkadur/fate/v1/lang/Type.java b/src/core/src/tonkadur/fate/v1/lang/Type.java index ad49268..b5438e5 100644 --- a/src/core/src/tonkadur/fate/v1/lang/Type.java +++ b/src/core/src/tonkadur/fate/v1/lang/Type.java @@ -1,10 +1,11 @@ package tonkadur.fate.v1.lang; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import tonkadur.parser.Context; import tonkadur.parser.Location; @@ -23,7 +24,8 @@ public class Type extends DeclaredEntity public static final Type SET; public static final Type STRING; - public static final Type[] NUMBER_TYPES; + public static final Set<Type> NUMBER_TYPES; + public static final Set<Type> SET_COMPATIBLE_TYPES; static { @@ -44,7 +46,16 @@ public class Type extends DeclaredEntity SET = new Type(base, null, "set"); STRING = new Type(base, null, "string"); - NUMBER_TYPES = new Type[]{FLOAT, INT}; + NUMBER_TYPES = new HashSet<Type>(); + NUMBER_TYPES.add(FLOAT); + NUMBER_TYPES.add(INT); + + SET_COMPATIBLE_TYPES = new HashSet<Type>(); + + SET_COMPATIBLE_TYPES.add(FLOAT); + SET_COMPATIBLE_TYPES.add(INT); + SET_COMPATIBLE_TYPES.add(STRING); + SET_COMPATIBLE_TYPES.add(BOOLEAN); } public static Type value_on_missing () @@ -147,7 +158,7 @@ public class Type extends DeclaredEntity result = candidate; } - return result; + return new Type(origin, result, name); } diff --git a/src/core/src/tonkadur/fate/v1/lang/meta/DeclarationCollection.java b/src/core/src/tonkadur/fate/v1/lang/meta/DeclarationCollection.java index 7bcaaa1..04bbfa9 100644 --- a/src/core/src/tonkadur/fate/v1/lang/meta/DeclarationCollection.java +++ b/src/core/src/tonkadur/fate/v1/lang/meta/DeclarationCollection.java @@ -83,7 +83,7 @@ public class DeclarationCollection <Declared extends DeclaredEntity> /***************************************************************************/ /**** PROTECTED ************************************************************/ /***************************************************************************/ - protected Declared assert_entity_can_be_added (Declared new_version) + protected Declared assert_entity_can_be_added (final Declared new_version) throws DuplicateDeclarationException, ConflictingDeclarationException, @@ -92,6 +92,7 @@ public class DeclarationCollection <Declared extends DeclaredEntity> { final DeclaredEntity de; final Declared previous_version; + Declared hint; previous_version = collection.get(new_version.get_name()); @@ -124,19 +125,15 @@ public class DeclarationCollection <Declared extends DeclaredEntity> return new_version; } - ErrorManager.handle - ( - new IncompatibleDeclarationException(new_version, previous_version) - ); - de = new_version.generate_comparable_to(previous_version); try { - new_version = (Declared) de; + hint = (Declared) de; } catch (final ClassCastException e) { + hint = null; e.printStackTrace(); System.exit(-1); @@ -146,10 +143,27 @@ public class DeclarationCollection <Declared extends DeclaredEntity> { ErrorManager.handle ( + new IncompatibleDeclarationException(new_version, previous_version) + ); + + ErrorManager.handle + ( new IncomparableDeclarationException(new_version, previous_version) ); } + else + { + ErrorManager.handle + ( + new IncompatibleDeclarationException + ( + new_version, + previous_version, + hint + ) + ); + } - return new_version; + return hint; } } |


