SemanticAnalysis::SemanticAnalysis(CompileContext &cc, TranslationUnit *tu) : cc_(cc), pool_(cc.pool()), types_(cc.types()), tu_(tu), funcstate_(nullptr) { }
bool VarDeclSpecHelper::receiveConstQualifier(CompileContext &cc, const SourceLocation &constLoc, Type *type) { VariableSymbol *sym = decl_->sym(); if (sym->isArgument()) { if (!!(sym->storage_flags() & StorageFlags::byref)) { cc.report(constLoc, rmsg::const_ref_has_no_meaning) << type; return true; } if (!type->passesByReference()) { cc.report(constLoc, rmsg::const_has_no_meaning) << type; return true; } } else if (TypeSupportsCompileTimeInterning(type)) { sym->storage_flags() |= StorageFlags::constval; } sym->storage_flags() |= StorageFlags::readonly; return true; }
SemanticAnalysis::SemanticAnalysis(CompileContext &cc, TranslationUnit *unit) : pool_(cc.pool()), cc_(cc), unit_(unit), scope_(unit_->globalScope()), fun_(nullptr), loop_(nullptr), hir_(nullptr), outp_(nullptr) { }
NameResolver::NameResolver(CompileContext &cc) : cc_(cc), pool_(cc.pool()), tr_(cc), layout_scope_(nullptr) { atom_String_ = cc_.add("String"); atom_Float_ = cc_.add("Float"); atom_any_ = cc_.add("any"); atom_Function_ = cc_.add("Function"); atom_bool_ = cc_.add("bool"); }
bool ASTType::resolveType(CompileContext& context, const ASTTypeVariables* ptypevariables) { if ( ptypevariables != NULL ) { const ASTTypeVariable* ptypevariable = ptypevariables->find(mObjectName); if ( ptypevariable != NULL ) { mKind = ASTType::eGeneric; mpTypeVariable = ptypevariable; return true; } } if ( mKind == eObject ) { for ( int index = 0; index < mTypeArguments.size(); index++ ) { if ( !mTypeArguments[index].resolveType(context, ptypevariables) ) { return false; } } mpObjectClass = &context.resolveClass(mObjectName); } else if ( mKind == eArray ) { mpObjectClass = &context.resolveClass(UTEXT("system.InternalArray")); return mpArrayType->resolveType(context, ptypevariables); } else if ( mKind == eString ) { mpObjectClass = &context.resolveClass(UTEXT("system.InternalString")); } return true; }
Analyzer(CompileContext &cc, Comments &comments) : cc_(cc), pool_(cc.pool()), comments_(comments) { atom_name_ = cc_.add("name"); atom_kind_ = cc_.add("kind"); atom_returnType_ = cc_.add("returnType"); atom_type_ = cc_.add("type"); atom_parameters_ = cc_.add("arguments"); atom_doc_start_ = cc_.add("docStart"); atom_doc_end_ = cc_.add("docEnd"); atom_properties_ = cc_.add("properties"); atom_methods_ = cc_.add("methods"); atom_getter_ = cc_.add("getter"); atom_setter_ = cc_.add("setter"); atom_entries_ = cc_.add("entries"); atom_constants_ = cc_.add("constants"); atom_decl_ = cc_.add("decl"); }
// Type Resolution ensures that any type specifier has a bound type, and that // any constant expression has a constant value. // // This pass involves a recursive walk through the AST. Unlike other passes, // it may recursively resolve other unrelated AST nodes. For example, // // typedef A = B; // typedef B = int; // // In order to resolve "A", we will recursively resolve "B". If we have a // recursive type, we have to prevent infintie recursion and report an error. // Recursive types always occur through name resolution, and there are many // patterns in which they can occur. // // ---- CONSTANT RECURSION ---- // // The first form of recursion we're concerned about is 'constant recursion'. // This occurs when resolving a constant expression, it is mutually dependent // on another constant expression. There are a few ways to do this. The first // is via enum values: // // 1: enum X { // 2: A = B, // 3: B, // 4: }; // // On line 2, resolving the type of 'A' depends on resolving 'B'. We cannot // resolve 'B' without knowing the type of 'A'. // // Another form of constant recursion is through constant definitions: // // 1: const int A = B; // 2: const int B = A; // // ---- TYPE RECURSION ---- // // We classify type recursion in two forms. The first is simple type recursion, // when a typedef refers to itself. These cycles are easy to break, and we // break them in visitTypedef() via a placeholder type. An example: // // typedef A = B // typedef B = A // // While visit "A", we will create a blank TypedefType object. We will then // visit B, which will build a TypedefType object wrapping A. Once back in A, // we do a quick check that A does not depend on itself for computing a // canonical type. // // The other form of type recursive is size-dependent types. An easy example of // this in C would be: // // struct X { // X x; // }; // // To allocate a struct we must be able to compute its size. But here, its size // infinitely expands, and so the type is not resolveable. Another case where // this can happen is with the `sizeof` constexpr. For example, // // int X[sizeof(Y)] = 10; // int Y[sizeof(X)] = 20; // // Here, the size of `x` is dependent on computing its own size. We will break // this cycle when calling resolveType for sizeof(X), since we will not have // finished resolving the type of X. In the future, we may be able to reach // something like this through typedefs as well: // // typedef X = int[sizeof(Y)]; // typedef Y = int[sizeof(X)]; // // This cycle would be broken by sizeof() itself, since it checks whether or // not it is trying to compute an unresolved type. // // Types can generally reference themselves as long as they do not create size // dependencies, and in the case of typedefs, as long as we can resolve them to // a canonical type that is not a typedef. // TypeResolver::TypeResolver(CompileContext &cc) : pool_(cc.pool()), cc_(cc) { }