Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions de.peeeq.wurstscript/parserspec/wurstscript.parseq
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ Expr =
| ExprMember
| ExprFunctionCall(@ignoreForEquality de.peeeq.wurstscript.parser.WPos source, Identifier funcNameId, TypeExprList typeArgs, Arguments args)
| ExprNewObject(@ignoreForEquality de.peeeq.wurstscript.parser.WPos source, Identifier typeNameId, TypeExprList typeArgs, Arguments args)
| ExprTypeRef(@ignoreForEquality de.peeeq.wurstscript.parser.WPos source, TypeExpr typ)
| ExprCast(@ignoreForEquality de.peeeq.wurstscript.parser.WPos source, TypeExpr typ, Expr expr)
| ExprInstanceOf(@ignoreForEquality de.peeeq.wurstscript.parser.WPos source, TypeExpr typ, Expr expr)
| ExprClosure(@ignoreForEquality de.peeeq.wurstscript.parser.WPos source, @ignoreForEquality de.peeeq.wurstscript.parser.WPos arrowSource, WShortParameters shortParameters, Expr implementation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ indexes:


expr:
exprPrimary
receiverType=genericTypeReceiver dotsTypeCall=('.'|'..') typeFuncName=ID? typeCallTypeArgs=typeArgs typeCallArgs=argumentList
| exprPrimary
| left=expr 'castTo' castToType=typeExpr
| left=expr 'instanceof' instaneofType=typeExpr
| receiver=expr dotsCall=('.'|'..') funcName=ID? typeArgs argumentList
Expand Down Expand Up @@ -443,6 +444,20 @@ stmtSkip:'skip';

typeArgs: ('<' (args+=typeExpr (',' args+=typeExpr)*)? '>')?;

typeArgsNonEmpty: '<' args+=typeExpr (',' args+=typeExpr)* '>';

genericTypeReceiver:
receiverTypePrefixes+=genericTypeReceiverPrefixPart* receiverTypeGenericPart=genericTypeReceiverGenericPart
;

genericTypeReceiverPrefixPart:
typeName=ID '.'
Comment thread
Frotty marked this conversation as resolved.
;

genericTypeReceiverGenericPart:
typeName=ID typeArgsNonEmpty
;

exprList : exprs+=expr (',' exprs+=expr)*;


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,11 @@ public List<Either<String, MarkedString>> case_TypeExprSimple(TypeExprSimple t)
return typeExpr(t);
}

@Override
public List<Either<String, MarkedString>> case_ExprTypeRef(ExprTypeRef e) {
return typeExpr(e.getTyp());
}

@Override
public List<Either<String, MarkedString>> case_Modifiers(Modifiers modifiers) {
return string("Modifiers for this declaration.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public static WurstType calculate(ExprFuncRef term) {
return WurstTypeCode.instance();
}

public static WurstType calculate(ExprTypeRef term) {
return term.getTyp().attrTyp();
}


public static WurstType calculate(ExprVarAccess term) {
NameLink varDef = term.attrNameLink();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static ImmutableCollection<FunctionSignature> calculate(FunctionCall fc)
}
} // TODO else check?

VariableBinding mapping = givenBinding(fc, sig.getDefinitionTypeVariables());
VariableBinding mapping = sig.getMapping().union(givenBinding(fc, sig.getDefinitionTypeVariables()));
sig = sig.setTypeArgs(fc, mapping);

resultBuilder.add(sig);
Expand Down Expand Up @@ -229,7 +229,7 @@ public static ImmutableCollection<FunctionSignature> calculate(ExprMemberMethod
}

// Apply explicit type args from the call-site (e.g., c.foo<T,...>(...))
VariableBinding explicit = GenericsHelper.givenBinding(mm, sig.getDefinitionTypeVariables());
VariableBinding explicit = sig.getMapping().union(GenericsHelper.givenBinding(mm, sig.getDefinitionTypeVariables()));
sig = sig.setTypeArgs(mm, explicit);

prepared.add(sig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ public static String description(ExprThis e) {
return "this has type " + htmlType(e.attrTyp());
}

public static String description(ExprTypeRef e) {
return "Type reference " + htmlType(e.attrTyp());
}

public static String description(ExprTypeId exprTypeId) {
return "typeId: returns the typeId of an object or class. The typeId is "
+ "a unique number for each class in the same type hierarchy.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public static ImmutableList<NameDef> calculate(ExprFuncRef exprFuncRef) {
return ImmutableList.emptyList();
}

public static ImmutableList<NameDef> calculate(ExprTypeRef exprTypeRef) {
return ImmutableList.emptyList();
}

public static ImmutableList<NameDef> calculate(ExprTypeId e) {
return e.getLeft().attrReadVariables();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,10 @@ public static void prettyPrint(ExprThis e, Spacer spacer, StringBuilder sb, int
sb.append("this");
}

public static void prettyPrint(ExprTypeRef e, Spacer spacer, StringBuilder sb, int indent) {
e.getTyp().prettyPrint(spacer, sb, indent);
}

public static void prettyPrint(ExprTypeId e, Spacer spacer, StringBuilder sb, int indent) {
e.getLeft().prettyPrint(spacer, sb, indent);
sb.append(".typeId");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import de.peeeq.wurstio.jassinterpreter.VarargArray;
import de.peeeq.wurstscript.WLogger;
import de.peeeq.wurstscript.ast.Annotation;
import de.peeeq.wurstscript.ast.ClassOrInterface;
import de.peeeq.wurstscript.ast.FuncDef;
import de.peeeq.wurstscript.ast.HasModifier;
import de.peeeq.wurstscript.ast.Modifier;
import de.peeeq.wurstscript.gui.WurstGui;
Expand Down Expand Up @@ -172,6 +174,15 @@ public static LocalState runFunc(ProgramState globalState, ImFunction f, @Nullab
subst.put(fvars.get(i2), targs.get(i2).getType());
}

ImClass sourceOwner = findSourceOwnerClass(f, globalState.getProg());
if (sourceOwner != null) {
ImTypeVars cvars = sourceOwner.getTypeVariables();
int n2 = Math.min(cvars.size(), targs.size());
for (int i2 = 0; i2 < n2; i2++) {
subst.put(cvars.get(i2), targs.get(i2).getType());
}
}

// 2) If the function is inside a class, also bind class type vars with the same call type args
Element owner = f.getParent();
while (owner != null && !(owner instanceof ImClass)) {
Expand Down Expand Up @@ -249,6 +260,26 @@ public static LocalState runFunc(ProgramState globalState, ImFunction f, @Nullab
}
}

private static @Nullable ImClass findSourceOwnerClass(ImFunction f, ImProg prog) {
if (!(f.getTrace() instanceof FuncDef)) {
return null;
}
FuncDef fd = (FuncDef) f.getTrace();
if (!fd.attrIsStatic()) {
return null;
}
ClassOrInterface owner = fd.attrNearestClassOrInterface();
if (owner == null) {
return null;
}
for (ImClass c : prog.getClasses()) {
if (c.getTrace() == owner) {
return c;
}
}
return null;
}


public static de.peeeq.wurstscript.ast.Element getTrace(ProgramState globalState, ImFunction f) {
Element lastStatement = globalState.getLastStatement();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,12 @@ private Arguments transformArgumentList(ArgumentListContext al) {
private ExprMemberMethod transformMemberMethodCall2(WPos source,
ExprContext receiver, Token dots, Token funcName,
TypeArgsContext typeArgs, ArgumentListContext args) {
Expr left = transformExpr(receiver);
return transformMemberMethodCall2(source, transformExpr(receiver), dots, funcName, typeArgs, args);
}

private ExprMemberMethod transformMemberMethodCall2(WPos source,
Expr left, Token dots, Token funcName,
TypeArgsContext typeArgs, ArgumentListContext args) {
if (dots.getType() == WurstParser.DOT) {
return Ast.ExprMemberMethodDot(source, left, text(funcName),
transformTypeArgs(typeArgs), transformArgumentList(args));
Expand Down Expand Up @@ -1091,6 +1096,11 @@ private Expr transformExpr(ExprContext e) {
} else if (e.castToType != null) {
return Ast.ExprCast(source, transformTypeExpr(e.castToType),
transformExpr(e.left));
} else if (e.dotsTypeCall != null) {
TypeExpr receiverType = transformGenericTypeReceiver(e.receiverType);
Expr left = Ast.ExprTypeRef(receiverType.getSource(), receiverType);
return transformMemberMethodCall2(source, left, e.dotsTypeCall,
e.typeFuncName, e.typeCallTypeArgs, e.typeCallArgs);
} else if (e.dotsVar != null) {
return transformExprMemberVarAccess2(source, e.receiver, e.dotsVar,
e.varName, e.indexes());
Expand Down Expand Up @@ -1120,6 +1130,23 @@ private Expr transformExpr(ExprContext e) {

}

private TypeExpr transformGenericTypeReceiver(GenericTypeReceiverContext receiverType) {
OptTypeExpr scopeType = Ast.NoTypeExpr();
TypeExpr result = null;

for (GenericTypeReceiverPrefixPartContext part : receiverType.receiverTypePrefixes) {
result = Ast.TypeExprSimple(source(part.typeName), scopeType,
part.typeName.getText(), Ast.TypeExprList());
scopeType = result;
}

GenericTypeReceiverGenericPartContext genericPart = receiverType.receiverTypeGenericPart;
result = Ast.TypeExprSimple(source(genericPart.typeName), scopeType,
genericPart.typeName.getText(), transformTypeArgs(genericPart.typeArgsNonEmpty()));

return result;
}

private int beginPos(ParseTree left) {
if (left instanceof ParserRuleContext) {
ParserRuleContext left2 = (ParserRuleContext) left;
Expand Down Expand Up @@ -1379,6 +1406,14 @@ private TypeExprList transformTypeArgs(TypeArgsContext typeArgs) {
return result;
}

private TypeExprList transformTypeArgs(TypeArgsNonEmptyContext typeArgs) {
TypeExprList result = Ast.TypeExprList();
for (TypeExprContext e : typeArgs.args) {
result.add(transformTypeExpr(e));
}
return result;
}

private WParameters transformFormalParameters(FormalParametersContext ps,
boolean makeConstant) {
WParameters result = Ast.WParameters();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ public static ImExpr translate(ExprNewObject e, ImTranslator t, ImFunction f) {
return wrapTranslation(e, t, translateIntern(e, t, f));
}

public static ImExpr translate(ExprTypeRef e, ImTranslator t, ImFunction f) {
throw new CompileError(e, "Type reference " + Utils.printTypeExpr(e.getTyp()) + " cannot be used as a value.");
}

public static ImExpr translate(ExprInstanceOf e, ImTranslator t, ImFunction f) {
return wrapTranslation(e, t, translateIntern(e, t, f));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,36 @@ private static boolean hasTypeVarNamed(ImTypeVars vars, String name) {
return false;
}

private static String uniqueTypeVarName(ImTypeVars vars, TypeParamDef tp) {
String name = tp.getName();
if (!hasTypeVarNamed(vars, name)) {
return name;
}

String baseName = name + "$" + typeParamOwnerName(tp);
String candidate = baseName;
int suffix = 2;
while (hasTypeVarNamed(vars, candidate)) {
candidate = baseName + suffix;
suffix++;
}
return candidate;
}

private static String typeParamOwnerName(TypeParamDef tp) {
de.peeeq.wurstscript.ast.Element e = tp.getParent();
while (e != null) {
if (e instanceof FuncDef) {
return ((FuncDef) e).getName();
}
if (e instanceof NamedScope) {
return ((NamedScope) e).getName();
}
e = e.getParent();
}
return "type";
}

public Map<TypeParamDef, ImTypeVar> getTypeVarOverridesForClass(ClassDef cd) {
Map<TypeParamDef, ImTypeVar> m = capturedOwnerTypeVarsByStaticClass.get(cd);
return (m == null) ? Collections.emptyMap() : m;
Expand All @@ -138,6 +168,17 @@ public void popContinueFlag() {
return continueFlagStack.peek();
}

public Map<TypeParamDef, ImTypeVar> getTypeVarOverridesForFunction(ImFunction f) {
Map<TypeParamDef, ImTypeVar> result = new IdentityHashMap<>();
for (ImTypeVar tv : f.getTypeVariables()) {
TypeParamDef tp = typeVariableReverse.get(tv);
if (tp != null) {
result.put(tp, tv);
}
}
return result;
}


public ImTranslator(WurstModel wurstProg, boolean isUnitTestMode, RunArgs runArgs) {
this.wurstProg = wurstProg;
Expand Down Expand Up @@ -930,7 +971,13 @@ public ImFunction getFuncFor(TranslatedToImFunction funcDef) {

ImTypeVars typeVars = collectTypeVarsForFunction(funcDef);
ImFunction f = ImFunction(funcDef, name, typeVars, ImVars(), ImVoid(), ImVars(), ImStmts(), flags);
funcDef.imCreateFuncSkeleton(this, f);
Map<TypeParamDef, ImTypeVar> ov = getTypeVarOverridesForFunction(f);
pushTypeVarOverrides(ov);
try {
funcDef.imCreateFuncSkeleton(this, f);
} finally {
popTypeVarOverrides(ov);
}

addFunction(f, funcDef);
functionMap.put(funcDef, f);
Expand Down Expand Up @@ -992,6 +1039,12 @@ private ImTypeVars collectTypeVarsForFunction(TranslatedToImFunction funcDef) {
funcDef.match(new TranslatedToImFunction.MatcherVoid() {
@Override
public void case_FuncDef(FuncDef funcDef) {
if (funcDef.attrIsStatic()) {
ClassOrInterface owner = funcDef.attrNearestClassOrInterface();
if (owner != null) {
handleTypeParameters(owner.getTypeParameters());
}
}
handleTypeParameters(funcDef.getTypeParameters());
}

Expand All @@ -1004,7 +1057,9 @@ private void handleTypeParameters(TypeParamDefs tps) {

private void handleTypeParameter(TypeParamDef tp) {
if (tp.getTypeParamConstraints() instanceof TypeExprList) {
typeVars.add(typeVariable.getFor(tp));
ImTypeVar v = JassIm.ImTypeVar(uniqueTypeVarName(typeVars, tp));
typeVariableReverse.put(v, tp);
typeVars.add(v);
}
}

Expand Down Expand Up @@ -1172,7 +1227,14 @@ public int getTupleIndex(TupleDef tupleDef, VarDef parameter) {
public ImVar getVarFor(VarDef varDef) {
ImVar v = varMap.get(varDef);
if (v == null) {
ImType type = varDef.attrTyp().imTranslateType(this);
Map<TypeParamDef, ImTypeVar> ov = getOwnerTypeVarOverridesForStaticClassVar(varDef);
pushTypeVarOverrides(ov);
ImType type;
try {
type = varDef.attrTyp().imTranslateType(this);
} finally {
popTypeVarOverrides(ov);
}
String name = varDef.getName();
if (isNamedScopeVar(varDef)) {
name = getNameFor(varDef.attrNearestNamedScope()) + "_" + name;
Expand All @@ -1184,6 +1246,25 @@ public ImVar getVarFor(VarDef varDef) {
return v;
}

private Map<TypeParamDef, ImTypeVar> getOwnerTypeVarOverridesForStaticClassVar(VarDef varDef) {
if (!(varDef instanceof GlobalVarDef) || !varDef.attrIsStatic()) {
return Collections.emptyMap();
}
ClassOrInterface owner = varDef.attrNearestClassOrInterface();
if (owner == null) {
return Collections.emptyMap();
}
Map<TypeParamDef, ImTypeVar> result = new IdentityHashMap<>();
if (owner instanceof AstElementWithTypeParameters) {
for (TypeParamDef tp : ((AstElementWithTypeParameters) owner).getTypeParameters()) {
if (tp.getTypeParamConstraints() instanceof TypeExprList) {
result.put(tp, typeVariable.getFor(tp));
}
}
}
return result;
}

private boolean isNamedScopeVar(VarDef varDef) {
if (varDef.getParent() == null) {
return false;
Expand Down Expand Up @@ -1217,10 +1298,16 @@ public void setTranslated(ClassDef c) {

public List<ImStmt> translateStatements(ImFunction f, List<WStatement> statements) {
List<ImStmt> result = Lists.newArrayList();
for (WStatement s : statements) {
lasttranslatedThing = s;
ImStmt translated = s.imTranslateStmt(this, f);
result.add(translated);
Map<TypeParamDef, ImTypeVar> ov = getTypeVarOverridesForFunction(f);
pushTypeVarOverrides(ov);
try {
for (WStatement s : statements) {
lasttranslatedThing = s;
ImStmt translated = s.imTranslateStmt(this, f);
result.add(translated);
}
} finally {
popTypeVarOverrides(ov);
}
return result;
}
Expand Down
Loading
Loading