Skip to content

Commit aed1871

Browse files
authored
Fix some issues with key-value loops (#2363)
1 parent 32f8a06 commit aed1871

File tree

11 files changed

+151
-73
lines changed

11 files changed

+151
-73
lines changed

DMCompiler/Bytecode/DMReference.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ public struct DMReference {
1515
public static readonly DMReference Invalid = new() { RefType = Type.Invalid };
1616

1717
public enum Type : byte {
18+
/// References nothing, reads return null and writes are no-op
19+
NoRef,
20+
1821
Src,
1922
Self,
2023
Usr,

DMCompiler/Bytecode/DreamProcOpcode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public enum DreamProcOpcode : byte {
132132
CreateFilteredListEnumerator = 0x41,
133133
[OpcodeMetadata(-1)]
134134
Power = 0x42,
135-
[OpcodeMetadata(0, OpcodeArgType.EnumeratorId, OpcodeArgType.Reference, OpcodeArgType.Reference, OpcodeArgType.Reference, OpcodeArgType.Label)]
135+
[OpcodeMetadata(0, OpcodeArgType.EnumeratorId, OpcodeArgType.Reference, OpcodeArgType.Reference, OpcodeArgType.Label)]
136136
EnumerateAssoc = 0x43,
137137
[OpcodeMetadata(-2)]
138138
Link = 0x44,

DMCompiler/DM/Builders/DMProcBuilder.cs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -259,20 +259,16 @@ private void ProcessStatementFor(DMASTProcStatementFor statementFor) {
259259
ProcessStatementVarDeclaration(new DMASTProcStatementVarDeclaration(statementFor.Location, decl.DeclPath, null, DMValueType.Anything));
260260
}
261261

262-
if (statementFor is { Expression2: DMASTExpressionIn dmastIn, Expression3: null }) {
263-
var expr2 = statementFor.Expression2 != null ? _exprBuilder.CreateIgnoreUnknownReference(statementFor.Expression2) : null;
262+
if (statementFor is { Expression2: DMASTExpressionIn dmastIn, Expression3: null }) { // for(var/i,j in expr) or for(i,j in expr)
263+
var valueVar = statementFor.Expression2 != null ? _exprBuilder.CreateIgnoreUnknownReference(statementFor.Expression2) : null;
264+
var list = _exprBuilder.Create(dmastIn.RHS);
264265

265266
// TODO: Wow this sucks
266-
if (expr2 is UnknownReference unknownRef) {
267-
if(statementFor.Expression1 is not DMASTVarDeclExpression || dmastIn.LHS is not DMASTIdentifier ident)
267+
if (valueVar is UnknownReference unknownRef) { // j in var/i,j isn't already a var
268+
if(dmastIn.LHS is not DMASTIdentifier ident)
268269
unknownRef.EmitCompilerError(compiler);
269-
else {
270+
else
270271
ProcessStatementVarDeclaration(new DMASTProcStatementVarDeclaration(statementFor.Location, new DMASTPath(statementFor.Location, new DreamPath(ident.Identifier)), null, DMValueType.Anything));
271-
var meep = dmastIn.LHS;
272-
expr2 = _exprBuilder.Create(meep);
273-
}
274-
} else {
275-
expr2 = _exprBuilder.Create(dmastIn.LHS);
276272
}
277273

278274
DMASTExpression outputExpr;
@@ -282,10 +278,10 @@ private void ProcessStatementFor(DMASTProcStatementFor statementFor) {
282278
outputExpr = statementFor.Expression1;
283279
}
284280

285-
var outputVar = _exprBuilder.Create(outputExpr);
286-
var list = _exprBuilder.Create(dmastIn.RHS);
281+
var keyVar = _exprBuilder.Create(outputExpr);
282+
valueVar = _exprBuilder.Create(dmastIn.LHS);
287283

288-
switch (outputVar) {
284+
switch (keyVar) {
289285
case Local outputLocal: {
290286
outputLocal.LocalVar.ExplicitValueType = statementFor.DMTypes;
291287
if(outputLocal.LocalVar is DMProc.LocalConstVariable)
@@ -298,7 +294,7 @@ private void ProcessStatementFor(DMASTProcStatementFor statementFor) {
298294
}
299295
}
300296

301-
switch (expr2) {
297+
switch (valueVar) {
302298
case Local assocLocal: {
303299
assocLocal.LocalVar.ExplicitValueType = statementFor.DMTypes;
304300
if(assocLocal.LocalVar is DMProc.LocalConstVariable)
@@ -311,7 +307,7 @@ private void ProcessStatementFor(DMASTProcStatementFor statementFor) {
311307
}
312308
}
313309

314-
ProcessStatementForList(list, outputVar, expr2, statementFor.DMTypes, statementFor.Body);
310+
ProcessStatementForList(list, keyVar, valueVar, statementFor.DMTypes, statementFor.Body);
315311
} else if (statementFor.Expression2 != null || statementFor.Expression3 != null) {
316312
var initializer = statementFor.Expression1 != null ? _exprBuilder.Create(statementFor.Expression1) : null;
317313
var comparator = statementFor.Expression2 != null ? _exprBuilder.Create(statementFor.Expression2) : null;
@@ -459,9 +455,8 @@ private void ProcessLoopAssignment(LValue lValue, LValue? assocValue = null, DME
459455
} else {
460456
if (assocValue != null && list != null) {
461457
DMReference assocRef = assocValue.EmitReference(ExprContext, string.Empty);
462-
DMReference listRef = list.EmitReference(ExprContext, string.Empty);
463458
DMReference outputRef = lValue.EmitReference(ExprContext, string.Empty);
464-
proc.EnumerateAssoc(assocRef, listRef, outputRef);
459+
proc.EnumerateAssoc(assocRef, outputRef);
465460
} else {
466461
DMReference outputRef = lValue.EmitReference(ExprContext, string.Empty);
467462
proc.Enumerate(outputRef);

DMCompiler/DM/DMProc.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -596,12 +596,11 @@ public void Enumerate(DMReference reference) {
596596
}
597597
}
598598

599-
public void EnumerateAssoc(DMReference assocRef, DMReference listRef, DMReference outputRef) {
599+
public void EnumerateAssoc(DMReference assocRef, DMReference outputRef) {
600600
if (_loopStack?.TryPeek(out var peek) ?? false) {
601601
WriteOpcode(DreamProcOpcode.EnumerateAssoc);
602602
WriteEnumeratorId(_enumeratorIdCounter - 1);
603603
WriteReference(assocRef);
604-
WriteReference(listRef);
605604
WriteReference(outputRef);
606605
WriteLabel($"{peek}_end");
607606
} else {

OpenDreamRuntime/DreamReference.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,19 @@
22

33
namespace OpenDreamRuntime;
44

5-
public struct DreamReference {
5+
public readonly struct DreamReference(DMRefType type, int value) : IEquatable<DreamReference> {
6+
public static readonly DreamReference NoRef = new(DMRefType.NoRef, 0);
67
public static readonly DreamReference Src = new(DMRefType.Src, 0);
78
public static readonly DreamReference Self = new(DMRefType.Self, 0);
89
public static readonly DreamReference Usr = new(DMRefType.Usr, 0);
910
public static readonly DreamReference Args = new(DMRefType.Args, 0);
1011
public static readonly DreamReference SuperProc = new(DMRefType.SuperProc, 0);
1112
public static readonly DreamReference ListIndex = new(DMRefType.ListIndex, 0);
1213

13-
private long _innerValue;
1414
public DMRefType Type => (DMRefType)(_innerValue >> 32);
1515
public int Value => (int)_innerValue;
1616

17-
public DreamReference(DMRefType type, int value) {
18-
_innerValue = ((long)type << 32) | (uint)value;
19-
}
17+
private readonly long _innerValue = ((long)type << 32) | (uint)value;
2018

2119
public static DreamReference CreateArgument(int index) {
2220
return new DreamReference(DMRefType.Argument, index);
@@ -45,4 +43,19 @@ public static DreamReference CreateSrcField(int nameId) {
4543
public static DreamReference CreateSrcProc(int nameId) {
4644
return new DreamReference(DMRefType.SrcProc, nameId);
4745
}
46+
47+
public bool Equals(DreamReference other) {
48+
return _innerValue == other._innerValue;
49+
}
50+
51+
public override bool Equals(object? obj) {
52+
return obj is DreamReference other && Equals(other);
53+
}
54+
55+
public override int GetHashCode() {
56+
return _innerValue.GetHashCode();
57+
}
58+
59+
public static bool operator ==(DreamReference a, DreamReference b) => a._innerValue == b._innerValue;
60+
public static bool operator !=(DreamReference a, DreamReference b) => a._innerValue != b._innerValue;
4861
}

OpenDreamRuntime/Objects/Types/DreamAssocList.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,19 @@ public bool ContainsKey(DreamValue key) {
2424
public IEnumerable<DreamValue> EnumerateValues() {
2525
return _values.Keys; // The keys, counter-intuitively
2626
}
27+
28+
public IEnumerable<KeyValuePair<DreamValue, DreamValue>> EnumerateAssocValues() {
29+
return _values;
30+
}
31+
32+
public DreamValue[] CopyToArray() {
33+
var array = new DreamValue[_values.Count];
34+
35+
_values.Keys.CopyTo(array, 0);
36+
return array;
37+
}
38+
39+
public Dictionary<DreamValue, DreamValue> CopyAssocValues() {
40+
return new(_values);
41+
}
2742
}

OpenDreamRuntime/Objects/Types/DreamList.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,21 @@ public IEnumerable<DreamValue> EnumerateValues() {
138138
return _values;
139139
}
140140

141+
public IEnumerable<KeyValuePair<DreamValue, DreamValue>> EnumerateAssocValues() {
142+
return _associativeValues ?? [];
143+
}
144+
145+
public DreamValue[] CopyToArray() {
146+
return _values.ToArray();
147+
}
148+
149+
public Dictionary<DreamValue, DreamValue> CopyAssocValues() {
150+
if (_associativeValues is null)
151+
return new();
152+
153+
return new(_associativeValues);
154+
}
155+
141156
public Dictionary<DreamValue, DreamValue> GetAssociativeValues() {
142157
return _associativeValues ??= new Dictionary<DreamValue, DreamValue>();
143158
}

OpenDreamRuntime/Objects/Types/IDreamList.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Linq;
2+
13
namespace OpenDreamRuntime.Objects.Types;
24

35
public interface IDreamList {
@@ -7,4 +9,13 @@ public interface IDreamList {
79
public DreamValue GetValue(DreamValue key);
810
public bool ContainsKey(DreamValue key);
911
public IEnumerable<DreamValue> EnumerateValues();
12+
public IEnumerable<KeyValuePair<DreamValue, DreamValue>> EnumerateAssocValues();
13+
14+
public DreamValue[] CopyToArray() {
15+
return EnumerateValues().ToArray();
16+
}
17+
18+
public Dictionary<DreamValue, DreamValue> CopyAssocValues() {
19+
return new(EnumerateAssocValues());
20+
}
1021
}

0 commit comments

Comments
 (0)