Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Construct to mixed2018 (#511)
This set of changes completes the goals of the original construct-to-mixed branch. Function unfortunately worked with Constructs, rather than the Mixed interface. This was a violation of the Dependency Inversion Principal, which has prevented several critical improvements to the language. The problem is that in Java, there is not multiple inheritance, so while normal classes could easily extend Construct and then be added into the ecosystem, for other types of classes, where it's impossible to extend Construct (particularly because they are already extending another class, which is true in at least the cases of enums and exceptions), these objects simply could not be added into the ecosystem.

Now, everything accepts and for the most part deals with Mixed, which is an interface. This has the unfortunate side effect of breaking binary compatibility with extensions, but this change has been in the works for at least three years. As part of this change, implementing enums was used as a test case. That has now also been done, and barring a few bugs, seems to mostly work. This allows access of enums as first class objects, rather than as arrays of strings as previously implemented through reflect_pull.

The PR opens lots of possibilities in the future, and so is a welcome change to the base, but there are a few short term goals after this PR is merged:

* Move exceptions into first class status. Currently they are implemented as arrays, but this is a shoehorn and not ideal.
* Write up documentation for Enums. There is some documentation already available, and this may be mostly correct, but it should at least be read through to ensure it is correct, and then linked to the learning trail. It's also possible to iterate enums with foreach, and so this should be added as an example in various places.
* There are still a few bugs with enums, particularly it is not possible to assign an enum class to a variable. ClassType @s = ArraySortType; should work, but @s remains null. (The same is true even if @s is auto typed).
* Continue with object oriented notation. This provides a good framework to begin with. While it is possible to do EnumType[0] or EnumType['EnumName'], this is the reflective access mechanism, it should also be possible to access the enum by name like EnumType::EnumName.

Since this breaks extensions, the version number has been bumped to 3.3.4, and this PR should not be merged without coordination with extension authors. Also, before merging this PR, one more change should be made, which is to deprecate concatenation of bare strings.

* Start converting construct to mixed.

Also, the first pass at introducing Enums to the object model has been
done. This is not complete yet, until everything supports mixed, but
most of the work for that should have been done now.

* Finish implementing Mixed everywhere. Enums are first class.

Previously, exec(s) accepted an array of Constructs. While this worked
most of the time, it has serious limitations, because object types that
cannot extend Construct (i.e. enums, exceptions, dynamically defined
classes) cannot be passed around. Now, we use Mixed everywhere, instead
of Construct (at least in the interfaces), and so now things like enums
and other classes can implement Mixed, and be added into the ecosystem.
As part of this change, enums are now proper ClassTypes.

An interesting learning here is that we violated the Liskov Substitution
Pricipal early on. Had we not done that, and used an interface up front,
(depend on abstractions, not concretions) we would not have had to deal
with any of this.

Since this changes the interface of Function, this breaks ALL
extensions, thus the version has been bumped to 3.3.4. I have decided to
not add binary compatibility either, since that would introduce a
runtime penalty for every single function call, in every single script.

* This still doesn't work, due to a bug in the compiler

There is a bug in ForceImplements that doesn't respect the fact that
it's an interface.

* Support MDynamicEnum, bump version

MDynamicEnum is now supported, and these show up properly in the compiler
and reflection mechanisms. This is still not entirely useful, but this
sets the stage for some (now) easily implementable features.

* Implement Enums as objects, rather than strings

* Fix some bugs with class type system

* Allow ClassTypes to be standalone usable values

* Add a way for objects to provide a static constructor

Previously, in NativeTypeList, there was no way to customize how an invalid
instance was constructed. Now, if a subclass of Mixed provides a method named
ConstructInvalidInstance, this will be called instead. For now, this is not
necessary in any native classes, but since this picks up extension objects
as well, it might be useful already.

* enums extend mixed
  • Loading branch information
LadyCailin committed Nov 29, 2018
1 parent 676db51 commit 4964181
Show file tree
Hide file tree
Showing 288 changed files with 5,752 additions and 4,133 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.sk89q</groupId>
<artifactId>commandhelper</artifactId>
<version>3.3.3-SNAPSHOT</version>
<version>3.3.4-SNAPSHOT</version>
<name>CommandHelper</name>
<description>CommandHelper is a full blown scripting language built right into Minecraft</description>
<inceptionYear>2010</inceptionYear>
Expand Down
Expand Up @@ -83,6 +83,10 @@ public static void checkForceImplementation() throws Exception {
Set<Class<?>> s = ClassDiscovery.getDefaultInstance().loadClassesThatExtend(superClass);
checkImplements:
for(Class<?> c : s) {
if(c.isInterface()) {
// Interfaces are exempt from the requirement
continue;
}
// First, check if maybe it has a InterfaceRunner for it
findRunner:
for(Class<?> ir : ClassDiscovery.getDefaultInstance().loadClassesWithAnnotation(InterfaceRunnerFor.class)) {
Expand Down
Expand Up @@ -100,10 +100,21 @@ public static String Join(Map map, String entryGlue, String elementGlue, String
* @param glue The glue to use
* @return The concatenated string
*/
public static String Join(Set set, String glue) {
public static <T> String Join(Set<T> set, String glue) {
return Join(set, glue, null, null, null);
}

/**
* Joins a set together, rendering each item with the custom renderer.
* @param set
* @param glue
* @param r
* @return
*/
public static <T> String Join(Set<T> set, String glue, Renderer<T> r) {
return Join(set, glue, null, null, null, r);
}

/**
* Joins a set together (using StringBuilder's {
*
Expand Down Expand Up @@ -150,7 +161,7 @@ public static String Join(Set set, String glue, String lastGlue, String glueForT
* @param empty If the set is completely empty, this string is simply returned. If null, an empty string is used.
* @return The concatenated string
*/
public static String Join(Set set, String glue, String lastGlue, String glueForTwoItems, String empty) {
public static <T> String Join(Set<T> set, String glue, String lastGlue, String glueForTwoItems, String empty) {
return Join(set, glue, lastGlue, glueForTwoItems, empty, null);
}

Expand Down
22 changes: 11 additions & 11 deletions src/main/java/com/laytonsmith/PureUtilities/MSP/Burst.java
@@ -1,6 +1,6 @@
package com.laytonsmith.PureUtilities.MSP;

import com.laytonsmith.core.CHVersion;
import com.laytonsmith.core.MSVersion;
import com.laytonsmith.core.SimpleDocumentation;

/**
Expand All @@ -20,32 +20,32 @@ public class Burst {

public static enum BurstType implements SimpleDocumentation {
@RemoteCapability()
META("Provides meta information to the client/server. The payload will be a json with further information", CHVersion.V3_3_1),
META("Provides meta information to the client/server. The payload will be a json with further information", MSVersion.V3_3_1),
@RemoteCapability()
FUNCTION("This is a static function/procedure call. No rider information is provided, but the payload will"
+ " be a json array, with [0] being the fully qualified function name, and [1..] being the json"
+ " encoded arguments.", CHVersion.V3_3_1),
+ " encoded arguments.", MSVersion.V3_3_1),
@RemoteCapability()
METHOD("This is an instance based method call. The rider will be the json encoded object that this method"
+ " is being called on, and the payload will be the same as " + FUNCTION.name() + "'s payload.", CHVersion.V3_3_1),
+ " is being called on, and the payload will be the same as " + FUNCTION.name() + "'s payload.", MSVersion.V3_3_1),
@RemoteCapability()
RESPONSE("This is a response from a previous call. The payload will be the json encoded response.", CHVersion.V3_3_1),
RESPONSE("This is a response from a previous call. The payload will be the json encoded response.", MSVersion.V3_3_1),
@RemoteCapability()
VOID("This is a response from a previous call, but the function/procedure/method returned void. This"
+ " response is simply to inform the client/server that the response succeeded, while minimizing"
+ " the data transmitted", CHVersion.V3_3_1),
+ " the data transmitted", MSVersion.V3_3_1),
@RemoteCapability()
EXCEPTION("This is a response from a previous call, but the function/procedure/method returned with an exception."
+ " The payload will be the exception type, and the rider will be the exception message", CHVersion.V3_3_1),
+ " The payload will be the exception type, and the rider will be the exception message", MSVersion.V3_3_1),
@RemoteCapability()
ERROR("While handling the request, the remote failed unexpectedly. The payload will simply contain error information"
+ " in an unspecified format, which is intended to be helpful, but should not typically be shown to the"
+ " end user.", CHVersion.V3_3_1);
+ " end user.", MSVersion.V3_3_1);

String doc;
CHVersion version;
MSVersion version;

private BurstType(String doc, CHVersion version) {
private BurstType(String doc, MSVersion version) {
this.doc = doc;
this.version = version;
}
Expand All @@ -61,7 +61,7 @@ public String docs() {
}

@Override
public CHVersion since() {
public MSVersion since() {
return version;
}

Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("BlockFace")
@MEnum("com.commandhelper.BlockFace")
public enum MCBlockFace {
NORTH(0, 0, -1),
EAST(1, 0, 0),
Expand Down
Expand Up @@ -12,14 +12,14 @@
import com.laytonsmith.core.constructs.CBoolean;
import com.laytonsmith.core.constructs.CClosure;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.Construct;
import com.laytonsmith.core.constructs.Target;
import com.laytonsmith.core.environments.CommandHelperEnvironment;
import com.laytonsmith.core.events.Driver;
import com.laytonsmith.core.events.EventUtils;
import com.laytonsmith.core.exceptions.ConfigRuntimeException;
import com.laytonsmith.core.exceptions.FunctionReturnException;
import com.laytonsmith.core.functions.Commands;
import com.laytonsmith.core.natives.interfaces.Mixed;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.command.Command;
Expand Down Expand Up @@ -214,15 +214,15 @@ public List<String> handleTabComplete(MCCommandSender sender, String alias, Stri
new CArray(t) // reserved for an obgen style command array
);
} catch (FunctionReturnException e) {
Construct fret = e.getReturn();
Mixed fret = e.getReturn();
if(fret instanceof CArray) {
List<String> ret = new ArrayList<>();
if(((CArray) fret).inAssociativeMode()) {
for(Construct key : ((CArray) fret).keySet()) {
for(Mixed key : ((CArray) fret).keySet()) {
ret.add(((CArray) fret).get(key, Target.UNKNOWN).val());
}
} else {
for(Construct value : ((CArray) fret).asList()) {
for(Mixed value : ((CArray) fret).asList()) {
ret.add(value.val());
}
}
Expand Down Expand Up @@ -257,7 +257,7 @@ public boolean handleCustomCommand(MCCommandSender sender, String label, String[
new CArray(t) // reserved for an obgen style command array
);
} catch (FunctionReturnException e) {
Construct fret = e.getReturn();
Mixed fret = e.getReturn();
if(fret instanceof CBoolean) {
return ((CBoolean) fret).getBoolean();
}
Expand Down
Expand Up @@ -3,12 +3,12 @@
import com.laytonsmith.abstraction.bukkit.BukkitMCServer;
import com.laytonsmith.core.Static;
import com.laytonsmith.core.constructs.CString;
import com.laytonsmith.core.constructs.Construct;
import com.laytonsmith.core.constructs.Target;
import com.laytonsmith.core.events.AbstractEvent;
import com.laytonsmith.core.events.BindableEvent;
import com.laytonsmith.core.events.EventMixinInterface;
import com.laytonsmith.core.exceptions.EventException;
import com.laytonsmith.core.natives.interfaces.Mixed;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.entity.Entity;
Expand Down Expand Up @@ -40,8 +40,8 @@ public void cancel(BindableEvent e, boolean state) {
}

@Override
public Map<String, Construct> evaluate_helper(BindableEvent event) throws EventException {
Map<String, Construct> map = new HashMap<>();
public Map<String, Mixed> evaluate_helper(BindableEvent event) throws EventException {
Map<String, Mixed> map = new HashMap<>();
map.put("event_type", new CString(mySuper.getName(), Target.UNKNOWN));
String macro;
Object e = event._GetObject();
Expand Down
Expand Up @@ -6,12 +6,12 @@

public interface MCHorse extends MCTameable, MCVehicle, MCInventoryHolder {

@MEnum("HorseColor")
@MEnum("com.commandhelper.HorseColor")
enum MCHorseColor {
BLACK, BROWN, CHESTNUT, CREAMY, DARK_BROWN, GRAY, WHITE
}

@MEnum("HorsePattern")
@MEnum("com.commandhelper.HorsePattern")
enum MCHorsePattern {
NONE, SOCKS, WHITEFIELD, WHITE_DOTS, BLACK_DOTS
}
Expand Down
Expand Up @@ -4,7 +4,7 @@

public interface MCLlama extends MCChestedHorse {

@MEnum("LlamaColor")
@MEnum("com.commandhelper.LlamaColor")
enum MCLlamaColor {
CREAMY, WHITE, BROWN, GRAY
}
Expand Down
Expand Up @@ -13,7 +13,7 @@ public interface MCTropicalFish extends MCLivingEntity {
MCTropicalFish.MCPattern getPattern();
void setPattern(MCTropicalFish.MCPattern pattern);

@MEnum("TropicalFishPattern")
@MEnum("com.commandhelper.TropicalFishPattern")
enum MCPattern {
KOB,
SUNSTREAK,
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/laytonsmith/abstraction/enums/MCArt.java
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("Art")
@MEnum("com.commandhelper.Art")
public enum MCArt {
KEBAB,
AZTEC,
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("BarColor")
@MEnum("com.commandhelper.BarColor")
public enum MCBarColor {
PINK,
BLUE,
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("BarStyle")
@MEnum("com.commandhelper.BarStyle")
public enum MCBarStyle {
SOLID,
SEGMENTED_6,
Expand Down
Expand Up @@ -2,7 +2,6 @@

import com.laytonsmith.PureUtilities.ClassLoading.DynamicEnum;
import com.laytonsmith.annotations.MDynamicEnum;
import com.laytonsmith.annotations.MEnum;
import com.laytonsmith.core.Static;

import java.util.ArrayList;
Expand All @@ -12,7 +11,7 @@
import java.util.Map;
import java.util.Set;

@MDynamicEnum("BiomeType")
@MDynamicEnum("com.commandhelper.BiomeType")
public abstract class MCBiomeType<Concrete> extends DynamicEnum<MCBiomeType.MCVanillaBiomeType, Concrete> {

protected static final Map<String, MCBiomeType> MAP = new HashMap<>();
Expand Down Expand Up @@ -70,7 +69,6 @@ public String concreteName() {
return MAP.values();
}

@MEnum("VanillaBiomeType")
public enum MCVanillaBiomeType {
OCEAN,
PLAINS,
Expand Down
Expand Up @@ -7,7 +7,7 @@
/**
* All supported color values for chat
*/
@MEnum("ChatColor")
@MEnum("com.commandhelper.ChatColor")
public enum MCChatColor {

/**
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("ClickType")
@MEnum("com.commandhelper.ClickType")
public enum MCClickType {
/**
* The left (or primary) mouse button.
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("CollisionType")
@MEnum("com.commandhelper.CollisionType")
public enum MCCollisionType {
BLOCK,
ENTITY
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("CreeperType")
@MEnum("com.commandhelper.CreeperType")
public enum MCCreeperType {
POWERED
}
Expand Up @@ -6,7 +6,7 @@
* Criteria names which trigger an objective to be modified by actions in-game
*
*/
@MEnum("Criteria")
@MEnum("com.commandhelper.Criteria")
public enum MCCriteria {
DEATHCOUNT("deathCount"),
HEALTH("health"),
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("Difficulty")
@MEnum("com.commandhelper.Difficulty")
public enum MCDifficulty {
PEACEFUL(0),
EASY(1),
Expand Down
Expand Up @@ -6,7 +6,7 @@
* Scoreboard displayslots
*
*/
@MEnum("DisplaySlot")
@MEnum("com.commandhelper.DisplaySlot")
public enum MCDisplaySlot {
BELOW_NAME,
PLAYER_LIST,
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("DragType")
@MEnum("com.commandhelper.DragType")
public enum MCDragType {
SINGLE,
EVEN
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("DyeColor")
@MEnum("com.commandhelper.DyeColor")
public enum MCDyeColor {
WHITE,
ORANGE,
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("Effect")
@MEnum("com.commandhelper.Effect")
public enum MCEffect {
/**
* VISUAL
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.laytonsmith.annotations.MEnum;

@MEnum("EntityEffect")
@MEnum("com.commandhelper.EntityEffect")
public enum MCEntityEffect {
ARROW_PARTICLES,
RABBIT_JUMP,
Expand Down
Expand Up @@ -3,7 +3,6 @@
import com.laytonsmith.PureUtilities.ClassLoading.DynamicEnum;
import com.laytonsmith.abstraction.MCEntity;
import com.laytonsmith.annotations.MDynamicEnum;
import com.laytonsmith.annotations.MEnum;
import com.laytonsmith.core.Static;

import java.util.ArrayList;
Expand All @@ -13,7 +12,7 @@
import java.util.Map;
import java.util.Set;

@MDynamicEnum("EntityType")
@MDynamicEnum("com.commandhelper.EntityType")
public abstract class MCEntityType<Concrete> extends DynamicEnum<MCEntityType.MCVanillaEntityType, Concrete> {

// To be filled by the implementer
Expand Down Expand Up @@ -100,7 +99,6 @@ public boolean isSpawnable() {
return MAP.values();
}

@MEnum("VanillaEntityType")
public enum MCVanillaEntityType {
AREA_EFFECT_CLOUD(true),
ARMOR_STAND(true),
Expand Down

0 comments on commit 4964181

Please sign in to comment.