void SymbolCheckVisitor::checkUnknown(const ASTType& type) { if ( type.isUnknown() ) { error(E0051, UTEXT("Unknown class type ") + type.getObjectName(), type.getPosition()); } }
virtual ASTType *getType() { if(type->isArray()) return type; //XXX bit silly? if(alloc == STACK) return type; //else heap alloc return type->getReferenceTy(); }
void CollectCustomTypes_TemplateArguments(bool verbose = false) { auto templateArguments = tools::LINQSelect(allChildren, [](ASTNode* it) { return it->GetType() == ASTNode::Type::TemplateArg; }); for (auto it : templateArguments) { ASTType* itType = (ASTType*)it; if (itType->ToIdentifierString().empty() == false) continue; // template argument does not define a type if (itType->HasModifier(CxxToken::Type::Class) == false && itType->HasModifier(CxxToken::Type::Typename)) continue; // template argument does not have "class" or "typename" auto parents = it->GatherParents(); auto scopes = tools::LINQSelect(parents, [](ASTNode* it) { return it->GetType() == ASTNode::Type::Namespace || it->GetType() == ASTNode::Type::Template || (it->GetType() >= ASTNode::Type::Class && it->GetType() <= ASTNode::Type::Union); }); std::reverse(scopes.begin(), scopes.end()); std::string v; for (auto itScope : scopes) { v.append(itScope->ToString()); v.append("::"); } v.append(itType->ToNameString()); if (verbose) { fprintf(stderr, "CollectCustomType_TemplateArgument: %s\n", v.c_str()); } CollectCustomTypes_Add(v, it); } }
// static ASTType ASTType::greaterType(const ASTType& left, const ASTType& right) { if ( left.greater(right) ) return right; else if ( right.greater(left) ) return left; return ASTType(); }
void SymbolCheckVisitor::visit(ASTArrayInit& ast) { visitChildren(ast); ASTType elementtype = mCurrentType; mCurrentType.setKind(ASTType::eArray); mCurrentType.setArrayType(elementtype.clone()); mCurrentType.setArrayDimension(1); // need to determine the depth of the array! }
bool ASTType::isDerivedFrom(const ASTType& that) const { if ( !isUnknown() && !that.isUnknown() ) { return that.getObjectClass().isBase(getObjectClass()) || that.getObjectClass().isImplementing(getObjectClass()); } return false; }
void ASTType::determineArrayDimension() { mArrayDimension = 1; ASTType* ptype = mpArrayType; while ( ptype->isArray() ) { ptype = ptype->mpArrayType; mArrayDimension++; } }
// static ASTType* ASTType::fromString(const String& type) { std::size_t pos = type.lastIndexOf('['); if ( pos != String::npos ) { String arraytype = type.subStr(0, pos); ASTType* parray = new ASTType(ASTType::eArray); parray->setArrayType(fromString(arraytype)); parray->determineArrayDimension(); return parray; } if ( type == SBool ) { return new ASTType(ASTType::eBoolean); } else if ( type == SInt ) { return new ASTType(ASTType::eInt); } else if ( type == SReal ) { return new ASTType(ASTType::eReal); } else if ( type == SChar ) { return new ASTType(ASTType::eChar); } else if ( type == SString ) { return new ASTType(ASTType::eString); } else if ( type == SVoid ) { return new ASTType(ASTType::eVoid); } else { String value; // todo, what with generics? ASTType::Kind kind = ASTType::eObject; if ( type[0] == '~' ) { kind = ASTType::eGeneric; value = type.subStr(1, type.length() - 1); } else value = type; ASTType* ptype = new ASTType(kind); ptype->setObjectName(value); return ptype; } return NULL; }
void CodeGeneratorVisitor::visit(const ASTCast& ast) { ast.getNode().accept(*this); ASTType from = mCurrentType; mCurrentType = ast.getType(); // add cast instruction if ( mCurrentType.isObject() ) { } else if ( mCurrentType.isArray() ) { } else { switch ( from.getKind() ) { case ASTType::eBoolean: if ( mCurrentType.isString() ) mBuilder.emit(CIL_bconv_str); break; case ASTType::eInt: if ( mCurrentType.isReal() ) mBuilder.emit(CIL_iconv_real); else if ( mCurrentType.isString() ) mBuilder.emit(CIL_iconv_str); break; case ASTType::eReal: if ( mCurrentType.isInt() ) mBuilder.emit(CIL_rconv_int); else if ( mCurrentType.isString() ) mBuilder.emit(CIL_rconv_str); break; case ASTType::eChar: if ( mCurrentType.isString() ) mBuilder.emit(CIL_cconv_str); break; case ASTType::eString: if ( mCurrentType.isBoolean() ) mBuilder.emit(CIL_sconv_bool); else if ( mCurrentType.isInt() ) mBuilder.emit(CIL_sconv_int); else if ( mCurrentType.isReal() ) mBuilder.emit(CIL_rconv_str); break; default: break; } } }
virtual ASTType *getType() { ASTType *lhsty = lhs->getType(); if(lhsty->getPointerElementTy()) { return lhsty->getPointerElementTy(); } if(lhsty->isTuple()) { int ind = index->asInteger(); return lhsty->asTuple()->getMemberType(ind); } //XXX provide type if expression is const and type is struct? return NULL; }
void SymbolCheckVisitor::visit(ASTExpression& ast) { mCurrentType.clear(); ast.getLeft().accept(*this); if ( ast.hasRight() ) { ASTType lefttype = mCurrentType; mCurrentType.clear(); if ( isVariable(ast.getLeft()) ) { ast.getRight().accept(*this); if ( !mCurrentType.greater(lefttype) ) { error(E0020, UTEXT("Invalid type for assignment. Can not assign ") + mCurrentType.toString() + UTEXT(" to ") + lefttype.toString(), ast); } } else { error(E0021, UTEXT("Can only assign to variables."), ast); } } }
void SymbolCheckVisitor::checkCondition(const ASTNode& node, const ASTType& type) { if ( !type.isBoolean() ) { error(E0008, UTEXT("Condition expression must return a boolean value."), node); } }
void SymbolCheckVisitor::visit(ASTForeach& ast) { ScopedScope scope(mScopeStack); ASTVariable& iteratorvar = ast.getIteratorVariable(); ASTVariable& var = ast.getVariable(); if ( var.hasInit() ) { ASTVariableInit& varinit = var.getInit(); varinit.getExpression().accept(*this); ASTClass& iterableclass = mContext.resolveClass(UTEXT("engine.collections.Iterable")); ASTType* piteratortype = new ASTType(); if ( mCurrentType.isObject() ) { if( mCurrentType.getObjectClass().isImplementing(iterableclass) ) { piteratortype->setKind(ASTType::eObject); piteratortype->setObjectClass(iterableclass); } else { error(E0009, UTEXT("Container ") + var.getName() + UTEXT(" must be iterable for use in foreach."), ast); } } else if ( mCurrentType.isArray() ) { piteratortype->setKind(ASTType::eInt); } iteratorvar.setType(piteratortype); } else { error(E0010, UTEXT("Missing required initializer for foreach variable ") + var.getName(), ast); } mpFunction->addLocal(iteratorvar.getType().clone()); mpFunction->addLocal(var.getType().clone()); ScopeVariable* pvariable = ScopeVariable::fromVariable(var); mScopeStack.add(pvariable); ast.getBody().accept(*this); }
Expression *Expression::coerceTo(ASTType *ty) { ASTType *expty = getType(); if(expty->is(ty)) { return this; } if(coercesTo(ty)) { //TODO: note in AST that this is implicit return new CastExpression(ty, this, loc); } emit_message(msg::ERROR, "attempt to coerce expression of type '" + expty->getName() + "' to incompatible type '" + ty->getName() + "'", loc); return NULL; }
//TODO XXX ASTType *DotExpression::getType() { if(rhs == "sizeof" || rhs == "offsetof") { return ASTType::getLongTy(); } ASTType *lhstype = lhs->getType(); if(rhs == "ptr" && lhstype->isArray()) { return lhstype->asArray()->arrayOf->getPointerTy(); } if(rhs == "size" && lhstype->isArray()) { return ASTType::getLongTy(); } //if type is pointer, implicit dereference on dot expression if(lhstype->asPointer()) { lhstype = lhstype->asPointer()->ptrTo; } if(ASTUserType *uty = lhstype->asUserType()) { Identifier *dotid = uty->getDeclaration()->lookup(rhs); if(dotid) return dotid->getType(); } return NULL; }
bool ASTType::equals(const ASTType& that) const { if ( (isObject() || isArray()) && that.isNull() ) { return true; } return mKind == that.mKind && (isObject() ? mpObjectClass == that.mpObjectClass : true); }
virtual std::string asString() { std::stringstream str; if(alloc == STACK) { str << type->getName(); } else { //HEAP str << "new " << type->getName(); } if(call) { str << "("; std::list<Expression*>::iterator it = args.begin(); while(it != args.end()) { str << (*it)->asString(); it++; if(it != args.end()) str << ", "; } str << ")"; } return str.str(); }
void OOCheckVisitor::validateNullConcatenate(ASTConcatenate& concatenate, const ASTType& left, const ASTType& right) { bool haserror = false; if ( left.isNull() ) { haserror = ( !right.isObject() && !right.isArray() ); if ( concatenate.getMode() == ASTConcatenate::eEquals || concatenate.getMode() == ASTConcatenate::eUnequals ) { // swap left/right side so null is always on righthand side (easier for code generation) concatenate.swapSides(); } } else if ( right.isNull() ) { haserror = ( !left.isObject() && !left.isArray() ); } if ( haserror ) { error(E0058, UTEXT("Invalid concatenation with null operator! Only == and != are supported."), concatenate); } }
void Traverse(State* state, ASTNode* node) { bool recurse = true; StructureScope scope; StructureScope* backup; // PRE switch (node->GetType()) { case ASTNode::Type::Root: *state->Data += string_format("namespace reflector {\n"); backup = state->StructScope; state->StructScope = &scope; state->StructScope->Name = "~ROOT~"; break; case ASTNode::Type::File: *state->Data += string_format("// FILE: \"%s\"\n", node->ToString().c_str()); break; case ASTNode::Type::Namespace: *state->Data += string_format("// NAMESPACE: \"%s\"\n", node->ToString().c_str()); break; case ASTNode::Type::Public: state->StructScope->VisibilityType = "Public"; break; case ASTNode::Type::Protected: state->StructScope->VisibilityType = "Protected"; break; case ASTNode::Type::Private: state->StructScope->VisibilityType = "Private"; break; case ASTNode::Type::Class: case ASTNode::Type::Struct: backup = state->StructScope; state->StructScope = &scope; state->StructScope->Name = node->ToString(); break; case ASTNode::Type::DclHead: // recurse these break; case ASTNode::Type::AntFwd: // ignore these case ASTNode::Type::AntBack: case ASTNode::Type::DclSub: recurse = false; break; default: *state->Data += string_format("// UNKNOWN: %s \"%s\"\n", node->GetTypeString(), node->ToString().c_str()); recurse = false; }; // recurse if (recurse) { auto& children = node->Children(); for (size_t i = 0; i < children.size(); i++) { Traverse(state, children[i]); } } // POST switch (node->GetType()) { case ASTNode::Type::DclSub: { ASTType* typeNode = (ASTType*)node; ASTType combined(typeNode->tokenSource); if (typeNode->head != 0) combined = typeNode->CombineWithHead(); else combined.MergeData(typeNode); state->StructScope->Members[Types::Member].push_back(vCount); *state->Data += string_format("StructureMember m_%d = { VisibilityEnum::%s, \"%s\", \"%s\", reflector_offsetof(%s, %s), reflector_sizeof(%s, %s), 1 };\n", vCount++, state->StructScope->VisibilityType, combined.ToIdentifierString().c_str(), combined.ToString(false).c_str(), state->StructScope->Name.c_str(), combined.ToIdentifierString().c_str(), state->StructScope->Name.c_str(), combined.ToIdentifierString().c_str()); recurse = false; break; } case ASTNode::Type::Root: *state->Data += string_format("} // end namespace reflector\n\n"); state->StructScope = backup; break; case ASTNode::Type::File: *state->Data += string_format("// END FILE: \"%s\"\n", node->ToString().c_str()); break; case ASTNode::Type::Class: case ASTNode::Type::Struct: // collect members std::string memberLocation = "0"; if (state->StructScope->Members[Types::Member].size() > 0) { std::string members; for (auto it : state->StructScope->Members[Types::Member]) { members += string_format("&m_%d,", it); } if (members.size() > 0) members.pop_back(); *state->Data += string_format("StructureMember* sm_%d[] = { %s };\n", vCount, members.c_str()); memberLocation = "sm_" + intToString(vCount); } const char* type = "Class"; if (node->GetType() == ASTNode::Type::Struct) type = "Struct"; *state->Data += string_format("Structure s_%d(VisibilityEnum::%s, Structure::Type::%s, \"%s\", %d, %s, 0, 0);\n", vCount++, state->StructScope->VisibilityType, type, node->ToString().c_str(), state->StructScope->Members[Types::Member].size(), memberLocation.c_str()); // return structscope state->StructScope = backup; break; }; }
void SymbolCheckVisitor::visit(ASTConcatenate& ast) { ast.getLeft().accept(*this); ASTType lefttype = mCurrentType; mCurrentType.clear(); ast.getRight().accept(*this); switch ( ast.getMode() ) { case ASTConcatenate::eMul: case ASTConcatenate::eDiv: case ASTConcatenate::eRem: case ASTConcatenate::ePlus: case ASTConcatenate::eMinus: { ASTType righttype = mCurrentType; mCurrentType = ASTType::greaterType(lefttype, righttype); if ( mCurrentType.isValid() ) { // optionally add casts if necessary if ( mCurrentType.isChar() && lefttype.isString() ) { // add char is now allowed directly: // str = str + char <- no casts // str = char + str <- casts char to string break; } if ( !lefttype.equals(mCurrentType) ) { ASTCast* pcast = new ASTCast(); pcast->setType(mCurrentType.clone()); pcast->setNode(ast.useLeft()); ast.setLeft(pcast); } if ( !righttype.equals(mCurrentType) ) { ASTCast* pcast = new ASTCast(); pcast->setType(mCurrentType.clone()); pcast->setNode(ast.useRight()); ast.setRight(pcast); } } else { String op = UTEXT("+"); error(E0022, UTEXT("Can not execute operator ") + op + UTEXT(" on types ") + lefttype.toString() + UTEXT(" and ") + righttype.toString(), ast); } } break; case ASTConcatenate::eBitwiseOr: case ASTConcatenate::eBitwiseXor: case ASTConcatenate::eBitwiseAnd: case ASTConcatenate::eShiftLeft: case ASTConcatenate::eShiftRight: { ASTType righttype = mCurrentType; if ( !lefttype.isInt() || !righttype.isInt() ) { error(E0023, UTEXT("Bitwise operators only operate on int values."), ast); } } break; case ASTConcatenate::eAnd: case ASTConcatenate::eOr: { if ( !lefttype.isBoolean() || !mCurrentType.isBoolean() ) { String op = UTEXT("&&"); // add toString to Mode error(E0024, UTEXT("Operator ") + op + UTEXT(" requires boolean expressions."), ast); } } break; case ASTConcatenate::eEquals: case ASTConcatenate::eUnequals: case ASTConcatenate::eSmallerEqual: case ASTConcatenate::eSmaller: case ASTConcatenate::eGreater: case ASTConcatenate::eGreaterEqual: { ASTType comp = ASTType::greaterType(lefttype, mCurrentType); if ( !comp.isValid() ) { error(E0025, UTEXT("Can not compare ") + lefttype.toString() + UTEXT(" with ") + mCurrentType.toString(), ast); } else if ( ast.getMode() >= ASTConcatenate::eSmallerEqual ) { if ( comp.isObject() || comp.isArray() || comp.isBoolean() ) { error(E0026, UTEXT("Invalid type ") + comp.toString() + UTEXT(" for operator."), ast); } } mCurrentType = ASTType(ASTType::eBoolean); } break; case ASTConcatenate::eInvalid: error(E0001, UTEXT("Invalid compiler state!"), ast); break; } }
void SymbolCheckVisitor::checkFunctionAccess(const ASTClass& klass, ASTAccess& access, bool isstatic) { ASTType before = mCurrentType; ASTSignature signature; ASTNodes& arguments = access.getArguments(); for ( int index = 0; index < arguments.size(); index++ ) { ASTExpression& expr = dynamic_cast<ASTExpression&>(arguments[index]); expr.accept(*this); signature.append(mCurrentType.clone()); } const ASTTypeList* ptypelist = NULL; if ( access.hasTypeArguments() ) ptypelist = &access.getTypeArguments(); else ptypelist = &before.getTypeArguments(); const ASTFunction* pfunction = klass.findBestMatch(access.getName(), signature, *ptypelist); if ( pfunction != NULL ) { const ASTSignature& funcsig = pfunction->getSignature(); // check if cast is required for ( int index = 0; index < signature.size(); index++ ) { const ASTType& type = signature[index]; const ASTType& fnctype = funcsig[index]; if ( !fnctype.isGeneric() && !type.equals(fnctype) ) { ASTCast* pcast = new ASTCast(); pcast->setType(fnctype.clone()); pcast->setNode(&access.getArguments()[index]); access.replaceArgument(index, pcast); } } if ( isstatic && !pfunction->getModifiers().isStatic() ) { error(E0047, UTEXT("Can not call non static function ") + pfunction->getName(), access); } access.setFunction(*pfunction); const ASTType& type = pfunction->getType(); if ( type.isGeneric() ) { const ASTTypeVariable& typevariable = type.getTypeVariable(); mCurrentType = before.getTypeArguments()[typevariable.getIndex()]; } else if ( !type.getTypeArguments().empty() ) { mCurrentType = pfunction->getType(); // if we get a generic type argument, replace it with the actual variable. const ASTType& arg = type.getTypeArguments()[0]; if ( arg.isGeneric() ) { const ASTTypeVariable* pvariable = klass.getTypeVariables().find(arg.getObjectName()); if ( pvariable != NULL ) { mCurrentType.replaceArgument(before.getTypeArguments()[pvariable->getIndex()]); } } } else { mCurrentType = pfunction->getType(); } } else { String arguments = UTEXT("(") + signature.toString() + ')'; error(E0048, UTEXT("No matching function ") + klass.getName() + '.' + access.getName() + arguments + UTEXT(" defined."), access); } }
void ResolveTypes(ASTNode* node, ScopeResolveTypes& tscope, bool verbose=false) { # define LOCATIONINFO " (line %d, source \"%s\").\n" # define LOCATIONINFODATA nodeType->tokenSource->Tokens[nodeType->typeName[0].Index].TokenLine, nodeType->tokenSource->SourceIdentifier() bool isScope = false; ASTType* nodeType = dynamic_cast<ASTType*>(node); if (nodeType && nodeType->HasType() && nodeType->IsBuiltinType() == false) { bool typeNameFromRoot = false; std::string typeName = nodeType->ToNameString(false); if (typeName.size() >= 2 && typeName.at(0) == ':' && typeName.at(1) == ':') { typeNameFromRoot = true; typeName.erase(typeName.begin(), typeName.begin() + 2); } if (verbose) { fprintf(stderr, "RESOLVE "); for (auto it : tscope.usingNamespaces) fprintf(stderr, "{%s} ", it.c_str()); for (auto it : tscope.inScopes) fprintf(stderr, "[%s] ", it->ToString().c_str()); fprintf(stderr, "%s", nodeType->ToNameString().c_str()); } // check if name points directly to node std::string resolvedAs; //if (typeNameFromRoot) { // try to find directly if (resolvedAs.empty()) { auto found = allCustomTypes.find(typeName); if (found != allCustomTypes.end()) { nodeType->resolvedType = found->second; resolvedAs = found->first; } } // go backwards over scopes and try to find that way if (resolvedAs.empty()) { for (int i = tscope.inScopes.size() - 1; i >= 0; i--) { std::string prefix; for (int j = 0; j <= i; j++) prefix += tscope.inScopes[j]->ToString() + "::"; auto found = allCustomTypes.find(prefix + typeName); if (found != allCustomTypes.end()) { nodeType->resolvedType = found->second; resolvedAs = found->first; break; } } } // try finding with "using namespace" if (resolvedAs.empty()) { for (int i = 0; i < tscope.usingNamespaces.size(); i++) { auto found = allCustomTypes.find(tscope.usingNamespaces[i] + "::" + typeName); if (found != allCustomTypes.end()) { if (resolvedAs.empty() == false) fprintf(stderr, "Warning: Ambiguous \"using namespace\" detected during type resolve: \"%s\" could also be \"%s\". Using latter." LOCATIONINFO, resolvedAs.c_str(), found->first.c_str(), LOCATIONINFODATA); nodeType->resolvedType = found->second; resolvedAs = found->first; } } } } if (verbose) fprintf(stderr, " AS \"%s\"\n", resolvedAs.c_str()); if (resolvedAs.empty() && nodeType->GetType() != ASTNode::Type::TemplateArg) fprintf(stderr, "Warning: Type \"%s\" could not be resolved " LOCATIONINFO, typeName.c_str(), LOCATIONINFODATA); # undef LOCATIONINFO # undef LOCATIONINFODATA } // nesting switch (node->GetType()) { case ASTNode::Type::Class: case ASTNode::Type::Struct: case ASTNode::Type::Union: case ASTNode::Type::Namespace: case ASTNode::Type::Template: isScope = true; break; case ASTNode::Type::NamespaceUsing: if (verbose) fprintf(stderr, "USING NAMESPACE %s\n", node->ToString().c_str()); tscope.usingNamespaces.push_back(node->ToString()); return; // has no subchildren } if (isScope) { ScopeResolveTypes subscope = tscope; if (node->GetType() != ASTNode::Type::File) subscope.inScopes.push_back(node); auto& children = node->Children(); for (size_t i = 0; i < children.size(); i++) { ResolveTypes(children[i], subscope, verbose); } } else { auto& children = node->Children(); for (size_t i = 0; i < children.size(); i++) { ResolveTypes(children[i], tscope, verbose); } } }
virtual std::string asString() { return type->getName(); }
void SymbolCheckVisitor::visit(ASTAccess& ast) { const String& name = ast.getName(); bool wasstatic = mStatic; mStatic = false; switch ( ast.getKind() ) { case ASTAccess::eVariable: { if ( mCurrentType.isValid() ) { const ASTClass& aclass = mCurrentType.getObjectClass(); const ASTField* pfield = NULL; if ( wasstatic ) { pfield = aclass.findStatic(name); } else { pfield = aclass.findField(name); // <-- here type of variable can be a generic, so map it to the declaration } if ( pfield != NULL ) { // variable access of reference class const ASTVariable& var = pfield->getVariable(); ast.setAccess(ASTAccess::eRefField); ast.setField(*pfield); const ASTType& type = var.getType(); if ( type.isGeneric() ) { const ASTTypeVariable& typevariable = type.getTypeVariable(); if ( ast.hasTypeArguments() ) { mCurrentType = ast.getTypeArguments()[typevariable.getIndex()]; } else { mCurrentType = mCurrentType.getTypeArguments()[typevariable.getIndex()]; } } else { mCurrentType = type; } } else { error(E0035, UTEXT("Class ") + aclass.getName() + UTEXT(" has no member variable ") + name, ast); } } else { // // local variable const ScopeVariable* pvariable = mScopeStack.find(name); if ( pvariable != NULL ) { const ASTVariable& var = pvariable->getVariable(); ast.setAccess(var.isArgument() ? ASTAccess::eArgument : ASTAccess::eLocal); ast.setVariable(pvariable->getVariable()); mCurrentType = pvariable->getType(); } else { // variable access on own class or local variable ASTField* pfield = mpClass->findField(name); if ( pfield == NULL ) pfield = mpClass->findStatic(name); if ( pfield != NULL ) { const ASTVariable& var = pfield->getVariable(); // if in a function (not the case for member intialization) check if we aren't accessing // none static members from a static function. if ( mpFunction != NULL && (mpFunction->getModifiers().isStatic() && !var.getModifiers().isStatic()) ) { error(E0036, UTEXT("Can not access instance member ") + var.getName(), ast); } // variable access on current class ast.setAccess(ASTAccess::eField); ast.setField(*pfield); mCurrentType = pfield->getVariable().getType(); } else { error(E0037, UTEXT("Identifier ") + name + UTEXT(" is not defined."), ast); } } } if ( wasstatic && !ast.getVariable().getModifiers().isStatic() ) { error(E0038, UTEXT("Can not access non static variable ") + ast.getName() + UTEXT(" from static"), ast); } } break; case ASTAccess::eFunction: { if ( mCurrentType.isValid() ) { switch ( mCurrentType.getKind() ) { case ASTType::eObject: { ASSERT(mCurrentType.hasObjectClass()); const ASTClass& type = mCurrentType.getObjectClass(); checkFunctionAccess(type, ast, wasstatic); } break; case ASTType::eArray: { const ASTClass& arrayclass = mContext.resolveClass(UTEXT("system.InternalArray")); checkFunctionAccess(arrayclass, ast, wasstatic); } break; case ASTType::eString: { const ASTClass& stringclass = mContext.resolveClass(UTEXT("system.InternalString")); checkFunctionAccess(stringclass, ast, wasstatic); } break; case ASTType::eVoid: { error(E0039, UTEXT("Can not invoke a method on a void object."), ast); } break; default: { error(E0040, UTEXT("Can not invoke method on basic types."), ast); } break; } } else { checkFunctionAccess(*mpClass, ast, wasstatic); } } break; case ASTAccess::eArray: { if ( !mCurrentType.isArray() ) { error(E0041, mCurrentType.toString() + UTEXT(" is not an array type."), ast); } else { ast.setAccess(ASTAccess::eArrayAccess); ASTType before = mCurrentType; ASTNodes& arguments = ast.getArguments(); for ( int index = 0; index < arguments.size(); index++ ) { ASTExpression& expr = dynamic_cast<ASTExpression&>(arguments[index]); expr.accept(*this); if ( !mCurrentType.isInt() ) { error(E0042, UTEXT("Array access expression must be of type int."), ast); } } mCurrentType = before.getArrayType(); } } break; case ASTAccess::eStatic: mCurrentType = ast.getStaticType(); mStatic = true; break; case ASTAccess::eClass: { if ( !mCurrentType.isObject() ) { warning(W0002, UTEXT("The class operator currently is only supported for objects."), ast); } if ( !wasstatic ) ast.setAccess(ASTAccess::eField); else ast.setAccess(ASTAccess::eRefField); mCurrentType.clear(); mCurrentType.setKind(ASTType::eObject); mCurrentType.setObjectName(UTEXT("system.Class")); mCurrentType.setObjectClass(mContext.resolveClass(UTEXT("system.Class"))); } break; case ASTAccess::eInvalid: default: { error(E0043, UTEXT("Unknown access detected."), ast); } break; } }
void SymbolCheckVisitor::visit(ASTNew& ast) { switch ( ast.getKind() ) { case ASTNew::eObject: { ASTType before = mCurrentType; ASTSignature signature; ASTNodes& arguments = ast.getArguments(); for ( int index = 0; index < arguments.size(); index++ ) { ASTExpression& expr = dynamic_cast<ASTExpression&>(arguments[index]); expr.accept(*this); signature.append(mCurrentType.clone()); } checkUnknown(ast.getType()); if ( ast.getType().hasObjectClass() ) { const ASTClass& newclass = ast.getType().getObjectClass(); const ASTFunction* pfunction = newclass.findBestMatch(newclass.getName(), signature, before.getTypeArguments()); if ( pfunction == NULL ) { String arguments = UTEXT("(") + signature.toString() + ')'; error(E0029, UTEXT("No matching constructor ") + newclass.getFullName() + arguments + UTEXT(" defined."), ast); } else { ast.setConstructor(*pfunction); } } mCurrentType = ast.getType(); } break; case ASTNew::eArray: { ASTNodes& arguments = ast.getArguments(); for ( int index = 0; index < arguments.size(); index++ ) { ASTExpression& expr = dynamic_cast<ASTExpression&>(arguments[index]); expr.accept(*this); if ( !mCurrentType.isInt() ) { error(E0030, UTEXT("Array size expression should be of type int."), ast); } } mCurrentType = ast.getType(); } break; case ASTNew::eInvalid: error(E0001, UTEXT("Invalid compiler state!"), ast); break; } }
/// \brief Test whether that is greater than this type bool ASTType::greater(const ASTType& that) const { if ( isNull() && (that.isObject() || that.isArray() || that.isString() || that.isGeneric()) ) { return true; } else if ( isObject() && that.isObject() ) { // check if 'that' is a extending or implemented this if ( !(mTypeArguments == that.mTypeArguments) ) { return false; } return getObjectClass().isBase(that.getObjectClass()) || getObjectClass().isImplementing(that.getObjectClass()); } else if ( isArray() && that.isArray() ) { return mpArrayType->equals(*that.mpArrayType) && mArrayDimension == that.mArrayDimension; } else if ( isGeneric() ) { if ( that.isObject() ) { return that.getObjectName() == UTEXT("system.Object"); // object is greater than a generic (its da uber type) } else if ( that.isGeneric() ) { return mObjectName == that.mObjectName; } } else if ( !isObject() && !that.isObject() ) { switch ( that.mKind ) { case eBoolean: return mKind == eBoolean; case eInt: return mKind == eInt; case eReal: return mKind == eInt || mKind == eReal; case eChar: return mKind == eChar; case eString: return mKind == eString || mKind == eInt || mKind == eReal || mKind == eBoolean || mKind == eChar; default: break; } } // no implicit primitive to basic or vs yet return false; }
virtual std::string asString() { return type->getName() + ": " + expression->asString(); }
//TODO: use const char? ASTType *ASTType::getStringTy(Expression *sz) { //ASTType *cchar = ASTType::getCharTy()->getConstTy(); ASTType *cchar = ASTType::getCharTy(); return cchar->getArrayTy(sz); }
void CodeGeneratorVisitor::visit(const ASTAccess& ast) { switch ( ast.getKind() ) { case ASTAccess::eVariable: { switch ( ast.getAccess() ) { case ASTAccess::eField: case ASTAccess::eRefField: { const ASTField& field = ast.getField(); if ( ast.getAccess() == ASTAccess::eField && !field.getVariable().getModifiers().isStatic() ) { // only emit loading this for current fields // with reference the object is already there mBuilder.emit(CIL_ldarg, 0); } handleField(field); } break; case ASTAccess::eArgument: case ASTAccess::eLocal: { const ASTVariable& var = ast.getVariable(); handleVariable(var); } break; default: break; } const ASTType& type = ast.getVariable().getType(); if ( mCurrentType.isValid() && type.isGeneric() ) { const ASTTypeVariable& typevariable = type.getTypeVariable(); if ( ast.getTypeArguments().size() > 0 ) { mCurrentType = ast.getTypeArguments()[typevariable.getIndex()]; } else { mCurrentType = mCurrentType.getTypeArguments()[typevariable.getIndex()]; } } else mCurrentType = type; } break; case ASTAccess::eArray: { // the array object is now on top of the stack mExpr = 1; ASTType before = mCurrentType; // add indices on stack reverseVisitChildren(ast); mBuilder.emit(CIL_ldelem, ast.getArguments().size()); } break; case ASTAccess::eFunction: { const ASTFunction& function = ast.getFunction(); if ( !mCurrentType.isValid() ) { mBuilder.emit(CIL_ldarg, 0); // this } ASTType before = mCurrentType; visitChildren(ast); if ( mWasSuper ) { String name = function.getClass().getFullName() + '.' + function.getPrototype(); mBuilder.emit(CIL_call, name); mWasSuper = false; } else if ( function.getModifiers().isPureNative() ) { const String qualifiedname = function.getClass().getFullName() + '.' + function.getPrototype(); mBuilder.emit(CIL_call_native, qualifiedname); } else if ( function.getModifiers().isStatic() ) // first check for static so native statics are possible as well { String name = (before.isValid() ? before.getObjectClass().getFullName() : mpClass->getFullName()) + '.' + function.getPrototype(); mBuilder.emit(CIL_call, name); } else { if ( before.isObject() && before.getObjectClass().getKind() == ASTClass::eInterface ) { String name = before.getObjectClass().getFullName() + '.' + function.getPrototype(); mBuilder.emit(CIL_call_interface, name); } else { String name = function.getClass().getFullName() + '.' + function.getPrototype(); mBuilder.emit(CIL_call_virt, name); } } const ASTType& type = function.getType(); if ( type.isGeneric() ) { const ASTTypeVariable& typevariable = type.getTypeVariable(); mCurrentType = before.getTypeArguments()[typevariable.getIndex()]; } else mCurrentType = function.getType(); } break; case ASTAccess::eClass: { if ( ast.getAccess() == ASTAccess::eField ) { mBuilder.emit(CIL_ldclass, String::empty()); } else { mBuilder.emit(CIL_ldclass, mCurrentType.getObjectClass().getFullName()); } mCurrentType.clear(); mCurrentType.setKind(ASTType::eObject); mCurrentType.setObjectName(UTEXT("system.Class")); mCurrentType.setObjectClass(mContext.resolveClass(UTEXT("system.Class"))); } break; case ASTAccess::eStatic: { mCurrentType = ast.getStaticType(); // the function/variable access pushes it's own label. } break; case ASTAccess::eInvalid: break; } mpAccess = * }
//TODO: use const char? ASTType *ASTType::getStringTy(unsigned sz) { //ASTType *cchar = ASTType::getCharTy()->getConstTy(); ASTType *cchar = ASTType::getCharTy(); return cchar->getArrayTy(sz); }