Skip to content

Commit

Permalink
GH-556 Support reassignation of parametrized types
Browse files Browse the repository at this point in the history
  • Loading branch information
dzikoysk committed Dec 31, 2020
1 parent 902eadf commit 9116a89
Show file tree
Hide file tree
Showing 30 changed files with 338 additions and 204 deletions.
38 changes: 23 additions & 15 deletions examples/lang/generics.panda
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
module lang

require java:collections
main {
/* Parametrized instance */
Foo<String> parametrizedType = new Foo<String>('test')

/* Parametrized return type */
String parametrizedValue = parametrizedType.getValue()
// Int invalidValue = genericType.getValue() /* Should not compile */

/* Parametrized arguments */
parametrizedType.setValue(parametrizedValue)
// genericType.setValue(10) /* Should not compile */

type Foo<V> {
/* Parametrized reassignation */
Foo<String> sameParametrizedType = parametrizedType
Foo<Object> lowerParametrizedType = sameParametrizedType
Bar<String> lowerBaseType = sameParametrizedType
}

type Foo<V> : Bar<V> {
constructor (V barValue) {
base(barValue)
}
}

type Bar<V> {
internal mut V value

constructor (V value) {
Expand All @@ -17,17 +38,4 @@ type Foo<V> {
shared getValue () -> V {
return value
}

}

main {
Foo<String> genericType = new Foo<String>('test')

/* Generic return type */
String value = genericType.getValue()
// Int invalidValue = genericType.getValue() /* Should not compile */

/* Generic parameter */
genericType.setValue(value)
// genericType.setValue(10) /* Should not compile */
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public class PandaType extends AbstractMetadata implements Type {
protected final Module module;
protected final String kind;
protected final State state;
protected final Option<TypeScope> typeScope;
protected final Completable<? extends Class<?>> associated;
protected final List<TypedSignature> bases = new ArrayList<>();
protected final Map<Reference, Autocast<?, ?>> autocasts = new HashMap<>();
Expand All @@ -70,8 +71,9 @@ public PandaType(PandaTypeMetadata<?, ?> metadata) {
this.kind = ValidationUtils.notNull(metadata.kind, "The kind of type is not defined");
this.state = ValidationUtils.notNull(metadata.state, "State of type is missing");
this.associated = ValidationUtils.notNull(metadata.associatedType, "Associated type is missing");

this.typeScope = Option.of(metadata.typeScope);
ValidationUtils.notNull(metadata.bases, "Bases are not defined").forEach(this::addBase);

this.reference = new Reference(this);
}

Expand Down Expand Up @@ -245,6 +247,11 @@ public Completable<? extends Class<?>> getAssociated() {
return associated;
}

@Override
public Option<TypeScope> getTypeScope() {
return typeScope;
}

@Override
public Option<TypeLoader> getTypeLoader() {
return Option.of(typeLoader);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class PandaTypeMetadata<BUILDER extends PandaTypeMetadata<BUILDER, ?>, TY
protected Signature signature;
protected Module module;
protected Location location;
protected TypeScope typeScope;
protected Completable<? extends Class<?>> associatedType;
protected List<TypedSignature> bases = new ArrayList<>();
protected String kind = Kind.TYPE;
Expand All @@ -56,6 +57,11 @@ public BUILDER module(Module module) {
return getThis();
}

public BUILDER typeScope(TypeScope typeScope) {
this.typeScope = typeScope;
return getThis();
}

public BUILDER location(Location location) {
this.location = location;
return getThis();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ default boolean is(String name) {
*/
Completable<? extends Class<?>> getAssociated();

Option<TypeScope> getTypeScope();

/**
* Get state of type
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,26 @@ public final class TypeFrame extends AbstractFrame<TypeScope> {

protected final int id;
protected final Process process;
protected final Object[] baseArguments;

public TypeFrame(Process process, TypeScope scope, Object[] baseArguments) {
super(scope, scope.getType().getFields().getDeclaredProperties().size());
protected TypeInstance typeInstance;
protected Object[] baseArguments;

public TypeFrame(Process process, TypeScope scope) {
super(scope, scope.getReference().fetchType().getFields().getProperties().size());

this.id = ID.getAndIncrement();
this.process = process;
}

public void setTypeInstance(TypeInstance typeInstance) {
this.typeInstance = typeInstance;
}

public TypeInstance getTypeInstance() {
return typeInstance;
}

public void setBaseArguments(Object[] baseArguments) {
this.baseArguments = baseArguments;
}

Expand All @@ -51,7 +64,7 @@ public int getId() {

@Override
public String toString() {
return framedScope.getType().getSimpleName() + "#" + String.format("%06X", id & 0xFFFFF);
return framedScope.getReference().getSimpleName() + "#" + String.format("%06X", id & 0xFFFFF);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,82 +17,30 @@
package org.panda_lang.language.architecture.type;

import org.jetbrains.annotations.Nullable;
import org.panda_lang.language.PandaFrameworkException;
import org.panda_lang.language.architecture.expression.Expression;
import org.panda_lang.language.architecture.statement.AbstractFramedScope;
import org.panda_lang.language.architecture.type.member.constructor.TypeConstructor;
import org.panda_lang.language.architecture.type.member.field.TypeField;
import org.panda_lang.language.architecture.type.member.parameter.ParameterUtils;
import org.panda_lang.language.architecture.type.member.parameter.PropertyParameter;
import org.panda_lang.language.interpreter.source.Location;
import org.panda_lang.language.runtime.PandaRuntimeException;
import org.panda_lang.language.runtime.ProcessStack;
import org.panda_lang.utilities.commons.ArrayUtils;
import org.panda_lang.utilities.commons.function.Option;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;

public final class TypeScope extends AbstractFramedScope {

private final Type type;
private final Reference reference;

public TypeScope(Location location, Type type) {
public TypeScope(Location location, Reference reference) {
super(location);
this.type = type;
}

public TypeInstance createInstance(ProcessStack stack, @Nullable Object instance, TypeConstructor constructor, List<PropertyParameter> parameters, Object[] arguments) throws Exception {
Object[] baseArguments = constructor.getBaseCall()
.flatMap(call -> Option.attempt(Exception.class, () -> call.evaluate(stack, instance)))
.orElseGet(() -> new Object[0]);

TypeFrame typeFrame = new TypeFrame(stack.getProcess(), this, baseArguments);
TypeInstance typeInstance;

try {
Constructor<? extends TypeInstance> nativeConstructor = getConstructor(parameters);
typeInstance = nativeConstructor.newInstance(ArrayUtils.merge(typeFrame, arguments, Object[]::new));
} catch (InvocationTargetException targetException) {
throw new PandaRuntimeException(targetException.getTargetException().getMessage(), targetException.getTargetException());
}

for (TypeField field : type.getFields().getDeclaredProperties()) {
if (!field.hasDefaultValue()) {
continue;
}

if (field.isStatic()) {
field.fetchStaticValue(); // just init
continue;
}

Expression expression = field.getDefaultValue();
typeInstance.__panda__get_frame().set(field.getPointer(), expression.evaluate(stack, typeInstance));
}

return typeInstance;
this.reference = reference;
}

@SuppressWarnings("unchecked")
private Constructor<? extends TypeInstance> getConstructor(List<PropertyParameter> parameters) {
Class<?>[] parameterTypes = ArrayUtils.merge(TypeFrame.class, ParameterUtils.parametersToClasses(parameters), Class[]::new);

try {
return (Constructor<? extends TypeInstance>) type.getAssociated().get().getConstructor(parameterTypes);
} catch (NoSuchMethodException e) {
throw new PandaFrameworkException("Associated class does not implement " + Arrays.toString(parameterTypes) + " constructor");
}
public TypeFrame revive(ProcessStack stack, @Nullable Object instance, TypeConstructor constructor, Object[] arguments) throws Exception {
return new TypeFrame(stack.getProcess(), this);
}

public Location getLocation() {
return location;
}

public Type getType() {
return type;
public Reference getReference() {
return reference;
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.panda_lang.language.architecture.type;
package org.panda_lang.language.architecture.type.generator;

import javassist.CannotCompileException;
import javassist.ClassPool;
Expand All @@ -9,6 +9,11 @@
import javassist.Modifier;
import javassist.NotFoundException;
import org.panda_lang.language.architecture.dynamic.Frame;
import org.panda_lang.language.architecture.type.Kind;
import org.panda_lang.language.architecture.type.State;
import org.panda_lang.language.architecture.type.Type;
import org.panda_lang.language.architecture.type.TypeFrame;
import org.panda_lang.language.architecture.type.TypeInstance;
import org.panda_lang.language.architecture.type.member.constructor.TypeConstructor;
import org.panda_lang.language.architecture.type.member.method.TypeMethod;
import org.panda_lang.language.architecture.type.member.parameter.ParameterUtils;
Expand Down Expand Up @@ -53,12 +58,16 @@ public CtClass allocate(Type type) {

public void generate(Type type) throws CannotCompileException, NotFoundException {
CtClass javaType = generatedClasses.get(type);

// supertype

if (!javaType.isInterface() && type.getSuperclass().isDefined()) {
javaType.setSuperclass(getCtClass(type.getSuperclass().get().fetchType()));
}

boolean hasGeneratedSuperclass = ArrayUtils.contains(javaType.getSuperclass().getInterfaces(), CT_TYPE_INSTANCE_CLASS);
boolean generateFields = !hasGeneratedSuperclass && !javaType.isInterface();

// interfaces

for (TypedSignature baseSignature : type.getBases()) {
Expand All @@ -71,7 +80,7 @@ public void generate(Type type) throws CannotCompileException, NotFoundException

// fields

if (!javaType.isInterface()) {
if (generateFields) {
CtField frameField = new CtField(CT_TYPE_FRAME_CLASS, "__panda__frame", javaType);
javaType.addField(frameField);
}
Expand All @@ -81,7 +90,7 @@ public void generate(Type type) throws CannotCompileException, NotFoundException
{
javaType.addInterface(CT_TYPE_INSTANCE_CLASS);

if (!javaType.isInterface()) {
if (generateFields) {
CtMethod getter = new CtMethod(CT_TYPE_FRAME_CLASS, "__panda__get_frame", new CtClass[0], javaType);
getter.setBody("{ return $0.__panda__frame; }");
javaType.addMethod(getter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected TypeConstructor generate(TypeLoader typeLoader) {
.parameters(typeParameters)
.type(type)
.returnType(type.getSignature())
.callback((pandaConstructor, frame, instance, arguments) -> constructor.newInstance(arguments))
.invoker((pandaConstructor, frame, instance, arguments) -> constructor.newInstance(arguments))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected TypeMethod generate(TypeLoader typeLoader) {
// TODO: Generate bytecode
method.setAccessible(true);

MemberInvoker<TypeMethod, Object> methodBody = (typeMethod, stack, instance, arguments) -> {
MemberInvoker<TypeMethod, Object, Object> methodBody = (typeMethod, stack, instance, arguments) -> {
int amountOfArgs = arguments.length;
int parameterCount = method.getParameterCount();
Object varargs = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.panda_lang.language.architecture.type.signature.Signature;
import org.panda_lang.language.interpreter.source.Localizable;
import org.panda_lang.language.interpreter.source.Location;
import org.panda_lang.utilities.commons.ObjectUtils;

import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -59,7 +60,7 @@ public abstract static class PandaParametrizedExecutableBuilder<E extends Member
protected Type type;
protected Signature returnType;
protected Location location;
protected MemberInvoker<E, Object> callback;
protected MemberInvoker<E, Object, Object> invoker;
protected Visibility visibility = Visibility.OPEN;
protected List<? extends PropertyParameter> parameters = Collections.emptyList();
protected boolean isNative;
Expand Down Expand Up @@ -99,8 +100,8 @@ public T isNative(boolean isNative) {
return returnThis();
}

public T callback(MemberInvoker<E, Object> callback) {
this.callback = callback;
public T invoker(MemberInvoker<E, ?, ?> invoker) {
this.invoker = ObjectUtils.cast(invoker);
return returnThis();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@
public abstract class AbstractParametrizedMember<E extends Member> extends AbstractMember<E> implements ParametrizedMember {

private final List<? extends PropertyParameter> parameters;
private final MemberInvoker<E, Object> callback;
private final MemberInvoker<E, Object, Object> invoker;

protected AbstractParametrizedMember(PandaParametrizedExecutableBuilder<E, ?> builder) {
super(builder);

this.parameters = builder.parameters;
this.callback = builder.callback;
this.invoker = builder.invoker;
}

@Override
@SuppressWarnings("unchecked")
public Object invoke(ProcessStack stack, Object instance, Object... arguments) throws Exception {
return callback.invoke((E) this, stack, instance, arguments);
return invoker.invoke((E) this, stack, instance, arguments);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import org.jetbrains.annotations.Nullable;
import org.panda_lang.language.runtime.ProcessStack;

public interface MemberInvoker<E extends Member, T> {
public interface MemberInvoker<E extends Member, T, R> {

Object invoke(E property, ProcessStack stack, @Nullable T instance, Object[] arguments) throws Exception;
R invoke(E property, ProcessStack stack, @Nullable T instance, Object[] arguments) throws Exception;

}
Loading

0 comments on commit 9116a89

Please sign in to comment.