Skip to content

Commit 4d2f600

Browse files
committed
Type checking unsigned int and long, and static initializers for them. Chapter 12 type checking complete
1 parent e33e52c commit 4d2f600

File tree

8 files changed

+177
-24
lines changed

8 files changed

+177
-24
lines changed

src/com/plasstech/lang/c/parser/FunDecl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,11 @@ public record FunDecl(String name, FunType funType, List<String> paramNames, Opt
1515
public <R> R accept(Visitor<R> visitor) {
1616
return visitor.visit(this);
1717
}
18+
19+
public BlockItem nthItem(int i) {
20+
if (body.isEmpty()) {
21+
return null;
22+
}
23+
return body.get().items().get(i);
24+
}
1825
}

src/com/plasstech/lang/c/typecheck/Initializer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ public static Initializer of(long value, Type type) {
1111
if (type.equals(Type.LONG)) {
1212
return new Initializer(new LongInit(value));
1313
}
14+
// Not sure if this is right. Page 280
15+
if (type.equals(Type.UNSIGNED_INT)) {
16+
return new Initializer(new UIntInit((int) value));
17+
}
18+
if (type.equals(Type.UNSIGNED_LONG)) {
19+
return new Initializer(new ULongInit(value));
20+
}
1421
throw new IllegalStateException("Cannot create of type " + type.toString());
1522
}
1623

src/com/plasstech/lang/c/typecheck/StaticInit.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ public interface StaticInit {
55

66
long valueAsLong();
77

8+
// Name for the asm generation
89
String name();
910
}
Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
11
package com.plasstech.lang.c.typecheck;
22

3-
import com.plasstech.lang.c.lex.TokenType;
4-
53
public interface Type {
64
String name();
75

8-
record SimpleType(String name) implements Type {
6+
default int size() {
7+
return 0;
8+
}
9+
10+
default boolean signed() {
11+
return false;
12+
}
13+
14+
record SimpleType(String name, int size, boolean signed) implements Type {
915
@Override
1016
public final String toString() {
1117
return name;
1218
}
1319
}
1420

15-
Type INT = new SimpleType("int");
16-
Type LONG = new SimpleType("long");
17-
Type UNSIGNED_INT = new SimpleType("unsigned int");
18-
Type UNSIGNED_LONG = new SimpleType("unsigned long");
19-
Type NO_TYPE = new SimpleType("no type");
20-
21-
static Type fromTokenType(TokenType type) {
22-
return switch (type) {
23-
case INT -> INT;
24-
case LONG -> LONG;
25-
default -> throw new IllegalArgumentException("Unexpected value: " + type);
26-
};
27-
}
21+
Type INT = new SimpleType("int", 32, true);
22+
Type LONG = new SimpleType("long", 64, true);
23+
Type UNSIGNED_INT = new SimpleType("unsigned int", 32, false);
24+
Type UNSIGNED_LONG = new SimpleType("unsigned long", 64, false);
25+
Type NO_TYPE = new SimpleType("no type", 0, false);
2826
}

src/com/plasstech/lang/c/typecheck/TypeChecker.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@ private Optional<Long> getDeclInitialValue(VarDecl decl) {
210210
if (ci.type().equals(Type.LONG)) {
211211
yield Optional.of(ci.asLong());
212212
}
213+
// Page 280. Not sure if this is right.
214+
if (ci.type().equals(Type.UNSIGNED_INT)) {
215+
yield Optional.of(ci.asLong());
216+
}
217+
if (ci.type().equals(Type.UNSIGNED_LONG)) {
218+
yield Optional.of(ci.asLong());
219+
}
213220
throw new IllegalArgumentException("Unexpected value: " + ci.type());
214221
}
215222
default -> Optional.empty();
@@ -254,12 +261,21 @@ private Return typeCheckReturn(Return r) {
254261
return new Return(convertTo(typeCheckExp(r.exp()), currentRetType));
255262
}
256263

257-
// Page 254
258-
private static Type getCommonType(Type t1, Type t2) {
259-
if (t1.equals(t2)) {
260-
return t1;
264+
// Page 254, 280
265+
private static Type getCommonType(Type type1, Type type2) {
266+
if (type1.equals(type2)) {
267+
return type1;
268+
}
269+
if (type1.size() == type2.size()) {
270+
if (type1.signed()) {
271+
return type2;
272+
}
273+
return type1;
274+
}
275+
if (type1.size() > type2.size()) {
276+
return type1;
261277
}
262-
return Type.LONG;
278+
return type2;
263279
}
264280

265281
// Page 255
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.plasstech.lang.c.typecheck;
2+
3+
public record UIntInit(int value) implements StaticInit {
4+
@Override
5+
public long valueAsLong() {
6+
return value;
7+
}
8+
9+
@Override
10+
public int bytes() {
11+
return 4;
12+
}
13+
14+
@Override
15+
public String name() {
16+
return "long";
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.plasstech.lang.c.typecheck;
2+
3+
public record ULongInit(long value) implements StaticInit {
4+
@Override
5+
public long valueAsLong() {
6+
return value;
7+
}
8+
9+
@Override
10+
public int bytes() {
11+
return 8;
12+
}
13+
14+
@Override
15+
public String name() {
16+
return "quad";
17+
}
18+
}

test/com/plasstech/lang/c/typecheck/TypeCheckerTest.java

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ int main(long a) {
259259
""";
260260
Program program = validate(input);
261261
FunDecl fd = (FunDecl) program.declarations().get(0);
262-
Return r = (Return) fd.body().get().items().get(0);
262+
Return r = (Return) fd.nthItem(0);
263263
assertThat(r.exp().type()).isEqualTo(Type.INT);
264264
}
265265

@@ -273,7 +273,7 @@ long main(long a) {
273273
""";
274274
Program program = validate(input);
275275
FunDecl fd = (FunDecl) program.declarations().get(0);
276-
Return r = (Return) fd.body().get().items().get(1);
276+
Return r = (Return) fd.nthItem(1);
277277
assertThat(r.exp().type()).isEqualTo(Type.LONG);
278278
}
279279

@@ -287,7 +287,7 @@ int main(long a) {
287287
""";
288288
Program program = validate(input);
289289
FunDecl fd = (FunDecl) program.declarations().get(0);
290-
Return r = (Return) fd.body().get().items().get(1);
290+
Return r = (Return) fd.nthItem(1);
291291
assertThat(r.exp().type()).isEqualTo(Type.INT);
292292
}
293293

@@ -331,4 +331,92 @@ int main(void) {
331331
assertThrows(SemanticAnalyzerException.class, () -> validate(input));
332332
assertThat(e.getMessage()).contains("Conflicting types for 'foo'");
333333
}
334+
335+
@Test
336+
public void unsignedIntAndIntBecomesUnsignedInt() {
337+
String input = """
338+
unsigned int main(unsigned int a) {
339+
int b = 1;
340+
return b + a;
341+
}
342+
""";
343+
Program program = validate(input);
344+
FunDecl fd = (FunDecl) program.declarations().get(0);
345+
Return r = (Return) fd.nthItem(1);
346+
assertThat(r.exp().type()).isEqualTo(Type.UNSIGNED_INT);
347+
}
348+
349+
@Test
350+
public void unsignedIntAndUnsignedLongBecomesUnsignedLong() {
351+
String input = """
352+
unsigned long main(unsigned long a) {
353+
unsigned int b = 1u;
354+
return b + a;
355+
}
356+
""";
357+
Program program = validate(input);
358+
FunDecl fd = (FunDecl) program.declarations().get(0);
359+
Return r = (Return) fd.nthItem(1);
360+
assertThat(r.exp().type()).isEqualTo(Type.UNSIGNED_LONG);
361+
}
362+
363+
@Test
364+
public void unsignedIntAndLongBecomesLong() {
365+
String input = """
366+
unsigned int main(unsigned int a) {
367+
long b = 1L;
368+
return b + a; // it actually IS a long but then it gets cast AGAIN to the return type
369+
}
370+
""";
371+
Program program = validate(input);
372+
FunDecl fd = (FunDecl) program.declarations().get(0);
373+
Return r = (Return) fd.nthItem(1);
374+
assertThat(r.exp().type()).isEqualTo(Type.UNSIGNED_INT);
375+
}
376+
377+
@Test
378+
public void unsignedLongAndLongBecomesUnsignedLong() {
379+
String input = """
380+
unsigned long main(unsigned long a) {
381+
signed long b = 1L;
382+
return b + a;
383+
}
384+
""";
385+
Program program = validate(input);
386+
FunDecl fd = (FunDecl) program.declarations().get(0);
387+
Return r = (Return) fd.nthItem(1);
388+
assertThat(r.exp().type()).isEqualTo(Type.UNSIGNED_LONG);
389+
}
390+
391+
@Test
392+
public void staticInitUnsignedIntOverflow() {
393+
String input = """
394+
static unsigned int u = 4294967299L;
395+
""";
396+
validate(input);
397+
Symbol u = symbols.get("u");
398+
StaticAttr attr = (StaticAttr) u.attribute();
399+
assertThat(attr.init()).isInstanceOf(Initializer.class);
400+
Initializer initialValue = (Initializer) attr.init();
401+
assertThat(initialValue.staticInit()).isInstanceOf(UIntInit.class);
402+
UIntInit staticInit = (UIntInit) initialValue.staticInit();
403+
// whoa, this actually works. Thanks Java.
404+
assertThat(staticInit.value()).isEqualTo(3);
405+
}
406+
407+
@Test
408+
public void staticInitIntOverflow() {
409+
String input = """
410+
static int u = 4294967246u;
411+
""";
412+
validate(input);
413+
Symbol u = symbols.get("u");
414+
StaticAttr attr = (StaticAttr) u.attribute();
415+
assertThat(attr.init()).isInstanceOf(Initializer.class);
416+
Initializer initialValue = (Initializer) attr.init();
417+
assertThat(initialValue.staticInit()).isInstanceOf(IntInit.class);
418+
IntInit staticInit = (IntInit) initialValue.staticInit();
419+
// whoa, this actually works. Thanks Java.
420+
assertThat(staticInit.value()).isEqualTo(-50);
421+
}
334422
}

0 commit comments

Comments
 (0)