diff --git a/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasConstant.cod b/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasConstant.cod new file mode 100644 index 0000000..c9d0feb --- /dev/null +++ b/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasConstant.cod @@ -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) + } +} diff --git a/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasNotConstantInvalid.cod b/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasNotConstantInvalid.cod new file mode 100644 index 0000000..985f530 --- /dev/null +++ b/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasNotConstantInvalid.cod @@ -0,0 +1,9 @@ +unit test.typealiasconstant + +share TypeAliasNotConstantInvalid { + share main() { + byte: type = u8 + n: byte = 3 + out(n) + } +} diff --git a/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasNotTypeValueInvalid.cod b/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasNotTypeValueInvalid.cod new file mode 100644 index 0000000..80f97df --- /dev/null +++ b/src/main/cod/demo/src/main/test/typealiasconstant/TypeAliasNotTypeValueInvalid.cod @@ -0,0 +1,9 @@ +unit test.typealiasconstant + +share TypeAliasNotTypeValueInvalid { + share main() { + BYTE := 12 + n: BYTE = 3 + out(n) + } +} diff --git a/src/main/java/cod/interpreter/InterpreterVisitor.java b/src/main/java/cod/interpreter/InterpreterVisitor.java index 10a8080..75a86de 100644 --- a/src/main/java/cod/interpreter/InterpreterVisitor.java +++ b/src/main/java/cod/interpreter/InterpreterVisitor.java @@ -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) { @@ -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); } } @@ -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 scope = ctx.getLocalsStack().get(i); + if (scope.containsKey(aliasName)) { + return new AliasLookupResult(true, scope.get(aliasName)); + } + } + Map 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) { diff --git a/src/main/java/cod/parser/ExpressionParser.java b/src/main/java/cod/parser/ExpressionParser.java index a3b57dd..56241a5 100644 --- a/src/main/java/cod/parser/ExpressionParser.java +++ b/src/main/java/cod/parser/ExpressionParser.java @@ -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);