Implement |const| keyword.
authorDavid Anderson <dvander@alliedmods.net>
Wed Dec 26 17:14:12 2012 -0800 (2012-12-26)
changeset 24118f3010a358c
parent 240 e3c851a14f16
child 242 b7d14a8b918e
Implement |const| keyword.
src/API.cpp
src/Messages.tbl
src/Structures.cpp
src/TypeManager.cpp
src/Types.cpp
src/Types.h
src/compiler/AST.h
src/compiler/NameBinding.cpp
src/compiler/Parser.cpp
src/compiler/Parser.h
src/compiler/SemanticAnalysis.cpp
src/compiler/SemanticAnalysis.h
tests/basic/const-arg-1.err
tests/basic/const-arg-1.sp
tests/basic/const-arg-2.err
tests/basic/const-arg-2.sp
tests/basic/const-arg-3.err
tests/basic/const-arg-3.sp
tests/basic/const-arg-4.err
tests/basic/const-arg-4.sp
tests/basic/const-arg-5.out
tests/basic/const-arg-5.sp
tests/basic/const-global-1.err
tests/basic/const-global-1.sp
tests/basic/const-global-2.err
tests/basic/const-global-2.sp
tests/basic/const-global-3.err
tests/basic/const-global-3.sp
tests/basic/const-local-1.err
tests/basic/const-local-1.sp
tests/basic/const-local-2.err
tests/basic/const-local-2.sp
tests/basic/const-local-3.out
tests/basic/const-local-3.sp
     1.1 --- a/src/API.cpp	Tue Dec 25 18:13:02 2012 -0800
     1.2 +++ b/src/API.cpp	Wed Dec 26 17:14:12 2012 -0800
     1.3 @@ -295,9 +295,10 @@
     1.4  
     1.5      for (unsigned i = 0; i < nparams; i++) {
     1.6          if (!CheckInvokeType(params[i], fun->argType(i))) {
     1.7 +            char name[255];
     1.8              ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
     1.9                                      GetInvokeTypeName(params[i].type()),
    1.10 -                                    GetTypeName(fun->argType(i)));
    1.11 +                                    GetTypeName(fun->argType(i), name, sizeof(name)));
    1.12              return false;
    1.13          }
    1.14      }
    1.15 @@ -308,7 +309,9 @@
    1.16          !returnType->isEnum() &&
    1.17          !returnType->isVoid())
    1.18      {
    1.19 -        ke::ZONE()->reportError(Message_CannotInvokeReturnType, GetTypeName(returnType));
    1.20 +        char name[255];
    1.21 +        ke::ZONE()->reportError(Message_CannotInvokeReturnType,
    1.22 +                                GetTypeName(returnType, name, sizeof(name)));
    1.23          return false;
    1.24      }
    1.25  
     2.1 --- a/src/Messages.tbl	Tue Dec 25 18:13:02 2012 -0800
     2.2 +++ b/src/Messages.tbl	Wed Dec 26 17:14:12 2012 -0800
     2.3 @@ -41,7 +41,6 @@
     2.4  MSG(ForwardDeclareMismatches,       SyntaxError,            "declaration does not match original forward signature")
     2.5  MSG(ArrayCantBeReference,           SyntaxError,            "this type cannot be used with a reference")
     2.6  MSG(ArraySizeMustBeConstant,        SyntaxError,            "array size must be a constant integer")
     2.7 -MSG(ReferenceIsConstant,            SyntaxError,            "cannot assign to a constant lvalue")
     2.8  MSG(MultiArrayInNative,             SyntaxError,            "multidimensional arrays cannot be passed to natives")
     2.9  MSG(InvalidVarArgs,                 SyntaxError,            "varargs cannot be const or ref")
    2.10  MSG(VarArgsOutsideNative,           SyntaxError,            "variadic arguments can only be specified on natives")
    2.11 @@ -80,4 +79,7 @@
    2.12  MSG(ImportsMustBeFirst,             SyntaxError,            "import statements must come before other statements")
    2.13  MSG(ImportedNameAlreadyBound,       TypeError,              "imported name has already been bound")
    2.14  MSG(CannotResolveImport,            TypeError,              "cannot resolve import %s")
    2.15 -MSG(InvalidCoercion,                TypeError,              "cannot coerce type '%s' to type '%s'")
    2.16 \ No newline at end of file
    2.17 +MSG(InvalidCoercion,                TypeError,              "cannot coerce type '%s' to type '%s'")
    2.18 +MSG(CannotConstReference,           TypeError,              "constant outparams are not allowed")
    2.19 +MSG(CannotModifyConst,              TypeError,              "cannot change constant value or structure")
    2.20 +MSG(InvalidConstOnFormal,           TypeError,              "const parameters must be arrays or structs")
    2.21 \ No newline at end of file
     3.1 --- a/src/Structures.cpp	Tue Dec 25 18:13:02 2012 -0800
     3.2 +++ b/src/Structures.cpp	Wed Dec 26 17:14:12 2012 -0800
     3.3 @@ -133,14 +133,16 @@
     3.4                  childStructMap = StructMap::cast(StructType::cast(desc->type())->newMap());
     3.5                  child = Struct::New(zone, childStructMap, tenure);
     3.6              } else if (desc->type()->isArray()) {
     3.7 -                assert(false);
     3.8 -#if 0
     3.9 -                childArrayMap = ArrayMap::cast(desc->type()->newMap());
    3.10 -                if (desc->type()->isFixedLength())
    3.11 +                // :TODO: don't create empty arrays for ref slots here.
    3.12 +                // Instead, make a separate Initialize function, so we
    3.13 +                // can avoid double-creating arrays for module globals.
    3.14 +                //  (const char:x[] = "x")
    3.15 +                ArrayType *type = ArrayType::cast(desc->type());
    3.16 +                childArrayMap = ArrayMap::cast(type->newMap());
    3.17 +                if (type->isFixedLength())
    3.18                      child = Array::NewFixed(zone, childArrayMap, tenure);
    3.19                  else
    3.20                      child = Array::NewEmpty(zone, childArrayMap, tenure);
    3.21 -#endif
    3.22              }
    3.23              if (!child)
    3.24                  return NULL;
     4.1 --- a/src/TypeManager.cpp	Tue Dec 25 18:13:02 2012 -0800
     4.2 +++ b/src/TypeManager.cpp	Wed Dec 26 17:14:12 2012 -0800
     4.3 @@ -102,9 +102,12 @@
     4.4  }
     4.5  
     4.6  Type *
     4.7 -TypeManager::qualify(Handle<Type> type, TypeQualifiers quals)
     4.8 +TypeManager::qualify(Handle<Type> argType, TypeQualifiers quals)
     4.9  {
    4.10 -    assert(!type->hasTypeQualifiers());
    4.11 +    Local<Type> type(zone_, argType->unqualified());
    4.12 +
    4.13 +    if (!quals)
    4.14 +        return type;
    4.15  
    4.16      LookupKey key(type, quals);
    4.17  
     5.1 --- a/src/Types.cpp	Tue Dec 25 18:13:02 2012 -0800
     5.2 +++ b/src/Types.cpp	Wed Dec 26 17:14:12 2012 -0800
     5.3 @@ -218,32 +218,84 @@
     5.4      return type;
     5.5  }
     5.6  
     5.7 -// :TODO: this leaks an interior pointer.
     5.8 -const char *
     5.9 -ke::GetTypeName(Type *type)
    5.10 +static size_t
    5.11 +FormatVA(char *buffer, size_t maxlen, const char *text, va_list ap)
    5.12 +{
    5.13 +    size_t len = vsnprintf(buffer, maxlen, text, ap);
    5.14 +    if (len >= maxlen) {
    5.15 +        buffer[maxlen - 1] = '\0';
    5.16 +        return maxlen - 1;
    5.17 +    }
    5.18 +    return len;
    5.19 +}
    5.20 +
    5.21 +static size_t
    5.22 +Format(char *buffer, size_t maxlen, const char *text, ...)
    5.23  {
    5.24 -    if (type->isArray())
    5.25 -        return "array";
    5.26 +    va_list ap;
    5.27 +    va_start(ap, text);
    5.28 +    size_t len = FormatVA(buffer, maxlen, text, ap);
    5.29 +    va_end(ap);
    5.30 +    return len;
    5.31 +}
    5.32 +
    5.33 +static size_t
    5.34 +FormatTypeName(Type *type, char *buffer, size_t maxlen)
    5.35 +{
    5.36 +    if (type->isArray()) {
    5.37 +        ArrayType *atype = ArrayType::cast(type);
    5.38 +        Type *innermost = atype->innermost();
    5.39 +
    5.40 +        size_t len = FormatTypeName(innermost, buffer, maxlen);
    5.41 +        for (;;) {
    5.42 +            if (atype->isFixedLength())
    5.43 +                len += Format(buffer + len, maxlen - len, "[%d]", atype->fixedLength());
    5.44 +            else
    5.45 +                len += Format(buffer + len, maxlen - len, "[]");
    5.46 +            if (!atype->contained()->isArray())
    5.47 +                break;
    5.48 +            atype = ArrayType::cast(atype->contained());
    5.49 +        }
    5.50 +        return len;
    5.51 +    }
    5.52 +    if (type->hasTypeQualifiers()) {
    5.53 +        size_t len = 0;
    5.54 +        if (type->quals() & TypeQual_Const)
    5.55 +            len += Format(buffer, maxlen, "const ");
    5.56 +        return len + FormatTypeName(type->unqualified(), buffer + len, maxlen - len);
    5.57 +    }
    5.58      if (type->isFunction())
    5.59 -        return "function";
    5.60 +        return Format(buffer, maxlen, "function");
    5.61      if (type->isVoid())
    5.62 -        return "void";
    5.63 +        return Format(buffer, maxlen, "void");
    5.64 +    if (type->isUnchecked())
    5.65 +        return Format(buffer, maxlen, "unchecked");
    5.66      if (type->isEnum())
    5.67 -        return EnumType::cast(type)->name()->chars();
    5.68 +        return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars());
    5.69      if (type->isStruct())
    5.70 -        return StructType::cast(type)->name()->chars();
    5.71 -    if (type->isReference())
    5.72 -        type = ReferenceType::cast(type)->contained();
    5.73 +        return Format(buffer, maxlen, "%s", StructType::cast(type)->name()->chars());
    5.74 +    if (type->isReference()) {
    5.75 +        ReferenceType *ref = ReferenceType::cast(type);
    5.76 +        size_t len = Format(buffer, maxlen, "&");
    5.77 +        return len + FormatTypeName(ref->contained(), buffer + len, maxlen - len);
    5.78 +    }
    5.79      switch (type->primitive()) {
    5.80        case PrimitiveType_Bool:
    5.81 -        return "bool";
    5.82 +        return Format(buffer, maxlen, "bool");
    5.83        case PrimitiveType_Char:
    5.84 -        return "String";
    5.85 +        return Format(buffer, maxlen, "char");
    5.86        case PrimitiveType_Int32:
    5.87 -        return "int";
    5.88 +        return Format(buffer, maxlen, "int");
    5.89        case PrimitiveType_Float:
    5.90 -        return "Float";
    5.91 +        return Format(buffer, maxlen, "float");
    5.92        default:
    5.93 -        return "<unknown>";
    5.94 +        return Format(buffer, maxlen, "<UNKNOWN>");
    5.95      }
    5.96  }
    5.97 +
    5.98 +const char *
    5.99 +ke::GetTypeName(Type *type, char *buffer, size_t maxlen)
   5.100 +{
   5.101 +    FormatTypeName(type, buffer, maxlen);
   5.102 +    return buffer;
   5.103 +}
     6.1 --- a/src/Types.h	Tue Dec 25 18:13:02 2012 -0800
     6.2 +++ b/src/Types.h	Wed Dec 26 17:14:12 2012 -0800
     6.3 @@ -64,34 +64,8 @@
     6.4  {
     6.5      TypeQual_None           = 0,
     6.6  
     6.7 -    // Const qualifier that has not been determined yet.
     6.8 -    TypeQual_UnkConst       = (1 << 0),
     6.9 -
    6.10 -    // For simplification, SP2 differentiates between two meanings of const.
    6.11 -    // "StoreConst" means that the value itself may not be changed. For
    6.12 -    // example,
    6.13 -    //     const a = 5;
    6.14 -    //
    6.15 -    // Specifies that the storage of "a" is immutable.
    6.16 -    //
    6.17 -    // In addition, "RefConst" means that the memory at a reference may not
    6.18 -    // be changed. For example,
    6.19 -    //
    6.20 -    //     const char:text[] = "asdfasdfasdf";
    6.21 -    //
    6.22 -    // Specifies a readonly view of a character array, however, |text| itself
    6.23 -    // may be repointed to another readonly character array.
    6.24 -    //
    6.25 -    // The meaning of "const" is inferred based on the scope and type:
    6.26 -    //
    6.27 -    //                   +---------+---------+-------+
    6.28 -    //                   | Array   | Struct  | Other |
    6.29 -    //   +---------------+---------+---------+-------+
    6.30 -    //   | GLOBAL/STATIC | Ref|Str | Ref|Str | Str   |
    6.31 -    //   | LOCAL         | Ref     | Ref|Str | Str   |
    6.32 -    //   +---------------+---------+---------+-------+
    6.33 -    TypeQual_StoreConst     = (1 << 1),
    6.34 -    TypeQual_RefConst       = (1 << 2)
    6.35 +    // Values of this type cannot be modified.
    6.36 +    TypeQual_Const       = (1 << 2)
    6.37  };
    6.38  
    6.39  class Type : public Object
    6.40 @@ -233,7 +207,7 @@
    6.41      }
    6.42  
    6.43      TypeQualifiers quals() {
    6.44 -        if (hasTypeQualifiers())
    6.45 +        if (!hasTypeQualifiers())
    6.46              return TypeQual_None;
    6.47          return quals_;
    6.48      }
    6.49 @@ -544,7 +518,7 @@
    6.50      }
    6.51  };
    6.52  
    6.53 -const char *GetTypeName(Type *type);
    6.54 +const char *GetTypeName(Type *type, char *buffer, size_t maxlen);
    6.55  
    6.56  }
    6.57  
     7.1 --- a/src/compiler/AST.h	Tue Dec 25 18:13:02 2012 -0800
     7.2 +++ b/src/compiler/AST.h	Wed Dec 26 17:14:12 2012 -0800
     7.3 @@ -193,6 +193,9 @@
     7.4      ExpressionList *dims() const {
     7.5          return dims_;
     7.6      }
     7.7 +    TypeQualifiers quals() const {
     7.8 +        return qual_;
     7.9 +    }
    7.10  };
    7.11  
    7.12  class Parameter : public PoolObject
    7.13 @@ -200,23 +203,23 @@
    7.14      ScopedRoot<String> name_;
    7.15      Expression *type_;
    7.16      bool reference_;
    7.17 -    bool const_;
    7.18      Expression *initializer_;
    7.19      VariableSymbol *sym_;
    7.20      SourcePosition pos_;
    7.21      ExpressionList *dims_;
    7.22 +    TypeQualifiers quals_;
    7.23  
    7.24    public:
    7.25 -    Parameter(Handle<String> name, Expression *type, bool reference, bool isConst,
    7.26 +    Parameter(Handle<String> name, Expression *type, bool reference, TypeQualifiers quals,
    7.27                ExpressionList *dims, Expression *initializer, const SourcePosition &pos)
    7.28        : name_(name),
    7.29          type_(type),
    7.30          reference_(reference),
    7.31 -        const_(isConst),
    7.32          initializer_(initializer),
    7.33          sym_(NULL),
    7.34          pos_(pos),
    7.35 -        dims_(dims)
    7.36 +        dims_(dims),
    7.37 +        quals_(quals)
    7.38      {
    7.39      }
    7.40  
    7.41 @@ -229,8 +232,8 @@
    7.42      bool reference() const {
    7.43          return reference_;
    7.44      }
    7.45 -    bool isConst() const {
    7.46 -        return const_;
    7.47 +    TypeQualifiers quals() const {
    7.48 +        return quals_;
    7.49      }
    7.50      ExpressionList *dims() const {
    7.51          return dims_;
     8.1 --- a/src/compiler/NameBinding.cpp	Tue Dec 25 18:13:02 2012 -0800
     8.2 +++ b/src/compiler/NameBinding.cpp	Wed Dec 26 17:14:12 2012 -0800
     8.3 @@ -543,11 +543,14 @@
     8.4          if (node->initialization())
     8.5              node->initialization()->accept(this);
     8.6  
     8.7 -        Local<Type> type(zone_, bindType(node->type()));
     8.8 +        Local<Type> type(zone_, bindType(node->type(), node->quals()));
     8.9          if (!type)
    8.10              return;
    8.11  
    8.12 -        if (node->dims() || type->isArray()) {
    8.13 +        // We don't allow array typedefs yet.
    8.14 +        assert(!type->isArray());
    8.15 +
    8.16 +        if (node->dims()) {
    8.17              int dims[MAX_ARRAY_DEPTH];
    8.18              int levels = evaluateDimensions(node->pos(), type, node->dims(), dims);
    8.19              if (levels < 0)
    8.20 @@ -568,11 +571,25 @@
    8.21  
    8.22              // If we got extra dimensions, we need to build a new type.
    8.23              if (node->dims()) {
    8.24 -                if ((type = buildArrayType(type, dims, node->dims()->length())) == NULL)
    8.25 +                if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL)
    8.26                      return;
    8.27              }
    8.28          }
    8.29  
    8.30 +        // If we're in global scope, and we received a |const| qualifier, then
    8.31 +        // we extend this to array reference as well. This is to sort of mimic
    8.32 +        // SP1 functionality, but also means that you cannot have changeable
    8.33 +        // const pointers in global scope.
    8.34 +        if ((node->quals() & TypeQual_Const) &&
    8.35 +            type->isArray() &&
    8.36 +            link_->scope()->kind() == Scope::GLOBAL)
    8.37 +        {
    8.38 +            if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL)
    8.39 +                return;
    8.40 +            if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL)
    8.41 +                return;
    8.42 +        }
    8.43 +
    8.44          // If the node already has a symbol (meaning it was a global), then
    8.45          // we don't have to do anything more.
    8.46          if (node->sym()) {
    8.47 @@ -817,15 +834,17 @@
    8.48          return true;
    8.49      }
    8.50  
    8.51 -    ArrayType *buildArrayType(Handle<Type> contained, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
    8.52 +    ArrayType *buildArrayType(Handle<Type> contained, TypeQualifiers quals, int dims[MAX_ARRAY_DEPTH], size_t postlevels) {
    8.53          Local<Type> type(zone_, contained);
    8.54 +
    8.55          for (size_t i = postlevels - 1; i < postlevels; i--) {
    8.56              int size = dims[i] > 0
    8.57                         ? dims[i]
    8.58                         : ArrayType::DYNAMIC_ARRAY_SIZE;
    8.59              
    8.60 -            type = zone_->types()->newArray(contained, size);
    8.61 -            if (!type)
    8.62 +            if ((type = zone_->types()->newArray(contained, size)) == NULL)
    8.63 +                return NULL;
    8.64 +            if ((type = zone_->types()->qualify(type, quals)) == NULL)
    8.65                  return NULL;
    8.66          }
    8.67          return ArrayType::cast(type);
    8.68 @@ -834,7 +853,7 @@
    8.69      bool fillFunctionType(Handle<FunctionType> fun, const FunctionSignature &sig) {
    8.70          Local<Type> type(zone_);
    8.71          if (!fun->returnType()) {
    8.72 -            if ((type = bindType(sig.returnType())) == NULL)
    8.73 +            if ((type = bindType(sig.returnType(), TypeQual_None)) == NULL)
    8.74                  return false;
    8.75              fun->setReturnType(type);
    8.76          }
    8.77 @@ -845,10 +864,12 @@
    8.78  
    8.79          for (size_t i = 0; i < sig.parameters()->length(); i++) {
    8.80              Parameter *param = sig.parameters()->at(i);
    8.81 -            if ((type = bindType(param->type())) == NULL)
    8.82 +            if ((type = bindType(param->type(), param->quals())) == NULL)
    8.83                  return false;
    8.84  
    8.85 -            if (type->isArray() || param->dims()) {
    8.86 +            assert(!type->isArray());
    8.87 +
    8.88 +            if (param->dims()) {
    8.89                  int dims[MAX_ARRAY_DEPTH];
    8.90                  int levels = evaluateDimensions(param->pos(), type, param->dims(), dims);
    8.91                  if (levels < 0)
    8.92 @@ -858,7 +879,7 @@
    8.93                  // Unlike variables, we do not infer anything about array
    8.94                  // sizes from its default initializer.
    8.95                  if (param->dims()) {
    8.96 -                    if ((type = buildArrayType(type, dims, param->dims()->length())) == NULL)
    8.97 +                    if ((type = buildArrayType(type, param->quals(), dims, param->dims()->length())) == NULL)
    8.98                          return false;
    8.99                  }
   8.100  
   8.101 @@ -873,9 +894,19 @@
   8.102                      cc_.reportError(param->pos(), Message_ArrayCantBeReference);
   8.103                      return false;
   8.104                  }
   8.105 +                if (param->quals() & TypeQual_Const) {
   8.106 +                    cc_.reportError(param->pos(), Message_CannotConstReference);
   8.107 +                    return false;
   8.108 +                }
   8.109                  if ((type = zone_->types()->getReference(type, false)) == NULL)
   8.110                      return false;
   8.111              }
   8.112 +            if (param->quals() & TypeQual_Const) {
   8.113 +                if (!type->isArray() && !type->isStruct()) {
   8.114 +                    cc_.reportError(param->pos(), Message_InvalidConstOnFormal);
   8.115 +                    return false;
   8.116 +                }
   8.117 +            }
   8.118  
   8.119              if (type->isVoid()) {
   8.120                  cc_.reportError(param->type()->pos(), Message_CannotDeclareVoid);
   8.121 @@ -891,27 +922,31 @@
   8.122          return true;
   8.123      }
   8.124  
   8.125 -    Type *bindType(Expression *expr) {
   8.126 +    Type *bindType(Expression *expr, TypeQualifiers quals) {
   8.127 +        Local<Type> type(zone_);
   8.128 +
   8.129          if (!expr) {
   8.130              // If no type was declared, we return int32.
   8.131 -            return zone_->types()->getPrimitive(PrimitiveType_Int32);
   8.132 -        }
   8.133 -        
   8.134 -        expr->accept(this);
   8.135 +            type = zone_->types()->getPrimitive(PrimitiveType_Int32);
   8.136 +        } else {
   8.137 +            expr->accept(this);
   8.138  
   8.139 -        NameProxy *proxy = expr->asNameProxy();
   8.140 -        assert(proxy);
   8.141 +            NameProxy *proxy = expr->asNameProxy();
   8.142 +            assert(proxy);
   8.143  
   8.144 -        Symbol *sym = proxy->sym();
   8.145 -        if (!sym)
   8.146 -            return NULL;
   8.147 +            Symbol *sym = proxy->sym();
   8.148 +            if (!sym)
   8.149 +                return NULL;
   8.150  
   8.151 -        if (!sym->isType()) {
   8.152 -            cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
   8.153 -            return NULL;
   8.154 +            if (!sym->isType()) {
   8.155 +                cc_.reportError(expr->pos(), Message_IdentifierIsNotAType, sym->name()->chars());
   8.156 +                return NULL;
   8.157 +            }
   8.158 +
   8.159 +            type = sym->type();
   8.160          }
   8.161  
   8.162 -        return sym->type();
   8.163 +        return zone_->types()->qualify(type, quals);
   8.164      }
   8.165  
   8.166    private:
     9.1 --- a/src/compiler/Parser.cpp	Tue Dec 25 18:13:02 2012 -0800
     9.2 +++ b/src/compiler/Parser.cpp	Wed Dec 26 17:14:12 2012 -0800
     9.3 @@ -1044,7 +1044,7 @@
     9.4        case TOK_NEW:
     9.5        {
     9.6          TypeQualifiers quals = (kind == TOK_CONST)
     9.7 -                              ? TypeQual_UnkConst
     9.8 +                              ? TypeQual_Const
     9.9                                : TypeQual_None;
    9.10          scanner_.scan();
    9.11          if ((statement = vars(quals)) == NULL)
    9.12 @@ -1253,7 +1253,10 @@
    9.13  
    9.14      if (!match(TOK_RPAREN)) {
    9.15          while (true) {
    9.16 -            bool isConst = match(TOK_CONST);
    9.17 +            TypeQualifiers quals = TypeQual_None;
    9.18 +            if (match(TOK_CONST))
    9.19 +                quals = TypeQualifiers(quals | TypeQual_Const);
    9.20 +
    9.21              bool ref = match(TOK_AMPERSAND);
    9.22  
    9.23              SourcePosition begin = scanner_.begin();
    9.24 @@ -1263,7 +1266,7 @@
    9.25                  return NULL;
    9.26  
    9.27              if (!name) {
    9.28 -                if (isConst || ref) {
    9.29 +                if ((quals & TypeQual_Const) || ref) {
    9.30                      cc_.reportError(begin, Message_InvalidVarArgs);
    9.31                      return NULL;
    9.32                  }
    9.33 @@ -1289,7 +1292,7 @@
    9.34                      return NULL;
    9.35              }
    9.36  
    9.37 -            Parameter *parameter = new (pool_) Parameter(name, type, ref, isConst, dims, expr, begin);
    9.38 +            Parameter *parameter = new (pool_) Parameter(name, type, ref, quals, dims, expr, begin);
    9.39              if (!parameters->append(parameter))
    9.40                  return NULL;
    9.41  
    9.42 @@ -1335,42 +1338,11 @@
    9.43      return DeclareIntrinsicType(zone, scope, name, primitive);
    9.44  }
    9.45  
    9.46 -bool
    9.47 -Parser::setupIntrinsics()
    9.48 -{
    9.49 -#if 0
    9.50 -    if (!DeclareIntrinsicType(zone_, scope_, "Float", PrimitiveType_Float))
    9.51 -        return false;
    9.52 -    if (!DeclareIntrinsicType(zone_, scope_, "_", PrimitiveType_Int32))
    9.53 -        return false;
    9.54 -    if (!DeclareIntrinsicType(zone_, scope_, "bool", PrimitiveType_Bool))
    9.55 -        return false;
    9.56 -    if (!DeclareIntrinsicType(zone_, scope_, "String", PrimitiveType_Char))
    9.57 -        return false;
    9.58 -
    9.59 -    Local<Type> unchecked(zone_, zone_->types()->getUnchecked());
    9.60 -    if (!DeclareIntrinsicType(zone_, scope_, "unchecked", unchecked))
    9.61 -        return false;
    9.62 -
    9.63 -    Local<Type> voidType(zone_, zone_->types()->getVoid());
    9.64 -    if (!DeclareIntrinsicType(zone_, scope_, "void", voidType))
    9.65 -        return false;
    9.66 -
    9.67 -    Local<Type> intType(zone_, zone_->types()->getPrimitive(PrimitiveType_Int32));
    9.68 -    if (!DeclareIntrinsicType(zone_, scope_, "int", intType))
    9.69 -        return false;
    9.70 -#endif
    9.71 -    return true;
    9.72 -}
    9.73 -
    9.74  ParseTree *
    9.75  Parser::parse()
    9.76  {
    9.77      StatementList *statements = new (pool_) StatementList();
    9.78  
    9.79 -    if (!setupIntrinsics())
    9.80 -        return NULL;
    9.81 -
    9.82      for (;;) {
    9.83          Statement *statement = NULL;
    9.84  
    9.85 @@ -1412,7 +1384,7 @@
    9.86              if (kind != TOK_LABEL)
    9.87                  scanner_.scan();
    9.88              if (kind == TOK_PUBLIC && peek(TOK_CONST)) {
    9.89 -                if ((statement = var(TypeQual_UnkConst)) == NULL)
    9.90 +                if ((statement = var(TypeQual_Const)) == NULL)
    9.91                      return NULL;
    9.92                  if (!matchSemicolon())
    9.93                      return NULL;
    9.94 @@ -1428,7 +1400,7 @@
    9.95            case TOK_CONST:
    9.96            case TOK_NEW:
    9.97            {
    9.98 -            TypeQualifiers quals = (kind == TOK_NEW) ? TypeQual_UnkConst : TypeQual_None;
    9.99 +            TypeQualifiers quals = (kind == TOK_CONST) ? TypeQual_Const : TypeQual_None;
   9.100              // Note: at global scope, we don't accept comma-delimited
   9.101              // declarations yet, to see if we can get away with forcing
   9.102              // a nicer top-level style.
    10.1 --- a/src/compiler/Parser.h	Tue Dec 25 18:13:02 2012 -0800
    10.2 +++ b/src/compiler/Parser.h	Wed Dec 26 17:14:12 2012 -0800
    10.3 @@ -95,8 +95,6 @@
    10.4      Statement *returnStatement();
    10.5      ImportStatement *import();
    10.6  
    10.7 -    bool setupIntrinsics();
    10.8 -
    10.9    public:
   10.10      Parser(Zone *zone, CompileContext &cc, const char *stream, size_t length);
   10.11  
    11.1 --- a/src/compiler/SemanticAnalysis.cpp	Tue Dec 25 18:13:02 2012 -0800
    11.2 +++ b/src/compiler/SemanticAnalysis.cpp	Wed Dec 26 17:14:12 2012 -0800
    11.3 @@ -731,6 +731,11 @@
    11.4      if (!lval)
    11.5          return;
    11.6  
    11.7 +    if (lval->type()->quals() & TypeQual_Const) {
    11.8 +        cc_.reportError(node->pos(), Message_CannotModifyConst);
    11.9 +        return;
   11.10 +    }
   11.11 +
   11.12      HIR *hir = eval(node->expression());
   11.13      if ((hir = coerce(hir, lval->type(), Coerce_Assign)) == NULL)
   11.14          return;
   11.15 @@ -838,7 +843,7 @@
   11.16  HIR *
   11.17  SemanticAnalysis::typeCheckArray(const SourcePosition &pos,
   11.18                                   HIR *from,
   11.19 -                                 Handle<Type> argActual,
   11.20 +                                 Handle<ArrayType> argActual,
   11.21                                   CoercionKind kind)
   11.22  {
   11.23      Local<Type> argGiven(zone_, from->type());
   11.24 @@ -888,7 +893,7 @@
   11.25          // We treat declaration separately from assignment, since for
   11.26          // declaration we can just immediately use the cloned version.
   11.27          bool shouldDuplicate = true;
   11.28 -        if (0 /*actual->isConst() :TODO */ ||
   11.29 +        if ((actual->quals() & TypeQual_Const) ||
   11.30              (actual->isFixedLength() && kind == Coerce_Assign))
   11.31          {
   11.32              shouldDuplicate = false;
   11.33 @@ -959,11 +964,18 @@
   11.34          actual = ArrayType::cast(actual->contained());
   11.35      }
   11.36  
   11.37 +    bool givenConst = !!(given->contained()->quals() & TypeQual_Const);
   11.38 +    bool actualConst = !!(actual->contained()->quals() & TypeQual_Const);
   11.39 +
   11.40      // These arrays must contain the same innermost type.
   11.41 -    if (given->contained() != actual->contained()) {
   11.42 +    if (given->contained()->unqualified() != actual->contained()->unqualified() ||
   11.43 +        (givenConst && !actualConst))
   11.44 +    {
   11.45 +        char aname[255];
   11.46 +        char gname[255];
   11.47          cc_.reportError(pos, Message_TypeMismatch,
   11.48 -                        GetTypeName(actual->contained()),
   11.49 -                        GetTypeName(given->contained()));
   11.50 +                        GetTypeName(argActual, aname, sizeof(aname)),
   11.51 +                        GetTypeName(argGiven, gname, sizeof(gname)));
   11.52          return false;
   11.53      }
   11.54  
   11.55 @@ -973,9 +985,11 @@
   11.56  HIR *
   11.57  SemanticAnalysis::typeFailure(const SourcePosition &pos, Handle<Type> from, Handle<Type> to)
   11.58  {
   11.59 +    char fname[255];
   11.60 +    char tname[255];
   11.61      cc_.reportError(pos, Message_InvalidCoercion,
   11.62 -                    GetTypeName(from),
   11.63 -                    GetTypeName(to));
   11.64 +                    GetTypeName(from, fname, sizeof(fname)),
   11.65 +                    GetTypeName(to, tname, sizeof(tname)));
   11.66      return NULL;
   11.67  }
   11.68  
   11.69 @@ -992,8 +1006,10 @@
   11.70      if (to->isEnum() && *from != to)
   11.71          return typeFailure(hir->node()->pos(), from, to);
   11.72      
   11.73 -    if (to->isArray())
   11.74 -        return typeCheckArray(SourcePosition(), hir, to, kind);
   11.75 +    if (to->isArray()) {
   11.76 +        Local<ArrayType> atype(zone_, ArrayType::cast(to));
   11.77 +        return typeCheckArray(hir->node()->pos(), hir, atype, kind);
   11.78 +    }
   11.79      
   11.80      return hir;
   11.81  }
    12.1 --- a/src/compiler/SemanticAnalysis.h	Tue Dec 25 18:13:02 2012 -0800
    12.2 +++ b/src/compiler/SemanticAnalysis.h	Wed Dec 26 17:14:12 2012 -0800
    12.3 @@ -183,7 +183,7 @@
    12.4  
    12.5      HIR *typeCheckArray(const SourcePosition &pos,
    12.6                          HIR *from,
    12.7 -                        Handle<Type> argActual,
    12.8 +                        Handle<ArrayType> argActual,
    12.9                          CoercionKind kind);
   12.10  
   12.11    private:
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/tests/basic/const-arg-1.err	Wed Dec 26 17:14:12 2012 -0800
    13.3 @@ -0,0 +1,1 @@
    13.4 +  line 3, col 12: cannot change constant value or structure
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/tests/basic/const-arg-1.sp	Wed Dec 26 17:14:12 2012 -0800
    14.3 @@ -0,0 +1,4 @@
    14.4 +f(const char:text[])
    14.5 +{
    14.6 +    text[0] = 0;
    14.7 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/tests/basic/const-arg-2.err	Wed Dec 26 17:14:12 2012 -0800
    15.3 @@ -0,0 +1,1 @@
    15.4 +  line 1, col 7: const parameters must be arrays or structs
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tests/basic/const-arg-2.sp	Wed Dec 26 17:14:12 2012 -0800
    16.3 @@ -0,0 +1,3 @@
    16.4 +f(const a)
    16.5 +{
    16.6 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tests/basic/const-arg-3.err	Wed Dec 26 17:14:12 2012 -0800
    17.3 @@ -0,0 +1,1 @@
    17.4 +  line 1, col 7: constant outparams are not allowed
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tests/basic/const-arg-3.sp	Wed Dec 26 17:14:12 2012 -0800
    18.3 @@ -0,0 +1,3 @@
    18.4 +f(const &a)
    18.5 +{
    18.6 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tests/basic/const-arg-4.err	Wed Dec 26 17:14:12 2012 -0800
    19.3 @@ -0,0 +1,1 @@
    19.4 +  line 8, col 7: type mismatch (expected 'char[]', got 'const char[]')
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tests/basic/const-arg-4.sp	Wed Dec 26 17:14:12 2012 -0800
    20.3 @@ -0,0 +1,9 @@
    20.4 +f(char:text[])
    20.5 +{
    20.6 +}
    20.7 +
    20.8 +main()
    20.9 +{
   20.10 +    const char:text[] = "";
   20.11 +    f(text);
   20.12 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tests/basic/const-arg-5.out	Wed Dec 26 17:14:12 2012 -0800
    21.3 @@ -0,0 +1,1 @@
    21.4 +9798
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tests/basic/const-arg-5.sp	Wed Dec 26 17:14:12 2012 -0800
    22.3 @@ -0,0 +1,14 @@
    22.4 +native PrintNum(num);
    22.5 +
    22.6 +
    22.7 +f(const char:text[])
    22.8 +{
    22.9 +    PrintNum(text[0]);
   22.10 +}
   22.11 +
   22.12 +public main()
   22.13 +{
   22.14 +    new char:q[20] = "blub";
   22.15 +    f("asdf");
   22.16 +    f(q);
   22.17 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/tests/basic/const-global-1.err	Wed Dec 26 17:14:12 2012 -0800
    23.3 @@ -0,0 +1,1 @@
    23.4 +  line 4, col 7: cannot change constant value or structure
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/tests/basic/const-global-1.sp	Wed Dec 26 17:14:12 2012 -0800
    24.3 @@ -0,0 +1,5 @@
    24.4 +const a = 5;
    24.5 +public main()
    24.6 +{
    24.7 +    a = 10;
    24.8 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/tests/basic/const-global-2.err	Wed Dec 26 17:14:12 2012 -0800
    25.3 @@ -0,0 +1,1 @@
    25.4 +  line 5, col 12: cannot change constant value or structure
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/tests/basic/const-global-2.sp	Wed Dec 26 17:14:12 2012 -0800
    26.3 @@ -0,0 +1,6 @@
    26.4 +const char:text[] = "Adsf";
    26.5 +
    26.6 +public main()
    26.7 +{
    26.8 +    text[0] = 0;
    26.9 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/tests/basic/const-global-3.err	Wed Dec 26 17:14:12 2012 -0800
    27.3 @@ -0,0 +1,1 @@
    27.4 +  line 4, col 10: cannot change constant value or structure
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/tests/basic/const-global-3.sp	Wed Dec 26 17:14:12 2012 -0800
    28.3 @@ -0,0 +1,5 @@
    28.4 +const char:text[] = "";
    28.5 +public main()
    28.6 +{
    28.7 +    text = "a";
    28.8 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/tests/basic/const-local-1.err	Wed Dec 26 17:14:12 2012 -0800
    29.3 @@ -0,0 +1,1 @@
    29.4 +  line 4, col 7: cannot change constant value or structure
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/tests/basic/const-local-1.sp	Wed Dec 26 17:14:12 2012 -0800
    30.3 @@ -0,0 +1,6 @@
    30.4 +public main()
    30.5 +{
    30.6 +    const a = 5;
    30.7 +    a = 10;
    30.8 +}
    30.9 +
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/tests/basic/const-local-2.err	Wed Dec 26 17:14:12 2012 -0800
    31.3 @@ -0,0 +1,1 @@
    31.4 +  line 4, col 12: cannot change constant value or structure
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/tests/basic/const-local-2.sp	Wed Dec 26 17:14:12 2012 -0800
    32.3 @@ -0,0 +1,5 @@
    32.4 +public main()
    32.5 +{
    32.6 +    const char:text[] = "hello, gabe newell!";
    32.7 +    text[5] = 10;
    32.8 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/tests/basic/const-local-3.out	Wed Dec 26 17:14:12 2012 -0800
    33.3 @@ -0,0 +1,1 @@
    33.4 +107
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/tests/basic/const-local-3.sp	Wed Dec 26 17:14:12 2012 -0800
    34.3 @@ -0,0 +1,9 @@
    34.4 +native PrintNum(num);
    34.5 +
    34.6 +public main()
    34.7 +{
    34.8 +    const char:a[] = "what";
    34.9 +    const char:b[] = "k";
   34.10 +    a = b;
   34.11 +    PrintNum(a[0]);
   34.12 +}