Skip to content

Commit 4345db7

Browse files
committed
Model the lengths of open arrays as NativeInt in Delphi 12+
Closes #142
1 parent fa18f61 commit 4345db7

File tree

5 files changed

+108
-13
lines changed

5 files changed

+108
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
### Changed
1818

1919
- `NativeInt` and `NativeUInt` are now treated as weak aliases in Delphi 12+.
20+
- The length of open arrays is now modeled as `NativeInt` in Delphi 12+.
2021
- Performance improvements.
2122

2223
### Fixed

delphi-frontend/src/main/java/au/com/integradev/delphi/type/factory/TypeFactoryImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,4 +590,8 @@ public IntegerType integerFromLiteralValue(BigInteger value) {
590590
.findFirst()
591591
.orElseThrow(IllegalStateException::new);
592592
}
593+
594+
public CompilerVersion getCompilerVersion() {
595+
return compilerVersion;
596+
}
593597
}

delphi-frontend/src/main/java/au/com/integradev/delphi/type/intrinsic/IntrinsicReturnType.java

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.sonar.plugins.communitydelphi.api.type.IntrinsicType.UNICODESTRING;
2727
import static org.sonar.plugins.communitydelphi.api.type.IntrinsicType.WIDECHAR;
2828

29+
import au.com.integradev.delphi.compiler.CompilerVersion;
2930
import au.com.integradev.delphi.type.TypeImpl;
3031
import au.com.integradev.delphi.type.factory.ArrayOption;
3132
import au.com.integradev.delphi.type.factory.TypeFactoryImpl;
@@ -40,6 +41,8 @@
4041
import org.sonar.plugins.communitydelphi.api.type.TypeFactory;
4142

4243
public abstract class IntrinsicReturnType extends TypeImpl {
44+
private static final CompilerVersion VERSION_ATHENS = CompilerVersion.fromVersionNumber("36.0");
45+
4346
@Override
4447
public String getImage() {
4548
return "<" + getClass().getSimpleName() + ">";
@@ -53,6 +56,10 @@ public int size() {
5356

5457
public abstract Type getReturnType(List<Type> arguments);
5558

59+
public static Type length(TypeFactory typeFactory) {
60+
return new LengthReturnType(typeFactory);
61+
}
62+
5663
public static Type high(TypeFactory typeFactory) {
5764
return new HighLowReturnType(typeFactory);
5865
}
@@ -89,11 +96,45 @@ public static Type argumentByIndex(int index) {
8996
return new ArgumentByIndexReturnType(index);
9097
}
9198

99+
private static final class LengthReturnType extends IntrinsicReturnType {
100+
private final Type byteType;
101+
private final Type integerType;
102+
private final Type openArraySizeType;
103+
104+
private LengthReturnType(TypeFactory typeFactory) {
105+
this.byteType = typeFactory.getIntrinsic(IntrinsicType.BYTE);
106+
this.integerType = typeFactory.getIntrinsic(IntrinsicType.INTEGER);
107+
this.openArraySizeType =
108+
typeFactory.getIntrinsic(
109+
((TypeFactoryImpl) typeFactory).getCompilerVersion().compareTo(VERSION_ATHENS) >= 0
110+
? IntrinsicType.NATIVEINT
111+
: IntrinsicType.INTEGER);
112+
}
113+
114+
@Override
115+
public Type getReturnType(List<Type> arguments) {
116+
Type type = arguments.get(0);
117+
if (type.is(IntrinsicType.SHORTSTRING)) {
118+
return byteType;
119+
} else if (type.isOpenArray()) {
120+
return openArraySizeType;
121+
} else {
122+
return integerType;
123+
}
124+
}
125+
}
126+
92127
private static final class HighLowReturnType extends IntrinsicReturnType {
93128
private final Type integerType;
129+
private final Type openArraySizeType;
94130

95131
private HighLowReturnType(TypeFactory typeFactory) {
96132
this.integerType = typeFactory.getIntrinsic(IntrinsicType.INTEGER);
133+
this.openArraySizeType =
134+
typeFactory.getIntrinsic(
135+
((TypeFactoryImpl) typeFactory).getCompilerVersion().compareTo(VERSION_ATHENS) >= 0
136+
? IntrinsicType.NATIVEINT
137+
: IntrinsicType.INTEGER);
97138
}
98139

99140
@Override
@@ -104,7 +145,9 @@ public Type getReturnType(List<Type> arguments) {
104145
type = ((ClassReferenceType) type).classType();
105146
}
106147

107-
if (type.isArray() || type.isString()) {
148+
if (type.isOpenArray()) {
149+
type = openArraySizeType;
150+
} else if (type.isArray() || type.isString()) {
108151
type = integerType;
109152
}
110153

delphi-frontend/src/main/java/au/com/integradev/delphi/type/intrinsic/IntrinsicsInjector.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,10 @@ private void buildRoutines() {
212212
routine("Insert").param(LIKE_DYNAMIC_ARRAY).varParam(LIKE_DYNAMIC_ARRAY).param(type(INTEGER));
213213
routine("IsConstValue").param(TypeFactory.untypedType()).returns(type(BOOLEAN));
214214
routine("IsManagedType").param(ANY_CLASS_REFERENCE).returns(type(BOOLEAN));
215-
routine("Length").param(type(SHORTSTRING)).returns(type(BYTE));
216-
routine("Length").param(type(ANSISTRING)).returns(type(INTEGER));
217-
routine("Length").param(type(UNICODESTRING)).returns(type(INTEGER));
218-
routine("Length").param(ANY_ARRAY).returns(type(INTEGER));
215+
routine("Length").param(type(SHORTSTRING)).returns(IntrinsicReturnType.length(typeFactory));
216+
routine("Length").param(type(ANSISTRING)).returns(IntrinsicReturnType.length(typeFactory));
217+
routine("Length").param(type(UNICODESTRING)).returns(IntrinsicReturnType.length(typeFactory));
218+
routine("Length").param(ANY_ARRAY).returns(IntrinsicReturnType.length(typeFactory));
219219
routine("Lo").param(type(INTEGER)).returns(type(BYTE));
220220
routine("Low")
221221
.varParam(TypeFactory.untypedType())

delphi-frontend/src/test/java/au/com/integradev/delphi/type/intrinsic/IntrinsicReturnTypeTest.java

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
import static org.assertj.core.api.Assertions.*;
2222
import static org.mockito.Mockito.mock;
2323

24+
import au.com.integradev.delphi.compiler.CompilerVersion;
25+
import au.com.integradev.delphi.compiler.Toolchain;
2426
import au.com.integradev.delphi.type.factory.ArrayOption;
2527
import au.com.integradev.delphi.type.factory.TypeFactoryImpl;
26-
import au.com.integradev.delphi.utils.types.TypeFactoryUtils;
2728
import java.util.List;
2829
import java.util.Set;
2930
import org.junit.jupiter.api.Test;
@@ -34,23 +35,69 @@
3435
import org.sonar.plugins.communitydelphi.api.type.TypeFactory;
3536

3637
class IntrinsicReturnTypeTest {
37-
private static final TypeFactory TYPE_FACTORY = TypeFactoryUtils.defaultFactory();
38+
private static final TypeFactory TYPE_FACTORY =
39+
new TypeFactoryImpl(Toolchain.DCC64, CompilerVersion.fromVersionNumber("35.0"));
40+
private static final TypeFactory TYPE_FACTORY_ATHENS =
41+
new TypeFactoryImpl(Toolchain.DCC64, CompilerVersion.fromVersionNumber("36.0"));
42+
43+
@Test
44+
void testLength() {
45+
Type shortString = TYPE_FACTORY.getIntrinsic(IntrinsicType.SHORTSTRING);
46+
Type ansiString = TYPE_FACTORY.getIntrinsic(IntrinsicType.ANSISTRING);
47+
Type wideString = TYPE_FACTORY.getIntrinsic(IntrinsicType.WIDESTRING);
48+
Type unicodeString = TYPE_FACTORY.getIntrinsic(IntrinsicType.UNICODESTRING);
49+
Type fixedArray =
50+
((TypeFactoryImpl) TYPE_FACTORY).array(null, ansiString, Set.of(ArrayOption.FIXED));
51+
Type dynamicArray =
52+
((TypeFactoryImpl) TYPE_FACTORY).array(null, ansiString, Set.of(ArrayOption.DYNAMIC));
53+
Type openArray =
54+
((TypeFactoryImpl) TYPE_FACTORY).array(null, ansiString, Set.of(ArrayOption.OPEN));
55+
56+
var length35 = (IntrinsicReturnType) IntrinsicReturnType.length(TYPE_FACTORY);
57+
assertThat(length35.getReturnType(List.of(shortString)).is(IntrinsicType.BYTE)).isTrue();
58+
assertThat(length35.getReturnType(List.of(ansiString)).is(IntrinsicType.INTEGER)).isTrue();
59+
assertThat(length35.getReturnType(List.of(wideString)).is(IntrinsicType.INTEGER)).isTrue();
60+
assertThat(length35.getReturnType(List.of(unicodeString)).is(IntrinsicType.INTEGER)).isTrue();
61+
assertThat(length35.getReturnType(List.of(fixedArray)).is(IntrinsicType.INTEGER)).isTrue();
62+
assertThat(length35.getReturnType(List.of(dynamicArray)).is(IntrinsicType.INTEGER)).isTrue();
63+
assertThat(length35.getReturnType(List.of(openArray)).is(IntrinsicType.INTEGER)).isTrue();
64+
65+
var length36 = (IntrinsicReturnType) IntrinsicReturnType.length(TYPE_FACTORY_ATHENS);
66+
assertThat(length36.getReturnType(List.of(shortString)).is(IntrinsicType.BYTE)).isTrue();
67+
assertThat(length36.getReturnType(List.of(ansiString)).is(IntrinsicType.INTEGER)).isTrue();
68+
assertThat(length36.getReturnType(List.of(wideString)).is(IntrinsicType.INTEGER)).isTrue();
69+
assertThat(length36.getReturnType(List.of(unicodeString)).is(IntrinsicType.INTEGER)).isTrue();
70+
assertThat(length36.getReturnType(List.of(fixedArray)).is(IntrinsicType.INTEGER)).isTrue();
71+
assertThat(length36.getReturnType(List.of(dynamicArray)).is(IntrinsicType.INTEGER)).isTrue();
72+
assertThat(length36.getReturnType(List.of(openArray)).is(IntrinsicType.NATIVEINT)).isTrue();
73+
}
3874

3975
@Test
4076
void testHighLow() {
4177
Type smallInt = TYPE_FACTORY.getIntrinsic(IntrinsicType.SMALLINT);
4278
Type integer = TYPE_FACTORY.getIntrinsic(IntrinsicType.INTEGER);
79+
Type nativeInt = TYPE_FACTORY.getIntrinsic(IntrinsicType.NATIVEINT);
4380
Type string = TYPE_FACTORY.getIntrinsic(IntrinsicType.UNICODESTRING);
4481
Type array = ((TypeFactoryImpl) TYPE_FACTORY).array(null, string, Set.of(ArrayOption.DYNAMIC));
82+
Type openArray = ((TypeFactoryImpl) TYPE_FACTORY).array(null, string, Set.of(ArrayOption.OPEN));
4583
Type classType = mock(StructType.class);
4684
Type classReference = TYPE_FACTORY.classOf("Foo", classType);
4785

48-
var high = (IntrinsicReturnType) IntrinsicReturnType.high(TYPE_FACTORY);
49-
assertThat(high.getReturnType(List.of(smallInt)).is(smallInt)).isTrue();
50-
assertThat(high.getReturnType(List.of(integer)).is(integer)).isTrue();
51-
assertThat(high.getReturnType(List.of(string)).is(integer)).isTrue();
52-
assertThat(high.getReturnType(List.of(array)).is(integer)).isTrue();
53-
assertThat(high.getReturnType(List.of(classReference))).isSameAs(classType);
86+
var high35 = (IntrinsicReturnType) IntrinsicReturnType.high(TYPE_FACTORY);
87+
assertThat(high35.getReturnType(List.of(smallInt)).is(smallInt)).isTrue();
88+
assertThat(high35.getReturnType(List.of(integer)).is(integer)).isTrue();
89+
assertThat(high35.getReturnType(List.of(string)).is(integer)).isTrue();
90+
assertThat(high35.getReturnType(List.of(array)).is(integer)).isTrue();
91+
assertThat(high35.getReturnType(List.of(openArray)).is(integer)).isTrue();
92+
assertThat(high35.getReturnType(List.of(classReference))).isSameAs(classType);
93+
94+
var high36 = (IntrinsicReturnType) IntrinsicReturnType.high(TYPE_FACTORY_ATHENS);
95+
assertThat(high36.getReturnType(List.of(smallInt)).is(smallInt)).isTrue();
96+
assertThat(high36.getReturnType(List.of(integer)).is(integer)).isTrue();
97+
assertThat(high36.getReturnType(List.of(string)).is(integer)).isTrue();
98+
assertThat(high36.getReturnType(List.of(array)).is(integer)).isTrue();
99+
assertThat(high36.getReturnType(List.of(openArray)).is(nativeInt)).isTrue();
100+
assertThat(high36.getReturnType(List.of(classReference))).isSameAs(classType);
54101
}
55102

56103
@Test

0 commit comments

Comments
 (0)