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
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
unit test.typealiasconstant

share TypeAliasConstant {
share main() {
BYTE: type = u8
n: BYTE = 3
out("n=" + n)

WHOLE: type = int
FRACTION: type = float
WORD: type = text
FLAG: type = bool

a: WHOLE = 42
b: FRACTION = 2.5
c: WORD = "ok"
d: FLAG = true

out("a=" + a)
out("b=" + b)
out("c=" + c)
out("d=" + d)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
unit test.typealiasconstant

share TypeAliasNotConstantInvalid {
share main() {
byte: type = u8
n: byte = 3
out(n)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
unit test.typealiasconstant

share TypeAliasNotTypeValueInvalid {
share main() {
BYTE := 12
n: BYTE = 3
out(n)
}
}
81 changes: 74 additions & 7 deletions src/main/java/cod/interpreter/InterpreterVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,8 @@ public Object visit(Var node) {

if (node.explicitType != null) {
String declaredType = node.explicitType;
ctx.setVariableType(node.name, declaredType);
String resolvedDeclaredType = resolveVariableTypeAliasIfAny(declaredType, ctx);
ctx.setVariableType(node.name, resolvedDeclaredType);

if (TYPE.toString().equals(declaredType)) {
if (val instanceof String) {
Expand All @@ -401,23 +402,23 @@ public Object visit(Var node) {
}
}

if (val == null && declaredType.contains("|none")) {
if (val == null && resolvedDeclaredType.contains("|none")) {
val = createNoneValue();
ctx.setVariable(node.name, val);
}

if (!typeSystem.validateType(declaredType, val)) {
if (typeSystem.isNoneValue(val) && declaredType.contains("|none")) {
if (!typeSystem.validateType(resolvedDeclaredType, val)) {
if (typeSystem.isNoneValue(val) && resolvedDeclaredType.contains("|none")) {
val = createNoneValue();
ctx.setVariable(node.name, val);
} else {
throw new ProgramError("Type mismatch for " + node.name + ". Expected " + declaredType);
throw new ProgramError("Type mismatch for " + node.name + ". Expected " + resolvedDeclaredType);
}
}

if (declaredType.contains("|")) {
if (resolvedDeclaredType.contains("|")) {
String activeType = typeSystem.getConcreteType(typeSystem.unwrap(val));
val = new TypeHandler.Value(val, activeType, declaredType);
val = new TypeHandler.Value(val, activeType, resolvedDeclaredType);
ctx.setVariable(node.name, val);
}
}
Expand Down Expand Up @@ -447,6 +448,72 @@ private boolean isVariableDeclaredInAnyScope(ExecutionContext ctx, String name)
return contextHandler.isVariableDeclaredInAnyScope(ctx, name);
}

private String resolveVariableTypeAliasIfAny(String declaredType, ExecutionContext ctx) {
if (declaredType == null || typeSystem.isTypeLiteral(declaredType)) {
return declaredType;
}
if (ctx == null) {
return declaredType;
}

AliasLookupResult alias = findTypeAliasValue(declaredType, ctx);
if (alias == null || !alias.found) {
return declaredType;
}

if (!NamingValidator.isAllCaps(declaredType)) {
throw new ProgramError(
"Type alias '" + declaredType + "' must be declared as a constant name (ALL_CAPS). " +
"Declare it like: BYTE: type = u8");
}

Object rawAliasValue = alias.value;
if (rawAliasValue instanceof TypeHandler.Value && ((TypeHandler.Value) rawAliasValue).isTypeValue()) {
Object typeSig = ((TypeHandler.Value) rawAliasValue).value;
if (typeSig instanceof String && typeSystem.isTypeLiteral((String) typeSig)) {
return (String) typeSig;
}
}
Object aliasValue = typeSystem.unwrap(rawAliasValue);
if (aliasValue instanceof String && typeSystem.isTypeLiteral((String) aliasValue)) {
return (String) aliasValue;
}
if (aliasValue instanceof TextLiteral) {
String literal = ((TextLiteral) aliasValue).value;
if (typeSystem.isTypeLiteral(literal)) {
return literal;
}
}

throw new ProgramError(
"Type alias constant '" + declaredType + "' must hold a type value. " +
"Declare it like: BYTE: type = u8");
}

private AliasLookupResult findTypeAliasValue(String aliasName, ExecutionContext ctx) {
for (int i = ctx.getScopeDepth() - 1; i >= 0; i--) {
Map<String, Object> scope = ctx.getLocalsStack().get(i);
if (scope.containsKey(aliasName)) {
return new AliasLookupResult(true, scope.get(aliasName));
}
}
Map<String, Object> slots = ctx.getSlotValues();
if (slots != null && slots.containsKey(aliasName)) {
return new AliasLookupResult(true, slots.get(aliasName));
}
return new AliasLookupResult(false, null);
}

private static final class AliasLookupResult {
private final boolean found;
private final Object value;

private AliasLookupResult(boolean found, Object value) {
this.found = found;
this.value = value;
}
}

@Override
public Object visit(StmtIf node) {
if (node == null) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/cod/parser/ExpressionParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ else if (is(NONE)) {
Token noneToken = expect(NONE);
baseExpr = ASTFactory.createNoneLiteral(noneToken);
}
else if (is(INT, TEXT, FLOAT, BOOL, TYPE)) {
else if (is(INT, TEXT, FLOAT, BOOL, TYPE, I8, I16, I32, I64, U8, U16, U32, U64, F32, F64)) {
Token typeToken = now();
String typeName = expect(KEYWORD).getText();
baseExpr = ASTFactory.createTextLiteral(typeName, typeToken);
Expand Down