Permalink
Browse files

Add ValueType semantics

This allows objects to mark themselves as value types. Currently, all
primitives are marked as such. In the future, the compiler may be able
to further optimize these types, particularly if true compilation is
added. For now, this is unused, and the compiler treats everything as
pass by reference, but this is not ideal. At least going forward now,
the ValueType class is established, and other classes can go ahead and
start marking themselves as such. Eventually, this mechanism can
probably be exposed to user classes, but for now it is internal only.
  • Loading branch information...
LadyCailin committed Dec 3, 2018
1 parent dbeef87 commit b24b6dc4d36350fe9a96d2bcf8ea4257df1c4292
Showing with 238 additions and 68 deletions.
  1. +29 −29 pom.xml
  2. +3 −1 src/main/java/com/laytonsmith/PureUtilities/ClassLoading/ClassMirror/FieldMirror.java
  3. +4 −0 src/main/java/com/laytonsmith/PureUtilities/Common/Annotations/AnnotationChecks.java
  4. +4 −0 src/main/java/com/laytonsmith/core/constructs/CBareString.java
  5. +5 −0 src/main/java/com/laytonsmith/core/constructs/CBoolean.java
  6. +10 −0 src/main/java/com/laytonsmith/core/constructs/CDecimal.java
  7. +5 −0 src/main/java/com/laytonsmith/core/constructs/CDouble.java
  8. +1 −1 src/main/java/com/laytonsmith/core/constructs/CFunction.java
  9. +4 −0 src/main/java/com/laytonsmith/core/constructs/CInt.java
  10. +4 −0 src/main/java/com/laytonsmith/core/constructs/CKeyword.java
  11. +2 −0 src/main/java/com/laytonsmith/core/constructs/CNumber.java
  12. +8 −0 src/main/java/com/laytonsmith/core/constructs/CNumberRunner.java
  13. +4 −1 src/main/java/com/laytonsmith/core/constructs/CPrimitive.java
  14. +10 −1 src/main/java/com/laytonsmith/core/constructs/CPrimitiveRunner.java
  15. +14 −0 src/main/java/com/laytonsmith/core/constructs/CSecureString.java
  16. +4 −0 src/main/java/com/laytonsmith/core/constructs/CString.java
  17. +0 −12 src/main/java/com/laytonsmith/core/constructs/Construct.java
  18. +3 −1 src/main/java/com/laytonsmith/core/constructs/InstanceofUtil.java
  19. +1 −1 src/main/java/com/laytonsmith/core/constructs/NativeTypeList.java
  20. +1 −1 src/main/java/com/laytonsmith/core/functions/DataHandling.java
  21. +37 −0 src/main/java/com/laytonsmith/core/natives/interfaces/ValueType.java
  22. +41 −0 src/main/java/com/laytonsmith/core/natives/interfaces/ValueTypeInterfaceRunner.java
  23. +17 −20 src/main/java/com/laytonsmith/core/profiler/Profiler.java
  24. +27 −0 src/test/java/com/laytonsmith/core/constructs/ClassInfoTest.java
58 pom.xml
@@ -803,38 +803,11 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.1</version>
<configuration>
<reportPlugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.5</version>
<reportSets>
<reportSet>
<reports>
<report>license</report>
<report>index</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.4</version>
</plugin>
</reportPlugins>
</configuration>
</plugin>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<version>0.8.2</version>
<configuration>
<excludes>
<!-- Application starter -->
@@ -955,4 +928,31 @@
<url>http://maven-annotation-plugin.googlecode.com/svn/trunk/mavenrepo</url>
</pluginRepository>
</pluginRepositories>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.5</version>
<reportSets>
<reportSet>
<reports>
<report>license</report>
<report>index</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8.1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.4</version>
</plugin>
</plugins>
</reporting>
</project>
@@ -22,8 +22,10 @@ public FieldMirror(Field field) {
super(field);
Object value = null;
try {
// Try to get the value. This will work if the value is hardcoded, i.e. public int i = 5; but will fail
// in some cases. In those cases, that's ok, we just will have a null value here.
value = field.get(null);
} catch (IllegalArgumentException | IllegalAccessException ex) {
} catch (IllegalArgumentException | IllegalAccessException | NullPointerException ex) {
//
}
this.value = value;
@@ -83,6 +83,10 @@ public static void checkForceImplementation() throws Exception {
Set<Class<?>> s = ClassDiscovery.getDefaultInstance().loadClassesThatExtend(superClass);
checkImplements:
for(Class<?> c : s) {
if((c.getModifiers() & Modifier.ABSTRACT) != 0) {
// Abstract classes are not required to implement any ForceImplementation methods
continue;
}
if(c.isInterface()) {
// Interfaces are exempt from the requirement
continue;
@@ -32,4 +32,8 @@ public String docs() {
return new CClassType[]{};
}
@Override
public CBareString duplicate() {
return new CBareString(val(), getTarget());
}
}
@@ -134,4 +134,9 @@ public Version since() {
return EnumSet.of(ObjectModifier.FINAL, ObjectModifier.PUBLIC);
}
@Override
public CBoolean duplicate() {
return new CBoolean(val, getTarget());
}
}
@@ -32,6 +32,11 @@ public CDecimal(double value, Target t) {
val = new BigDecimal(value);
}
public CDecimal(BigDecimal value, Target t) {
super(value.toPlainString(), ConstructType.INT, t);
val = value;
}
@Override
public boolean isDynamic() {
return false;
@@ -73,4 +78,9 @@ public Version since() {
return CClassType.EMPTY_CLASS_ARRAY;
}
@Override
public CDecimal duplicate() {
return new CDecimal(val, getTarget());
}
}
@@ -67,4 +67,9 @@ public Version since() {
return CClassType.EMPTY_CLASS_ARRAY;
}
@Override
public CDouble duplicate() {
return new CDouble(val, getTarget());
}
}
@@ -24,7 +24,7 @@ public CFunction(String name, Target t) {
@Override
public String toString() {
return getValue();
return val();
}
@Override
@@ -66,4 +66,8 @@ public Version since() {
return CClassType.EMPTY_CLASS_ARRAY;
}
@Override
public CInt duplicate() {
return new CInt(val, getTarget());
}
}
@@ -48,4 +48,8 @@ public String docs() {
return new CClassType[]{};
}
@Override
public CKeyword duplicate() {
throw new UnsupportedOperationException("Should have been removed at compile time");
}
}
@@ -19,11 +19,13 @@ public CNumber(String value, ConstructType type, Target t) {
@Override
public CClassType[] getSuperclasses() {
// Implemented in the Runner
throw new UnsupportedOperationException();
}
@Override
public CClassType[] getInterfaces() {
// Implemented in the Runner
throw new UnsupportedOperationException();
}
@@ -4,6 +4,7 @@
import com.laytonsmith.PureUtilities.Version;
import com.laytonsmith.core.MSVersion;
import com.laytonsmith.core.natives.interfaces.AbstractMixedInterfaceRunner;
import com.laytonsmith.core.natives.interfaces.ObjectType;
/**
*
@@ -32,4 +33,11 @@ public Version since() {
return CClassType.EMPTY_CLASS_ARRAY;
}
@Override
public ObjectType getObjectType() {
return ObjectType.ABSTRACT;
}
}
@@ -3,12 +3,13 @@
import com.laytonsmith.PureUtilities.Version;
import com.laytonsmith.annotations.typeof;
import com.laytonsmith.core.MSVersion;
import com.laytonsmith.core.natives.interfaces.ValueType;
/**
*
*/
@typeof("ms.lang.primitive")
public abstract class CPrimitive extends Construct {
public abstract class CPrimitive extends Construct implements ValueType {
@SuppressWarnings("FieldNameHidesFieldInSuperclass")
public static final CClassType TYPE = CClassType.get("ms.lang.primitive");
@@ -19,11 +20,13 @@ public CPrimitive(String value, ConstructType type, Target t) {
@Override
public CClassType[] getSuperclasses() {
// Implemented in the Runner
throw new UnsupportedOperationException();
}
@Override
public CClassType[] getInterfaces() {
// Implemented in the Runner
throw new UnsupportedOperationException();
}
@@ -5,6 +5,8 @@
import com.laytonsmith.core.MSVersion;
import com.laytonsmith.core.natives.interfaces.AbstractMixedInterfaceRunner;
import com.laytonsmith.core.natives.interfaces.Mixed;
import com.laytonsmith.core.natives.interfaces.ObjectType;
import com.laytonsmith.core.natives.interfaces.ValueType;
/**
*
@@ -30,6 +32,13 @@ public Version since() {
@Override
public CClassType[] getInterfaces() {
return CClassType.EMPTY_CLASS_ARRAY;
return new CClassType[]{ValueType.TYPE};
}
@Override
public ObjectType getObjectType() {
return ObjectType.ABSTRACT;
}
}
@@ -49,6 +49,15 @@ public CSecureString(CArray val, Target t) {
construct(CArrayToByteArray(val, t));
}
// duplicate constructor
private CSecureString(byte[] encrypted, Cipher decrypter, int encLength, int actualLength, Target t) {
super("**secure string**", t);
this.encrypted = encrypted;
this.decrypter = decrypter;
this.encLength = encLength;
this.actualLength = actualLength;
}
private void construct(byte[] val) {
try {
actualLength = val.length;
@@ -204,4 +213,9 @@ public static void fixKeyLength() {
}
}
@Override
public CSecureString duplicate() {
return new CSecureString(encrypted, decrypter, encLength, actualLength, getTarget());
}
}
@@ -164,4 +164,8 @@ public ObjectType getObjectType() {
return ObjectType.CLASS;
}
@Override
public CString duplicate() {
return new CString(val(), getTarget());
}
}
@@ -77,18 +77,6 @@ public void setTarget(Target target) {
this.target = target;
}
/**
* Duplicate of {@link #val()}
* @return
*
* @deprecated Use {@link #val()]
*
*/
@Deprecated
public final String getValue() {
return val();
}
public int getLineNum() {
return target.line();
}
@@ -45,7 +45,9 @@
blacklist.addAll(getAllCastableClassesWithBlacklist(iface, blacklist));
}
} catch (UnsupportedOperationException ex) {
// This is a phantom class, which is allowed
if(c.getClass().getAnnotation(typeof.class) != null) {
throw new RuntimeException("Unexpected UnsupportedOperationException from " + c.getName());
}
}
return blacklist;
}
@@ -295,7 +295,7 @@ public static Mixed getInvalidInstanceForUse(FullyQualifiedClassName fqcn) throw
}
if(MEnumType.class.isAssignableFrom(c)) {
return getNativeEnumType(fqcn);
} else {
} else { // Not abstract
return ReflectionUtils.instantiateUnsafe(c);
}
}
@@ -2194,7 +2194,7 @@ public static Procedure getProcedure(Target t, Environment env, Script parent, P
} else {
boolean thisNodeIsAssign = false;
if(nodes[i].getData() instanceof CFunction) {
if(((CFunction) nodes[i].getData()).getValue().equals("assign")) {
if(((CFunction) nodes[i].getData()).val().equals("assign")) {
thisNodeIsAssign = true;
if((nodes[i].getChildren().size() == 3 && Construct.IsDynamicHelper(nodes[i].getChildAt(0).getData()))
|| Construct.IsDynamicHelper(nodes[i].getChildAt(1).getData())) {
@@ -0,0 +1,37 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.laytonsmith.core.natives.interfaces;
import com.laytonsmith.PureUtilities.Common.Annotations.ForceImplementation;
import com.laytonsmith.annotations.typeof;
import com.laytonsmith.core.constructs.CClassType;
/**
* Represents a class that supports passing by value. Value types must meet a few assumptions, they are immutable,
* it may be faster to pass by value than by reference, and if value a and b are equal, then they could be also the same
* reference with no ill effects to any programs. The compiler may choose to pass by value or by reference, and it
* should be the same either way.
*
* Primitives are a good example of this, (and in fact, the primitive class implements this interface) but more
* complex object types may benefit from this as well.
*/
@typeof("ms.lang.ValueType")
public interface ValueType extends Mixed {
@SuppressWarnings("FieldNameHidesFieldInSuperclass")
public static final CClassType TYPE = CClassType.get("ms.lang.ValueType");
/**
* Returns a duplicated value of this object. The duplicate MUST be equals(), and it MUST NOT be ref_equals(). The
* compiler may choose to call this method or not, if not, then the values would be ref_equals.
* @return The interface defines the return type as {@code ValueType}, but the actual type returned MUST be of the
* type defined in this class. The method is @ForceImplementation'd, to remind the programmer that this must be
* overridden in every class, to return the appropriate type.
*/
@ForceImplementation
ValueType duplicate();
}
Oops, something went wrong.

0 comments on commit b24b6dc

Please sign in to comment.