# HG changeset patch # User David Anderson # Date 1359336870 28800 # Node ID 219b49bf4a03fb50e6e8a743c4bd1bfc4768caec # Parent 05de34f712fe4e281521d3801d19e9ef6fc66966 Add support for importing enum types and enum values (as constexprs). diff -r 05de34f712fe -r 219b49bf4a03 src/ObjectVisitor.h --- a/src/ObjectVisitor.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/ObjectVisitor.h Sun Jan 27 17:34:30 2013 -0800 @@ -54,6 +54,7 @@ size_t iterateEnumType(Object *obj) { visitField(obj, EnumType::offsetOfName()); + visitField(obj, EnumType::offsetOfFields()); return sizeof(EnumType); } diff -r 05de34f712fe -r 219b49bf4a03 src/RootScopes.h --- a/src/RootScopes.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/RootScopes.h Sun Jan 27 17:34:30 2013 -0800 @@ -2,19 +2,19 @@ * * Copyright (C) 2012 David Anderson * - * This file is part of JITCraft. + * This file is part of SourcePawn. * - * JITCraft is free software: you can redistribute it and/or modify it under + * SourcePawn is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * - * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with - * JITCraft. If not, see http://www.gnu.org/licenses/. + * SourcePawn. If not, see http://www.gnu.org/licenses/. */ #ifndef _include_jc_root_scopes_h_ #define _include_jc_root_scopes_h_ diff -r 05de34f712fe -r 219b49bf4a03 src/TypeManager.cpp --- a/src/TypeManager.cpp Sat Jan 12 16:35:26 2013 -0800 +++ b/src/TypeManager.cpp Sun Jan 27 17:34:30 2013 -0800 @@ -52,6 +52,10 @@ if (!importableType_) return false; + typeType_ = Type::NewType(zone_); + if (!typeType_) + return false; + if ((primitiveTypes_[PrimitiveType_Int32] = Type::NewPrimitive(zone_, PrimitiveType_Int32)) == NULL) return false; if ((primitiveTypes_[PrimitiveType_Float] = Type::NewPrimitive(zone_, PrimitiveType_Float)) == NULL) @@ -141,6 +145,7 @@ visitor->visit(uncheckedType_.address()); visitor->visit(stringType_.address()); visitor->visit(importableType_.address()); + visitor->visit(typeType_.address()); for (unsigned i = 0; i < PrimitiveTypes_Total; i++) { visitor->visit(primitiveTypes_[i].address()); visitor->visit(referenceTypes_[i].address()); diff -r 05de34f712fe -r 219b49bf4a03 src/TypeManager.h --- a/src/TypeManager.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/TypeManager.h Sun Jan 27 17:34:30 2013 -0800 @@ -82,6 +82,9 @@ Type *getImportable() { return importableType_; } + Type *getType() { + return typeType_; + } ReferenceType *getReference(Handle type, bool isConst); ArrayType *newArray(Handle contained, int elements); ArrayType *newExternalArray(Handle contained); @@ -100,6 +103,7 @@ Unbarriered stringType_; Unbarriered uncheckedType_; Unbarriered importableType_; + Unbarriered typeType_; Unbarriered primitiveTypes_[PrimitiveTypes_Total]; Unbarriered referenceTypes_[PrimitiveTypes_Total]; diff -r 05de34f712fe -r 219b49bf4a03 src/Types.cpp --- a/src/Types.cpp Sat Jan 12 16:35:26 2013 -0800 +++ b/src/Types.cpp Sun Jan 27 17:34:30 2013 -0800 @@ -78,6 +78,17 @@ } Type * +Type::NewType(Zone *zone) +{ + Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); + if (!type) + return NULL; + + type->init(TYPE); + return type; +} + +Type * Type::NewPrimitive(Zone *zone, PrimitiveType prim) { Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); @@ -167,6 +178,7 @@ type->init(ENUM); type->name_ = name; + type->fields_ = NULL; return type; } diff -r 05de34f712fe -r 219b49bf4a03 src/Types.h --- a/src/Types.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/Types.h Sun Jan 27 17:34:30 2013 -0800 @@ -65,7 +65,11 @@ TypeQual_None = 0, // Values of this type cannot be modified. - TypeQual_Const = (1 << 2) + TypeQual_Const = (1 << 0), + + // Values of this type can be treated as constant expressions. This allows + // us to export compile-time constants from modules. + TypeQual_ConstExpr = (1 << 1) }; class Type : public Object @@ -115,7 +119,10 @@ // Importable types are mainly used during the compilation process // to distinguish between normal names and static imports. - IMPORTABLE + IMPORTABLE, + + // The type of types. + TYPE }; void init(Kind kind, Type *root = NULL); @@ -128,6 +135,7 @@ public: static Type *NewVoid(Zone *zone); static Type *NewUnchecked(Zone *zone); + static Type *NewType(Zone *zone); static Type *NewPrimitive(Zone *zone, PrimitiveType type); static Type *NewString(Zone *zone); static Type *NewQualified(Zone *zone, TypeQualifiers qual, Handle type); @@ -210,6 +218,9 @@ bool isEnum() { return kind() == ENUM; } + bool isType() { + return kind() == TYPE; + } bool hasTypeQualifiers() { return kind_ == QUALTYPE; } @@ -252,6 +263,9 @@ static inline size_t offsetOfName() { return OFFSETOF(EnumType, name_); } + static inline size_t offsetOfFields() { + return OFFSETOF(EnumType, fields_); + } // End GC Descriptor. static EnumType *cast(Object *obj) { @@ -261,6 +275,7 @@ private: Barriered name_; + Barriered fields_; }; class ReferenceType : public Type diff -r 05de34f712fe -r 219b49bf4a03 src/compiler/AST.h --- a/src/compiler/AST.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/compiler/AST.h Sun Jan 27 17:34:30 2013 -0800 @@ -873,11 +873,13 @@ ScopedRoot name; Expression *expr; SourcePosition pos; + ConstantSymbol *sym; Entry(Handle name, Expression *expr, const SourcePosition &pos) : name(name), expr(expr), - pos(pos) + pos(pos), + sym(NULL) { } }; @@ -885,17 +887,18 @@ typedef PoolList EntryList; public: - EnumStatement(const SourcePosition &pos, Handle name, EntryList *entries) + EnumStatement(const SourcePosition &pos, TokenKind visibility, Handle name, EntryList *entries) : Statement(pos), name_(name), sym_(NULL), - entries_(entries) + entries_(entries), + visibility_(visibility) { } DECLARE_NODE(EnumStatement); - String *name() const { + Handle name() const { return name_; } EntryList *entries() const { @@ -908,9 +911,13 @@ TypeSymbol *sym() const { return sym_; } + TokenKind visibility() const { + return visibility_; + } private: EntryList *entries_; + TokenKind visibility_; }; class IncDecExpression : public Expression diff -r 05de34f712fe -r 219b49bf4a03 src/compiler/CompileContext.h --- a/src/compiler/CompileContext.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/compiler/CompileContext.h Sun Jan 27 17:34:30 2013 -0800 @@ -62,7 +62,7 @@ importScope_(NULL), globalScope_(NULL), module_(module), - oom_(false), + enoughMemory_(true), dependencyFailed_(false) { } @@ -83,7 +83,7 @@ } bool failed() const { return errors_.length() || - oom_ || + !enoughMemory_ || dependencyFailed_; } void setImportScope(ImportScope *scope) { @@ -108,17 +108,17 @@ dependencyFailed_ = true; } void setOutOfMemory() { - oom_ = true; + enoughMemory_ = false; } void appendError(const char *report, unsigned line, unsigned col) { - oom_ |= errors_.append(CompileError(line, col, report)); + enoughMemory_ |= errors_.append(CompileError(line, col, report)); } const Vector *errors() { return &errors_; } private: - bool oom_; + bool enoughMemory_; bool dependencyFailed_; Vector errors_; }; diff -r 05de34f712fe -r 219b49bf4a03 src/compiler/NameBinding.cpp --- a/src/compiler/NameBinding.cpp Sat Jan 12 16:35:26 2013 -0800 +++ b/src/compiler/NameBinding.cpp Sun Jan 27 17:34:30 2013 -0800 @@ -137,12 +137,14 @@ return; } - bool declareSystemType(ImportScope *scope, const char *name, Handle type) { + bool declareSystemType(ImportScope *scope, const char *name, Handle effective) { Local tag(zone_, zone_->makeSymbol(name)); if (!tag) return false; - TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type); + Local type(zone_, zone_->types()->getType()); + + TypeSymbol *sym = new (pool_) TypeSymbol(scope, tag, type, effective); return scope->addSymbol(sym); } @@ -214,7 +216,8 @@ return; if (name) { - TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, type); + Local symType(zone_, zone_->types()->getType()); + TypeSymbol *sym = new (pool_) TypeSymbol(scope, name, symType, type); if (!registerName(scope, sym)) return; @@ -224,6 +227,10 @@ } } + // We want each field of the expression to qualify as a constant expression. + if ((type = zone_->types()->qualify(type, TypeQual_ConstExpr)) == NULL) + return; + int value = 0; for (size_t i = 0; i < node->entries()->length(); i++) { EnumStatement::Entry &entry = node->entries()->at(i); @@ -237,7 +244,7 @@ assert(box.type() == PrimitiveType_Int32); value = box.toInt(); } - + ConstantSymbol *sym = new (pool_) ConstantSymbol(scope, entry.name, entry.pos, type, box); if (!registerName(scope, sym)) return; @@ -246,6 +253,7 @@ return; } + entry.sym = sym; value++; } } @@ -756,7 +764,7 @@ return NULL; } - type = sym->type(); + type = sym->toType()->effective(); } return zone_->types()->qualify(type, quals); @@ -771,6 +779,18 @@ class GlobalBuilder : public NameBinderBase { + typedef ScopedRoot ScopedDescriptor; + struct PrimitiveFill { + ScopedDescriptor *desc; + BoxedPrimitive prim; + + PrimitiveFill(ScopedDescriptor *desc, BoxedPrimitive prim) + : desc(desc), + prim(prim) + { + } + }; + public: GlobalBuilder(Zone *zone, CompileContext &cc, TranslationUnit *unit) : NameBinderBase(zone, cc, unit), @@ -788,6 +808,17 @@ stmt->accept(this); } + Local globals(zone_, createGlobals()); + if (!globals) + return NULL; + + populate(globals); + + return globals; + } + + private: + Struct *createGlobals() { Local descs(zone_, FixedArray::New(zone_, descriptors_.length(), Heap::Tenure_Old)); if (!descs) return NULL; @@ -804,7 +835,47 @@ return Struct::New(zone_, map, Heap::Tenure_Old); } + void populate(Handle globals) { + // This is a huge hack, but it's probably better than a full extra + // pass. The problem is that until we have all the descriptors, we + // can't start setting constexprs in the struct, and we need to set + // them now so they're available during full semantic analysis. To + // work around this, we build up the list of values we need to set + // as we build up descriptors, and then populate the global struct + // with this set. + // + // Note, this code is also kind of dead until we support linking. We + // handle constexprs explicitly in importFrom(), by sniffing out the + // symbol type. That code will go away later. + for (size_t i = 0; i < primitiveFills_.length(); i++) { + const PrimitiveFill &fill = primitiveFills_[i]; + assert(fill.prim.type() == PrimitiveType_Int32); + globals->set(*fill.desc, fill.prim.toInt()); + } + } + + public: void visitEnumStatement(EnumStatement *stmt) { + if (stmt->visibility() != TOK_PUBLIC || !stmt->name()) + return; + + Local type(zone_, zone_->types()->getType()); + Descriptor *desc = Descriptor::New(zone_, stmt->name(), type, Descriptor::Public); + if (!desc) + return; + if (!descriptors_.append(new (pool_) ScopedRoot(desc))) + return; + + for (size_t i = 0; i < stmt->entries()->length(); i++) { + EnumStatement::Entry &e = stmt->entries()->at(i); + ScopedDescriptor *desc = new (pool_) ScopedDescriptor(Descriptor::New(zone_, e.name, e.sym->type(), Descriptor::Public)); + if (!desc || !descriptors_.append(desc)) + return; + + // Save the value so we can export it immediately. + if (!primitiveFills_.append(PrimitiveFill(desc, e.sym->value()))) + return; + } } void visitNameProxy(NameProxy *proxy) { @@ -917,11 +988,33 @@ return false; } - ImplicitSymbol *sym = new (pool_) ImplicitSymbol(unit_->importScope(), - import->name(), - node->pos(), - import->type(), - node->importIndex()); + Symbol *sym; + if (import->isType()) { + // Fuck it, make a TypeSymbol instead of an ImplicitSymbol. This + // makes bindType() much simpler. We may run into problems + // implementing linking, but it seems unlikely, as long as we are + // exporting Types in module structs. + Local type(zone_, zone_->types()->getType()); + sym = new (pool_) TypeSymbol(unit_->importScope(), + import->name(), + type, + import->toType()->effective()); + } else if (import->isConstant()) { + // Same deal. No reason to lookup in the module globals if we + // already have a symbol. + sym = new (pool_) ConstantSymbol(unit_->importScope(), + import->name(), + node->pos(), + import->type(), + import->toConstant()->value()); + } else { + sym = new (pool_) ImplicitSymbol(unit_->importScope(), + import->name(), + node->pos(), + import->type(), + node->importIndex()); + } + if (!unit_->importScope()->addSymbol(sym)) return false; @@ -963,6 +1056,7 @@ StructureBufferBuilder builder_; Vector *> descriptors_; GlobalScope *globalScope_; + Vector primitiveFills_; }; class NameBinder : public NameBinderBase diff -r 05de34f712fe -r 219b49bf4a03 src/compiler/Parser.cpp --- a/src/compiler/Parser.cpp Sat Jan 12 16:35:26 2013 -0800 +++ b/src/compiler/Parser.cpp Sun Jan 27 17:34:30 2013 -0800 @@ -1106,7 +1106,7 @@ break; case TOK_ENUM: - if ((statement = enum_()) == NULL) + if ((statement = enum_(TOK_NONE)) == NULL) return NULL; break; @@ -1189,7 +1189,7 @@ } Statement * -Parser::enum_() +Parser::enum_(TokenKind kind) { // enum ::= "enum" name? { enum_members? } // enum_members ::= enum_member ","? | @@ -1229,7 +1229,7 @@ if (!expect(TOK_RBRACE)) return NULL; - return new (pool_) EnumStatement(pos, name, entries); + return new (pool_) EnumStatement(pos, kind, name, entries); } template @@ -1460,6 +1460,11 @@ return NULL; if (!matchSemicolon()) return NULL; + } else if (kind == TOK_PUBLIC && peek(TOK_ENUM)) { + if ((statement = enum_(kind)) == NULL) + return NULL; + if (!matchSemicolon()) + return NULL; } else { if ((statement = function(kind)) == NULL) return NULL; @@ -1485,7 +1490,7 @@ } case TOK_ENUM: - if ((statement = enum_()) == NULL) + if ((statement = enum_(TOK_NONE)) == NULL) return NULL; if (!matchSemicolon()) return NULL; diff -r 05de34f712fe -r 219b49bf4a03 src/compiler/Parser.h --- a/src/compiler/Parser.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/compiler/Parser.h Sun Jan 27 17:34:30 2013 -0800 @@ -82,7 +82,7 @@ Statement *switch_(); Statement *struct_(); - Statement *enum_(); + Statement *enum_(TokenKind kind); Statement *if_(); Statement *block(); Statement *function(TokenKind tok); diff -r 05de34f712fe -r 219b49bf4a03 src/compiler/SemanticAnalysis.cpp --- a/src/compiler/SemanticAnalysis.cpp Sat Jan 12 16:35:26 2013 -0800 +++ b/src/compiler/SemanticAnalysis.cpp Sun Jan 27 17:34:30 2013 -0800 @@ -1103,7 +1103,7 @@ if (from->isInt32() && to->isBool()) return new (pool_) HConvert(hir->node(), to, OP_CVT_I2B, hir); - if (to->isEnum() && *from != to) + if (to->isEnum() && from->unqualified() != to->unqualified()) return typeFailure(hir->node()->pos(), from, to); if (to->isArray()) { @@ -1231,10 +1231,10 @@ return; } - if (!IsValidUncheckedType(sym->type())) { + if (!IsValidUncheckedType(sym->effective())) { char name[255]; cc_.reportError(node->pos(), Message_InvalidUncheckedCastTo, - GetTypeName(hir->type(), name, sizeof(name))); + GetTypeName(sym->type(), name, sizeof(name))); return; } if (!IsValidUncheckedType(hir->type())) { @@ -1244,7 +1244,7 @@ return; } - hir_ = new (pool_) HUnary(node, hir->type(), TOK_LABEL, hir); + hir_ = new (pool_) HUnary(node, sym->effective(), TOK_LABEL, hir); break; } } diff -r 05de34f712fe -r 219b49bf4a03 src/compiler/Symbols.h --- a/src/compiler/Symbols.h Sat Jan 12 16:35:26 2013 -0800 +++ b/src/compiler/Symbols.h Sun Jan 27 17:34:30 2013 -0800 @@ -160,8 +160,9 @@ class TypeSymbol : public Symbol { public: - TypeSymbol(Scope *scope, Handle name, Handle type) - : Symbol(scope, name, SourcePosition()) + TypeSymbol(Scope *scope, Handle name, Handle type, Handle effective) + : Symbol(scope, name, SourcePosition()), + effective_(effective) { type_ = type; } @@ -169,6 +170,12 @@ Kind kind() const { return kType; } + Handle effective() { + return effective_; + } + + private: + ScopedRoot effective_; }; class FunctionSymbol : public Symbol diff -r 05de34f712fe -r 219b49bf4a03 tests/basic/import_enum_a.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/import_enum_a.out Sun Jan 27 17:34:30 2013 -0800 @@ -0,0 +1,1 @@ +2 diff -r 05de34f712fe -r 219b49bf4a03 tests/basic/import_enum_a.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/import_enum_a.sp Sun Jan 27 17:34:30 2013 -0800 @@ -0,0 +1,10 @@ +import shell; +import import_enum_b.*; + +public main() +{ + new Crab:crab = TotalCrab; + + shell.PrintNum(crab); +} + diff -r 05de34f712fe -r 219b49bf4a03 tests/basic/import_enum_b.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/import_enum_b.sp Sun Jan 27 17:34:30 2013 -0800 @@ -0,0 +1,7 @@ +public enum Crab +{ + A, + B, + TotalCrab +}; +