Пример #1
0
void SymbolCheckVisitor::checkUnknown(const ASTType& type)
{
   if ( type.isUnknown() )
   {
      error(E0051, UTEXT("Unknown class type ") + type.getObjectName(), type.getPosition());
   }
}
Пример #2
0
    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);
		}
	}
Пример #4
0
// 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();
}
Пример #5
0
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!
}
Пример #6
0
bool ASTType::isDerivedFrom(const ASTType& that) const
{
   if ( !isUnknown() && !that.isUnknown() )
   {
      return that.getObjectClass().isBase(getObjectClass())
          || that.getObjectClass().isImplementing(getObjectClass());
   }

   return false;
}
Пример #7
0
void ASTType::determineArrayDimension()
{
   mArrayDimension = 1;
   ASTType* ptype = mpArrayType;
   while ( ptype->isArray() )
   {
      ptype = ptype->mpArrayType;
      mArrayDimension++;
   }
}
Пример #8
0
// 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;
}
Пример #9
0
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;
      }
   }
}
Пример #10
0
    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;
    }
Пример #11
0
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);
      }
   }
}
Пример #12
0
void SymbolCheckVisitor::checkCondition(const ASTNode& node, const ASTType& type)
{
   if ( !type.isBoolean() )
   {
      error(E0008, UTEXT("Condition expression must return a boolean value."), node);
   }
}
Пример #13
0
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);
}
Пример #14
0
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;
}
Пример #15
0
//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;
}
Пример #16
0
bool ASTType::equals(const ASTType& that) const
{
   if ( (isObject() || isArray()) && that.isNull() )
   {
      return true;
   }

   return mKind == that.mKind
       && (isObject() ? mpObjectClass == that.mpObjectClass : true);
}
Пример #17
0
    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();
    }
Пример #18
0
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);
   }
}
Пример #19
0
	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;
		};


	}
Пример #20
0
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;
   }
}
Пример #21
0
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);
			}
		}
	}
Пример #23
0
 virtual std::string asString() {
     return type->getName();
 }
Пример #24
0
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;
   }
}
Пример #25
0
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;
   }
}
Пример #26
0
/// \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;
}
Пример #27
0
 virtual std::string asString() {
     return type->getName() + ": " + expression->asString();
 }
Пример #28
0
//TODO: use const char?
ASTType *ASTType::getStringTy(Expression *sz) {
    //ASTType *cchar = ASTType::getCharTy()->getConstTy();
    ASTType *cchar = ASTType::getCharTy();
    return cchar->getArrayTy(sz);
}
Пример #29
0
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 = &ast;
}
Пример #30
0
//TODO: use const char?
ASTType *ASTType::getStringTy(unsigned sz) {
    //ASTType *cchar = ASTType::getCharTy()->getConstTy();
    ASTType *cchar = ASTType::getCharTy();
    return cchar->getArrayTy(sz);
}