| summaryrefslogtreecommitdiff |
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2020-07-20 00:51:37 +0200 |
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2020-07-20 00:51:37 +0200 |
| commit | 39fc3eb50f3984bb128439a2cf190e51267529d9 (patch) | |
| tree | b8a36bad9b60a480c1b6fafcbd73200cd498e354 | |
| parent | 99171d9707c58c4f9841a00bf6fd22c4660a81e4 (diff) | |
Simplifies refs, adds remaining missing stuff.
28 files changed, 1123 insertions, 80 deletions
diff --git a/data/examples/the_thief/include/characters.fate b/data/examples/the_thief/include/characters.fate index 37dea7d..650f253 100644 --- a/data/examples/the_thief/include/characters.fate +++ b/data/examples/the_thief/include/characters.fate @@ -10,57 +10,48 @@ (require include/locations.fate) -(set_fields - (variable oscar) +(set_fields oscar (name Oscar) (agility 50) (perception 50) (money 20) - (location room0) ) +(add (ref oscar) room0.occupants) -(set_fields - (variable carla) +(set_fields carla (name Carla) (agility 75) (perception 35) (money 7) - (location room1) ) +(add (ref carla) room1.occupants) -(set_fields - (variable simon) +(set_fields simon (name Simon) (agility 35) (perception 75) (money 80) - (location room1) ) +(add (ref simon) room2.occupants) -(set_fields - (variable julie) +(set_fields julie (name Julie) (agility 60) (perception 60) (money 90) - (location room2) ) +(add (ref julie) corridor.occupants) -(set_fields - (variable statue) + +(set_fields statue (name ( A oddly human shaped statue, with clothes adorned )) (agility 0) (perception 0) (money 30) - (location corridor) ) - -;; Alright, but we clearly need to be able to point to variables using a type. -;; like (pointer (variable carla)) -> pointer to variable of type character -;; (a string, really) resolves to (variable carla), but allows characters to be -;; put in a set, for example. +(add (ref statue) corridor.occupants) diff --git a/data/examples/the_thief/include/locations.fate b/data/examples/the_thief/include/locations.fate index d7beb18..e46c504 100644 --- a/data/examples/the_thief/include/locations.fate +++ b/data/examples/the_thief/include/locations.fate @@ -1,2 +1,41 @@ (fate_version 1) +(require type/location.fate) + +(declare_variable local location room0) +(declare_variable local location room1) +(declare_variable local location room2) +(declare_variable local location corridor) + +(set_fields room0 + (name ( Room 0 )) + (description + ( An luxurious bedroom, well lit. ) + ) + (luminosity 80) +) + +(set_fields room1 + (name ( Room 1 )) + (description + ( An overly large kitchen, unevenly lit. ) + ) + (luminosity 35) +) + +(set_fields room2 + (name ( Room 2 )) + (description + ( An tiny and messy study, unlit. ) + ) + (luminosity 0) +) + +(set_fields corridor + (name Corridor) + (description + ( A long corridor, with many decorations, and many hiding places. ) + ) + (luminosity 50) +) + diff --git a/data/examples/the_thief/include/type/character.fate b/data/examples/the_thief/include/type/character.fate index 5882fd5..6278ad9 100644 --- a/data/examples/the_thief/include/type/character.fate +++ b/data/examples/the_thief/include/type/character.fate @@ -1,12 +1,12 @@ (fate_version 1) (require stat.fate) -(require location.fate) (declare_dict_type character (string name) (stat agility) (stat perception) (int money) - (location location) ) + +(declare_ref_type character character_ptr) diff --git a/data/examples/the_thief/include/type/location.fate b/data/examples/the_thief/include/type/location.fate index faec74a..9db494f 100644 --- a/data/examples/the_thief/include/type/location.fate +++ b/data/examples/the_thief/include/type/location.fate @@ -1,3 +1,15 @@ (fate_version 1) -(declare_set_type string location) +(require character.fate) + +(declare_set_type character_ptr occupants) +(declare_subtype int luminosity) + +(declare_dict_type location + (string name) + (string description) + (luminosity luminosity) + (occupants occupants) +) + +(declare_ref_type location location_ptr) diff --git a/src/core/src/tonkadur/Main.java b/src/core/src/tonkadur/Main.java index 21bc077..23666dd 100644 --- a/src/core/src/tonkadur/Main.java +++ b/src/core/src/tonkadur/Main.java @@ -14,7 +14,6 @@ public class Main private Main () {}; public static void main (final String[] args) - throws IOException { final World world; final Context context; @@ -22,9 +21,18 @@ public class Main world = new World(); context = Context.build(args[0]); - Utils.add_file_content(context.get_current_file(), context, world); - - System.out.println("Parsing completed."); - System.out.println(world.toString()); + try + { + Utils.add_file_content(context.get_current_file(), context, world); + + System.out.println("Parsing completed."); + System.out.println(world.toString()); + } + catch (final Exception e) + { + System.err.println("Parsing failed."); + System.err.println(world.toString()); + e.printStackTrace(); + } } } diff --git a/src/core/src/tonkadur/fate/v1/error/ConflictingTypeException.java b/src/core/src/tonkadur/fate/v1/error/ConflictingTypeException.java index 5a1d06e..3b49861 100644 --- a/src/core/src/tonkadur/fate/v1/error/ConflictingTypeException.java +++ b/src/core/src/tonkadur/fate/v1/error/ConflictingTypeException.java @@ -47,10 +47,10 @@ public class ConflictingTypeException extends ParsingError sb.append(System.lineSeparator()); sb.append("Resulting type '"); - sb.append(given_type.get_name()); + sb.append(given_type.toString()); sb.append("' "); sb.append(" conflicts with the expected one ('"); - sb.append(expected_type.get_name()); + sb.append(expected_type.toString()); sb.append("')."); return sb.toString(); diff --git a/src/core/src/tonkadur/fate/v1/error/IncompatibleTypeException.java b/src/core/src/tonkadur/fate/v1/error/IncompatibleTypeException.java index 6ada2c3..20ab742 100644 --- a/src/core/src/tonkadur/fate/v1/error/IncompatibleTypeException.java +++ b/src/core/src/tonkadur/fate/v1/error/IncompatibleTypeException.java @@ -79,7 +79,7 @@ public class IncompatibleTypeException extends ParsingError { sb.append(System.lineSeparator()); sb.append("Recommended compatible type: "); - sb.append(hint.get_name()); + sb.append(hint.toString()); } return sb.toString(); diff --git a/src/core/src/tonkadur/fate/v1/error/NotAValueMacroException.java b/src/core/src/tonkadur/fate/v1/error/NotAValueMacroException.java new file mode 100644 index 0000000..b235ad9 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/error/NotAValueMacroException.java @@ -0,0 +1,53 @@ +package tonkadur.fate.v1.error; + +import tonkadur.error.ErrorLevel; + +import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +public class NotAValueMacroException extends ParsingError +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final String macro_name; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + public NotAValueMacroException (final Origin origin, final String macro_name) + { + super + ( + ErrorLevel.ERROR, + ErrorCategory.INVALID_USE, + origin + ); + + this.macro_name = macro_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("Macro '"); + sb.append(macro_name); + sb.append + ( + "' is not defined as a single value and thus cannot be used as one." + ); + sb.append(System.lineSeparator()); + sb.append("Does it contain instructions?"); + sb.append(System.lineSeparator()); + sb.append("Is it a sequence of multiple values?"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/Macro.java b/src/core/src/tonkadur/fate/v1/lang/Macro.java index 7834bfc..6030663 100644 --- a/src/core/src/tonkadur/fate/v1/lang/Macro.java +++ b/src/core/src/tonkadur/fate/v1/lang/Macro.java @@ -1,10 +1,22 @@ package tonkadur.fate.v1.lang; +import java.util.ArrayList; +import java.util.List; + import tonkadur.parser.Origin; import tonkadur.fate.v1.lang.meta.DeclaredEntity; import tonkadur.fate.v1.lang.meta.InstructionNode; import tonkadur.fate.v1.lang.meta.TypedEntryList; +import tonkadur.fate.v1.lang.meta.ValueNode; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.instruction.Display; +import tonkadur.fate.v1.lang.instruction.InstructionList; + +import tonkadur.fate.v1.lang.valued_node.Cast; +import tonkadur.fate.v1.lang.valued_node.ValueToText; public class Macro extends DeclaredEntity { @@ -50,6 +62,71 @@ public class Macro extends DeclaredEntity return root; } + public List<Type> get_signature () + { + final List<Type> result; + + result = new ArrayList<Type>(); + + for (final TypedEntryList.TypedEntry entry: parameters.get_entries()) + { + result.add(entry.get_type()); + } + + return result; + } + + public ValueNode get_value_node_representation () + { + final Cast result_cast; + InstructionList root_as_il; + InstructionNode instr; + ValueNode result; + + if (!(root instanceof InstructionList)) + { + return null; + } + + root_as_il = (InstructionList) root; + + if (root_as_il.get_instructions().size() != 1) + { + return null; + } + + instr = root_as_il.get_instructions().get(0); + + if (!(instr instanceof Display)) + { + return null; + } + + result = ((Display) instr).get_content(); + + if (!(result instanceof ValueToText)) + { + return result; + } + + result = ((ValueToText) result).get_value(); + + if (!(result instanceof Cast)) + { + return result; + } + + result_cast = (Cast) result; + + if (result_cast.is_autogenerated()) + { + return result_cast.get_parent(); + } + else + { + return result; + } + } /**** Compatibility ********************************************************/ /* diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/AddElement.java b/src/core/src/tonkadur/fate/v1/lang/instruction/AddElement.java index 9cc9b3b..775fa63 100644 --- a/src/core/src/tonkadur/fate/v1/lang/instruction/AddElement.java +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/AddElement.java @@ -81,7 +81,12 @@ public class AddElement extends InstructionNode collection_true_type = (CollectionType) collection_type; collection_element_type = collection_true_type.get_content_type(); - if (element.get_type().can_be_used_as(collection_element_type)) + if + ( + element.get_type().can_be_used_as(collection_element_type) + || + (element.get_type().try_merging_with(collection_element_type) != null) + ) { return new AddElement(origin, element, collection); } diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/EventCall.java b/src/core/src/tonkadur/fate/v1/lang/instruction/EventCall.java new file mode 100644 index 0000000..8706f9c --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/EventCall.java @@ -0,0 +1,167 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.ArrayList; +import java.util.List; + +import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +import tonkadur.functional.Merge; + +import tonkadur.error.ErrorManager; + +import tonkadur.fate.v1.error.IncompatibleTypeException; +import tonkadur.fate.v1.error.IncomparableTypeException; +import tonkadur.fate.v1.error.InvalidArityException; + +import tonkadur.fate.v1.lang.Event; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionNode; +import tonkadur.fate.v1.lang.meta.ValueNode; + +public class EventCall extends InstructionNode +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final Event event; + protected final List<ValueNode> parameters; + + /***************************************************************************/ + /**** PROTECTED ************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + protected EventCall + ( + final Origin origin, + final Event event, + final List<ValueNode> parameters + ) + { + super(origin); + + this.event = event; + this.parameters = parameters; + } + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + public static EventCall build + ( + final Origin origin, + final Event event, + final List<ValueNode> parameters + ) + throws Throwable + { + final List<Boolean> type_checks; + final List<Type> signature; + + signature = event.get_signature(); + + if (parameters.size() != signature.size()) + { + ErrorManager.handle + ( + new InvalidArityException + ( + origin, + parameters.size(), + signature.size(), + signature.size() + ) + ); + } + + (new Merge<Type, ValueNode, Boolean>() + { + @Override + public Boolean risky_lambda (final Type t, final ValueNode p) + throws ParsingError + { + if ((t == null) || (p == null)) + { + return Boolean.FALSE; + } + else + { + final Type hint; + + if (p.get_type().can_be_used_as(t)) + { + return Boolean.TRUE; + } + + if (p.get_type().try_merging_with(t) != null) + { + return Boolean.TRUE; + } + + ErrorManager.handle + ( + new IncompatibleTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + + hint = (Type) p.get_type().generate_comparable_to(t); + + if (hint.equals(Type.ANY)) + { + ErrorManager.handle + ( + new IncomparableTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + } + + return Boolean.FALSE; + } + } + }).risky_merge(signature, parameters); + + return new EventCall(origin, event, parameters); + } + + /**** Accessors ************************************************************/ + public Event get_event () + { + return event; + } + + public List<ValueNode> get_parameters () + { + return parameters; + } + + /**** Misc. ****************************************************************/ + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("(EventCall ("); + sb.append(event.get_name()); + + for (final ValueNode param: parameters) + { + sb.append(" "); + sb.append(param.toString()); + } + + sb.append("))"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/MacroCall.java b/src/core/src/tonkadur/fate/v1/lang/instruction/MacroCall.java new file mode 100644 index 0000000..f00c9f2 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/MacroCall.java @@ -0,0 +1,167 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.ArrayList; +import java.util.List; + +import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +import tonkadur.functional.Merge; + +import tonkadur.error.ErrorManager; + +import tonkadur.fate.v1.error.IncompatibleTypeException; +import tonkadur.fate.v1.error.IncomparableTypeException; +import tonkadur.fate.v1.error.InvalidArityException; + +import tonkadur.fate.v1.lang.Macro; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionNode; +import tonkadur.fate.v1.lang.meta.ValueNode; + +public class MacroCall extends InstructionNode +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final Macro macro; + protected final List<ValueNode> parameters; + + /***************************************************************************/ + /**** PROTECTED ************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + protected MacroCall + ( + final Origin origin, + final Macro macro, + final List<ValueNode> parameters + ) + { + super(origin); + + this.macro = macro; + this.parameters = parameters; + } + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + public static MacroCall build + ( + final Origin origin, + final Macro macro, + final List<ValueNode> parameters + ) + throws Throwable + { + final List<Boolean> type_checks; + final List<Type> signature; + + signature = macro.get_signature(); + + if (parameters.size() != signature.size()) + { + ErrorManager.handle + ( + new InvalidArityException + ( + origin, + parameters.size(), + signature.size(), + signature.size() + ) + ); + } + + (new Merge<Type, ValueNode, Boolean>() + { + @Override + public Boolean risky_lambda (final Type t, final ValueNode p) + throws ParsingError + { + if ((t == null) || (p == null)) + { + return Boolean.FALSE; + } + else + { + final Type hint; + + if (p.get_type().can_be_used_as(t)) + { + return Boolean.TRUE; + } + + if (p.get_type().try_merging_with(t) != null) + { + return Boolean.TRUE; + } + + ErrorManager.handle + ( + new IncompatibleTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + + hint = (Type) p.get_type().generate_comparable_to(t); + + if (hint.equals(Type.ANY)) + { + ErrorManager.handle + ( + new IncomparableTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + } + + return Boolean.FALSE; + } + } + }).risky_merge(signature, parameters); + + return new MacroCall(origin, macro, parameters); + } + + /**** Accessors ************************************************************/ + public Macro get_macro () + { + return macro; + } + + public List<ValueNode> get_parameters () + { + return parameters; + } + + /**** Misc. ****************************************************************/ + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("(MacroCall ("); + sb.append(macro.get_name()); + + for (final ValueNode param: parameters) + { + sb.append(" "); + sb.append(param.toString()); + } + + sb.append("))"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveAllOfElement.java b/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveAllOfElement.java index 937138c..0f6aba5 100644 --- a/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveAllOfElement.java +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveAllOfElement.java @@ -81,7 +81,12 @@ public class RemoveAllOfElement extends InstructionNode collection_true_type = (CollectionType) collection_type; collection_element_type = collection_true_type.get_content_type(); - if (element.get_type().can_be_used_as(collection_element_type)) + if + ( + element.get_type().can_be_used_as(collection_element_type) + || + (element.get_type().try_merging_with(collection_element_type) != null) + ) { return new RemoveAllOfElement(origin, element, collection); } diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveElement.java b/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveElement.java index c05ed5e..136524b 100644 --- a/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveElement.java +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/RemoveElement.java @@ -81,7 +81,12 @@ public class RemoveElement extends InstructionNode collection_true_type = (CollectionType) collection_type; collection_element_type = collection_true_type.get_content_type(); - if (element.get_type().can_be_used_as(collection_element_type)) + if + ( + element.get_type().can_be_used_as(collection_element_type) + || + (element.get_type().try_merging_with(collection_element_type) != null) + ) { return new RemoveElement(origin, element, collection); } diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/SetValue.java b/src/core/src/tonkadur/fate/v1/lang/instruction/SetValue.java index 9b50b47..efee224 100644 --- a/src/core/src/tonkadur/fate/v1/lang/instruction/SetValue.java +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/SetValue.java @@ -58,11 +58,17 @@ public class SetValue extends InstructionNode value_reference_type = value_reference.get_type(); - if (element.get_type().can_be_used_as(value_reference_type)) + if + ( + element.get_type().can_be_used_as(value_reference_type) + || + (element.get_type().try_merging_with(value_reference_type) != null) + ) { return new SetValue(origin, element, value_reference); } + ErrorManager.handle ( new ConflictingTypeException diff --git a/src/core/src/tonkadur/fate/v1/lang/type/Type.java b/src/core/src/tonkadur/fate/v1/lang/type/Type.java index 87ef5fe..ec961d8 100644 --- a/src/core/src/tonkadur/fate/v1/lang/type/Type.java +++ b/src/core/src/tonkadur/fate/v1/lang/type/Type.java @@ -124,6 +124,26 @@ public class Type extends DeclaredEntity return (parent == null); } + public Type try_merging_with (final Type t) + { + if (t.get_base_type() != get_base_type()) + { + return null; + } + + if (t.is_base_type()) + { + return this; + } + + if (is_base_type()) + { + return t; + } + + return null; + } + /**** Compatibility ********************************************************/ public boolean can_be_used_as (final Type t) { diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/Cast.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/Cast.java index 62a258f..9a084ce 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/Cast.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/Cast.java @@ -83,6 +83,7 @@ public class Cast extends ValueNode /**** MEMBERS **************************************************************/ /***************************************************************************/ protected final ValueNode value; + protected final boolean is_autogenerated; /***************************************************************************/ /**** PROTECTED ************************************************************/ @@ -92,11 +93,13 @@ public class Cast extends ValueNode ( final Origin origin, final Type to, - final ValueNode value + final ValueNode value, + final boolean is_autogenerated ) { super(origin, to); this.value = value; + this.is_autogenerated = is_autogenerated; } /***************************************************************************/ @@ -107,7 +110,8 @@ public class Cast extends ValueNode ( final Origin origin, final Type to, - final ValueNode value + final ValueNode value, + final boolean is_autogenerated ) throws IncompatibleTypeException, @@ -131,7 +135,7 @@ public class Cast extends ValueNode ) ) { - return new Cast(origin, to, value); + return new Cast(origin, to, value, is_autogenerated); } hint = (Type) value.get_type().generate_comparable_to(to); @@ -156,11 +160,21 @@ public class Cast extends ValueNode ); } - return new Cast(origin, hint, value); + return new Cast(origin, hint, value, is_autogenerated); } /**** Accessors ************************************************************/ + public ValueNode get_parent () + { + return value; + } + + public boolean is_autogenerated () + { + return is_autogenerated; + } + /**** Misc. ****************************************************************/ @Override public String toString () diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/CondValue.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/CondValue.java index fa8dcaf..0cdb45e 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/CondValue.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/CondValue.java @@ -55,7 +55,7 @@ public class CondValue extends ValueNode IncomparableTypeException { final Type first_type; - Type hint; + Type candidate_hint, hint; first_type = branches.get(0).get_cdr().get_type(); hint = first_type; @@ -80,6 +80,15 @@ public class CondValue extends ValueNode continue; } + candidate_hint = entry.get_cdr().get_type().try_merging_with(hint); + + if (candidate_hint != null) + { + hint = candidate_hint; + + continue; + } + ErrorManager.handle ( new ConflictingTypeException diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/CountOperator.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/CountOperator.java index 7eacc40..3b7787c 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/CountOperator.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/CountOperator.java @@ -80,7 +80,12 @@ public class CountOperator extends ValueNode collection_true_type = (CollectionType) collection_type; collection_element_type = collection_true_type.get_content_type(); - if (element.get_type().can_be_used_as(collection_element_type)) + if + ( + element.get_type().can_be_used_as(collection_element_type) + || + (element.get_type().try_merging_with(collection_element_type) != null) + ) { return new CountOperator(origin, element, collection); } diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/IfElseValue.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/IfElseValue.java index 1b40f73..a54c1b6 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/IfElseValue.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/IfElseValue.java @@ -59,7 +59,7 @@ public class IfElseValue extends ValueNode ConflictingTypeException, IncomparableTypeException { - final Type hint; + Type hint; final Type if_true_type; final Type if_false_type; @@ -85,6 +85,13 @@ public class IfElseValue extends ValueNode new IfElseValue(origin, if_true_type, condition, if_true, if_false); } + hint = if_true_type.try_merging_with(if_false_type); + + if (hint != null) + { + return new IfElseValue(origin, hint, condition, if_true, if_false); + } + ErrorManager.handle ( new ConflictingTypeException diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/IsMemberOperator.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/IsMemberOperator.java index 7701614..b0c8fa8 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/IsMemberOperator.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/IsMemberOperator.java @@ -80,7 +80,12 @@ public class IsMemberOperator extends ValueNode collection_true_type = (CollectionType) collection_type; collection_element_type = collection_true_type.get_content_type(); - if (element.get_type().can_be_used_as(collection_element_type)) + if + ( + element.get_type().can_be_used_as(collection_element_type) + || + (element.get_type().try_merging_with(collection_element_type) != null) + ) { return new IsMemberOperator(origin, element, collection); } diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/MacroValueCall.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/MacroValueCall.java new file mode 100644 index 0000000..1405e6f --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/MacroValueCall.java @@ -0,0 +1,185 @@ +package tonkadur.fate.v1.lang.valued_node; + +import java.util.ArrayList; +import java.util.List; + +import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +import tonkadur.functional.Merge; + +import tonkadur.error.ErrorManager; + +import tonkadur.fate.v1.error.IncompatibleTypeException; +import tonkadur.fate.v1.error.IncomparableTypeException; +import tonkadur.fate.v1.error.InvalidArityException; +import tonkadur.fate.v1.error.NotAValueMacroException; + +import tonkadur.fate.v1.lang.Macro; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.ValueNode; + +public class MacroValueCall extends ValueNode +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final Macro macro; + protected final ValueNode act_as; + protected final List<ValueNode> parameters; + + /***************************************************************************/ + /**** PROTECTED ************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + protected MacroValueCall + ( + final Origin origin, + final Macro macro, + final List<ValueNode> parameters, + final ValueNode act_as + ) + { + super(origin, act_as.get_type()); + + this.macro = macro; + this.parameters = parameters; + this.act_as = act_as; + } + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + public static MacroValueCall build + ( + final Origin origin, + final Macro macro, + final List<ValueNode> parameters + ) + throws Throwable + { + ValueNode act_as; + final List<Type> signature; + + act_as = macro.get_value_node_representation(); + + if (act_as == null) + { + ErrorManager.handle + ( + new NotAValueMacroException(origin, macro.get_name()) + ); + } + + signature = macro.get_signature(); + + if (parameters.size() != signature.size()) + { + ErrorManager.handle + ( + new InvalidArityException + ( + origin, + parameters.size(), + signature.size(), + signature.size() + ) + ); + } + + (new Merge<Type, ValueNode, Boolean>() + { + @Override + public Boolean risky_lambda (final Type t, final ValueNode p) + throws ParsingError + { + if ((t == null) || (p == null)) + { + return Boolean.FALSE; + } + else + { + final Type hint; + + if (p.get_type().can_be_used_as(t)) + { + return Boolean.TRUE; + } + + if (p.get_type().try_merging_with(t) != null) + { + return Boolean.TRUE; + } + + ErrorManager.handle + ( + new IncompatibleTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + + hint = (Type) p.get_type().generate_comparable_to(t); + + if (hint.equals(Type.ANY)) + { + ErrorManager.handle + ( + new IncomparableTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + } + + return Boolean.FALSE; + } + } + }).risky_merge(signature, parameters); + + return new MacroValueCall(origin, macro, parameters, act_as); + } + + /**** Accessors ************************************************************/ + public Macro get_macro () + { + return macro; + } + + public ValueNode get_actual_value_node () + { + return act_as; + } + + public List<ValueNode> get_parameters () + { + return parameters; + } + + /**** Misc. ****************************************************************/ + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("(MacroValueCall ("); + sb.append(macro.get_name()); + + for (final ValueNode param: parameters) + { + sb.append(" "); + sb.append(param.toString()); + } + + sb.append("))"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/Operation.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/Operation.java index 87ea676..8b7e2b2 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/Operation.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/Operation.java @@ -127,19 +127,26 @@ public class Operation extends ValueNode continue; } + previous_computed_type = computed_type; + computed_type = computed_type.try_merging_with(operand_type); + + if (computed_type != null) + { + continue; + } + ErrorManager.handle ( new IncompatibleTypeException ( operand.get_origin(), operand_type, - computed_type + previous_computed_type ) ); - previous_computed_type = computed_type; computed_type = - (Type) computed_type.generate_comparable_to(operand_type); + (Type) previous_computed_type.generate_comparable_to(operand_type); if (computed_type.equals(Type.ANY)) { diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/RefOperator.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/RefOperator.java index e6d03b2..d99bb76 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/RefOperator.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/RefOperator.java @@ -2,10 +2,9 @@ package tonkadur.fate.v1.lang.valued_node; import tonkadur.parser.Origin; -import tonkadur.fate.v1.lang.Variable; - import tonkadur.fate.v1.lang.type.RefType; +import tonkadur.fate.v1.lang.meta.Reference; import tonkadur.fate.v1.lang.meta.ValueNode; public class RefOperator extends ValueNode @@ -13,16 +12,16 @@ public class RefOperator extends ValueNode /***************************************************************************/ /**** MEMBERS **************************************************************/ /***************************************************************************/ - protected final Variable variable; + protected final Reference referred; /***************************************************************************/ /**** PROTECTED ************************************************************/ /***************************************************************************/ /**** Constructors *********************************************************/ - public RefOperator (final Origin origin, final Variable variable) + public RefOperator (final Origin origin, final Reference referred) { - super(origin, new RefType(origin, variable.get_type(), "auto generated")); - this.variable = variable; + super(origin, new RefType(origin, referred.get_type(), "auto generated")); + this.referred = referred; } /***************************************************************************/ @@ -40,7 +39,7 @@ public class RefOperator extends ValueNode sb.append(origin.toString()); sb.append("(Ref "); - sb.append(variable.get_name()); + sb.append(referred.get_name()); sb.append(") "); return sb.toString(); diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/TextWithEffect.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/TextWithEffect.java index 705ef64..b1fd88a 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/TextWithEffect.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/TextWithEffect.java @@ -4,6 +4,15 @@ import java.util.ArrayList; import java.util.List; import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +import tonkadur.functional.Merge; + +import tonkadur.error.ErrorManager; + +import tonkadur.fate.v1.error.IncompatibleTypeException; +import tonkadur.fate.v1.error.IncomparableTypeException; +import tonkadur.fate.v1.error.InvalidArityException; import tonkadur.fate.v1.lang.TextEffect; @@ -44,20 +53,6 @@ public class TextWithEffect extends TextNode /**** PUBLIC ***************************************************************/ /***************************************************************************/ /**** Constructors *********************************************************/ - public TextWithEffect - ( - final Origin origin, - final TextEffect effect, - final TextNode text - ) - { - super(origin); - - this.effect = effect; - this.parameters = new ArrayList<ValueNode>(); - this.text = text; - } - public static TextWithEffect build ( final Origin origin, @@ -65,8 +60,80 @@ public class TextWithEffect extends TextNode final List<ValueNode> parameters, final TextNode text ) + throws Throwable { - /* TODO: Checks */ + final List<Type> signature; + + signature = effect.get_signature(); + + if (parameters.size() != signature.size()) + { + ErrorManager.handle + ( + new InvalidArityException + ( + origin, + parameters.size(), + signature.size(), + signature.size() + ) + ); + } + + (new Merge<Type,ValueNode,Boolean>() + { + @Override + public Boolean risky_lambda (final Type t, final ValueNode p) + throws ParsingError + { + if ((t == null) || (p == null)) + { + return Boolean.FALSE; + } + else + { + final Type hint; + + if (p.get_type().can_be_used_as(t)) + { + return Boolean.TRUE; + } + + if (p.get_type().try_merging_with(t) != null) + { + return Boolean.TRUE; + } + + ErrorManager.handle + ( + new IncompatibleTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + + hint = (Type) p.get_type().generate_comparable_to(t); + + if (hint.equals(Type.ANY)) + { + ErrorManager.handle + ( + new IncomparableTypeException + ( + p.get_origin(), + p.get_type(), + t + ) + ); + } + + return Boolean.FALSE; + } + } + }).risky_merge(signature, parameters); + return new TextWithEffect(origin, effect, parameters, text); } diff --git a/src/core/src/tonkadur/fate/v1/lang/valued_node/ValueToText.java b/src/core/src/tonkadur/fate/v1/lang/valued_node/ValueToText.java index fcfac27..ec69776 100644 --- a/src/core/src/tonkadur/fate/v1/lang/valued_node/ValueToText.java +++ b/src/core/src/tonkadur/fate/v1/lang/valued_node/ValueToText.java @@ -49,11 +49,12 @@ public class ValueToText extends TextNode return new ValueToText ( - new Cast + Cast.build ( value.get_origin(), Type.STRING, - value + value, + true ) ); } diff --git a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 index 1efccd1..3ec977a 100644 --- a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 +++ b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 @@ -591,25 +591,89 @@ returns [InstructionNode result] ); } - | SET_FIELDS_KW WS+ value_reference WS * field_value_list WS* R_PAREN + | SET_FIELDS_KW WS+ value_reference WS* field_value_list WS* R_PAREN { - /* TODO */ + final Origin origin; + final List<InstructionNode> operations; + + origin = + CONTEXT.get_origin_at + ( + ($SET_FIELDS_KW.getLine()), + ($SET_FIELDS_KW.getCharPositionInLine()) + ); + + operations = new ArrayList<InstructionNode>(); + + for + ( + final Cons<Origin, Cons<String, ValueNode>> entry: + ($field_value_list.result) + ) + { + operations.add + ( + SetValue.build + ( + entry.get_car(), + entry.get_cdr().get_cdr(), + FieldReference.build + ( + entry.get_car(), + ($value_reference.result), + entry.get_cdr().get_car() + ) + ) + ); + } - $result = null; + $result = new InstructionList(origin, operations); } | EVENT_KW WS+ WORD WS+ value_list WS* R_PAREN { - /* TODO */ + final Origin origin; + final Event event; - $result = null; + origin = + CONTEXT.get_origin_at + ( + ($EVENT_KW.getLine()), + ($EVENT_KW.getCharPositionInLine()) + ); + + event = WORLD.events().get(origin, ($WORD.text)); + + $result = + EventCall.build + ( + origin, + event, + ($value_list.result) + ); } | MACRO_KW WS+ WORD WS+ value_list WS* R_PAREN { - /* TODO */ + final Origin origin; + final Macro macro; + + origin = + CONTEXT.get_origin_at + ( + ($MACRO_KW.getLine()), + ($MACRO_KW.getCharPositionInLine()) + ); + + macro = WORLD.macros().get(origin, ($WORD.text)); - $result = null; + $result = + MacroCall.build + ( + origin, + macro, + ($value_list.result) + ); } | SEQUENCE_KW WS+ WORD WS* R_PAREN @@ -956,7 +1020,7 @@ returns [TextNode result]: ); $result = - new TextWithEffect + TextWithEffect.build ( CONTEXT.get_origin_at ( @@ -964,6 +1028,7 @@ returns [TextNode result]: ($WORD.getCharPositionInLine()) ), effect, + new ArrayList<ValueNode>(), ($paragraph.result) ); } @@ -1550,7 +1615,7 @@ returns [ValueNode result] ); $result = - new TextWithEffect + TextWithEffect.build ( CONTEXT.get_origin_at ( @@ -1558,6 +1623,7 @@ returns [ValueNode result] ($WORD.getCharPositionInLine()) ), effect, + new ArrayList<ValueNode>(), ($paragraph.result) ); } @@ -1663,6 +1729,20 @@ returns [ValueNode result] $result = ($math_expression.result); } + | REF_KW WS+ value_reference WS* R_PAREN + { + $result = + new RefOperator + ( + CONTEXT.get_origin_at + ( + ($REF_KW.getLine()), + ($REF_KW.getCharPositionInLine()) + ), + ($value_reference.result) + ); + } + | CAST_KW WS+ WORD WS+ value WS* R_PAREN { final Origin target_type_origin; @@ -1686,7 +1766,8 @@ returns [ValueNode result] ($CAST_KW.getCharPositionInLine()) ), target_type, - ($value.result) + ($value.result), + false ); } @@ -1724,6 +1805,29 @@ returns [ValueNode result] } } + | MACRO_KW WS+ WORD WS+ value_list WS* R_PAREN + { + final Origin origin; + final Macro macro; + + origin = + CONTEXT.get_origin_at + ( + ($MACRO_KW.getLine()), + ($MACRO_KW.getCharPositionInLine()) + ); + + macro = WORLD.macros().get(origin, ($WORD.text)); + + $result = + MacroValueCall.build + ( + origin, + macro, + ($value_list.result) + ); + } + | value_reference { $result = ($value_reference.result); @@ -1877,6 +1981,52 @@ returns [Reference result] } } } + + | WORD + { + final Origin target_var_origin; + final Variable target_var; + final String[] subrefs; + + subrefs = ($WORD.text).split("\\."); + + target_var_origin = + CONTEXT.get_origin_at + ( + ($WORD.getLine()), + ($WORD.getCharPositionInLine()) + ); + + target_var = WORLD.variables().get(target_var_origin, subrefs[0]); + + $result = + new VariableReference + ( + CONTEXT.get_origin_at + ( + ($WORD.getLine()), + ($WORD.getCharPositionInLine()) + ), + target_var + ); + + if (subrefs.length > 1) + { + final List<String> subrefs_list; + + subrefs_list = new ArrayList(Arrays.asList(subrefs)); + + subrefs_list.remove(0); + + $result = + FieldReference.build + ( + target_var_origin, + ($result), + subrefs_list + ); + } + } ; catch [final Throwable e] { diff --git a/src/core/src/tonkadur/functional/Merge.java b/src/core/src/tonkadur/functional/Merge.java index 29d37c5..5d5dcb8 100644 --- a/src/core/src/tonkadur/functional/Merge.java +++ b/src/core/src/tonkadur/functional/Merge.java @@ -39,8 +39,47 @@ public class Merge <Input0, Input1, Output> return output; } + public List<Output> risky_merge + ( + final List<Input0> i0, + final List<Input1> i1 + ) + throws Throwable + { + final int result_size; + final List<Output> output; + final Iterator<Input0> it0; + final Iterator<Input1> it1; + + result_size = Math.max(i0.size(), i1.size()); + output = new ArrayList<Output>(result_size); + + it0 = i0.iterator(); + it1 = i1.iterator(); + + for (int i = 0; i < result_size; ++i) + { + output.add + ( + risky_lambda + ( + it0.hasNext() ? it0.next() : null, + it1.hasNext() ? it1.next() : null + ) + ); + } + + return output; + } + protected Output lambda (final Input0 i0, final Input1 i1) { return null; } + + protected Output risky_lambda (final Input0 i0, final Input1 i1) + throws Throwable + { + return null; + } } |


