# HG changeset patch # User David Anderson # Date 1357509141 28800 # Node ID 3c184218462dc6705624e444232161e95f20f133 # Parent b3cf7e052ddff321c60b18e80fd4d73c5f2dc489 Initial implementation of module imports. diff -r b3cf7e052ddf -r 3c184218462d src/Array.cpp --- a/src/Array.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Array.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -50,27 +50,6 @@ return map; } -ArrayMap * -ArrayMap::Attach(Zone *zone, Handle type) -{ - if (type->newMap()) - return ArrayMap::cast(type->newMap()); - - Local map(zone, ArrayMap::New(zone, type)); - if (!map) - return NULL; - - // Ensure the inner type has an ArrayMap if needed. - if (type->contained()->isArray()) { - Local contained(zone, ArrayType::cast(type->contained())); - if (!ArrayMap::Attach(zone, contained)) - return NULL; - } - - type->setNewMap(map); - return map; -} - Array * Array::NewRaw(Zone *zone, Handle map, unsigned nelements, Heap::Tenure tenure) { diff -r b3cf7e052ddf -r 3c184218462d src/Array.h --- a/src/Array.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Array.h Sun Jan 06 13:52:21 2013 -0800 @@ -166,12 +166,7 @@ Barriered type_; public: - // The way array maps work is kind of clownshoes. In the future, these - // should be created immediately (or lazily) on the Type directly, and not - // manually created via ::Attach. :TODO: do this when we begin caching - // array types. static ArrayMap *New(Zone *zone, Handle type); - static ArrayMap *Attach(Zone *zone, Handle type); // DependentArray maps are never attached, and are just free-floating, // rooted ultimately by the bytecode. A :TODO: that we might need to diff -r b3cf7e052ddf -r 3c184218462d src/Handles.h --- a/src/Handles.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Handles.h Sun Jan 06 13:52:21 2013 -0800 @@ -170,7 +170,7 @@ // A ScopedRoot is a special kind of handle for storing references on the // heap in bulk. template -class ScopedRoot +class ScopedRoot : public PoolObject { T **thingp_; diff -r b3cf7e052ddf -r 3c184218462d src/Heap-inl.h --- a/src/Heap-inl.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Heap-inl.h Sun Jan 06 13:52:21 2013 -0800 @@ -75,7 +75,7 @@ size_t actualBytes = Align(bytes, kObjectAlignment); // All objects must be at least two words. - assert(actualBytes >= sizeof(Object *) * 2); + assert(actualBytes >= kMinObjectSize); Address address = newObject(actualBytes, age); if (!address) { diff -r b3cf7e052ddf -r 3c184218462d src/Interpreter.cpp --- a/src/Interpreter.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Interpreter.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -898,7 +898,11 @@ case OP_GETFIELD: { - Struct *obj = Struct::cast(top.sp[-1].obj); + Struct *obj; + if (top.sp[-1].obj->is(MapKind_Module)) + obj = Module::cast(top.sp[-1].obj)->globals(); + else + obj = Struct::cast(top.sp[-1].obj); GetField(obj, READ_UINT32(top.pc), &top.sp[-1]); break; } @@ -1007,6 +1011,15 @@ break; } +case OP_IMPORT: +{ + unsigned index = READ_UINT32(top.pc); + + top.sp++; + top.sp[-1].obj = top.fp->code()->module()->getImportAt(index); + break; +} + default: assert(false); return false; diff -r b3cf7e052ddf -r 3c184218462d src/Messages.tbl --- a/src/Messages.tbl Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Messages.tbl Sun Jan 06 13:52:21 2013 -0800 @@ -85,4 +85,9 @@ MSG(InvalidUncheckedCastFrom, TypeError, "cannot perform an unchecked cast on type '%s'") MSG(InvalidUncheckedCastTo, TypeError, "cannot perform an unchecked cast to type '%s'") MSG(InvalidUnaryType, TypeError, "operator %s not defined for type '%s'") -MSG(CannotImportPath, SyntaxError, "could not find module or import '%s'") \ No newline at end of file +MSG(CannotImportPath, SyntaxError, "could not find module or import '%s'") +MSG(DuplicateImport, SyntaxError, "duplicate import name '%s'") +MSG(InvalidFieldExpression, TypeError, "type '%s' does not have any fields") +MSG(PackageDoesNotHaveMember, TypeError, "package does not have member '%s' (check imports)") +MSG(ImportWasNeverImported, TypeError, "'%s' was never imported") +MSG(FieldNotFound, TypeError, "field '%s' not found") \ No newline at end of file diff -r b3cf7e052ddf -r 3c184218462d src/Modules.h --- a/src/Modules.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Modules.h Sun Jan 06 13:52:21 2013 -0800 @@ -21,6 +21,7 @@ #include "Heap.h" #include "Code.h" #include "Functions.h" +#include "FixedArray.h" #include "Packages.h" namespace ke { @@ -36,6 +37,7 @@ Barriered globals_; void *nativeIdentity_; TranslationUnit *unit_; + Barriered imports_; public: static Module *New(Zone *zone, Handle package, Handle path, Handle name); @@ -63,6 +65,18 @@ unit_ = unit; } + unsigned imports() { + return imports_ ? imports_->length() / 2 : 0; + } + Importable *getImportAt(unsigned index) { + return Importable::cast(imports_->at(index * 2)); + } + FixedArray *importPathAt(unsigned index) { + return FixedArray::cast(imports_->at(index * 2 + 1)); + } + void setImports(Handle imports) { + imports_ = imports; + } void setCode(Handle code) { code_ = code; } @@ -77,6 +91,9 @@ static inline size_t offsetOfGlobals() { return OFFSETOF(Module, globals_); } + static inline size_t offsetOfImports() { + return OFFSETOF(Module, imports_); + } // End GC Descriptor. static inline Module *cast(Object *obj) { diff -r b3cf7e052ddf -r 3c184218462d src/ObjectVisitor.h --- a/src/ObjectVisitor.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/ObjectVisitor.h Sun Jan 06 13:52:21 2013 -0800 @@ -125,6 +125,7 @@ visitImportable(obj); visitField(obj, Module::offsetOfGlobals()); visitField(obj, Module::offsetOfCode()); + visitField(obj, Module::offsetOfImports()); return sizeof(Module); } @@ -213,7 +214,7 @@ unsigned noffsets = map->traceOffsetCount(); for (unsigned i = 0; i < noffsets; i++) visitField(obj, Struct::offsetOfSlotOffset(offsets[i])); - return obj->objSize(); + return Struct::SizeFor(map); } size_t iterateList(Object *obj) { @@ -388,7 +389,7 @@ return sizeof(List); case MapKind_Struct: - return Struct::cast(obj)->objSize(); + return Struct::SizeFor(StructMap::cast(map)); case MapKind_EnvironmentSlotDescriptorArray: return EnvironmentSlotDescriptorArray::cast(obj)->objSize(); diff -r b3cf7e052ddf -r 3c184218462d src/Opcodes.cpp --- a/src/Opcodes.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Opcodes.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -25,6 +25,7 @@ #include "Strings.h" #include "CompactBuffer.h" #include "Structures.h" +#include "Modules.h" #include "Heap-inl.h" using namespace ke; @@ -304,6 +305,19 @@ break; } + case OP_IMPORT: + { + unsigned index = READ_UINT32(pc); + FixedArray *path = code->module()->importPathAt(index); + fprintf(fp, " ; "); + for (unsigned i = 0; i < path->length(); i++) { + fprintf(fp, "%s", String::cast(path->at(i))->chars()); + if (i != path->length() - 1) + fprintf(fp, "."); + } + break; + } + default: // Unknown opcode! assert(false); diff -r b3cf7e052ddf -r 3c184218462d src/Opcodes.tbl --- a/src/Opcodes.tbl Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Opcodes.tbl Sun Jan 06 13:52:21 2013 -0800 @@ -265,4 +265,7 @@ // index = POP() // base = POP() // PUSH(array) -OPDEF(OP_DEPARRAY, "deparray", 5, 2, 1) \ No newline at end of file +OPDEF(OP_DEPARRAY, "deparray", 5, 2, 1) + +// Grabs an import object from the import table. +OPDEF(OP_IMPORT, "import", 5, 0, 1) \ No newline at end of file diff -r b3cf7e052ddf -r 3c184218462d src/Packages.cpp --- a/src/Packages.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Packages.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -69,6 +69,12 @@ return false; } +#ifndef NDEBUG + // Assert no duplicate names. + for (unsigned i = 0; i < pkg->contents_->length(); i++) + assert(pkg->contents_->at(i)->name() != obj->name()); +#endif + if (!pkg->contents_->append(zone, obj)) return false; diff -r b3cf7e052ddf -r 3c184218462d src/Spaces.h --- a/src/Spaces.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Spaces.h Sun Jan 06 13:52:21 2013 -0800 @@ -30,6 +30,7 @@ class Map; static const size_t kObjectAlignment = sizeof(Object *); +static const size_t kMinObjectSize = sizeof(Object *) * 2; // Every object gets two successive mark bits. These bits represent various // states during garbage collection: diff -r b3cf7e052ddf -r 3c184218462d src/Structures.cpp --- a/src/Structures.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Structures.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -56,7 +56,7 @@ } Descriptor * -Descriptor::New(Zone *zone, Handle name, Handle type) +Descriptor::New(Zone *zone, Handle name, Handle type, Visibility visibility) { Local desc(zone, Descriptor::cast(zone->allocate(MapKind_Descriptor, sizeof(Descriptor), Heap::Tenure_Old))); @@ -66,6 +66,7 @@ desc->name_ = name; desc->type_ = type; desc->offset_ = unsigned(-1); + desc->visibility_ = visibility; return desc; } @@ -111,12 +112,13 @@ Struct * Struct::New(Zone *zone, Handle map, Heap::Tenure tenure) { - size_t bytesNeeded = sizeof(Struct) + map->structureSize(); + size_t bytesNeeded = SizeFor(map); + Local obj(zone, Struct::cast(zone->allocate(map, bytesNeeded, tenure))); if (!obj) return NULL; - memset((Struct *)obj + 1, 0, map->structureSize()); + memset((Struct *)obj + 1, 0, (bytesNeeded - sizeof(Struct))); // Initialize any sub-structures. Right now, this is performed as part of // struct allocation, rather than inlined in bytecode, for simplicity. diff -r b3cf7e052ddf -r 3c184218462d src/Structures.h --- a/src/Structures.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Structures.h Sun Jan 06 13:52:21 2013 -0800 @@ -60,6 +60,14 @@ // Represents a property descriptor for a structure field. class Descriptor : public Object { + public: + enum Visibility { + Private, + Protected, + Public + }; + + private: // The name of the field. Barriered name_; @@ -69,8 +77,10 @@ // The offset into an object at which this field can be accessed. unsigned offset_; + Visibility visibility_; + public: - static Descriptor *New(Zone *zone, Handle name, Handle type); + static Descriptor *New(Zone *zone, Handle name, Handle type, Visibility visibility); String *name() { return name_; @@ -160,9 +170,6 @@ static bool Copy(Zone *zone, Handle dest, Handle src); - size_t objSize() { - return sizeof(Struct) + map()->structureSize(); - } StructMap *map() { return StructMap::cast(Object::map()); } @@ -171,6 +178,10 @@ return reinterpret_cast
(this) + offsetOfSlotOffset(desc->offset()); } + static inline size_t SizeFor(StructMap *map) { + return Max(sizeof(Struct) + map->structureSize(), kMinObjectSize); + } + template T get(Descriptor *desc) { return *reinterpret_cast(ref(desc)); } diff -r b3cf7e052ddf -r 3c184218462d src/TypeManager.cpp --- a/src/TypeManager.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/TypeManager.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -48,6 +48,10 @@ if (!stringType_) return false; + importableType_ = Type::NewImportable(zone_); + if (!importableType_) + return false; + if ((primitiveTypes_[PrimitiveType_Int32] = Type::NewPrimitive(zone_, PrimitiveType_Int32)) == NULL) return false; if ((primitiveTypes_[PrimitiveType_Float] = Type::NewPrimitive(zone_, PrimitiveType_Float)) == NULL) @@ -136,6 +140,7 @@ visitor->visit(voidType_.address()); visitor->visit(uncheckedType_.address()); visitor->visit(stringType_.address()); + visitor->visit(importableType_.address()); for (unsigned i = 0; i < PrimitiveTypes_Total; i++) { visitor->visit(primitiveTypes_[i].address()); visitor->visit(referenceTypes_[i].address()); diff -r b3cf7e052ddf -r 3c184218462d src/TypeManager.h --- a/src/TypeManager.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/TypeManager.h Sun Jan 06 13:52:21 2013 -0800 @@ -79,6 +79,9 @@ Type *getUnchecked() { return uncheckedType_; } + Type *getImportable() { + return importableType_; + } ReferenceType *getReference(Handle type, bool isConst); ArrayType *newArray(Handle contained, int elements); ArrayType *newExternalArray(Handle contained); @@ -96,6 +99,7 @@ Unbarriered voidType_; Unbarriered stringType_; Unbarriered uncheckedType_; + Unbarriered importableType_; Unbarriered primitiveTypes_[PrimitiveTypes_Total]; Unbarriered referenceTypes_[PrimitiveTypes_Total]; diff -r b3cf7e052ddf -r 3c184218462d src/Types.cpp --- a/src/Types.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Types.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -20,6 +20,7 @@ #include "Types.h" #include "Zone.h" #include "Strings.h" +#include "Array.h" #include "Structures.h" #include "Heap-inl.h" @@ -44,6 +45,17 @@ } Type * +Type::NewImportable(Zone *zone) +{ + Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); + if (!type) + return NULL; + + type->init(IMPORTABLE); + return type; +} + +Type * Type::NewString(Zone *zone) { Local type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old))); @@ -110,6 +122,11 @@ type->levels_ = 1; else type->levels_ = ArrayType::cast(contained)->levels() + 1; + + type->newMap_ = ArrayMap::New(zone, type); + if (!type->newMap_) + return NULL; + return type; } @@ -270,6 +287,8 @@ return Format(buffer, maxlen, "void"); if (type->isUnchecked()) return Format(buffer, maxlen, "unchecked"); + if (type->isImportable()) + return Format(buffer, maxlen, "import"); if (type->isEnum()) return Format(buffer, maxlen, "%s", EnumType::cast(type)->name()->chars()); if (type->isStruct()) diff -r b3cf7e052ddf -r 3c184218462d src/Types.h --- a/src/Types.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Types.h Sun Jan 06 13:52:21 2013 -0800 @@ -111,7 +111,11 @@ // Structs are composite records that may contain primitives, arrays, // functions, enums, and other structs. - STRUCT + STRUCT, + + // Importable types are mainly used during the compilation process + // to distinguish between normal names and static imports. + IMPORTABLE }; void init(Kind kind, Type *root = NULL); @@ -127,6 +131,7 @@ static Type *NewPrimitive(Zone *zone, PrimitiveType type); static Type *NewString(Zone *zone); static Type *NewQualified(Zone *zone, TypeQualifiers qual, Handle type); + static Type *NewImportable(Zone *zone); static Type *cast(Object *obj) { assert(!obj || @@ -160,6 +165,9 @@ bool isStruct() { return kind() == STRUCT; } + bool isImportable() { + return kind() == IMPORTABLE; + } PrimitiveType primitive() { assert(isPrimitive()); return root_->primitive_; diff -r b3cf7e052ddf -r 3c184218462d src/Utility.h --- a/src/Utility.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/Utility.h Sun Jan 06 13:52:21 2013 -0800 @@ -282,6 +282,12 @@ return t1 < t2 ? t1 : t2; } +template static inline T +Max(const T &t1, const T &t2) +{ + return t1 > t2 ? t1 : t2; +} + #define OFFSETOF(Class, Member) reinterpret_cast(&((Class *)NULL)->Member) } diff -r b3cf7e052ddf -r 3c184218462d src/compiler/AST.h --- a/src/compiler/AST.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/AST.h Sun Jan 06 13:52:21 2013 -0800 @@ -28,6 +28,7 @@ namespace ke { class Scope; +class Importable; struct PathComponent; #define ASTKINDS(_) \ @@ -128,21 +129,11 @@ class Expression : public AstNode { - ScopedRoot type_; - public: Expression(const SourcePosition &pos) - : AstNode(pos), - type_(NULL) + : AstNode(pos) { } - - void setType(Type *type) { - type_ = type; - } - Type *type() const { - return type_; - } }; typedef PoolList StatementList; @@ -497,14 +488,12 @@ { Expression *left_; ScopedRoot field_; - unsigned fieldIndex_; public: FieldExpression(const SourcePosition &pos, Expression *left, Handle field) : Expression(pos), left_(left), - field_(field), - fieldIndex_(unsigned(-1)) + field_(field) { } @@ -513,17 +502,9 @@ Expression *left() const { return left_; } - String *field() const { + Handle field() const { return field_; } - void setFieldIndex(unsigned index) { - assert(fieldIndex_ == unsigned(-1)); - fieldIndex_ = index; - } - unsigned fieldIndex() const { - assert(fieldIndex_ != unsigned(-1)); - return fieldIndex_; - } }; class CallExpression : public Expression @@ -1105,11 +1086,9 @@ class ImportStatement : public Statement { public: - ImportStatement(const SourcePosition &pos, PathComponent *path, TokenKind suffix) + ImportStatement(const SourcePosition &pos, PathComponent *path) : Statement(pos), - path_(path), - suffix_(suffix), - source_(NULL) + path_(path) { } @@ -1118,20 +1097,23 @@ PathComponent *path() const { return path_; } - void setImportSource(TranslationUnit *unit) { - source_ = unit; + void setSource(Importable *source) { + source_ = source; } - TranslationUnit *source() const { + Handle source() { return source_; } - TokenKind suffix() const { - return suffix_; + unsigned importIndex() { + return importIndex_; + } + void setImportIndex(unsigned index) { + importIndex_ = index; } private: PathComponent *path_; - TokenKind suffix_; - TranslationUnit *source_; + ScopedRoot source_; + unsigned importIndex_; }; typedef StructureStatement::FieldList FieldList; diff -r b3cf7e052ddf -r 3c184218462d src/compiler/BytecodeEmitter.h --- a/src/compiler/BytecodeEmitter.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/BytecodeEmitter.h Sun Jan 06 13:52:21 2013 -0800 @@ -681,6 +681,13 @@ jump(labels[i]); } + void import(unsigned index) { + ensure(OP_IMPORT_LENGTH); + writeOp(OP_IMPORT); + writeUint32(index); + markOop(1); + } + bool allocate(VariableSymbol *sym); Code *finish(); diff -r b3cf7e052ddf -r 3c184218462d src/compiler/CompileContext.cpp --- a/src/compiler/CompileContext.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/CompileContext.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -21,6 +21,8 @@ #include "../Interpreter.h" #include "../Packages.h" #include "../FileSystem.h" +#include "../FixedArray.h" +#include "../Vector.h" #include "Scanner.h" #include "CompileContext.h" #include "Parser.h" @@ -60,7 +62,7 @@ if (!strname) return false; - PathComponent p(new ScopedRoot(strname), NULL); + PathComponent p(new (zone_->pool()) ScopedRoot(strname), NULL); Local importable(zone_); if (!zone_->packages()->findOrAdd(package, &p, importable.address())) @@ -145,10 +147,17 @@ { PoolList *imports = unit->tree()->imports(); + if (!imports->length()) + return true; + + // We're allowed to use Handle<> here instead of ScopedRoot<> because + // we get the handle from ImportStatement which has a ScopedRoot<>. + Vector > vec; + for (size_t i = 0; i < imports->length(); i++) { ImportStatement *import = imports->at(i); - // Step 1. Crawl the path until we find a valid file to load. + // Crawl the path until we find a valid file to load. Local obj(zone_); Local package(zone_, unit->module()->parent()); if (!zone_->packages()->findOrAdd(package, import->path(), obj.address())) @@ -170,8 +179,52 @@ if (!add(module)) return false; } + + import->setSource(obj); + + // See if there are any duplicates. This is O(n^2), but we expect + // |n| to be small. + unsigned index = 0; + for (; index < vec.length(); index++) { + if (vec[index] == obj) + break; + } + if (index == vec.length() && !vec.append(import->source())) + return false; + + import->setImportIndex(index); + } + + if (!IsUint32MultiplySafe(vec.length(), 2)) { + zone_->reportAllocationOverflow(); + return false; } + // Create an array of the import and paths. + Local importables(zone_, FixedArray::New(zone_, vec.length() * 2, Heap::Tenure_Default)); + if (!importables) + return false; + + for (unsigned i = 0; i < vec.length(); i++) { + importables->set(zone_, i * 2, vec[i]); + + unsigned count = 0; + PathComponent *path = imports->at(i)->path(); + for (PathComponent *iter = path; iter; iter = iter->next) + count++; + + Local list(zone_, FixedArray::New(zone_, count, Heap::Tenure_Default)); + if (!list) + return false; + + count = 0; + for (PathComponent *iter = path; iter; iter = iter->next, count++) + list->set(zone_, count, iter->name); + + importables->set(zone_, i * 2 + 1, list); + } + + unit->module()->setImports(importables); return true; } diff -r b3cf7e052ddf -r 3c184218462d src/compiler/HIR.cpp --- a/src/compiler/HIR.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/HIR.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -50,9 +50,11 @@ void visitGlobal(HGlobal *global); void visitConvert(HConvert *convert); void visitIndex(HIndex *index); + void visitField(HField *field); void visitPostIncDec(HPostIncDec *hir); void visitToRef(HToRef *hir); void visitNewDependentArray(HNewDependentArray *hir); + void visitImport(HImport *import); private: Zone *zone_; @@ -286,6 +288,45 @@ } void +HField::bind(HIRVisitor *visitor, BytecodeEmitter &emitter_) +{ + __ note_position(node()->pos()); + base_->accept(visitor); +} + +void +HField::hold(BytecodeEmitter &emitter_) +{ + __ dup(); +} + +void +HField::swapAndPick(BytecodeEmitter &emitter_) +{ + // BASE VALUE + __ swap(); // VALUE BASE + __ pick2(); // VALUE BASE VALUE +} + +void +HField::store(BytecodeEmitter &emitter_) +{ + __ setfield(index_, type()); +} + +void +HField::load(BytecodeEmitter &emitter_) +{ + __ getfield(index_, type()); +} + +bool +HField::ref(BytecodeEmitter &emitter_) +{ + return false; +} + +void HIRTranslator::visitLocal(HLocal *local) { local->bind(this, emitter_); @@ -300,6 +341,13 @@ } void +HIRTranslator::visitField(HField *field) +{ + field->bind(this, emitter_); + field->load(emitter_); +} + +void HIRTranslator::visitGlobal(HGlobal *global) { global->bind(this, emitter_); @@ -486,11 +534,6 @@ Local type(zone_, ArrayType::cast(hir->type())); - // Attach an actual map to the dependent type, in case it's a new - // type. - if (!ArrayMap::Attach(zone_, type)) - return; - // The dependent map is used for the opcode, but is not attached. Local map(zone_, ArrayMap::NewDependent(zone_, type)); if (!map) @@ -500,6 +543,12 @@ } void +HIRTranslator::visitImport(HImport *import) +{ + __ import(import->index()); +} + +void ke::EmitHIR(Zone *zone, BytecodeEmitter &emitter, HIR *hir) { HIRTranslator translator(zone, emitter); diff -r b3cf7e052ddf -r 3c184218462d src/compiler/HIR.h --- a/src/compiler/HIR.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/HIR.h Sun Jan 06 13:52:21 2013 -0800 @@ -31,6 +31,7 @@ _(Integer) \ _(Float) \ _(String) \ + _(Import) \ _(Array) \ _(Store) \ _(ToRef) \ @@ -39,6 +40,7 @@ _(Index) \ _(Local) \ _(Global) \ + _(Field) \ /* End LValues */ \ _(Unary) \ _(Binary) \ @@ -184,6 +186,24 @@ ScopedRoot string_; }; +class HImport : public HIR +{ + public: + HImport(AstNode *node, Type *type, unsigned index) + : HIR(node, type), + index_(index) + { + } + + DEFINE_HIR(Import); + unsigned index() const { + return index_; + } + + private: + unsigned index_; +}; + class HArray : public HIR { public: @@ -319,6 +339,37 @@ HIR *right_; }; +class HField : public HLValue +{ + public: + HField(AstNode *node, HIR *left, Type *type, unsigned index) + : HLValue(node, type), + base_(left), + index_(index) + { + } + + DEFINE_HIR(Field); + + void bind(HIRVisitor *visitor, BytecodeEmitter &emitter_); + void hold(BytecodeEmitter &emitter_); + void swapAndPick(BytecodeEmitter &emitter_); + void store(BytecodeEmitter &emitter_); + void load(BytecodeEmitter &emitter_); + bool ref(BytecodeEmitter &emitter_); + + HIR *base() const { + return base_; + } + unsigned index() const { + return index_; + } + + private: + HIR *base_; + unsigned index_; +}; + class HGlobal : public HLValue { public: diff -r b3cf7e052ddf -r 3c184218462d src/compiler/NameBinding.cpp --- a/src/compiler/NameBinding.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/NameBinding.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -197,6 +197,7 @@ if (node->initialization()) node->initialization()->accept(this); } + void visitEnumStatement(EnumStatement *node) { Local name(zone_, node->name()); Local type(zone_); @@ -239,6 +240,7 @@ value++; } } + void visitFunctionStatement(FunctionStatement *node) { // We create function types ahead of time, not for any particular // reason. It makes things consistent with FunctionTypeStatement, @@ -260,9 +262,6 @@ { // We're in the global scope, for sure. assert(env_->scope()->kind() == Scope::GLOBAL); - GlobalScope *globals = (GlobalScope *)env_->scope(); - if (!globals->addPublic(sym)) - return; } node->setSymbol(sym); @@ -298,9 +297,11 @@ node->setScopes(argEnv.scope(), localEnv.scope()); } + void visitStructureStatement(StructureStatement *node) { assert(false); } + void visiFunctionTypeStatementt(FunctionTypeStatement *node) { assert(false); } @@ -492,73 +493,23 @@ static const int EVAL_ARRAY_SIZE = -1; static const int DYNAMIC_ARRAY_SIZE = -2; -class NameBinder : public AstVisitor +class NameBinderBase : public AstVisitor { public: - class AutoLinkScope - { - public: - AutoLinkScope(AutoLinkScope **prevp, Scope *scope) - : prevp_(prevp), - prev_(*prevp), - scope_(scope) - { - if (scope_) { - *prevp_ = this; - if (prev_) - scope_->setParent(prev_->scope()); - } - } - ~AutoLinkScope() { - if (scope_) { - assert(*prevp_ == this); - *prevp_ = prev_; - } - } - Scope *scope() const { - return scope_; - } - - private: - AutoLinkScope **prevp_; - AutoLinkScope *prev_; - Scope *scope_; - }; - - public: - NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit) + NameBinderBase(Zone *zone, CompileContext &cc, TranslationUnit *unit) : zone_(zone), pool_(zone->pool()), cc_(cc), - unit_(unit), - link_(NULL) + unit_(unit) { } - void bind() { - // Start with the import scope, and collect all imported names. - AutoLinkScope importScope(&link_, unit_->importScope()); - for (size_t i = 0; i < unit_->tree()->imports()->length(); i++) - unit_->tree()->imports()->at(i)->accept(this); - - // Next, enter the global scope and walk all statements. - AutoLinkScope globalScope(&link_, unit_->globalScope()); - for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) { - Statement *stmt = unit_->tree()->statements()->at(i); - stmt->accept(this); - } - } - - void visitVariableDeclaration(VariableDeclaration *node) { - // Bind the initializer before registering the declaration, so that we - // can error on bogus initializers (new x = x). - if (node->initialization()) - node->initialization()->accept(this); - + protected: + Type *buildVariableType(VariableDeclaration *node) { Local type(zone_, bindType(node->type(), node->quals())); if (!type) - return; + return NULL; // We don't allow array typedefs yet. assert(!type->isArray()); @@ -567,7 +518,7 @@ int dims[MAX_ARRAY_DEPTH]; int levels = evaluateDimensions(node->pos(), type, node->dims(), dims); if (levels < 0) - return; + return NULL; // Do some extra inference based on the initializer, if present. Expression *init = node->initialization(); @@ -577,7 +528,7 @@ ? ArrayType::cast(type)->contained() : type); if (!inferFixedArrayDimensions(init->toArrayLiteral(), contained, dims, levels)) - return; + return NULL; } else if (init->isStringLiteral()) { dims[levels - 1] = init->toStringLiteral()->string()->length() + 1; } @@ -586,180 +537,13 @@ // If we got extra dimensions, we need to build a new type. if (node->dims()) { if ((type = buildArrayType(type, node->quals(), dims, node->dims()->length())) == NULL) - return; + return NULL; } } - // If we're in global scope, and we received a |const| qualifier, then - // we extend this to array references as well. This is to sort of mimic - // SP1 functionality, but also means that you cannot have changeable - // const pointers in global scope. - if ((node->quals() & TypeQual_Const) && - type->isArray() && - link_->scope()->kind() == Scope::GLOBAL) - { - if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL) - return; - } - - // If the node already has a symbol (meaning it was a global), then - // we don't have to do anything more. - if (node->sym()) { - assert(node->sym()->scope()->kind() == Scope::GLOBAL); - node->sym()->setType(type); - return; - } - - VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type); - node->setSymbol(sym); - - if (Symbol *other = link_->scope()->localLookup(sym->name())) { - // Report, but allow errors to continue. - cc_.reportError(sym->pos(), Message_RedeclaredName, - sym->name()->chars(), - other->pos().line, - other->pos().col); - return; - } - - link_->scope()->addSymbol(sym); - } - void visitEnumStatement(EnumStatement *node) { - } - void visitFunctionStatement(FunctionStatement *node) { - AutoLinkScope argScope(&link_, node->argScope()); - AutoLinkScope varScope(&link_, node->varScope()); - - Local type(zone_, node->sym()->type()); - if (!fillFunctionType(type, node->signature())) - return; - - if (node->body()) - node->body()->accept(this); - } - void visitStructureStatement(StructureStatement *node) { - assert(false); - } - void visitFunctionTypeStatement(FunctionTypeStatement *node) { - assert(false); + return type; } - void visitNameProxy(NameProxy *proxy) { - Scope *scope = link_->scope(); - Symbol *sym = scope->lookup(proxy->name()); - if (!sym) - cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars()); - proxy->bind(sym); - } - void visitAssignment(Assignment *node) { - node->lvalue()->accept(this); - node->expression()->accept(this); - } - void visitBinaryExpression(BinaryExpression *node) { - node->left()->accept(this); - node->right()->accept(this); - } - void visitReturnStatement(ReturnStatement *node) { - node->expression()->accept(this); - } - void visitForStatement(ForStatement *node) { - AutoLinkScope scope(&link_, node->scope()); - - if (node->initialization()) - node->initialization()->accept(this); - if (node->condition()) - node->condition()->accept(this); - if (node->update()) - node->update()->accept(this); - node->body()->accept(this); - } - void visitBlockStatement(BlockStatement *node) { - AutoLinkScope scope(&link_, node->scope()); - for (size_t i = 0; i < node->statements()->length(); i++) - node->statements()->at(i)->accept(this); - } - void visitIntegerLiteral(IntegerLiteral *node) { - } - void visitExpressionStatement(ExpressionStatement *node) { - node->expression()->accept(this); - } - void visitCallExpression(CallExpression *node) { - node->callee()->accept(this); - for (size_t i = 0; i < node->arguments()->length(); i++) - node->arguments()->at(i)->accept(this); - } - void visitIfStatement(IfStatement *node) { - node->condition()->accept(this); - node->ifTrue()->accept(this); - if (node->ifFalse()) - node->ifFalse()->accept(this); - } - void visitIndexExpression(IndexExpression *node) { - node->left()->accept(this); - node->right()->accept(this); - } - void visitFloatLiteral(FloatLiteral *node) { - } - void visitWhileStatement(WhileStatement *node) { - node->condition()->accept(this); - node->body()->accept(this); - } - void visitBreakStatement(BreakStatement *node) { - } - void visitContinueStatement(ContinueStatement *node) { - } - void visitStringLiteral(StringLiteral *node) { - } - void visitIncDecExpression(IncDecExpression *node) { - node->expression()->accept(this); - } - void visitUnaryExpression(UnaryExpression *node) { - if (node->tag()) - node->tag()->accept(this); - node->expression()->accept(this); - } - void visitTernaryExpression(TernaryExpression *node) { - node->condition()->accept(this); - node->left()->accept(this); - node->right()->accept(this); - } - void visitBooleanLiteral(BooleanLiteral *node) { - } - void visitFieldExpression(FieldExpression *node) { - node->left()->accept(this); - } - void visitSwitchStatement(SwitchStatement *node) { - node->expression()->accept(this); - node->defaultCase()->accept(this); - for (size_t i = 0; i < node->cases()->length(); i++) { - // We don't test case expressions because they are literals. - Case *c = node->cases()->at(i); - c->statement()->accept(this); - } - } - void visitArrayLiteral(ArrayLiteral *node) { - for (size_t i = 0; i < node->expressions()->length(); i++) - node->expressions()->at(i)->accept(this); - } - void visitImportStatement(ImportStatement *node) { - if (node->suffix() == TOK_STAR) { - // Import every name. - assert(false); - } else { - assert(false); -#if 0 - GlobalScope *other = node->source()->globalScope(); - Symbol *sym = other->findPublic(node->name()); - if (!sym) { - cc_.reportError(node->pos(), Message_CannotResolveImport, node->name()->chars()); - return; - } - link_->scope()->addSymbol(sym); -#endif - } - } - - private: int evaluateDimensions(const SourcePosition &pos, Handle typeArg, ExpressionList *exprs, int dims[MAX_ARRAY_DEPTH]) { unsigned level = 0; Local type(zone_, typeArg); @@ -967,11 +751,344 @@ return zone_->types()->qualify(type, quals); } - private: + protected: Zone *zone_; PoolAllocator &pool_; CompileContext &cc_; TranslationUnit *unit_; +}; + +class GlobalBuilder : public NameBinderBase +{ + public: + GlobalBuilder(Zone *zone, CompileContext &cc, TranslationUnit *unit) + : NameBinderBase(zone, cc, unit) + { + } + + Struct *build() { + for (size_t i = 0; i < unit_->tree()->imports()->length(); i++) + unit_->tree()->imports()->at(i)->accept(this); + + // Next, enter the global scope and walk all statements. + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) { + Statement *stmt = unit_->tree()->statements()->at(i); + stmt->accept(this); + } + + Local descs(zone_, FixedArray::New(zone_, descriptors_.length(), Heap::Tenure_Old)); + if (!descs) + return NULL; + + for (unsigned i = 0; i < descriptors_.length(); i++) + descs->set(zone_, i, *descriptors_[i]); + + Local name(zone_, unit_->module()->name()); + Local type(zone_, StructType::New(zone_, name, descs)); + if (!type) + return NULL; + + Local map(zone_, type->newMap()); + return Struct::New(zone_, map, Heap::Tenure_Old); + } + + void visitEnumStatement(EnumStatement *stmt) { + } + + void visitNameProxy(NameProxy *proxy) { + // Don't report errors here, since we'll report them later. + Scope *scope = unit_->globalScope(); + Symbol *sym = scope->lookup(proxy->name()); + proxy->bind(sym); + } + + void visitFunctionStatement(FunctionStatement *node) { + Local type(zone_, node->sym()->type()); + if (!fillFunctionType(type, node->signature())) + return; + + unsigned offset; + if (!builder_.add(type, &offset)) + return; + + Descriptor::Visibility visibility = (node->token() == TOK_NATIVE || node->token() == TOK_FORWARD) + ? Descriptor::Public + : Descriptor::Private; + + Descriptor *desc = Descriptor::New(zone_, node->name(), type, visibility); + if (!desc) + return; + if (!descriptors_.append(new (pool_) ScopedRoot(desc))) + return; + } + + void visitVariableDeclaration(VariableDeclaration *node) { + Local type(zone_, buildVariableType(node)); + if (!type) + return; + + // If we're in global scope, and we received a |const| qualifier, then + // we extend this to array references as well. This is to sort of mimic + // SP1 functionality, but also means that you cannot have changeable + // const pointers in global scope. + if ((node->quals() & TypeQual_Const) && type->isArray()) { + if ((type = zone_->types()->qualify(type, TypeQual_Const)) == NULL) + return; + } + + node->sym()->setType(type); + + unsigned offset; + if (!builder_.add(type, &offset)) + return; + + Descriptor *desc = Descriptor::New(zone_, node->name(), type, Descriptor::Private); + if (!desc) + return; + if (!descriptors_.append(new (pool_) ScopedRoot(desc))) + return; + } + + void visitImportStatement(ImportStatement *node) { + // Eventually we'll handle |from| style imports as well. + { + PathComponent *path = node->path(); + while (path->next) + path = path->next; + + // Imports automatically go into the importScope. For now, we + // error if there are any duplicate symbols entered into the + // importScope. + if (Symbol *sym = unit_->importScope()->localLookup(path->name)) { + cc_.reportError(node->pos(), Message_DuplicateImport, path->name->chars()); + return; + } + + Local type(zone_, zone_->types()->getImportable()); + ImportSymbol *sym = new (pool_) ImportSymbol(unit_->importScope(), path->name, node->pos(), type, node->importIndex()); + if (!unit_->importScope()->addSymbol(sym)) + return; + } + } + + private: + StructureBufferBuilder builder_; + Vector *> descriptors_; +}; + +class NameBinder : public NameBinderBase +{ + public: + class AutoLinkScope + { + public: + AutoLinkScope(AutoLinkScope **prevp, Scope *scope) + : prevp_(prevp), + prev_(*prevp), + scope_(scope) + { + if (scope_) { + *prevp_ = this; + if (prev_) + scope_->setParent(prev_->scope()); + } + } + ~AutoLinkScope() { + if (scope_) { + assert(*prevp_ == this); + *prevp_ = prev_; + } + } + Scope *scope() const { + return scope_; + } + + private: + AutoLinkScope **prevp_; + AutoLinkScope *prev_; + Scope *scope_; + }; + + public: + NameBinder(Zone *zone, CompileContext &cc, TranslationUnit *unit) + : NameBinderBase(zone, cc, unit), + link_(NULL) + { + } + + void bind() { + // Start with the import scope, and collect all imported names. + AutoLinkScope importScope(&link_, unit_->importScope()); + + for (size_t i = 0; i < unit_->tree()->imports()->length(); i++) + unit_->tree()->imports()->at(i)->accept(this); + + // Next, enter the global scope and walk all statements. + AutoLinkScope globalScope(&link_, unit_->globalScope()); + for (size_t i = 0; i < unit_->tree()->statements()->length(); i++) { + Statement *stmt = unit_->tree()->statements()->at(i); + stmt->accept(this); + } + } + + void visitVariableDeclaration(VariableDeclaration *node) { + // Bind the initializer before registering the declaration, so that we + // can error on bogus initializers (new x = x). + if (node->initialization()) + node->initialization()->accept(this); + + // If the node already has a symbol (meaning it was a global), then + // we don't have to do anything more. + if (node->sym()) + return; + + Local type(zone_, buildVariableType(node)); + if (!type) + return; + + VariableSymbol *sym = new (pool_) VariableSymbol(link_->scope(), node->name(), node->pos(), type); + node->setSymbol(sym); + + if (Symbol *other = link_->scope()->localLookup(sym->name())) { + // Report, but allow errors to continue. + cc_.reportError(sym->pos(), Message_RedeclaredName, + sym->name()->chars(), + other->pos().line, + other->pos().col); + return; + } + + link_->scope()->addSymbol(sym); + } + void visitEnumStatement(EnumStatement *node) { + } + void visitFunctionStatement(FunctionStatement *node) { + AutoLinkScope argScope(&link_, node->argScope()); + AutoLinkScope varScope(&link_, node->varScope()); + + // If the function is in the global scope, we've already computed its + // type. + if (node->sym()->scope()->kind() != Scope::GLOBAL) { + Local type(zone_, node->sym()->type()); + if (!fillFunctionType(type, node->signature())) + return; + } + + if (node->body()) + node->body()->accept(this); + } + void visitStructureStatement(StructureStatement *node) { + assert(false); + } + void visitFunctionTypeStatement(FunctionTypeStatement *node) { + assert(false); + } + + void visitNameProxy(NameProxy *proxy) { + // We could have already bound globals. + if (proxy->sym()) + return; + + Scope *scope = link_->scope(); + Symbol *sym = scope->lookup(proxy->name()); + if (!sym) + cc_.reportError(proxy->pos(), Message_IdentifierNotFound, proxy->name()->chars()); + proxy->bind(sym); + } + void visitAssignment(Assignment *node) { + node->lvalue()->accept(this); + node->expression()->accept(this); + } + void visitBinaryExpression(BinaryExpression *node) { + node->left()->accept(this); + node->right()->accept(this); + } + void visitReturnStatement(ReturnStatement *node) { + node->expression()->accept(this); + } + void visitForStatement(ForStatement *node) { + AutoLinkScope scope(&link_, node->scope()); + + if (node->initialization()) + node->initialization()->accept(this); + if (node->condition()) + node->condition()->accept(this); + if (node->update()) + node->update()->accept(this); + node->body()->accept(this); + } + void visitBlockStatement(BlockStatement *node) { + AutoLinkScope scope(&link_, node->scope()); + for (size_t i = 0; i < node->statements()->length(); i++) + node->statements()->at(i)->accept(this); + } + void visitIntegerLiteral(IntegerLiteral *node) { + } + void visitExpressionStatement(ExpressionStatement *node) { + node->expression()->accept(this); + } + void visitCallExpression(CallExpression *node) { + node->callee()->accept(this); + for (size_t i = 0; i < node->arguments()->length(); i++) + node->arguments()->at(i)->accept(this); + } + void visitIfStatement(IfStatement *node) { + node->condition()->accept(this); + node->ifTrue()->accept(this); + if (node->ifFalse()) + node->ifFalse()->accept(this); + } + void visitIndexExpression(IndexExpression *node) { + node->left()->accept(this); + node->right()->accept(this); + } + void visitFloatLiteral(FloatLiteral *node) { + } + void visitWhileStatement(WhileStatement *node) { + node->condition()->accept(this); + node->body()->accept(this); + } + void visitBreakStatement(BreakStatement *node) { + } + void visitContinueStatement(ContinueStatement *node) { + } + void visitStringLiteral(StringLiteral *node) { + } + void visitIncDecExpression(IncDecExpression *node) { + node->expression()->accept(this); + } + void visitUnaryExpression(UnaryExpression *node) { + if (node->tag()) + node->tag()->accept(this); + node->expression()->accept(this); + } + void visitTernaryExpression(TernaryExpression *node) { + node->condition()->accept(this); + node->left()->accept(this); + node->right()->accept(this); + } + void visitBooleanLiteral(BooleanLiteral *node) { + } + void visitFieldExpression(FieldExpression *node) { + node->left()->accept(this); + } + void visitSwitchStatement(SwitchStatement *node) { + node->expression()->accept(this); + node->defaultCase()->accept(this); + for (size_t i = 0; i < node->cases()->length(); i++) { + // We don't test case expressions because they are literals. + Case *c = node->cases()->at(i); + c->statement()->accept(this); + } + } + void visitArrayLiteral(ArrayLiteral *node) { + for (size_t i = 0; i < node->expressions()->length(); i++) + node->expressions()->at(i)->accept(this); + } + void visitImportStatement(ImportStatement *node) { + } + + private: AutoLinkScope *link_; }; @@ -979,6 +1096,18 @@ ke::BindNamesAndTypes(Zone *zone, CompileContext &cc, TranslationUnit *unit) { AutoEnterCompileContext enter(cc, unit); + + // Because of the way globals work in Pawn, we need a precursor step to + // actually enter global symbols into the global struct. They're already + // in the global symbol table, so we know they won't clash. This process + // also binds any remaining types on global variables. + GlobalBuilder builder(zone, cc, unit); + Local globals(zone, builder.build()); + if (!globals || unit->failed()) + return; + + unit->module()->setGlobals(globals); + NameBinder binder(zone, cc, unit); binder.bind(); } diff -r b3cf7e052ddf -r 3c184218462d src/compiler/Parser.cpp --- a/src/compiler/Parser.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/Parser.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -1236,9 +1236,7 @@ static inline ScopedRoot * NewScopedRoot(PoolAllocator &pool, Handle obj) { - ScopedRoot *root = pool.alloc >(); - new (root) ScopedRoot(obj); - return root; + return new (pool) ScopedRoot(obj); } ImportStatement * @@ -1246,7 +1244,7 @@ { SourcePosition pos = scanner_.begin(); - // import ::= import_path ("." "*")? + // import ::= import_path // import_path ::= name | // name "." import_path @@ -1259,11 +1257,6 @@ TokenKind suffix = TOK_NONE; while (match(TOK_DOT)) { - if (match(TOK_STAR)) { - suffix = TOK_STAR; - break; - } - if ((name = expectName()) == NULL) return NULL; @@ -1271,7 +1264,7 @@ current = current->next; } - return new (pool_) ImportStatement(pos, root, suffix); + return new (pool_) ImportStatement(pos, root); } Statement * diff -r b3cf7e052ddf -r 3c184218462d src/compiler/Scopes.cpp --- a/src/compiler/Scopes.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/Scopes.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -168,47 +168,6 @@ return scope; } -bool -GlobalScope::addPublic(Symbol *sym) -{ - return publics_.append(sym); -} - -Symbol * -GlobalScope::findPublic(Handle name) -{ - for (size_t i = 0; i < publics_.length(); i++) { - if (publics_[i]->name() == name) - return publics_[i]; - } - return NULL; -} - -Struct * -GlobalScope::build(Zone *zone) -{ - Local descriptors(zone, FixedArray::New(zone, names_.length(), Heap::Tenure_Old)); - - for (size_t i = 0; i < names_.length(); i++) { - Handle name = names_[i]->name(); - Handle type = names_[i]->type(); - assert(type); - - Local desc(zone, Descriptor::New(zone, name, type)); - if (!desc) - return NULL; - - descriptors->set(zone, i, desc); - } - - Local type(zone, StructType::New(zone, Handle::Null(), descriptors)); - if (!type) - return NULL; - - Local map(zone, type->newMap()); - return Struct::New(zone, map, Heap::Tenure_Old); -} - ImportScope::ImportScope(PoolAllocator &pool) : Scope(pool, Scope::IMPORT, NULL) { diff -r b3cf7e052ddf -r 3c184218462d src/compiler/Scopes.h --- a/src/compiler/Scopes.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/Scopes.h Sun Jan 06 13:52:21 2013 -0800 @@ -101,15 +101,8 @@ public: static GlobalScope *New(PoolAllocator &pool, ImportScope *parent); - bool addPublic(Symbol *symbol); - Symbol *findPublic(Handle name); - Struct *build(Zone *zone); - private: GlobalScope(PoolAllocator &pool, ImportScope *parent); - - private: - PoolList publics_; }; class ImportScope : public Scope diff -r b3cf7e052ddf -r 3c184218462d src/compiler/SemanticAnalysis.cpp --- a/src/compiler/SemanticAnalysis.cpp Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/SemanticAnalysis.cpp Sun Jan 06 13:52:21 2013 -0800 @@ -93,11 +93,6 @@ stmt->accept(this); } - Local globals(zone_, unit_->globalScope()->build(zone_)); - if (!globals) - return; - unit_->module()->setGlobals(globals); - Local code(zone_, __ finish()); if (!code) return; @@ -448,7 +443,7 @@ __ float_(0); } else if (type->isArray()) { Local atype(zone_, ArrayType::cast(type)); - Local map(zone_, ArrayMap::Attach(zone_, atype)); + Local map(zone_, atype->newMap()); if (!map) return; @@ -570,6 +565,13 @@ Symbol *sym = proxy->sym(); switch (sym->kind()) { + case Symbol::kImport: + { + ImportSymbol *import = sym->toImport(); + hir_ = new (pool_) HImport(proxy, sym->type(), import->index()); + break; + } + case Symbol::kConstant: { ConstantSymbol *val = sym->toConstant(); @@ -936,7 +938,7 @@ // Transform the string literal into an array literal. We give it the // type of the left-hand side. The constness of the destination type // will determine whether HArray duplicates it or not. - Local map(zone_, ArrayMap::Attach(zone_, actual)); + Local map(zone_, actual->newMap()); if (!map) return NULL; @@ -1066,6 +1068,10 @@ { Local from(zone_, hir->type()); + // If the source is *ever* an importable, we just fail. + if (from->isImportable()) + return typeFailure(hir->node()->pos(), from, to); + if (from->isInt32() && to->isFloat()) return new (pool_) HConvert(hir->node(), to, OP_CVT_I2F, hir); if (from->isInt32() && to->isBool()) @@ -1218,6 +1224,70 @@ } } +void +SemanticAnalysis::import(HIR *hir, FieldExpression *node) +{ + // Note that we don't care if the hir type is "importable", since we + // can only do anything if the important has a constant binding. + unsigned index = hir->toImport()->index(); + Local importable(zone_, unit_->module()->getImportAt(index)); + + if (importable->isPackage()) { + // Look at what's already loaded and see if anything exists. We + // can't create stuff on-demand here since it's too late to add + // new translation units to the CompileContext. + Local package(zone_, Package::cast(importable)); + Local found(zone_, package->import(node->field())); + if (!found) { + cc_.reportError(node->pos(), Message_PackageDoesNotHaveMember, node->field()->chars()); + return; + } + + // If we did find something, make sure it is in our import list. + // If we didn't explicitly import it, we have no right to use it. + for (index = 0; index < unit_->module()->imports(); index++) { + if (unit_->module()->getImportAt(index) == importable) + break; + } + + if (index == unit_->module()->imports()) { + cc_.reportError(node->pos(), Message_ImportWasNeverImported, node->field()->chars()); + return; + } + + // Just create a new HImport. + hir_ = new (pool_) HImport(node, hir->type(), index); + } else { + // Modules can never have sub-modules or sub-packages. + unsigned index; + Local module(zone_, Module::cast(importable)); + Local map(zone_, module->globals()->map()); + Local desc(zone_, map->type()->lookupField(node->field(), &index)); + if (!desc) { + cc_.reportError(node->pos(), Message_FieldNotFound, node->field()->chars()); + return; + } + hir_ = new (pool_) HField(node, hir, desc->type(), index); + } +} + +void +SemanticAnalysis::visitFieldExpression(FieldExpression *node) +{ + HIR *hir = eval(node->left()); + if (!hir) + return; + + if (hir->isImport()) { + import(hir, node); + return; + } + + char name[255]; + cc_.reportError(node->pos(), Message_InvalidFieldExpression, + GetTypeName(hir->type(), name, sizeof(name))); +} + static inline TokenKind ToCompare(Expression *expr) { diff -r b3cf7e052ddf -r 3c184218462d src/compiler/SemanticAnalysis.h --- a/src/compiler/SemanticAnalysis.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/SemanticAnalysis.h Sun Jan 06 13:52:21 2013 -0800 @@ -67,6 +67,7 @@ void visitStringLiteral(StringLiteral *node); void visitUnaryExpression(UnaryExpression *node); void visitBooleanLiteral(BooleanLiteral *node); + void visitFieldExpression(FieldExpression *node); #if 0 void visitFunctionTypeStatement(FunctionTypeStatement *node); void visitImportStatement(ImportStatement *node); @@ -74,12 +75,12 @@ void visitSwitchStatement(SwitchStatement *node); void visitTernaryExpression(TernaryExpression *node); - void visitFieldExpression(FieldExpression *node); void visitArrayLiteral(ArrayLiteral *node); #endif private: bool checkArgumentCount(Handle type, unsigned actual); + void import(HIR *hir, FieldExpression *node); private: enum CoercionKind { diff -r b3cf7e052ddf -r 3c184218462d src/compiler/Symbols.h --- a/src/compiler/Symbols.h Tue Jan 01 20:08:34 2013 -0800 +++ b/src/compiler/Symbols.h Sun Jan 06 13:52:21 2013 -0800 @@ -38,8 +38,8 @@ _(Constant) \ /* A named type (class struct, typedef, etc) produces a TypeSymbol. */ \ _(Type) \ - /* // A module import produces a ModuleSymbol. */ \ - _(Module) + /* An import name. */ \ + _(Import) #define _(name) class name##Symbol; SYMBOL_KINDS(_) @@ -208,6 +208,28 @@ BoxedPrimitive value_; }; +class ImportSymbol : public Symbol +{ + public: + ImportSymbol(Scope *scope, Handle name, const SourcePosition &pos, Handle type, + unsigned index) + : Symbol(scope, name, pos), + index_(index) + { + type_ = type; + } + + Kind kind() const { + return kImport; + } + unsigned index() const { + return index_; + } + + private: + unsigned index_; +}; + } #endif // _include_sp2_symbol_h_ diff -r b3cf7e052ddf -r 3c184218462d tests/basic/import-sysroot-select.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/import-sysroot-select.out Sun Jan 06 13:52:21 2013 -0800 @@ -0,0 +1,1 @@ +5 is 5.000000 diff -r b3cf7e052ddf -r 3c184218462d tests/basic/import-sysroot-select.sp --- a/tests/basic/import-sysroot-select.sp Tue Jan 01 20:08:34 2013 -0800 +++ b/tests/basic/import-sysroot-select.sp Sun Jan 06 13:52:21 2013 -0800 @@ -1,5 +1,3 @@ -import shell; -import shell; import shell; public main() diff -r b3cf7e052ddf -r 3c184218462d tests/basic/shell.sp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/basic/shell.sp Sun Jan 06 13:52:21 2013 -0800 @@ -0,0 +1,3 @@ +native PrintNum(num); +native PrintString(const char:text[]); +native PrintFloat(float:f); diff -r b3cf7e052ddf -r 3c184218462d tests/shell.sp --- a/tests/shell.sp Tue Jan 01 20:08:34 2013 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -native PrintNum(num); - -native PrintString(const char:text[]); - -native PrintFloat(float:f);