diff --git a/Test.ash b/Test.ash index af8ca88..215f8cf 100644 --- a/Test.ash +++ b/Test.ash @@ -4,7 +4,8 @@ import Ifc2 public class Test { public static func main(args : [String]) { - + const c = 299792458 + c = 0 } } \ No newline at end of file diff --git a/src/ashc/error/AshError.java b/src/ashc/error/AshError.java index fbcf18a..bc3252d 100644 --- a/src/ashc/error/AshError.java +++ b/src/ashc/error/AshError.java @@ -100,6 +100,7 @@ public enum EnumError { PRIMTIVE_CANNOT_BE_OPTIONAL("A primitive type cannot be optional (%s)"), CANNOT_ASSIGN("Cannot assign %s to %s"), + ASSIGNMENT_OF_CONST("A const (\'%s\') cannot be reassigned"), CLOSURE_TYPE_NOT_INTERFACE("The type used is not an interface"), NO_INTERFACE_FOR_CLOSURE_FOUND("None of the imported interfaces have a function that is applicable to the given arguments and return type"); diff --git a/src/ashc/grammar/Node.java b/src/ashc/grammar/Node.java index db8f2eb..c79dff1 100644 --- a/src/ashc/grammar/Node.java +++ b/src/ashc/grammar/Node.java @@ -380,10 +380,10 @@ public void preAnalyse() { arg.preAnalyse(); if (!arg.errored) { final TypeI argType = arg.type.toTypeI(); - final Variable local = new Variable(arg.id, argType); + final Variable local = new Variable(arg.id, argType, false); local.isLocal = true; defConstructorScope.addVar(local); - final Field field = new Field(Scope.getNamespace().copy().add(arg.id), EnumModifier.PUBLIC.intVal, argType, false, false, type); + final Field field = new Field(Scope.getNamespace().copy().add(arg.id), EnumModifier.PUBLIC.intVal, argType, false, false, false, type); type.addField(field); argFields.add(field); defConstructor.parameters.add(argType); @@ -1069,7 +1069,7 @@ private void finishPreAnalysis() { scope = new FuncScope(returnType, isMutFunc, isGlobal || func.isStatic(), isGlobal, extType); Scope.push(scope); for (final NodeArg arg : args.args) - Semantics.addVar(new Variable(arg.id, arg.type.toTypeI())); + Semantics.addVar(new Variable(arg.id, arg.type.toTypeI(), false)); if (!isMutFunc && !isConstructor) { if (!type.id.equals("void")) returnType = type.toTypeI(); @@ -1246,7 +1246,7 @@ protected void analyseProperty(final TypeI type) { } if (setBlock != null) { Scope.push(new PropertyScope(var)); - final Variable newVar = new Variable("newVal", var.type); + final Variable newVar = new Variable("newVal", var.type, false); newVar.localID = var.isStatic() ? 0 : 1; Scope.getScope().addVar(newVar); setBlock.analyse(null); @@ -1292,6 +1292,10 @@ public void generate() { } } + public boolean isConst() { + return keyword.equals("const"); + } + } public static class NodeVarDecExplicit extends NodeVarDec { @@ -1311,7 +1315,7 @@ public void preAnalyse() { if (mod.asInt() == EnumModifier.STATIC.intVal) isStatic = true; modifiers |= mod.asInt(); } - var = new Field(name, modifiers, type.toTypeI(), setBlock != null, getBlock != null, Semantics.currentType()); + var = new Field(name, modifiers, type.toTypeI(), setBlock != null, getBlock != null, isConst(), Semantics.currentType()); if (!Semantics.fieldExists(var)) Semantics.addField(var); else semanticError(this, line, column, FIELD_ALREADY_EXISTS, id); } @@ -1331,7 +1335,7 @@ public void analyse(TypeI typeContext) { semanticError(this, line, column, MISSING_ASSIGNMENT); } if (var == null) { - var = new Variable(id, typeI); + var = new Variable(id, typeI, isConst()); Semantics.addVar((Variable) var); } analyseProperty(typeI); @@ -1356,7 +1360,7 @@ public void preAnalyse() { } expr.analyse(null); typeI = expr.getExprType(); - var = new Field(name, modifiers, typeI, setBlock != null, getBlock != null, Semantics.currentType()); + var = new Field(name, modifiers, typeI, setBlock != null, getBlock != null, isConst(), Semantics.currentType()); if (!Semantics.fieldExists(var)) Semantics.addField(var); else semanticError(this, line, column, FIELD_ALREADY_EXISTS, id); } @@ -1368,7 +1372,7 @@ public void analyse(TypeI typeContext) { if (!((Node) expr).errored) { final TypeI type = Semantics.filterNullType(expr.getExprType()); if (var == null) { - var = new Variable(id, type); + var = new Variable(id, type, isConst()); Semantics.addVar((Variable) var); } analyseProperty(type); @@ -1775,6 +1779,8 @@ public void analyse(TypeI typeContext) { expr.analyse(null); final TypeI exprType = expr.getExprType(); var.analyse(null); + Field v = Semantics.getVar(var.id); + if (v != null && v.isConstant) semanticError(this, var.line, var.column, ASSIGNMENT_OF_CONST, v.id); if (var.errored) errored = true; if (var.var != null) if (!var.var.type.canBeAssignedTo(expr.getExprType())) semanticError(this, line, column, CANNOT_ASSIGN, var.var.type, exprType); @@ -2789,7 +2795,7 @@ public void analyse(TypeI typeContext) { } else semanticError(this, line, column, CANNOT_ITERATE_TYPE, exprType); } Scope.push(new Scope(true)); - var = new Variable(varId, varType); + var = new Variable(varId, varType, false); Scope.getFuncScope().locals += exprType.isArray() ? 3 : 1; // Some local vars are reserved for use in the bytecode Semantics.addVar(var); block.analyse(null); @@ -3642,7 +3648,7 @@ public void analyse(TypeI typeContext) { argTypes = args.toTypeIList(); Scope.push(new FuncScope(typeI, false, false, false)); int i = 0; - for (TypeI arg : argTypes) Scope.getScope().addVar(new Variable(args.args.get(i++).id, arg)); + for (TypeI arg : argTypes) Scope.getScope().addVar(new Variable(args.args.get(i++).id, arg, false)); body.analyse(null); Scope.pop(); } diff --git a/src/ashc/semantics/Member.java b/src/ashc/semantics/Member.java index 6e41fb5..743fb33 100644 --- a/src/ashc/semantics/Member.java +++ b/src/ashc/semantics/Member.java @@ -319,8 +319,8 @@ public boolean hasEqualSignature(Function superFunc) { public static class Variable extends Field { - public Variable(final String id, final TypeI type) { - super(new QualifiedName(id), 0, type, false, false, Semantics.currentType()); + public Variable(final String id, final TypeI type, boolean isConstant) { + super(new QualifiedName(id), 0, type, false, false, isConstant, Semantics.currentType()); if (Scope.inFuncScope()) { isLocal = true; localID = ++Scope.getFuncScope().locals; @@ -339,19 +339,20 @@ public static class Field extends Member { public TypeI type; public String id; public int localID; - public boolean isSetProperty, isGetProperty; + public boolean isSetProperty, isGetProperty, isConstant; - public Field(final QualifiedName qualifiedName, final int modifiers, final TypeI type, final boolean isSetProperty, final boolean isGetProperty, final Type enclosingType) { + public Field(final QualifiedName qualifiedName, final int modifiers, final TypeI type, final boolean isSetProperty, final boolean isGetProperty, final boolean isConstant, final Type enclosingType) { super(qualifiedName, modifiers); id = qualifiedName.shortName; this.type = type; this.enclosingType = enclosingType; this.isGetProperty = isGetProperty; this.isSetProperty = isSetProperty; + this.isConstant = isConstant; } public Field(final FieldNode fNode, final Type enclosing) { - this(new QualifiedName(fNode.name.replace('/', '.')), fNode.access, TypeI.fromBytecodeName(fNode.desc.replace(";", "")), false, false, enclosing); + this(new QualifiedName(fNode.name.replace('/', '.')), fNode.access, TypeI.fromBytecodeName(fNode.desc.replace(";", "")), false, false, BitOp.or(fNode.access, EnumModifier.FINAL.intVal), enclosing); } @Override diff --git a/src/ashc/semantics/Semantics.java b/src/ashc/semantics/Semantics.java index 6982fc9..21de2c8 100644 --- a/src/ashc/semantics/Semantics.java +++ b/src/ashc/semantics/Semantics.java @@ -123,7 +123,8 @@ public static void addField(final Field field) { public static Field getVar(final String id, final TypeI type) { if (type.isTuple()) { for (final TypeI tupleType : type.tupleTypes) - if ((tupleType.tupleName != null) && tupleType.tupleName.equals(id)) return new Variable(id, tupleType); + if ((tupleType.tupleName != null) && tupleType.tupleName.equals(id)) + return new Variable(id, tupleType, false); } else { final Optional t = getType(type.shortName); if (t.isPresent()) return t.get().getField(id);