2013-09-26 15:16:58 -04:00
# include "ASTTransformation.h"
2013-12-31 23:43:49 -06:00
ASTTransformation : : ASTTransformation ( Importer * importerIn ) {
importer = importerIn ;
2014-05-10 19:28:36 -04:00
topScope = NULL ;
2014-06-26 01:45:44 -07:00
//Set up language level reserved identifier scope (only this, right now)
languageLevelReservedWords [ " this " ] . push_back ( new NodeTree < ASTData > ( " identifier " , ASTData ( identifier , Symbol ( " this " , true ) , NULL ) ) ) ;
//Set up language level special scope. (the final scope checked)
2014-03-06 13:13:40 -05:00
//Note the NULL type
2014-06-26 01:45:44 -07:00
languageLevelOperators [ " + " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " + " , true ) , NULL ) ) ) ;
languageLevelOperators [ " - " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " - " , true ) , NULL ) ) ) ;
languageLevelOperators [ " * " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " * " , true ) , NULL ) ) ) ;
languageLevelOperators [ " / " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " / " , true ) , NULL ) ) ) ;
languageLevelOperators [ " % " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " % " , true ) , NULL ) ) ) ;
languageLevelOperators [ " & " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " & " , true ) , NULL ) ) ) ;
languageLevelOperators [ " -- " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " -- " , true ) , NULL ) ) ) ;
languageLevelOperators [ " ++ " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " ++ " , true ) , NULL ) ) ) ;
2014-07-28 01:52:15 -07:00
languageLevelOperators [ " == " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " == " , true ) , new Type ( boolean ) ) ) ) ;
2015-03-16 06:24:59 -04:00
languageLevelOperators [ " != " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " != " , true ) , new Type ( boolean ) ) ) ) ;
2014-07-28 01:52:15 -07:00
languageLevelOperators [ " <= " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " <= " , true ) , new Type ( boolean ) ) ) ) ;
languageLevelOperators [ " >= " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " >= " , true ) , new Type ( boolean ) ) ) ) ;
languageLevelOperators [ " < " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " < " , true ) , new Type ( boolean ) ) ) ) ;
languageLevelOperators [ " > " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " > " , true ) , new Type ( boolean ) ) ) ) ;
languageLevelOperators [ " && " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " && " , true ) , new Type ( boolean ) ) ) ) ;
languageLevelOperators [ " || " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " || " , true ) , new Type ( boolean ) ) ) ) ;
languageLevelOperators [ " ! " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " ! " , true ) , new Type ( boolean ) ) ) ) ;
2014-06-26 01:45:44 -07:00
languageLevelOperators [ " *= " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " *= " , true ) , NULL ) ) ) ;
languageLevelOperators [ " += " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " += " , true ) , NULL ) ) ) ;
languageLevelOperators [ " -= " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " -= " , true ) , NULL ) ) ) ;
languageLevelOperators [ " . " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " . " , true ) , NULL ) ) ) ;
languageLevelOperators [ " -> " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " -> " , true ) , NULL ) ) ) ;
languageLevelOperators [ " [] " ] . push_back ( new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( " [] " , true ) , NULL ) ) ) ;
2013-09-26 15:16:58 -04:00
}
ASTTransformation : : ~ ASTTransformation ( ) {
//
}
2014-05-24 14:04:32 -04:00
//First pass defines all type_defs (objects and ailises)
NodeTree < ASTData > * ASTTransformation : : firstPass ( std : : string fileName , NodeTree < Symbol > * parseTree ) {
NodeTree < ASTData > * translationUnit = new NodeTree < ASTData > ( " translation_unit " , ASTData ( translation_unit ) ) ;
std : : vector < NodeTree < Symbol > * > children = parseTree - > getChildren ( ) ;
importer - > registerAST ( fileName , translationUnit , parseTree ) ; //Register ourselves with the importer.
2014-07-18 08:52:15 -07:00
//This puts us in the scope and the list of ASTs that go through all the passes
2014-05-24 14:04:32 -04:00
2014-06-17 00:10:57 -07:00
//Go through and define all types (type_defs whether they are classes or ailises, as well as including non-instantiated templates)
2014-05-24 14:04:32 -04:00
for ( NodeTree < Symbol > * i : children ) {
if ( i - > getDataRef ( ) - > getName ( ) = = " type_def " ) {
std : : string name ;
if ( i - > getChildren ( ) [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " ) // It's a template
name = concatSymbolTree ( i - > getChildren ( ) [ 1 ] ) ;
else //It's not
name = concatSymbolTree ( i - > getChildren ( ) [ 0 ] ) ;
NodeTree < ASTData > * firstDec = new NodeTree < ASTData > ( " type_def " , ASTData ( type_def , Symbol ( name , true , name ) ) ) ;
//If this is a template, go ahead and set it up. Pass 2 needs templates set up so it can (partially) instantiate them.
//So we give this typedef its name without any template types and make its type template_type, and point to this from node.
//Then, when this template is instantiated, it will run transform on from with the types filled in.
2014-07-18 08:52:15 -07:00
auto typedefChildren = i - > getChildren ( ) ;
if ( typedefChildren [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " ) {
if ( typedefChildren . size ( ) > 2 & & typedefChildren [ 2 ] - > getData ( ) . getName ( ) = = " traits " )
firstDec - > getDataRef ( ) - > valueType = new Type ( template_type , i , parseTraits ( i - > getChildren ( ) [ 2 ] ) ) ;
else
firstDec - > getDataRef ( ) - > valueType = new Type ( template_type , i ) ;
}
else if ( typedefChildren . size ( ) > 1 & & typedefChildren [ 1 ] - > getData ( ) . getName ( ) = = " traits " )
firstDec - > getDataRef ( ) - > valueType = new Type ( firstDec , parseTraits ( i - > getChildren ( ) [ 1 ] ) ) ;
else if ( typedefChildren . size ( ) = = 1 | | typedefChildren [ 1 ] - > getData ( ) . getName ( ) ! = " type " ) //We don't make the type for alises, because the second pass will assign it the type it points to
firstDec - > getDataRef ( ) - > valueType = new Type ( firstDec ) ;
2014-05-24 14:04:32 -04:00
translationUnit - > addChild ( firstDec ) ;
translationUnit - > getDataRef ( ) - > scope [ name ] . push_back ( firstDec ) ;
firstDec - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( translationUnit ) ;
}
}
//Now go through and do all imports
//We do this second so that if an import also imports us, all of our stuff has already been defined
for ( NodeTree < Symbol > * i : children ) {
if ( i - > getDataRef ( ) - > getName ( ) = = " import " ) {
2014-12-19 18:29:33 -05:00
auto importChildren = i - > getChildren ( ) ;
std : : string toImport = concatSymbolTree ( importChildren [ 0 ] ) ;
auto importNode = new NodeTree < ASTData > ( " import " , ASTData ( import , Symbol ( toImport , true ) ) ) ;
translationUnit - > addChild ( importNode ) ;
2014-05-24 14:04:32 -04:00
//Do the imported file too
NodeTree < ASTData > * outsideTranslationUnit = importer - > importFirstPass ( toImport + " .krak " ) ;
translationUnit - > getDataRef ( ) - > scope [ toImport ] . push_back ( outsideTranslationUnit ) ; //Put this transation_unit in the scope as it's files name
2014-12-19 18:29:33 -05:00
// Now go through and handle anything like import asdf: a; or import asdf: a,b; or import asdf: *;
// We do this by looping through the children and adding links to them as the scope in the import node. If it's *, we add the entire translationUnit link.
// Note that import affects scope in two ways:
// (1) The other file's translationUnit is added to our translationUnit's scope under it's name
// (2) The import node's scope contains the nodes indicated by the qualifiers after the import (i.e. the import a:b; or import a:*;)
for ( auto importQualifer : slice ( importChildren , 1 , - 1 ) ) { // Not the first child, that's the name of the file
auto name = concatSymbolTree ( importQualifer ) ;
if ( name = = " * " ) {
std : : vector < NodeTree < ASTData > * > tmp ;
tmp . push_back ( outsideTranslationUnit ) ;
importNode - > getDataRef ( ) - > scope [ " * " ] = tmp ;
} else {
bool found = false ;
for ( auto outsideScopeEntry : outsideTranslationUnit - > getDataRef ( ) - > scope ) {
if ( name = = outsideScopeEntry . first ) {
importNode - > getDataRef ( ) - > scope [ outsideScopeEntry . first ] = outsideScopeEntry . second ;
found = true ;
}
}
// If it's not found yet, put it in as a empty vector for pass 3.
// This makes sure that it does appear in the scope map, which is what we iterate through later.
if ( ! found )
importNode - > getDataRef ( ) - > scope [ name ] = std : : vector < NodeTree < ASTData > * > ( ) ;
}
}
2014-05-24 14:04:32 -04:00
}
}
return translationUnit ;
}
2014-07-18 08:52:15 -07:00
std : : set < std : : string > ASTTransformation : : parseTraits ( NodeTree < Symbol > * traitsNode ) {
std : : set < std : : string > traits ;
//Every other one b/c comma separated
for ( auto i : slice ( traitsNode - > getChildren ( ) , 0 , - 1 , 2 ) )
traits . insert ( concatSymbolTree ( i ) ) ;
return traits ;
}
2014-05-24 14:04:32 -04:00
//Second pass defines data inside objects, outside declaration statements, and function prototypes (since we have type_defs now)
void ASTTransformation : : secondPass ( NodeTree < ASTData > * ast , NodeTree < Symbol > * parseTree ) {
topScope = ast ; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated
std : : vector < NodeTree < Symbol > * > children = parseTree - > getChildren ( ) ;
//Go through and declare data internal to objects as well as all function prototypes (methods and otherwise)
//Note that this pass can instantiate class templates
for ( NodeTree < Symbol > * i : children ) {
if ( i - > getDataRef ( ) - > getName ( ) = = " type_def " ) {
if ( i - > getChildren ( ) [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " ) // It's a template
continue ; //We've already set upt the class templates
std : : vector < NodeTree < Symbol > * > typedefChildren = i - > getChildren ( ) ;
std : : string name = concatSymbolTree ( typedefChildren [ 0 ] ) ;
2014-07-18 08:52:15 -07:00
NodeTree < ASTData > * typeDef = ast - > getDataRef ( ) - > scope [ name ] [ 0 ] ; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations)
2014-05-24 14:04:32 -04:00
2014-07-18 08:52:15 -07:00
//It's an alias. Note that if typedefChildren.size() == 1 it's because its a regular class with no body, i.e. {}
if ( typedefChildren . size ( ) > 1 & & typedefChildren [ 1 ] - > getData ( ) . getName ( ) = = " type " ) {
2014-07-23 02:23:21 -07:00
Type * aliasedType = typeFromTypeNode ( typedefChildren [ 1 ] , ast , std : : map < std : : string , Type * > ( ) ) ;
2014-06-10 00:53:30 -07:00
typeDef - > getDataRef ( ) - > valueType = aliasedType ;
typeDef - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] [ 0 ] = aliasedType - > typeDefinition ; //So that object lookups find the right member. Note that this overrides translation_unit as a parent scope
2014-06-10 23:59:39 -07:00
// std::cout << name << " alias's to " << aliasedType->typeDefinition << std::endl;
// std::cout << "that is " << aliasedType->typeDefinition->getDataRef()->toString() << std::endl;
2014-05-24 14:04:32 -04:00
continue ;
}
//Do the inside of classes here
2014-06-10 00:53:30 -07:00
secondPassDoClassInsides ( typeDef , typedefChildren , std : : map < std : : string , Type * > ( ) ) ;
2014-05-24 14:04:32 -04:00
} else if ( i - > getDataRef ( ) - > getName ( ) = = " function " ) {
//Do prototypes of functions
ast - > addChild ( secondPassFunction ( i , ast , std : : map < std : : string , Type * > ( ) ) ) ;
} else if ( i - > getDataRef ( ) - > getName ( ) = = " declaration_statement " ) {
//Do declaration statements
ast - > addChild ( secondPassDeclaration ( i , ast , std : : map < std : : string , Type * > ( ) ) ) ;
}
}
}
2014-06-10 00:53:30 -07:00
void ASTTransformation : : secondPassDoClassInsides ( NodeTree < ASTData > * typeDef , std : : vector < NodeTree < Symbol > * > typedefChildren , std : : map < std : : string , Type * > templateTypeReplacements ) {
2014-06-09 00:21:38 -07:00
//We pull out this functionality into a new function because this is used in typeFromTypeNode to partially instantiate templates
for ( NodeTree < Symbol > * j : typedefChildren ) {
if ( j - > getDataRef ( ) - > getName ( ) = = " declaration_statement " ) {
//do declaration
2014-06-10 00:53:30 -07:00
typeDef - > addChild ( secondPassDeclaration ( j , typeDef , templateTypeReplacements ) ) ;
2014-06-09 00:21:38 -07:00
} else if ( j - > getDataRef ( ) - > getName ( ) = = " function " ) {
//do member method
2014-06-10 00:53:30 -07:00
typeDef - > addChild ( secondPassFunction ( j , typeDef , templateTypeReplacements ) ) ;
2014-06-09 00:21:38 -07:00
}
}
}
2014-05-24 14:04:32 -04:00
//This function may need to partially instantiate a class template
NodeTree < ASTData > * ASTTransformation : : secondPassDeclaration ( NodeTree < Symbol > * from , NodeTree < ASTData > * scope , std : : map < std : : string , Type * > templateTypeReplacements ) {
2014-06-26 01:45:44 -07:00
//Check here for method call (an error here)
NodeTree < ASTData > * decStmt = new NodeTree < ASTData > ( " declaration_statement " , ASTData ( declaration_statement ) ) ;
2014-05-24 14:04:32 -04:00
std : : string newIdentifierStr = concatSymbolTree ( from - > getChildren ( ) [ 1 ] ) ;
2014-07-23 02:23:21 -07:00
Type * identifierType = typeFromTypeNode ( from - > getChildren ( ) [ 0 ] , scope , templateTypeReplacements ) ;
2014-05-24 14:04:32 -04:00
std : : cout < < " Declaring an identifier " < < newIdentifierStr < < " to be of type " < < identifierType - > toString ( ) < < std : : endl ;
NodeTree < ASTData > * newIdentifier = new NodeTree < ASTData > ( " identifier " , ASTData ( identifier , Symbol ( newIdentifierStr , true ) , identifierType ) ) ;
scope - > getDataRef ( ) - > scope [ newIdentifierStr ] . push_back ( newIdentifier ) ;
decStmt - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
decStmt - > addChild ( newIdentifier ) ;
return decStmt ;
}
//This function may need to partially instantiate a class template
NodeTree < ASTData > * ASTTransformation : : secondPassFunction ( NodeTree < Symbol > * from , NodeTree < ASTData > * scope , std : : map < std : : string , Type * > templateTypeReplacements ) {
//If this is a function template
std : : vector < NodeTree < Symbol > * > children = from - > getChildren ( ) ;
NodeTree < ASTData > * functionDef = NULL ;
std : : string functionName ;
if ( children [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " ) {
functionName = concatSymbolTree ( children [ 2 ] ) ;
functionDef = new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( functionName , true ) , new Type ( template_type , from ) ) ) ;
scope - > getDataRef ( ) - > scope [ functionName ] . push_back ( functionDef ) ;
functionDef - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
2014-07-18 08:52:15 -07:00
std : : map < std : : string , Type * > yetToBeInstantiatedTemplateTypes ; //So that template types (like T) that have not been placed yet are found and given
//a special Type() - baseType = template_type_type
for ( auto i : slice ( children [ 0 ] - > getChildren ( ) , 1 , - 1 , 2 ) ) { //skip commas
if ( i - > getChildren ( ) . size ( ) = = 1 )
yetToBeInstantiatedTemplateTypes [ concatSymbolTree ( i ) ] = new Type ( template_type_type ) ; //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes
else //has traits
yetToBeInstantiatedTemplateTypes [ concatSymbolTree ( i - > getChildren ( ) [ 0 ] ) ] = new Type ( template_type_type , parseTraits ( i - > getChildren ( ) [ 1 ] ) ) ; //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes
}
2015-03-17 21:06:31 -04:00
// Just to see, I don't think templated functions actually need parameters at this point, and we might not have enough info anyway...
2014-07-23 02:23:21 -07:00
auto transChildren = transformChildren ( slice ( children , 3 , - 2 ) , std : : set < int > ( ) , functionDef , std : : vector < Type > ( ) , yetToBeInstantiatedTemplateTypes ) ;
2015-03-17 21:06:31 -04:00
std : : cout < < " Template function " < < functionName < < " has these parameters: " ;
for ( auto i : transChildren )
std : : cout < < " || " < < i - > getDataRef ( ) - > toString ( ) < < " || " ;
std : : cout < < " DoneList " < < std : : endl ;
functionDef - > addChildren ( transChildren ) ;
2014-05-24 14:04:32 -04:00
std : : cout < < " Finished Non-Instantiated Template function " < < functionName < < std : : endl ;
return functionDef ;
}
functionName = concatSymbolTree ( children [ 1 ] ) ;
2014-07-23 02:23:21 -07:00
functionDef = new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( functionName , true ) , typeFromTypeNode ( children [ 0 ] , scope , templateTypeReplacements ) ) ) ;
2014-05-24 14:04:32 -04:00
scope - > getDataRef ( ) - > scope [ functionName ] . push_back ( functionDef ) ;
functionDef - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
//We only do the parameter nodes. We don't do the body yet, as this is the secondPass
2014-07-23 02:23:21 -07:00
auto transChildren = transformChildren ( slice ( children , 2 , - 2 ) , std : : set < int > ( ) , functionDef , std : : vector < Type > ( ) , templateTypeReplacements ) ;
2014-06-09 00:21:38 -07:00
2014-05-24 14:04:32 -04:00
// std::cout << "REGULAR function " << functionName << " has " << transChildren.size() << " parameters: ";
// for (auto i : transChildren)
// std::cout << "||" << i->getDataRef()->toString() << "|| ";
// std::cout << "DoneList" << std::endl;
functionDef - > addChildren ( transChildren ) ;
return functionDef ;
}
2014-06-09 00:21:38 -07:00
2014-05-24 14:04:32 -04:00
//Third pass redoes all imports to import the new function prototypes and identifiers
void ASTTransformation : : thirdPass ( NodeTree < ASTData > * ast ) {
std : : vector < NodeTree < ASTData > * > children = ast - > getChildren ( ) ;
//Go through and do all imports again
for ( NodeTree < ASTData > * i : children ) {
if ( i - > getDataRef ( ) - > type = = import ) {
std : : string toImport = i - > getDataRef ( ) - > symbol . getName ( ) ;
NodeTree < ASTData > * outsideTranslationUnit = importer - > getUnit ( toImport + " .krak " ) ;
//Now add all functions to scope
std : : cout < < " Trying to re-import from " < < toImport < < std : : endl ;
2014-12-19 18:29:33 -05:00
for ( auto j = outsideTranslationUnit - > getDataRef ( ) - > scope . begin ( ) ; j ! = outsideTranslationUnit - > getDataRef ( ) - > scope . end ( ) ; j + + ) {
std : : cout < < " Looking at " < < j - > first < < std : : endl ;
// If we're supposed to import this... (meaning that this name is in the scope already)
if ( i - > getDataRef ( ) - > scope . find ( j - > first ) = = i - > getDataRef ( ) - > scope . end ( ) )
continue ;
std : : cout < < " Looking through " < < j - > first < < std : : endl ;
for ( auto k : j - > second )
if ( k - > getDataRef ( ) - > type = = function | | k - > getDataRef ( ) - > type = = identifier )
std : : cout < < " Copying " < < j - > first < < std : : endl , i - > getDataRef ( ) - > scope [ j - > first ] . push_back ( k ) ;
2014-05-24 14:04:32 -04:00
else
2014-12-19 18:29:33 -05:00
std : : cout < < " Not Copying " < < j - > first < < std : : endl ;
2014-05-24 14:04:32 -04:00
}
}
}
}
//The fourth pass finishes up by doing all function bodies
void ASTTransformation : : fourthPass ( NodeTree < ASTData > * ast , NodeTree < Symbol > * parseTree ) {
topScope = ast ; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated
std : : vector < NodeTree < Symbol > * > children = parseTree - > getChildren ( ) ;
//Go through and finish both regular functions and class methods
//Note that this pass can instantiate class AND function templates
for ( NodeTree < Symbol > * i : children ) {
if ( i - > getDataRef ( ) - > getName ( ) = = " type_def " ) {
if ( i - > getChildren ( ) [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " ) // It's a template
continue ; //We've already set up the class templates
std : : vector < NodeTree < Symbol > * > typedefChildren = i - > getChildren ( ) ;
std : : string name = concatSymbolTree ( typedefChildren [ 0 ] ) ;
NodeTree < ASTData > * typeDef = ast - > getDataRef ( ) - > scope [ name ] [ 0 ] ; //No overloaded types
2014-07-18 08:52:15 -07:00
//It's an alias. Note that typedefChildren.size() can equal one when it's a regular class with an empty body, i.e. {}
if ( typedefChildren . size ( ) > 1 & & typedefChildren [ 1 ] - > getData ( ) . getName ( ) = = " type " )
2014-05-24 14:04:32 -04:00
continue ; //We're done with aliases too
//Do the inside of classes here
for ( NodeTree < Symbol > * j : typedefChildren ) {
if ( j - > getDataRef ( ) - > getName ( ) = = " function " ) {
2014-07-23 02:23:21 -07:00
fourthPassFunction ( j , searchScopeForFunctionDef ( typeDef , j , std : : map < std : : string , Type * > ( ) ) , std : : map < std : : string , Type * > ( ) ) ; //do member method
2014-05-24 14:04:32 -04:00
}
}
} else if ( i - > getDataRef ( ) - > getName ( ) = = " function " ) {
//Do prototypes of functions
if ( i - > getChildren ( ) [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " )
continue ; //We've already set up function templates
2014-07-23 02:23:21 -07:00
fourthPassFunction ( i , searchScopeForFunctionDef ( ast , i , std : : map < std : : string , Type * > ( ) ) , std : : map < std : : string , Type * > ( ) ) ;
2014-05-24 14:04:32 -04:00
}
}
2014-07-23 02:23:21 -07:00
// We do these here, in a loop, so that we can do mututally recursive definitions
// even inside of class templates. As its methods may cause partial instantiation of
// other class templates, we need to do this until the size no longer changes.
std : : vector < NodeTree < ASTData > * > classTemplates ;
int lastSize = 0 ;
while ( lastSize ! = ast - > getDataRef ( ) - > scope . size ( ) ) {
lastSize = ast - > getDataRef ( ) - > scope . size ( ) ;
classTemplates . clear ( ) ;
for ( auto i : ast - > getDataRef ( ) - > scope ) {
if ( i . second [ 0 ] - > getDataRef ( ) - > type = = type_def & & i . second [ 0 ] - > getDataRef ( ) - > valueType - > templateTypeReplacement . size ( ) ) {
classTemplates . push_back ( i . second [ 0 ] ) ;
std : : cout < < " Saving " < < i . second [ 0 ] - > getDataRef ( ) - > toString ( ) < < " to instantiate. " < < std : : endl ;
}
}
for ( auto i : classTemplates ) {
Type * classTemplateType = i - > getDataRef ( ) - > valueType ;
std : : cout < < " Instantiating template " < < i - > getDataRef ( ) - > toString ( ) < < std : : endl ;
for ( NodeTree < Symbol > * j : classTemplateType - > templateDefinition - > getChildren ( ) )
if ( j - > getDataRef ( ) - > getName ( ) = = " function " )
fourthPassFunction ( j , searchScopeForFunctionDef ( i , j , classTemplateType - > templateTypeReplacement ) , classTemplateType - > templateTypeReplacement ) ; //do member method
classTemplateType - > templateTypeReplacement . clear ( ) ; // This template has been fully instantiated, clear it's map so it won't be instantiated again
}
}
2014-05-24 14:04:32 -04:00
}
//This function finds the right AST definition in a scope given its parseTree
2014-07-23 02:23:21 -07:00
NodeTree < ASTData > * ASTTransformation : : searchScopeForFunctionDef ( NodeTree < ASTData > * scope , NodeTree < Symbol > * parseTree , std : : map < std : : string , Type * > templateTypeReplacements ) {
2014-05-24 14:04:32 -04:00
std : : string functionName = concatSymbolTree ( parseTree - > getChildren ( ) [ 1 ] ) ;
std : : vector < Type > types ;
std : : vector < NodeTree < Symbol > * > children = parseTree - > getChildren ( ) ;
//Skipping the initial return type and identifier as well as the final code block
std : : cout < < " \n Searching scope for function def, function is : " < < concatSymbolTree ( children [ 1 ] ) < < " , children size is " < < children . size ( ) < < std : : endl ;
for ( int i = 2 ; i < children . size ( ) - 1 ; i + = 2 ) { //Skip over commas
std : : cout < < " Making type for lookup || " < < concatSymbolTree ( children [ i ] ) < < " || " < < std : : endl ;
2014-07-23 02:23:21 -07:00
Type type = * typeFromTypeNode ( children [ i ] - > getChildren ( ) [ 0 ] , scope , templateTypeReplacements ) ;
2014-05-24 14:04:32 -04:00
std : : cout < < " Type made: " < < type . toString ( ) < < std : : endl ;
types . push_back ( type ) ;
}
2014-07-23 02:23:21 -07:00
std : : cout < < " About to search scope about " < < concatSymbolTree ( children [ 1 ] ) < < std : : endl ;
2014-07-18 08:52:15 -07:00
NodeTree < ASTData > * result = functionLookup ( scope , functionName , types ) ;
2014-05-24 14:04:32 -04:00
std : : cout < < " Done searching scope about " < < concatSymbolTree ( children [ 1 ] ) < < std : : endl ;
return result ;
}
//This function does the function bodies given its start (the prototype)
//It is used in the fourth pass to finish things up
//Note that it may instantiate class OR function templates, which need to be fully instantiated
void ASTTransformation : : fourthPassFunction ( NodeTree < Symbol > * from , NodeTree < ASTData > * functionDef , std : : map < std : : string , Type * > templateTypeReplacements ) {
NodeTree < Symbol > * codeBlock = from - > getChildren ( ) [ from - > getChildren ( ) . size ( ) - 1 ] ;
2014-07-23 02:23:21 -07:00
functionDef - > addChild ( transform ( codeBlock , functionDef , std : : vector < Type > ( ) , templateTypeReplacements ) ) ;
2014-05-24 14:04:32 -04:00
}
2013-10-02 03:15:20 -04:00
NodeTree < ASTData > * ASTTransformation : : transform ( NodeTree < Symbol > * from ) {
2013-12-27 13:05:07 -06:00
//Set up top scope
2014-07-23 02:23:21 -07:00
return transform ( from , NULL , std : : vector < Type > ( ) , std : : map < std : : string , Type * > ( ) ) ;
2013-12-27 13:05:07 -06:00
}
2014-07-23 02:23:21 -07:00
NodeTree < ASTData > * ASTTransformation : : transform ( NodeTree < Symbol > * from , NodeTree < ASTData > * scope , std : : vector < Type > types , std : : map < std : : string , Type * > templateTypeReplacements ) {
2013-10-16 01:43:18 -04:00
Symbol current = from - > getData ( ) ;
std : : string name = current . getName ( ) ;
2014-02-03 11:41:25 -05:00
NodeTree < ASTData > * newNode = NULL ;
2013-10-16 01:43:18 -04:00
std : : vector < NodeTree < Symbol > * > children = from - > getChildren ( ) ;
2013-10-26 11:47:34 -04:00
std : : set < int > skipChildren ;
2014-07-18 08:52:15 -07:00
2014-12-19 18:29:33 -05:00
if ( name = = " identifier " | | name = = " scoped_identifier " ) {
2014-01-19 18:20:52 -05:00
//Make sure we get the entire name
std : : string lookupName = concatSymbolTree ( from ) ;
2014-03-06 13:13:40 -05:00
std : : cout < < " Looking up: " < < lookupName < < std : : endl ;
2014-07-18 08:52:15 -07:00
if ( types . size ( ) ) {
newNode = functionLookup ( scope , lookupName , types ) ;
if ( newNode = = NULL ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " scope lookup error! Could not find " < < lookupName < < " in identifier (functionLookup) " < < std : : endl ;
2014-07-18 08:52:15 -07:00
throw " LOOKUP ERROR: " + lookupName ;
}
} else {
auto possibleMatches = scopeLookup ( scope , lookupName ) ;
if ( ! possibleMatches . size ( ) ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " scope lookup error! Could not find " < < lookupName < < " in identifier (scopeLookup) " < < std : : endl ;
2014-07-18 08:52:15 -07:00
throw " LOOKUP ERROR: " + lookupName ;
}
newNode = possibleMatches [ 0 ] ;
}
2014-12-19 18:29:33 -05:00
return newNode ;
2014-01-07 13:14:58 -05:00
} else if ( name = = " type_def " ) {
2014-01-19 18:20:52 -05:00
//If it is an alisis of a type
2014-05-07 02:33:04 -04:00
std : : string typeAlias ;
2014-05-24 14:04:32 -04:00
std : : cout < < " The scope here at type_def is " < < scope - > getDataRef ( ) - > toString ( ) < < std : : endl ;
2014-01-19 18:20:52 -05:00
if ( children [ 1 ] - > getData ( ) . getName ( ) = = " type " ) {
2014-05-07 02:33:04 -04:00
typeAlias = concatSymbolTree ( children [ 0 ] ) ;
2014-05-24 14:04:32 -04:00
newNode = scope - > getDataRef ( ) - > scope [ typeAlias ] [ 0 ] ; //The node for this type_def has already been made by translation_unit.
//This is done so that types that reference each other can be declared in any order
2014-06-09 00:21:38 -07:00
2014-07-23 02:23:21 -07:00
newNode - > getDataRef ( ) - > valueType = typeFromTypeNode ( children [ 1 ] , scope , templateTypeReplacements ) ;
2014-05-08 01:07:57 -04:00
skipChildren . insert ( 0 ) ; //Don't want any children, it's unnecessary for ailising
skipChildren . insert ( 1 ) ;
2014-01-19 18:20:52 -05:00
} else { //Is a struct or class
2014-05-07 02:33:04 -04:00
Type * objectType = NULL ;
if ( children [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " ) {
typeAlias = concatSymbolTree ( children [ 1 ] ) ;
2014-05-09 02:56:55 -04:00
std : : cout < < " Template Type! " < < std : : endl ;
2014-05-24 14:04:32 -04:00
newNode = scope - > getDataRef ( ) - > scope [ typeAlias ] [ 0 ] ; //The node for this type_def has already been made by translation_unit.
//This is done so that types that reference each other can be declared in any order
// std::cout << "typeAlias is " << typeAlias << " and newNode is " << newNode << std::endl;
2014-05-09 02:56:55 -04:00
//So we give this typedef its name without any template types and make its type template_type, and point to this from node.
//Then, when this template is instantiated, it will run transform on from with the types filled in.
objectType = new Type ( template_type , from ) ;
2014-05-07 02:33:04 -04:00
} else {
typeAlias = concatSymbolTree ( children [ 0 ] ) ;
2014-05-24 14:04:32 -04:00
newNode = scope - > getDataRef ( ) - > scope [ typeAlias ] [ 0 ] ; //The node for this type_def has already been made by translation_unit.
//This is done so that types that reference each other can be declared in any order
2014-06-09 00:21:38 -07:00
2014-05-07 02:33:04 -04:00
objectType = new Type ( newNode ) ;
skipChildren . insert ( 0 ) ; //Identifier lookup will be ourselves, as we just added ourselves to the scope
}
newNode - > getDataRef ( ) - > valueType = objectType ; //Type is self-referential since this is the definition
2014-01-19 18:20:52 -05:00
}
2014-05-24 14:04:32 -04:00
//scope->getDataRef()->scope[typeAlias].push_back(newNode);
2014-03-06 13:13:40 -05:00
newNode - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
2014-05-09 02:56:55 -04:00
//Templates are done here. No need to go farther
if ( children [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " )
return newNode ;
2014-02-03 11:41:25 -05:00
scope = newNode ;
2013-10-16 01:43:18 -04:00
} else if ( name = = " function " ) {
2014-05-15 17:58:41 -04:00
std : : string functionName ;
2014-06-17 00:10:57 -07:00
/*MULTHERE*/ //If this is a function template
2014-05-15 17:58:41 -04:00
if ( children [ 0 ] - > getData ( ) . getName ( ) = = " template_dec " ) {
functionName = concatSymbolTree ( children [ 2 ] ) ;
newNode = new NodeTree < ASTData > ( name , ASTData ( function , Symbol ( functionName , true ) , new Type ( template_type , from ) ) ) ;
scope - > getDataRef ( ) - > scope [ functionName ] . push_back ( newNode ) ;
newNode - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
2014-05-19 20:00:35 -04:00
std : : map < std : : string , Type * > yetToBeInstantiatedTemplateTypes ; //So that template types (like T) that have not been placed yet are found and given
//a special Type() - baseType = template_type_type
2014-06-17 00:10:57 -07:00
for ( auto i : slice ( children [ 0 ] - > getChildren ( ) , 1 , - 1 , 2 ) ) //skip commas
yetToBeInstantiatedTemplateTypes [ concatSymbolTree ( i ) ] = new Type ( template_type_type ) ; //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes
2014-05-19 20:00:35 -04:00
2014-07-23 02:23:21 -07:00
auto transChildren = transformChildren ( slice ( children , 3 , - 2 ) , std : : set < int > ( ) , newNode , types , yetToBeInstantiatedTemplateTypes ) ;
2014-05-19 20:00:35 -04:00
std : : cout < < " Template function " < < functionName < < " has these parameters: " ;
for ( auto i : transChildren )
std : : cout < < " || " < < i - > getDataRef ( ) - > toString ( ) < < " || " ;
std : : cout < < " ??|| " < < std : : endl ;
newNode - > addChildren ( transChildren ) ;
std : : cout < < " Finished Non-Instantiated Template function " < < functionName < < std : : endl ;
2014-05-15 17:58:41 -04:00
return newNode ;
}
functionName = concatSymbolTree ( children [ 1 ] ) ;
2014-12-19 18:29:33 -05:00
for ( auto child : children )
std : : cout < < " Function child: " < < child - > getDataRef ( ) - > toString ( ) < < std : : endl ;
2014-07-23 02:23:21 -07:00
newNode = new NodeTree < ASTData > ( name , ASTData ( function , Symbol ( functionName , true ) , typeFromTypeNode ( children [ 0 ] , scope , templateTypeReplacements ) ) ) ;
2013-10-26 11:47:34 -04:00
skipChildren . insert ( 0 ) ;
skipChildren . insert ( 1 ) ;
2014-03-06 13:13:40 -05:00
scope - > getDataRef ( ) - > scope [ functionName ] . push_back ( newNode ) ;
newNode - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
2013-12-27 13:05:07 -06:00
scope = newNode ;
2014-06-09 00:21:38 -07:00
2014-03-06 13:13:40 -05:00
// auto transChildren = transformChildren(children, skipChildren, scope, types);
// std::cout << functionName << " ";
// for (auto i : transChildren)
// std::cout << "||" << i->getDataRef()->toString() << "|| ";
// std::cout << "??||" << std::endl;
// newNode->addChildren(transChildren);
// return newNode;
2014-06-09 00:21:38 -07:00
2014-05-15 17:58:41 -04:00
std : : cout < < " finished function (kinda, not children) " < < functionName < < std : : endl ;
2013-10-26 11:47:34 -04:00
} else if ( name = = " code_block " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( code_block ) ) ;
2014-03-06 13:13:40 -05:00
newNode - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
2013-12-27 13:05:07 -06:00
scope = newNode ;
2013-10-26 11:47:34 -04:00
} else if ( name = = " typed_parameter " ) {
2013-12-27 13:05:07 -06:00
//newNode = transform(children[1]); //Transform to get the identifier
std : : string parameterName = concatSymbolTree ( children [ 1 ] ) ;
2014-05-15 17:58:41 -04:00
std : : cout < < " Doing typed parameter " < < parameterName < < std : : endl ;
2014-05-07 02:33:04 -04:00
//std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type
2014-07-23 02:23:21 -07:00
newNode = new NodeTree < ASTData > ( " identifier " , ASTData ( identifier , Symbol ( parameterName , true ) , typeFromTypeNode ( children [ 0 ] , scope , templateTypeReplacements ) ) ) ;
2014-03-06 13:13:40 -05:00
scope - > getDataRef ( ) - > scope [ parameterName ] . push_back ( newNode ) ;
newNode - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
2014-05-15 17:58:41 -04:00
std : : cout < < " Done doing typed_parameter " < < parameterName < < std : : endl ;
2013-11-01 02:52:18 -04:00
return newNode ;
2013-12-27 13:05:07 -06:00
} else if ( name = = " boolean_expression " | | name = = " and_boolean_expression " | | name = = " bool_exp " ) {
2013-11-07 22:19:33 -05:00
//If this is an actual part of an expression, not just a premoted term
if ( children . size ( ) > 1 ) {
2014-03-06 13:13:40 -05:00
//We do children first so we can do appropriate scope searching with types (yay operator overloading!)
skipChildren . insert ( 1 ) ;
2014-07-23 02:23:21 -07:00
std : : vector < NodeTree < ASTData > * > transformedChildren = transformChildren ( children , skipChildren , scope , types , templateTypeReplacements ) ;
2014-02-03 11:41:25 -05:00
std : : string functionCallString = concatSymbolTree ( children [ 1 ] ) ;
2014-05-09 02:56:55 -04:00
NodeTree < ASTData > * function = doFunction ( scope , functionCallString , transformedChildren , templateTypeReplacements ) ;
2013-12-27 13:05:07 -06:00
if ( function = = NULL ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " scope lookup error! Could not find " < < functionCallString < < " in boolean stuff " < < std : : endl ;
2014-06-09 00:21:38 -07:00
throw " LOOKUP ERROR: " + functionCallString ;
2013-12-27 13:05:07 -06:00
}
2014-04-27 02:48:57 -04:00
newNode = function ;
// newNode = new NodeTree<ASTData>(functionCallString, ASTData(function_call, function->getDataRef()->valueType));
// newNode->addChild(function); // First child of function call is a link to the function
// newNode->addChildren(transformedChildren);
2013-11-07 22:19:33 -05:00
} else {
2014-01-01 17:29:19 -06:00
//std::cout << children.size() << std::endl;
2013-12-27 13:05:07 -06:00
if ( children . size ( ) = = 0 )
return new NodeTree < ASTData > ( ) ;
2014-07-23 02:23:21 -07:00
return transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ; //Just a promoted term, so do child
2013-11-07 22:19:33 -05:00
}
2013-12-18 18:05:21 -06:00
//Here's the order of ops stuff
2014-07-02 01:18:27 -07:00
} else if ( name = = " expression " | | name = = " shiftand " | | name = = " term " | | name = = " unarad " | | name = = " access_operation " ) {
2013-12-18 18:05:21 -06:00
//If this is an actual part of an expression, not just a premoted child
2013-12-23 01:26:24 -06:00
if ( children . size ( ) > 2 ) {
2014-07-23 02:23:21 -07:00
NodeTree < ASTData > * lhs = transform ( children [ 0 ] , scope , std : : vector < Type > ( ) , templateTypeReplacements ) ; //LHS does not inherit types
2014-03-06 13:13:40 -05:00
NodeTree < ASTData > * rhs ;
2014-05-09 02:56:55 -04:00
if ( name = = " access_operation " ) {
std : : cout < < " lhs is: " < < lhs - > getDataRef ( ) - > toString ( ) < < std : : endl ;
2014-07-23 02:23:21 -07:00
rhs = transform ( children [ 2 ] , lhs - > getDataRef ( ) - > valueType - > typeDefinition , types , templateTypeReplacements ) ; //If an access operation, then the right side will be in the lhs's type's scope
2014-05-09 02:56:55 -04:00
}
2014-03-06 13:13:40 -05:00
else
2014-07-23 02:23:21 -07:00
rhs = transform ( children [ 2 ] , scope , types , templateTypeReplacements ) ;
2014-03-06 13:13:40 -05:00
2013-10-26 15:05:42 -04:00
std : : string functionCallName = concatSymbolTree ( children [ 1 ] ) ;
2014-07-02 01:18:27 -07:00
if ( functionCallName = = " [ " )
functionCallName = " [] " ; //fudge the lookup of brackets because only one is at children[1] (the other is at children[3])
//std::cout << "scope lookup from expression or similar" << std::endl;
2014-03-06 13:13:40 -05:00
std : : vector < NodeTree < ASTData > * > transformedChildren ; transformedChildren . push_back ( lhs ) ; transformedChildren . push_back ( rhs ) ;
2014-05-19 20:00:35 -04:00
newNode = doFunction ( scope , functionCallName , transformedChildren , templateTypeReplacements ) ;
if ( newNode = = NULL ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " scope lookup error! Could not find " < < functionCallName < < " in expression " < < std : : endl ;
2014-06-09 00:21:38 -07:00
throw " LOOKUP ERROR: " + functionCallName ;
2013-12-27 13:05:07 -06:00
}
2014-02-03 11:41:25 -05:00
return newNode ;
//skipChildren.insert(1);
2014-05-15 17:58:41 -04:00
} else if ( children . size ( ) = = 2 ) {
//Is template instantiation
return findOrInstantiateFunctionTemplate ( children , scope , types , templateTypeReplacements ) ;
2013-10-26 15:05:42 -04:00
} else {
2014-07-23 02:23:21 -07:00
return transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ; //Just a promoted child, so do it instead
2013-10-26 11:47:34 -04:00
}
2013-12-23 01:26:24 -06:00
} else if ( name = = " factor " ) { //Do factor here, as it has all the weird unary operators
2014-03-06 13:13:40 -05:00
//If this is an actual part of an expression, not just a premoted child
2013-12-23 01:26:24 -06:00
//NO SUPPORT FOR CASTING YET
2014-05-06 13:54:53 -04:00
std : : string funcName ;
2013-12-23 01:26:24 -06:00
if ( children . size ( ) = = 2 ) {
2014-05-06 13:54:53 -04:00
funcName = concatSymbolTree ( children [ 0 ] ) ;
2014-02-18 21:55:00 -05:00
NodeTree < ASTData > * param ;
2015-03-24 15:47:08 -04:00
// I think this is where we look at pre vs post operators
if ( funcName = = " * " | | funcName = = " & " | | funcName = = " ++ " | | funcName = = " -- " | | funcName = = " + " | | funcName = = " - " | | funcName = = " ! " | | funcName = = " ~ " )
2014-07-23 02:23:21 -07:00
param = transform ( children [ 1 ] , scope , types , templateTypeReplacements ) ;
2013-12-23 01:26:24 -06:00
else
2014-07-23 02:23:21 -07:00
funcName = concatSymbolTree ( children [ 1 ] ) , param = transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ;
2013-12-23 01:26:24 -06:00
2015-03-24 15:47:08 -04:00
std : : cout < < " \t \t \t funcName= " < < funcName < < " param: " < < param - > getDataRef ( ) - > symbol . getName ( ) < < std : : endl ;
2014-01-01 17:29:19 -06:00
//std::cout << "scope lookup from factor" << std::endl;
2014-03-06 13:13:40 -05:00
std : : vector < NodeTree < ASTData > * > transformedChildren ; transformedChildren . push_back ( param ) ;
2014-05-09 02:56:55 -04:00
NodeTree < ASTData > * function = doFunction ( scope , funcName , transformedChildren , templateTypeReplacements ) ;
2015-03-24 15:47:08 -04:00
std : : cout < < " \t \t \t AFTER dofunction= " < < std : : endl ;
2013-12-27 13:05:07 -06:00
if ( function = = NULL ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " scope lookup error! Could not find " < < funcName < < " in factor " < < std : : endl ;
2014-06-09 00:21:38 -07:00
throw " LOOKUP ERROR: " + funcName ;
2013-12-27 13:05:07 -06:00
}
2014-02-18 21:55:00 -05:00
2014-05-06 13:54:53 -04:00
return function ;
2013-12-23 01:26:24 -06:00
} else {
2014-07-23 02:23:21 -07:00
return transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ; //Just a promoted child, so do it instead
2013-12-23 01:26:24 -06:00
}
2013-10-26 11:47:34 -04:00
} else if ( name = = " statement " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( statement ) ) ;
} else if ( name = = " if_statement " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( if_statement ) ) ;
2013-12-18 18:05:21 -06:00
} else if ( name = = " while_loop " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( while_loop ) ) ;
} else if ( name = = " for_loop " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( for_loop ) ) ;
2013-10-26 11:47:34 -04:00
} else if ( name = = " return_statement " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( return_statement ) ) ;
} else if ( name = = " assignment_statement " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( assignment_statement ) ) ;
2013-12-18 18:05:21 -06:00
std : : string assignFuncName = concatSymbolTree ( children [ 1 ] ) ;
if ( assignFuncName = = " = " ) {
2014-07-23 02:23:21 -07:00
newNode - > addChild ( transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ) ;
newNode - > addChild ( transform ( children [ 2 ] , scope , types , templateTypeReplacements ) ) ;
2013-12-18 18:05:21 -06:00
} else {
//For assignments like += or *=, expand the syntatic sugar.
2014-07-23 02:23:21 -07:00
NodeTree < ASTData > * lhs = transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ;
NodeTree < ASTData > * rhs = transform ( children [ 2 ] , scope , types , templateTypeReplacements ) ;
2014-03-06 13:13:40 -05:00
std : : vector < NodeTree < ASTData > * > transformedChildren ; transformedChildren . push_back ( lhs ) ; transformedChildren . push_back ( rhs ) ;
2013-12-27 13:05:07 -06:00
std : : string functionName = assignFuncName . substr ( 0 , 1 ) ;
2014-05-09 02:56:55 -04:00
NodeTree < ASTData > * operatorCall = doFunction ( scope , functionName , transformedChildren , templateTypeReplacements ) ;
2014-04-27 02:48:57 -04:00
if ( operatorCall = = NULL ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " scope lookup error! Could not find " < < functionName < < " in assignment_statement " < < std : : endl ;
2014-06-09 00:21:38 -07:00
throw " LOOKUP ERROR: " + functionName ;
2013-12-27 13:05:07 -06:00
}
2013-12-18 18:05:21 -06:00
newNode - > addChild ( lhs ) ;
2014-04-27 02:48:57 -04:00
newNode - > addChild ( operatorCall ) ;
2013-12-18 18:05:21 -06:00
}
return newNode ;
2013-11-01 02:52:18 -04:00
} else if ( name = = " declaration_statement " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( declaration_statement ) ) ;
2013-12-27 13:05:07 -06:00
// NodeTree<ASTData>* newIdentifier = transform(children[1], scope); //Transform the identifier
// newIdentifier->getDataRef()->valueType = Type(concatSymbolTree(children[0]));//set the type of the identifier
std : : string newIdentifierStr = concatSymbolTree ( children [ 1 ] ) ;
2014-07-23 02:23:21 -07:00
Type * identifierType = typeFromTypeNode ( children [ 0 ] , scope , templateTypeReplacements ) ;
2014-05-09 02:56:55 -04:00
std : : cout < < " Declaring an identifier " < < newIdentifierStr < < " to be of type " < < identifierType - > toString ( ) < < std : : endl ;
2014-01-19 18:20:52 -05:00
NodeTree < ASTData > * newIdentifier = new NodeTree < ASTData > ( " identifier " , ASTData ( identifier , Symbol ( newIdentifierStr , true ) , identifierType ) ) ;
2014-03-06 13:13:40 -05:00
scope - > getDataRef ( ) - > scope [ newIdentifierStr ] . push_back ( newIdentifier ) ;
newNode - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( scope ) ;
2013-11-01 02:52:18 -04:00
newNode - > addChild ( newIdentifier ) ;
2014-05-07 02:33:04 -04:00
2014-06-26 01:45:44 -07:00
if ( children . size ( ) > 2 & & concatSymbolTree ( children [ 2 ] ) = = " . " ) {
//A bit of a special case for declarations - if there's anything after just the normal 1 node declaration, it's either
//an expression that is assigned to the declaration (int a = 4;) or a member call (Object a.constructAThing())
//This code is a simplified version of the code in function_call with respect to access_operation.
//Note that in this case, what is lhs there is our newIdentifier here (the declaration of the left side of the access operation)
auto sliced = slice ( children , 4 , - 1 ) ;
2014-07-23 02:23:21 -07:00
std : : vector < NodeTree < ASTData > * > initPositionFuncParams = transformChildren ( sliced , std : : set < int > ( ) , scope , types , templateTypeReplacements ) ;
NodeTree < ASTData > * rhs = transform ( children [ 3 ] , identifierType - > typeDefinition , mapNodesToTypes ( initPositionFuncParams ) , templateTypeReplacements ) ; //If an access operation, then the right side will be in the lhs's type's scope
2014-06-26 01:45:44 -07:00
std : : vector < NodeTree < ASTData > * > transformedChildren ; transformedChildren . push_back ( newIdentifier ) ; transformedChildren . push_back ( rhs ) ;
NodeTree < ASTData > * accessFuncCall = doFunction ( scope , " . " , transformedChildren , templateTypeReplacements ) ;
accessFuncCall - > getDataRef ( ) - > valueType = rhs - > getDataRef ( ) - > valueType ;
//Now we borrow a bit of code from function_call below to actually use our new accessFuncCall to setup a "initPosition" function call
//that will follow the identifier in this declaration node
std : : string initPosFuncName = newIdentifierStr + " . " + concatSymbolTree ( children [ 3 ] ) ;
NodeTree < ASTData > * initPositionFuncCall = new NodeTree < ASTData > ( initPosFuncName , ASTData ( function_call , Symbol ( initPosFuncName , true ) ) ) ;
initPositionFuncCall - > addChild ( accessFuncCall ) ;
initPositionFuncCall - > getDataRef ( ) - > valueType = accessFuncCall - > getDataRef ( ) - > valueType ;
initPositionFuncCall - > addChildren ( initPositionFuncParams ) ;
newNode - > addChild ( initPositionFuncCall ) ;
return newNode ;
}
2013-11-01 02:52:18 -04:00
skipChildren . insert ( 0 ) ; //These, the type and the identifier, have been taken care of.
skipChildren . insert ( 1 ) ;
2014-07-23 02:23:21 -07:00
newNode - > addChildren ( transformChildren ( children , skipChildren , scope , types , templateTypeReplacements ) ) ;
2014-06-26 01:45:44 -07:00
return newNode ;
} else if ( name = = " if_comp " ) {
2013-12-22 01:34:59 -06:00
newNode = new NodeTree < ASTData > ( name , ASTData ( if_comp ) ) ;
2013-12-27 13:05:07 -06:00
newNode - > addChild ( new NodeTree < ASTData > ( " identifier " , ASTData ( identifier , Symbol ( concatSymbolTree ( children [ 0 ] ) , true ) ) ) ) ;
skipChildren . insert ( 0 ) ; //Don't do the identifier. The identifier lookup will fail. That's why we do it here.
2013-12-22 01:34:59 -06:00
} else if ( name = = " simple_passthrough " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( simple_passthrough ) ) ;
2013-10-26 11:47:34 -04:00
} else if ( name = = " function_call " ) {
2014-01-19 18:20:52 -05:00
std : : string functionCallName = concatSymbolTree ( children [ 0 ] ) ;
2013-10-26 15:05:42 -04:00
newNode = new NodeTree < ASTData > ( functionCallName , ASTData ( function_call , Symbol ( functionCallName , true ) ) ) ;
2014-05-15 17:58:41 -04:00
2014-03-06 13:13:40 -05:00
skipChildren . insert ( 0 ) ;
2014-07-23 02:23:21 -07:00
std : : vector < NodeTree < ASTData > * > transformedChildren = transformChildren ( children , skipChildren , scope , types , templateTypeReplacements ) ;
2014-02-03 11:41:25 -05:00
std : : cout < < " scope lookup from function_call: " < < functionCallName < < std : : endl ;
for ( auto i : children )
std : : cout < < i < < " : " < < i - > getName ( ) < < " : " < < i - > getDataRef ( ) - > getName ( ) < < std : : endl ;
2014-03-06 13:13:40 -05:00
2014-07-23 02:23:21 -07:00
NodeTree < ASTData > * function = transform ( children [ 0 ] , scope , mapNodesToTypes ( transformedChildren ) , templateTypeReplacements ) ;
2014-02-03 11:41:25 -05:00
std : : cout < < " The thing: " < < function < < " : " < < function - > getName ( ) < < std : : endl ;
for ( auto i : function - > getChildren ( ) )
std : : cout < < i - > getName ( ) < < " " ;
std : : cout < < std : : endl ;
2013-12-27 13:05:07 -06:00
newNode - > addChild ( function ) ;
2014-02-18 21:55:00 -05:00
newNode - > getDataRef ( ) - > valueType = function - > getDataRef ( ) - > valueType ;
2014-03-06 13:13:40 -05:00
newNode - > addChildren ( transformedChildren ) ;
return newNode ;
2013-10-26 15:05:42 -04:00
} else if ( name = = " parameter " ) {
2014-07-23 02:23:21 -07:00
return transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ; //Don't need a parameter node, just the value
2013-12-23 01:26:24 -06:00
} else if ( name = = " type " ) {
std : : string theConcat = concatSymbolTree ( from ) ; //We have no symbol, so this will concat our children
2014-07-23 02:23:21 -07:00
newNode = new NodeTree < ASTData > ( name , ASTData ( value , Symbol ( theConcat , true ) , typeFromTypeNode ( from , scope , templateTypeReplacements ) ) ) ;
2013-10-26 15:05:42 -04:00
} else if ( name = = " number " ) {
2014-07-23 02:23:21 -07:00
return transform ( children [ 0 ] , scope , types , templateTypeReplacements ) ;
2013-10-26 15:05:42 -04:00
} else if ( name = = " integer " ) {
2014-01-07 13:14:58 -05:00
newNode = new NodeTree < ASTData > ( name , ASTData ( value , Symbol ( concatSymbolTree ( from ) , true ) , new Type ( integer ) ) ) ;
2014-07-18 08:52:15 -07:00
} else if ( name = = " floating_literal " ) {
std : : string literal = concatSymbolTree ( from ) ;
ValueType type = double_percision ;
if ( literal . back ( ) = = ' f ' ) {
literal = literal . substr ( 0 , literal . length ( ) - 1 ) ;
type = floating ;
} else if ( literal . back ( ) = = ' d ' ) {
literal = literal . substr ( 0 , literal . length ( ) - 1 ) ;
type = double_percision ;
}
newNode = new NodeTree < ASTData > ( name , ASTData ( value , Symbol ( literal , true ) , new Type ( type ) ) ) ;
2014-05-03 20:46:10 -04:00
} else if ( name = = " char " ) { //Is this correct? This might be a useless old thing
2014-01-07 13:14:58 -05:00
newNode = new NodeTree < ASTData > ( name , ASTData ( value , Symbol ( concatSymbolTree ( children [ 0 ] ) , true ) , new Type ( character , 1 ) ) ) ; //Indirection of 1 for array
2013-12-22 01:34:59 -06:00
} else if ( name = = " string " | | name = = " triple_quoted_string " ) {
2014-01-07 13:14:58 -05:00
newNode = new NodeTree < ASTData > ( name , ASTData ( value , Symbol ( concatSymbolTree ( children [ 0 ] ) , true ) , new Type ( character , 1 ) ) ) ; //Indirection of 1 for array
2014-07-28 01:52:15 -07:00
} else if ( name = = " character " ) {
2014-05-03 20:46:10 -04:00
newNode = new NodeTree < ASTData > ( name , ASTData ( value , Symbol ( concatSymbolTree ( children [ 0 ] ) , true ) , new Type ( character , 0 ) ) ) ; //Indirection of 0 for character
2014-07-28 01:52:15 -07:00
} else if ( name = = " bool " ) {
newNode = new NodeTree < ASTData > ( name , ASTData ( value , Symbol ( concatSymbolTree ( children [ 0 ] ) , true ) , new Type ( boolean , 0 ) ) ) ; //Indirection of 0 for character
2014-07-23 02:23:21 -07:00
} else if ( name = = " AmbiguityPackOuter " | | name = = " AmbiguityPackInner " ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " /////////////////////////////////////////////////////////////////////////////// " < < std : : endl ;
std : : cerr < < " Ambigious program when parsed by this grammer! This is a bug, please report it. " < < std : : endl ;
std : : cerr < < " /////////////////////////////////////////////////////////////////////////////// " < < std : : endl ;
2014-07-23 02:23:21 -07:00
throw " Ambigious parse! " ;
} else {
// Should get rid of this eventually. Right now it handles cases like sign, alpha, a comma, etc
2015-03-14 02:50:18 -04:00
std : : cout < < " Unhandled syntax node: " < < name < < std : : endl ;
2013-10-16 01:43:18 -04:00
return new NodeTree < ASTData > ( ) ;
}
2014-03-06 13:13:40 -05:00
//Do all children but the ones we skip
2014-07-23 02:23:21 -07:00
newNode - > addChildren ( transformChildren ( children , skipChildren , scope , types , templateTypeReplacements ) ) ;
2013-10-16 01:43:18 -04:00
return newNode ;
}
2014-03-06 13:13:40 -05:00
//We use this functionality a lot at different places
2014-07-23 02:23:21 -07:00
std : : vector < NodeTree < ASTData > * > ASTTransformation : : transformChildren ( std : : vector < NodeTree < Symbol > * > children , std : : set < int > skipChildren , NodeTree < ASTData > * scope , std : : vector < Type > types , std : : map < std : : string , Type * > templateTypeReplacements ) {
2014-03-06 13:13:40 -05:00
std : : vector < NodeTree < ASTData > * > transformedChildren ;
// In general, iterate through children and do them. Might not do this for all children.
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
if ( skipChildren . find ( i ) = = skipChildren . end ( ) ) {
2014-07-23 02:23:21 -07:00
NodeTree < ASTData > * transChild = transform ( children [ i ] , scope , types , templateTypeReplacements ) ;
2014-03-06 13:13:40 -05:00
if ( transChild - > getDataRef ( ) - > type ) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData.
transformedChildren . push_back ( transChild ) ;
else
delete transChild ;
}
}
return transformedChildren ;
}
2014-05-09 02:56:55 -04:00
//Extract types from already transformed nodes
2014-03-06 13:13:40 -05:00
std : : vector < Type > ASTTransformation : : mapNodesToTypes ( std : : vector < NodeTree < ASTData > * > nodes ) {
std : : vector < Type > types ;
2014-05-05 13:52:12 -04:00
for ( auto i : nodes ) {
std : : cout < < i - > getDataRef ( ) - > toString ( ) < < std : : endl ;
2014-03-06 13:13:40 -05:00
types . push_back ( * ( i - > getDataRef ( ) - > valueType ) ) ;
2014-05-05 13:52:12 -04:00
}
2014-03-06 13:13:40 -05:00
return types ;
}
2014-05-09 02:56:55 -04:00
//Simple way to extract strings from syntax trees. Used often for identifiers, strings, types
2013-10-16 01:43:18 -04:00
std : : string ASTTransformation : : concatSymbolTree ( NodeTree < Symbol > * root ) {
std : : string concatString ;
2013-12-27 13:05:07 -06:00
std : : string ourValue = root - > getDataRef ( ) - > getValue ( ) ;
2013-10-16 01:43:18 -04:00
if ( ourValue ! = " NoValue " )
concatString + = ourValue ;
std : : vector < NodeTree < Symbol > * > children = root - > getChildren ( ) ;
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
2014-06-09 00:21:38 -07:00
concatString + = concatSymbolTree ( children [ i ] ) ;
2013-10-16 01:43:18 -04:00
}
return concatString ;
2013-09-26 15:16:58 -04:00
}
2013-12-27 13:05:07 -06:00
2014-05-09 02:56:55 -04:00
//We pass in the actual children (parameters) to allow us to handle overloaded operator methods (where a parameter is actually the scope of the method)
NodeTree < ASTData > * ASTTransformation : : doFunction ( NodeTree < ASTData > * scope , std : : string lookup , std : : vector < NodeTree < ASTData > * > nodes , std : : map < std : : string , Type * > templateTypeReplacements ) {
2014-06-26 01:45:44 -07:00
auto LLElementIterator = languageLevelOperators . find ( lookup ) ;
2014-04-27 02:48:57 -04:00
NodeTree < ASTData > * newNode ;
2014-06-26 01:45:44 -07:00
if ( LLElementIterator ! = languageLevelOperators . end ( ) ) {
2014-03-14 15:55:45 -04:00
std : : cout < < " Checking for early method level operator overload " < < std : : endl ;
std : : string lookupOp = " operator " + lookup ;
for ( auto i : nodes )
std : : cout < < i - > getDataRef ( ) - > toString ( ) < < " " ;
std : : cout < < std : : endl ;
NodeTree < ASTData > * operatorMethod = NULL ;
if ( nodes [ 0 ] - > getDataRef ( ) - > valueType & & nodes [ 0 ] - > getDataRef ( ) - > valueType - > typeDefinition )
2014-07-18 08:52:15 -07:00
operatorMethod = functionLookup ( nodes [ 0 ] - > getDataRef ( ) - > valueType - > typeDefinition , lookupOp , mapNodesToTypes ( slice ( nodes , 1 , - 1 ) ) ) ;
2014-03-14 15:55:45 -04:00
if ( operatorMethod ) {
2014-06-09 00:21:38 -07:00
//Ok, so we construct
2014-03-14 15:55:45 -04:00
std : : cout < < " Early method level operator was found " < < std : : endl ;
//return operatorMethod;
2014-04-27 02:48:57 -04:00
NodeTree < ASTData > * newNode = new NodeTree < ASTData > ( lookupOp , ASTData ( function_call , Symbol ( lookupOp , true ) ) ) ;
NodeTree < ASTData > * dotFunctionCall = new NodeTree < ASTData > ( " . " , ASTData ( function_call , Symbol ( " . " , true ) ) ) ;
2014-06-26 01:45:44 -07:00
dotFunctionCall - > addChild ( languageLevelOperators [ " . " ] [ 0 ] ) ; //function definition
2014-04-27 02:48:57 -04:00
dotFunctionCall - > addChild ( nodes [ 0 ] ) ; // The object whose method we're calling
dotFunctionCall - > addChild ( operatorMethod ) ; //The method we're calling
newNode - > addChild ( dotFunctionCall ) ; // First child of function call is a link to the function definition
newNode - > addChildren ( slice ( nodes , 1 , - 1 ) ) ; //The rest of the parameters to the operator
2014-03-14 15:55:45 -04:00
//Set the value of this function call
2014-04-27 02:48:57 -04:00
newNode - > getDataRef ( ) - > valueType = operatorMethod - > getDataRef ( ) - > valueType ;
return newNode ;
2014-03-14 15:55:45 -04:00
}
std : : cout < < " Early method level operator was NOT found " < < std : : endl ;
}
2014-06-09 00:21:38 -07:00
2014-04-27 02:48:57 -04:00
newNode = new NodeTree < ASTData > ( lookup , ASTData ( function_call , Symbol ( lookup , true ) ) ) ;
2014-07-18 08:52:15 -07:00
NodeTree < ASTData > * function = functionLookup ( scope , lookup , mapNodesToTypes ( nodes ) ) ;
2015-03-14 16:53:00 -04:00
std : : cout < < " Num of newNode children " < < newNode - > getChildren ( ) . size ( ) < < std : : endl ;
2014-04-27 02:48:57 -04:00
newNode - > addChild ( function ) ;
2015-03-14 16:53:00 -04:00
std : : cout < < " Num of newNode children " < < newNode - > getChildren ( ) . size ( ) < < std : : endl ;
2014-04-27 02:48:57 -04:00
newNode - > addChildren ( nodes ) ;
2015-03-14 16:53:00 -04:00
std : : cout < < " Num of newNode children " < < newNode - > getChildren ( ) . size ( ) < < std : : endl ;
std : : cout < < " nodes " < < nodes . size ( ) < < std : : endl ;
2014-05-05 13:52:12 -04:00
//Specially handle dereference and address of to assign the correct type
//We need some significant other type corrections here, maybe to the point of being their own function. (int + float, etc.)
2015-03-14 16:53:00 -04:00
std : : cout < < " the passed in nodes " < < std : : endl ;
2014-05-05 13:52:12 -04:00
for ( auto i : nodes )
std : : cout < < i - > getDataRef ( ) - > toString ( ) < < " " ;
std : : cout < < std : : endl ;
2015-03-14 16:53:00 -04:00
2014-05-05 13:52:12 -04:00
std : : vector < Type > oldTypes = mapNodesToTypes ( nodes ) ;
2015-03-14 16:53:00 -04:00
std : : cout < < " the oldtypes size " < < oldTypes . size ( ) < < std : : endl ;
2014-05-19 20:00:35 -04:00
if ( ( nodes . size ( ) ! = 2 & & lookup = = " * " ) | | lookup = = " & " | | lookup = = " [] " ) {
2014-05-05 13:52:12 -04:00
Type * newType = oldTypes [ 0 ] . clone ( ) ;
2014-05-19 20:00:35 -04:00
if ( lookup = = " * " | | lookup = = " [] " )
newType - > decreaseIndirection ( ) ;
2014-05-20 23:53:19 -04:00
else
newType - > increaseIndirection ( ) ;
2014-05-19 20:00:35 -04:00
2014-07-06 23:42:25 -07:00
newNode - > getDataRef ( ) - > valueType = newType , std : : cout < < " Operator " + lookup < < " is altering indirection from " < < oldTypes [ 0 ] . toString ( ) < < " to " < < newType - > toString ( ) < < std : : endl ;
2014-05-05 13:52:12 -04:00
} else {
newNode - > getDataRef ( ) - > valueType = function - > getDataRef ( ) - > valueType , std : : cout < < " Some other || " < < lookup < < " || " < < std : : endl ;
}
2015-03-24 15:47:08 -04:00
// Set the value of this function call if it has not already been set
// It's important that it's the last parameter, the rhs if it has one
// because of the . operator, etc
if ( newNode - > getDataRef ( ) - > valueType = = NULL ) {
std : : cout < < " The value type from doFunction was null! (for " < < lookup < < " ) " < < std : : endl ;
newNode - > getDataRef ( ) - > valueType = oldTypes [ oldTypes . size ( ) - 1 ] . clone ( ) ;
std : : cout < < " function call to " < < lookup < < " - " < < newNode - > getName ( ) < < " is now " < < newNode - > getDataRef ( ) - > valueType < < std : : endl ;
}
2014-04-27 02:48:57 -04:00
return newNode ;
2014-03-14 15:55:45 -04:00
}
2014-07-18 08:52:15 -07:00
//Lookup a function that takes in parameters matching the types passed in
NodeTree < ASTData > * ASTTransformation : : functionLookup ( NodeTree < ASTData > * scope , std : : string lookup , std : : vector < Type > types ) {
2014-06-26 01:45:44 -07:00
//We first check to see if it's one of the special reserved identifiers (only this, for now) and return early if it is.
auto LLElementIterator = languageLevelReservedWords . find ( lookup ) ;
if ( LLElementIterator ! = languageLevelReservedWords . end ( ) ) {
std : : cout < < " found it at language level as reserved word. " < < std : : endl ;
return LLElementIterator - > second [ 0 ] ;
}
//We search the languageLevelOperators to see if it's an operator. If so, we modifiy the lookup with a preceding "operator"
LLElementIterator = languageLevelOperators . find ( lookup ) ;
if ( LLElementIterator ! = languageLevelOperators . end ( ) )
2014-03-14 15:55:45 -04:00
lookup = " operator " + lookup ;
2014-05-09 02:56:55 -04:00
2014-07-18 08:52:15 -07:00
//Look up the name
std : : vector < NodeTree < ASTData > * > possibleMatches = scopeLookup ( scope , lookup ) ;
std : : cout < < " Function lookup of " < < lookup < < " has " < < possibleMatches . size ( ) < < " possible matches. " < < std : : endl ;
if ( possibleMatches . size ( ) ) {
for ( auto i : possibleMatches ) {
//We're not looking for types
if ( i - > getDataRef ( ) - > type = = type_def )
continue ;
2014-05-24 14:04:32 -04:00
2014-07-18 08:52:15 -07:00
std : : vector < NodeTree < ASTData > * > children = i - > getChildren ( ) ;
2014-05-21 01:20:39 -04:00
//We subtract one from the children to get the type size only if there is at least one child AND
// the last node is actually a body node, as it may not have been generated yet if we're in the body
//and this function is recursive or if this is a non-instantiated template function
2014-12-19 18:29:33 -05:00
int numTypes = ( children . size ( ) > 0 & & children [ children . size ( ) - 1 ] - > getDataRef ( ) - > type = = code_block ) ? children . size ( ) - 1 : children . size ( ) ;
if ( types . size ( ) ! = numTypes ) {
std : : cout < < " Type sizes do not match between two " < < lookup < < " ( " < < types . size ( ) < < " , " < < numTypes < < " ), types are: " ;
2014-03-06 13:13:40 -05:00
for ( auto j : types )
std : : cout < < j . toString ( ) < < " " ;
std : : cout < < std : : endl ;
2014-12-19 18:29:33 -05:00
std : : cout < < " Versus " < < std : : endl ;
for ( int j = 0 ; j < numTypes ; j + + ) {
std : : cout < < " vs " < < children [ j ] - > getDataRef ( ) - > valueType - > toString ( ) < < std : : endl ;
}
for ( auto child : children )
std : : cout < < " \t " < < child - > getDataRef ( ) - > toString ( ) < < std : : endl ;
std : : cout < < std : : endl ;
2014-03-06 13:13:40 -05:00
continue ;
}
bool typesMatch = true ;
for ( int j = 0 ; j < types . size ( ) ; j + + ) {
2014-05-19 20:00:35 -04:00
Type * tmpType = children [ j ] - > getDataRef ( ) - > valueType ;
//Don't worry if types don't match if it's a template type
2014-05-24 14:04:32 -04:00
// std::cout << "Checking for segfaults, we have" << std::endl;
// std::cout << types[j].toString() << std::endl;
// std::cout << tmpType->toString() << std::endl;
// std::cout << "Done!" << std::endl;
2014-05-19 20:00:35 -04:00
if ( types [ j ] ! = * tmpType & & tmpType - > baseType ! = template_type_type ) {
2014-03-06 13:13:40 -05:00
typesMatch = false ;
2014-05-19 20:00:35 -04:00
std : : cout < < " Types do not match between two " < < lookup < < " " < < types [ j ] . toString ( ) ;
std : : cout < < " vs " < < children [ j ] - > getDataRef ( ) - > valueType - > toString ( ) < < std : : endl ;
2014-03-06 13:13:40 -05:00
break ;
}
}
if ( typesMatch )
2014-07-18 08:52:15 -07:00
return i ;
2014-03-06 13:13:40 -05:00
}
2013-12-27 13:05:07 -06:00
}
2014-03-06 13:13:40 -05:00
2014-07-18 08:52:15 -07:00
std : : cout < < " could not find " < < lookup < < " in standard scopes, checking for operator " < < std : : endl ;
2014-03-06 13:13:40 -05:00
//Note that we don't check for types. At some point we should, as we don't know how to add objects/structs without overloaded operators, etc
2014-03-14 15:55:45 -04:00
//Also, we've already searched for the element because this is also how we keep track of operator overloading
2014-06-26 01:45:44 -07:00
if ( LLElementIterator ! = languageLevelOperators . end ( ) ) {
2014-03-06 13:13:40 -05:00
std : : cout < < " found it at language level as operator. " < < std : : endl ;
2014-03-14 15:55:45 -04:00
return LLElementIterator - > second [ 0 ] ;
2014-03-06 13:13:40 -05:00
}
2014-03-14 15:55:45 -04:00
std : : cout < < " Did not find, returning NULL " < < std : : endl ;
2014-07-18 08:52:15 -07:00
return NULL ;
}
2014-07-20 14:21:41 -07:00
//Lookup class templates. It evaluates possible matches on traits
NodeTree < ASTData > * ASTTransformation : : templateClassLookup ( NodeTree < ASTData > * scope , std : : string lookup , std : : vector < Type * > templateInstantiationTypes ) {
2015-01-07 03:03:14 -05:00
std : : set < NodeTree < ASTData > * > mostFittingTemplates ;
2014-07-20 14:21:41 -07:00
int bestNumTraitsSatisfied = - 1 ;
auto possibleMatches = scopeLookup ( scope , lookup ) ;
std : : cout < < " Template Class instantiation has " < < possibleMatches . size ( ) < < " possible matches. " < < std : : endl ;
for ( auto i : possibleMatches ) {
NodeTree < Symbol > * templateSyntaxTree = i - > getDataRef ( ) - > valueType - > templateDefinition ;
auto nameTraitsPairs = makeTemplateNameTraitPairs ( templateSyntaxTree - > getChildren ( ) [ 0 ] ) ;
//Check if sizes match between the placeholder and actual template types
if ( nameTraitsPairs . size ( ) ! = templateInstantiationTypes . size ( ) )
continue ;
bool traitsEqual = true ;
int typeIndex = 0 ;
int currentTraitsSatisfied = 0 ;
for ( auto j : nameTraitsPairs ) {
2014-07-23 02:23:21 -07:00
if ( ! subset ( j . second , templateInstantiationTypes [ typeIndex ] - > traits ) ) {
2014-07-20 14:21:41 -07:00
traitsEqual = false ;
2014-07-23 02:23:21 -07:00
std : : cout < < " Traits not subset for " < < j . first < < " and " < < templateInstantiationTypes [ typeIndex ] - > toString ( ) < < " : " ;
2014-07-20 14:21:41 -07:00
//std::cout << baseType << " " << indirection << " " << typeDefinition << " " << templateDefinition << " " << traits << ;
std : : copy ( j . second . begin ( ) , j . second . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < " vs " ;
std : : copy ( templateInstantiationTypes [ typeIndex ] - > traits . begin ( ) , templateInstantiationTypes [ typeIndex ] - > traits . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < std : : endl ;
break ;
2014-07-23 02:23:21 -07:00
} else {
std : : cout < < " Traits ARE subset for " < < j . first < < " and " < < templateInstantiationTypes [ typeIndex ] - > toString ( ) < < " : " ;
//std::cout << baseType << " " << indirection << " " << typeDefinition << " " << templateDefinition << " " << traits << ;
std : : copy ( j . second . begin ( ) , j . second . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < " vs " ;
std : : copy ( templateInstantiationTypes [ typeIndex ] - > traits . begin ( ) , templateInstantiationTypes [ typeIndex ] - > traits . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < std : : endl ;
2014-07-20 14:21:41 -07:00
}
2014-07-23 02:23:21 -07:00
currentTraitsSatisfied + = j . second . size ( ) ;
2014-07-20 14:21:41 -07:00
typeIndex + + ;
}
if ( ! traitsEqual )
continue ;
//See if this is a better match than the current best
if ( currentTraitsSatisfied > bestNumTraitsSatisfied ) {
mostFittingTemplates . clear ( ) ;
std : : cout < < " Class satisfying " < < currentTraitsSatisfied < < " beats previous " < < bestNumTraitsSatisfied < < std : : endl ;
bestNumTraitsSatisfied = currentTraitsSatisfied ;
} else if ( currentTraitsSatisfied < bestNumTraitsSatisfied )
continue ;
2015-01-07 03:03:14 -05:00
mostFittingTemplates . insert ( i ) ;
2014-07-20 14:21:41 -07:00
std : : cout < < " Current class fits, satisfying " < < currentTraitsSatisfied < < " traits " < < std : : endl ;
}
if ( ! mostFittingTemplates . size ( ) ) {
std : : cout < < " No template classes fit for " < < lookup < < " ! " < < std : : endl ;
throw " No matching template classes " ;
} else if ( mostFittingTemplates . size ( ) > 1 ) {
std : : cout < < " Multiple template classes fit with equal number of traits satisfied for " < < lookup < < " ! " < < std : : endl ;
throw " Multiple matching template classes " ;
}
2015-01-07 03:03:14 -05:00
return * mostFittingTemplates . begin ( ) ;
2014-07-20 14:21:41 -07:00
}
2014-07-18 08:52:15 -07:00
//Lookup function for template functions. It has some extra concerns compared to function lookup, namely traits
NodeTree < ASTData > * ASTTransformation : : templateFunctionLookup ( NodeTree < ASTData > * scope , std : : string lookup , std : : vector < Type * > templateInstantiationTypes , std : : vector < Type > types ) {
2015-01-07 03:03:14 -05:00
std : : set < NodeTree < ASTData > * > mostFittingTemplates ;
2014-07-18 08:52:15 -07:00
int bestNumTraitsSatisfied = - 1 ;
auto possibleMatches = scopeLookup ( scope , lookup ) ;
std : : cout < < " Template Function instantiation has " < < possibleMatches . size ( ) < < " possible matches. " < < std : : endl ;
2014-07-20 14:21:41 -07:00
int index = 1 ;
2014-07-18 08:52:15 -07:00
for ( auto i : possibleMatches ) {
2014-07-20 14:21:41 -07:00
std : : cout < < " Possibility " < < index + + < < std : : endl ;
2014-07-18 08:52:15 -07:00
NodeTree < Symbol > * templateSyntaxTree = i - > getDataRef ( ) - > valueType - > templateDefinition ;
2014-07-20 20:42:26 -07:00
if ( ! templateSyntaxTree ) {
std : : cout < < " Not a template, skipping " < < std : : endl ;
continue ;
}
2014-07-18 08:52:15 -07:00
2014-07-20 14:21:41 -07:00
auto nameTraitsPairs = makeTemplateNameTraitPairs ( templateSyntaxTree - > getChildren ( ) [ 0 ] ) ;
2014-07-18 08:52:15 -07:00
//Check if sizes match between the placeholder and actual template types
if ( nameTraitsPairs . size ( ) ! = templateInstantiationTypes . size ( ) )
continue ;
std : : map < std : : string , Type * > typeMap ;
bool traitsEqual = true ;
int typeIndex = 0 ;
int currentTraitsSatisfied = 0 ;
for ( auto j : nameTraitsPairs ) {
2014-07-23 02:23:21 -07:00
if ( ! subset ( j . second , templateInstantiationTypes [ typeIndex ] - > traits ) ) {
2014-07-18 08:52:15 -07:00
traitsEqual = false ;
2014-07-23 02:23:21 -07:00
std : : cout < < " Traits not a subset for " < < j . first < < " and " < < templateInstantiationTypes [ typeIndex ] - > toString ( ) < < " : " ;
2014-07-18 08:52:15 -07:00
std : : copy ( j . second . begin ( ) , j . second . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < " vs " ;
std : : copy ( templateInstantiationTypes [ typeIndex ] - > traits . begin ( ) , templateInstantiationTypes [ typeIndex ] - > traits . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < std : : endl ;
break ;
2014-07-23 02:23:21 -07:00
} else {
std : : cout < < " Traits ARE a subset for " < < j . first < < " and " < < templateInstantiationTypes [ typeIndex ] - > toString ( ) < < " : " ;
std : : copy ( j . second . begin ( ) , j . second . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < " vs " ;
std : : copy ( templateInstantiationTypes [ typeIndex ] - > traits . begin ( ) , templateInstantiationTypes [ typeIndex ] - > traits . end ( ) , std : : ostream_iterator < std : : string > ( std : : cout , " " ) ) ;
std : : cout < < std : : endl ;
2014-07-18 08:52:15 -07:00
}
//As we go, build up the typeMap for when we transform the parameters for parameter checking
typeMap [ j . first ] = templateInstantiationTypes [ typeIndex ] ;
2014-07-23 02:23:21 -07:00
currentTraitsSatisfied + = j . second . size ( ) ;
2014-07-18 08:52:15 -07:00
typeIndex + + ;
}
if ( ! traitsEqual )
continue ;
std : : vector < NodeTree < Symbol > * > functionParameters = slice ( templateSyntaxTree - > getChildren ( ) , 3 , - 2 , 2 ) ; //skip template, return type, name, intervening commas, and the code block
std : : cout < < functionParameters . size ( ) < < " " < < types . size ( ) < < std : : endl ;
if ( functionParameters . size ( ) ! = types . size ( ) )
continue ;
bool parameterTypesMatch = true ;
for ( int j = 0 ; j < functionParameters . size ( ) ; j + + ) {
2014-07-23 02:23:21 -07:00
auto paramType = typeFromTypeNode ( functionParameters [ j ] - > getChildren ( ) [ 0 ] , scope , typeMap ) ;
2014-07-18 08:52:15 -07:00
std : : cout < < " Template param type: " < < paramType - > toString ( ) < < " : Needed Type: " < < types [ j ] . toString ( ) < < std : : endl ;
if ( * paramType ! = types [ j ] ) {
parameterTypesMatch = false ;
2014-07-20 14:21:41 -07:00
std : : cout < < " Not equal template param: " < < paramType - > toString ( ) < < " : Needed Type actual param: " < < types [ j ] . toString ( ) < < std : : endl ;
2014-07-18 08:52:15 -07:00
break ;
}
}
if ( ! parameterTypesMatch )
continue ;
//See if this is a better match than the current best
if ( currentTraitsSatisfied > bestNumTraitsSatisfied ) {
mostFittingTemplates . clear ( ) ;
std : : cout < < " Function satisfying " < < currentTraitsSatisfied < < " beats previous " < < bestNumTraitsSatisfied < < std : : endl ;
bestNumTraitsSatisfied = currentTraitsSatisfied ;
} else if ( currentTraitsSatisfied < bestNumTraitsSatisfied )
continue ;
2015-01-07 03:03:14 -05:00
mostFittingTemplates . insert ( i ) ;
2014-07-18 08:52:15 -07:00
std : : cout < < " Current function fits, satisfying " < < currentTraitsSatisfied < < " traits " < < std : : endl ;
}
if ( ! mostFittingTemplates . size ( ) ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " No template functions fit for " < < lookup < < " ! " < < std : : endl ;
2014-07-18 08:52:15 -07:00
throw " No matching template functions " ;
} else if ( mostFittingTemplates . size ( ) > 1 ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " Multiple template functions fit with equal number of traits satisfied for " < < lookup < < " ! " < < std : : endl ;
2014-07-18 08:52:15 -07:00
throw " Multiple matching template functions " ;
}
2015-01-07 03:03:14 -05:00
return * mostFittingTemplates . begin ( ) ;
2014-07-18 08:52:15 -07:00
}
//Extract pairs of type names and traits
2014-07-20 14:21:41 -07:00
std : : vector < std : : pair < std : : string , std : : set < std : : string > > > ASTTransformation : : makeTemplateNameTraitPairs ( NodeTree < Symbol > * templateNode ) {
2014-07-18 08:52:15 -07:00
std : : vector < NodeTree < Symbol > * > templateParams = slice ( templateNode - > getChildren ( ) , 1 , - 2 , 2 ) ; //Skip <, >, and interveaning commas
std : : vector < std : : pair < std : : string , std : : set < std : : string > > > typePairs ;
for ( auto i : templateParams ) {
if ( i - > getChildren ( ) . size ( ) > 1 )
typePairs . push_back ( std : : make_pair ( concatSymbolTree ( i - > getChildren ( ) [ 0 ] ) , parseTraits ( i - > getChildren ( ) [ 1 ] ) ) ) ;
else
typePairs . push_back ( std : : make_pair ( concatSymbolTree ( i - > getChildren ( ) [ 0 ] ) , std : : set < std : : string > ( ) ) ) ;
}
return typePairs ;
}
std : : map < std : : string , Type * > ASTTransformation : : makeTemplateFunctionTypeMap ( NodeTree < Symbol > * templateNode , std : : vector < Type * > types ) {
2014-07-20 14:21:41 -07:00
auto typePairs = makeTemplateNameTraitPairs ( templateNode ) ;
2014-07-18 08:52:15 -07:00
std : : map < std : : string , Type * > typeMap ;
int typeIndex = 0 ;
std : : cout < < typePairs . size ( ) < < " " < < types . size ( ) < < std : : endl ;
for ( auto i : typePairs ) {
typeMap [ i . first ] = types [ typeIndex ] ;
std : : cout < < " Mapping " < < i . first < < " to " < < types [ typeIndex ] - > toString ( ) < < std : : endl ;
typeIndex + + ;
}
return typeMap ;
}
2014-12-19 18:29:33 -05:00
// We need recursion protection
2014-07-23 02:23:21 -07:00
std : : vector < NodeTree < ASTData > * > ASTTransformation : : scopeLookup ( NodeTree < ASTData > * scope , std : : string lookup , bool includeModules ) {
2014-12-19 18:29:33 -05:00
return scopeLookup ( scope , lookup , includeModules , std : : vector < NodeTree < ASTData > * > ( ) ) ;
}
std : : vector < NodeTree < ASTData > * > ASTTransformation : : scopeLookup ( NodeTree < ASTData > * scope , std : : string lookup , bool includeModules , std : : vector < NodeTree < ASTData > * > visited ) {
2015-03-14 02:42:07 -04:00
std : : cout < < " Scp][e looking up " < < lookup < < std : : endl ;
2014-12-19 18:29:33 -05:00
// Don't visit this node again when looking for the smae lookup. Note that we don't prevent coming back for the scope operator, as that should be able to come back.
visited . push_back ( scope ) ;
2014-07-20 20:42:26 -07:00
//We first check to see if it's one of the special reserved identifiers (only this, for now) and return early if it is.
auto LLElementIterator = languageLevelReservedWords . find ( lookup ) ;
if ( LLElementIterator ! = languageLevelReservedWords . end ( ) ) {
std : : cout < < " found it at language level as reserved word. " < < std : : endl ;
return LLElementIterator - > second ;
}
2014-07-18 08:52:15 -07:00
std : : vector < NodeTree < ASTData > * > matches ;
2014-12-19 18:29:33 -05:00
// First, we check for scope operator (::) but only if occurs before a "<" as this would signal the beginning of a template instatiation inside type
// If we find it, we look up the left side of the :: and then use the resuts as the scope for looking up the right side, recursively.
size_t scopeOpPos = lookup . find ( " :: " ) ;
size_t angleBrktPos = lookup . find ( " < " ) ;
if ( scopeOpPos ! = std : : string : : npos & & ( angleBrktPos = = std : : string : : npos | | scopeOpPos < angleBrktPos ) ) {
std : : cout < < " Has :: operator, doing left then right " < < std : : endl ;
for ( auto scopeMatch : scopeLookup ( scope , strSlice ( lookup , 0 , scopeOpPos ) , true ) ) {
std : : cout < < " Trying right side with found left side " < < scopeMatch - > getDataRef ( ) - > toString ( ) < < std : : endl ;
auto addMatches = scopeLookup ( scopeMatch , strSlice ( lookup , scopeOpPos + 2 , - 1 ) , includeModules ) ;
matches . insert ( matches . end ( ) , addMatches . begin ( ) , addMatches . end ( ) ) ;
}
return matches ;
}
2014-07-18 08:52:15 -07:00
std : : map < std : : string , std : : vector < NodeTree < ASTData > * > > scopeMap = scope - > getDataRef ( ) - > scope ;
auto possibleMatches = scopeMap . find ( lookup ) ;
2014-07-23 02:23:21 -07:00
if ( possibleMatches ! = scopeMap . end ( ) ) {
for ( auto i : possibleMatches - > second )
if ( includeModules | | i - > getName ( ) ! = " translation_unit " )
matches . push_back ( i ) ;
std : : cout < < " Found " < < possibleMatches - > second . size ( ) < < " match(s) at " < < scope - > getDataRef ( ) - > toString ( ) < < std : : endl ;
}
2014-12-19 18:29:33 -05:00
// Add results from our enclosing scope, if it exists.
// If it doesn't we should be at the top of a translation unit, and we should check the scope of import statements.
2014-07-18 08:52:15 -07:00
auto enclosingIterator = scopeMap . find ( " ~enclosing_scope " ) ;
if ( enclosingIterator ! = scopeMap . end ( ) ) {
2014-12-19 18:29:33 -05:00
std : : vector < NodeTree < ASTData > * > upperResult = scopeLookup ( enclosingIterator - > second [ 0 ] , lookup , includeModules , visited ) ;
2014-07-18 08:52:15 -07:00
matches . insert ( matches . end ( ) , upperResult . begin ( ) , upperResult . end ( ) ) ;
2014-12-19 18:29:33 -05:00
} else {
// Ok, let's iterate through and check for imports
for ( auto child : scope - > getChildren ( ) ) {
if ( child - > getDataRef ( ) - > type = = import ) {
auto importScope = child - > getDataRef ( ) - > scope ;
// Check if there is a match named explicily in the import's scope (i.e. looking for a and the import is import somefile: a;)
// If so, add it's members to our matches
auto importLookupItr = importScope . find ( lookup ) ;
if ( importLookupItr ! = importScope . end ( ) ) {
auto addMatches = importLookupItr - > second ;
matches . insert ( matches . end ( ) , addMatches . begin ( ) , addMatches . end ( ) ) ;
}
// Check if there is an uncionditional import to follow (i.e. import somefile: *;)
// If so, continue the search in that scope
auto importStarItr = importScope . find ( " * " ) ;
if ( importStarItr ! = importScope . end ( ) ) {
auto addMatches = scopeLookup ( importStarItr - > second [ 0 ] , lookup , includeModules , visited ) ;
matches . insert ( matches . end ( ) , addMatches . begin ( ) , addMatches . end ( ) ) ;
}
}
}
2014-07-18 08:52:15 -07:00
}
return matches ;
2013-12-27 13:05:07 -06:00
}
2014-01-07 13:14:58 -05:00
2015-03-11 01:58:10 -04:00
// Find the translation unit that is the top of the passed in node
NodeTree < ASTData > * ASTTransformation : : getUpperTranslationUnit ( NodeTree < ASTData > * node ) {
auto scope = node - > getDataRef ( ) - > scope ;
auto iter = scope . find ( " ~enclosing_scope " ) ;
while ( iter ! = scope . end ( ) ) {
node = iter - > second [ 0 ] ;
scope = node - > getDataRef ( ) - > scope ;
iter = scope . find ( " ~enclosing_scope " ) ;
}
return node ;
}
2014-05-09 02:56:55 -04:00
//Create a type from a syntax tree. This can get complicated with templates
2014-07-23 02:23:21 -07:00
Type * ASTTransformation : : typeFromTypeNode ( NodeTree < Symbol > * typeNode , NodeTree < ASTData > * scope , std : : map < std : : string , Type * > templateTypeReplacements ) {
2014-06-09 00:21:38 -07:00
std : : string typeIn = concatSymbolTree ( typeNode ) ;
2014-05-07 02:33:04 -04:00
2014-01-07 13:14:58 -05:00
int indirection = 0 ;
ValueType baseType ;
NodeTree < ASTData > * typeDefinition = NULL ;
2014-07-18 08:52:15 -07:00
std : : set < std : : string > traits ;
2014-01-07 13:14:58 -05:00
while ( typeIn [ typeIn . size ( ) - indirection - 1 ] = = ' * ' ) indirection + + ;
std : : string edited = strSlice ( typeIn , 0 , - ( indirection + 1 ) ) ;
if ( edited = = " void " )
baseType = void_type ;
else if ( edited = = " bool " )
baseType = boolean ;
else if ( edited = = " int " )
baseType = integer ;
else if ( edited = = " float " )
2014-05-07 02:33:04 -04:00
baseType = floating ;
else if ( edited = = " double " )
2014-01-07 13:14:58 -05:00
baseType = double_percision ;
else if ( edited = = " char " )
baseType = character ;
else {
baseType = none ;
2014-07-18 08:52:15 -07:00
auto possibleMatches = scopeLookup ( scope , edited ) ;
if ( possibleMatches . size ( ) ) {
typeDefinition = possibleMatches [ 0 ] ;
traits = typeDefinition - > getDataRef ( ) - > valueType - > traits ;
}
2014-05-09 02:56:55 -04:00
//So either this is an uninstatiated template class type, or this is literally a template type T, and we should get it from our
//templateTypeReplacements map. We try this first
if ( templateTypeReplacements . find ( edited ) ! = templateTypeReplacements . end ( ) ) {
2014-05-15 17:58:41 -04:00
std : : cout < < " Template type! ( " < < edited < < " ) " < < std : : endl ;
2014-05-09 02:56:55 -04:00
Type * templateTypeReplacement = templateTypeReplacements [ edited ] - > clone ( ) ;
2014-05-19 20:00:35 -04:00
templateTypeReplacement - > modifyIndirection ( indirection ) ;
2014-05-09 02:56:55 -04:00
return templateTypeReplacement ;
}
2014-07-18 08:52:15 -07:00
std : : cout < < edited < < " was not found in templateTypeReplacements " < < std : : endl ;
std : : cout < < " templateTypeReplacements consists of : " ;
for ( auto i : templateTypeReplacements )
std : : cout < < i . first < < " " ;
std : : cout < < std : : endl ;
2014-07-23 02:23:21 -07:00
// getChildren()[1] is \* because of pointer instead of template_inst
// To counter this, for every indirection we step down a level
for ( int i = 0 ; i < indirection ; i + + )
typeNode = typeNode - > getChildren ( ) [ 0 ] ;
std : : cout < < possibleMatches . size ( ) < < " " < < typeNode - > getChildren ( ) . size ( ) < < std : : endl ;
if ( typeNode - > getChildren ( ) . size ( ) > 1 )
std : : cout < < typeNode - > getChildren ( ) [ 1 ] - > getDataRef ( ) - > getName ( ) < < std : : endl ;
2014-07-18 08:52:15 -07:00
//If not, we better instantiate it and then add it to the highest (not current) scope
if ( possibleMatches . size ( ) = = 0 & & typeNode - > getChildren ( ) . size ( ) > 1 & & typeNode - > getChildren ( ) [ 1 ] - > getData ( ) . getName ( ) = = " template_inst " ) {
2014-05-09 02:56:55 -04:00
std : : cout < < " Template type: " < < edited < < " not yet instantiated " < < std : : endl ;
2014-07-20 14:21:41 -07:00
//We pull out the replacement types first so that we can choose the correct possibly overloaded template
std : : vector < NodeTree < Symbol > * > templateParamInstantiationNodes = slice ( typeNode - > getChildren ( ) [ 1 ] - > getChildren ( ) , 1 , - 2 , 2 ) ; //same
std : : vector < Type * > templateParamInstantiationTypes ;
std : : string instTypeString = " " ;
for ( int i = 0 ; i < templateParamInstantiationNodes . size ( ) ; i + + ) {
2014-07-23 02:23:21 -07:00
Type * instType = typeFromTypeNode ( templateParamInstantiationNodes [ i ] , scope , templateTypeReplacements ) ;
2015-03-17 21:06:31 -04:00
/*******************************************************************************
* WE RETURN EARLY IF ONE OF OUR REPLACEMENT INST TYPES IS TEMPLATE_TYPE_TYPE
* WE DO THIS BECAUSE WE CAN ' T ACTUALLY INSTATNTIATE WITH THIS .
* THIS CAN HAPPEN IN THE FOLLOWING SITUATIONS .
* template < T > | T | fun ( | vec < T > | a ) { return a . at ( 0 ) ; }
* etc
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if ( instType - > baseType = = template_type_type )
return instType ;
2014-07-20 14:21:41 -07:00
templateParamInstantiationTypes . push_back ( instType ) ;
instTypeString + = ( instTypeString = = " " ) ? instType - > toString ( false ) : " , " + instType - > toString ( false ) ;
}
//Finish creating the new name for this instantiation
2014-06-17 00:10:57 -07:00
std : : string classNameWithoutTemplate = concatSymbolTree ( typeNode - > getChildren ( ) [ 0 ] ) ;
2015-03-11 01:58:10 -04:00
std : : string templateLookupName = classNameWithoutTemplate + " < " + instTypeString + " > " ;
2014-05-09 02:56:55 -04:00
2014-07-23 02:23:21 -07:00
// Recheck for prior definition here, now that we have the true name.
2015-03-11 01:58:10 -04:00
possibleMatches = scopeLookup ( scope , templateLookupName ) ;
2014-07-23 02:23:21 -07:00
if ( possibleMatches . size ( ) ) {
typeDefinition = possibleMatches [ 0 ] ;
traits = typeDefinition - > getDataRef ( ) - > valueType - > traits ;
2015-03-11 01:58:10 -04:00
std : : cout < < " Found already instantiated template of " < < templateLookupName < < " at second check " < < std : : endl ;
2014-07-23 02:23:21 -07:00
} else {
2015-03-11 01:58:10 -04:00
std : : cout < < " Did not find already instantiated template of " < < templateLookupName < < " at second check " < < std : : endl ;
2014-07-23 02:23:21 -07:00
//Look up this template's plain definition. It's type has the syntax tree that we need to parse
NodeTree < ASTData > * templateDefinition = templateClassLookup ( scope , concatSymbolTree ( typeNode - > getChildren ( ) [ 0 ] ) , templateParamInstantiationTypes ) ;
if ( templateDefinition = = NULL )
std : : cout < < " Template definition is null! " < < std : : endl ;
else
std : : cout < < " Template definition is not null! " < < std : : endl ;
2015-03-11 01:58:10 -04:00
std : : string fullyInstantiatedName = templateDefinition - > getDataRef ( ) - > symbol . getName ( ) + " < " + instTypeString + " > " ;
2014-07-23 02:23:21 -07:00
NodeTree < Symbol > * templateSyntaxTree = templateDefinition - > getDataRef ( ) - > valueType - > templateDefinition ;
//Create a new map of template type names to actual types.
std : : vector < NodeTree < Symbol > * > templateParamPlaceholderNodes = slice ( templateSyntaxTree - > getChildren ( ) [ 0 ] - > getChildren ( ) , 1 , - 2 , 2 ) ; //Don't get beginning or end for < or >, skip commas in the middle
std : : map < std : : string , Type * > newTemplateTypeReplacement ;
for ( int i = 0 ; i < templateParamInstantiationTypes . size ( ) ; i + + )
newTemplateTypeReplacement [ concatSymbolTree ( templateParamPlaceholderNodes [ i ] ) ] = templateParamInstantiationTypes [ i ] ;
typeDefinition = new NodeTree < ASTData > ( " type_def " , ASTData ( type_def , Symbol ( fullyInstantiatedName , true , fullyInstantiatedName ) ) ) ;
traits = templateDefinition - > getDataRef ( ) - > valueType - > traits ; // We have the same traits as the template definition
Type * selfType = new Type ( typeDefinition , traits ) ; // Type is self-referential since this is the definition.
typeDefinition - > getDataRef ( ) - > valueType = selfType ;
//Note that we're adding to the current top scope. This makes it more efficient by preventing multiple instantiation and should not cause any problems
//It also makes sure it gets generated in the right place
2015-03-11 01:58:10 -04:00
//std::cout << "Adding to top scope and template's origional scope with fullyInstantiatedName " << fullyInstantiatedName << std::endl;
//topScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition);
//topScope->addChild(typeDefinition); Add this object the the highest scope's
// Actually, let's just put it in the scope of the origional template, which should work just fine under the new scoping rules and will ACTUALLY prevent multiple instantiation.
// At least, hopefully it will if we also check it's scope for it. Which I think it should be anyway. Yeah, I think it should work.
std : : cout < < " Adding to template top scope and template's origional scope with fullyInstantiatedName " < < fullyInstantiatedName < < std : : endl ;
auto templateTopScope = getUpperTranslationUnit ( templateDefinition ) ;
templateTopScope - > getDataRef ( ) - > scope [ fullyInstantiatedName ] . push_back ( typeDefinition ) ;
templateTopScope - > addChild ( typeDefinition ) ; // Add this object the the highest scope's
2014-07-28 01:52:15 -07:00
//NodeTree<ASTData>* templateHighScope = templateDefinition->getDataRef()->scope["~enclosing_scope"][0];
//if (topScope != templateHighScope)
//templateHighScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition);
// We put it in the scope of the template so that it can find itself (as it's scope is its template definition)
templateDefinition - > getDataRef ( ) - > scope [ fullyInstantiatedName ] . push_back ( typeDefinition ) ;
2014-07-23 02:23:21 -07:00
//Note that the instantiated template's scope is the template's definition.
typeDefinition - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( templateDefinition ) ;
// We only partially instantiate templates no matter what now
// They are all fully instantiated in the loop at the end of the 4th pass
// This is done for code simplicity and so that that loop can do template class methods
// that instantiate other templates that instantiate other templates while still retaining the
// deferred method allowing us to correctly instantiate multiple levels of mututally recursive definitions.
2014-06-10 00:53:30 -07:00
selfType - > templateDefinition = templateSyntaxTree ; //We're going to still need this when we finish instantiating
selfType - > templateTypeReplacement = newTemplateTypeReplacement ; //Save the types for use when this is fully instantiated in pass 4
secondPassDoClassInsides ( typeDefinition , templateSyntaxTree - > getChildren ( ) , newTemplateTypeReplacement ) ; //Use these types when instantiating data members
2014-07-23 02:23:21 -07:00
}
2014-07-18 08:52:15 -07:00
} else if ( possibleMatches . size ( ) = = 0 ) {
2014-06-09 00:21:38 -07:00
std : : cout < < " Could not find type " < < edited < < " , returning NULL " < < std : : endl ;
return NULL ;
2014-05-09 02:56:55 -04:00
} else {
2014-07-18 08:52:15 -07:00
std : : cout < < " Type: " < < edited < < " already instantiated with " < < typeDefinition < < " , will be " < < Type ( baseType , typeDefinition , indirection , traits ) . toString ( ) < < std : : endl ;
2014-05-09 02:56:55 -04:00
}
2014-01-07 13:14:58 -05:00
}
2014-07-18 08:52:15 -07:00
Type * toReturn = new Type ( baseType , typeDefinition , indirection , traits ) ;
2014-05-09 02:56:55 -04:00
std : : cout < < " Returning type " < < toReturn - > toString ( ) < < std : : endl ;
return toReturn ;
2014-01-07 13:14:58 -05:00
}
2014-05-15 17:58:41 -04:00
NodeTree < ASTData > * ASTTransformation : : findOrInstantiateFunctionTemplate ( std : : vector < NodeTree < Symbol > * > children , NodeTree < ASTData > * scope , std : : vector < Type > types , std : : map < std : : string , Type * > templateTypeReplacements ) {
//First look to see if we can find this already instantiated
2014-06-17 00:10:57 -07:00
std : : cout < < " \n \n Finding or instantiating templated function \n \n " < < std : : endl ;
2014-05-15 17:58:41 -04:00
std : : string functionName = concatSymbolTree ( children [ 0 ] ) ;
2014-06-17 00:10:57 -07:00
auto unsliced = children [ 1 ] - > getChildren ( ) ;
std : : vector < NodeTree < Symbol > * > templateParamInstantiationNodes = slice ( unsliced , 1 , - 2 , 2 ) ; //skip <, >, and commas
std : : string instTypeString = " " ;
std : : vector < Type * > templateActualTypes ;
for ( int i = 0 ; i < templateParamInstantiationNodes . size ( ) ; i + + ) {
2014-07-23 02:23:21 -07:00
Type * instType = typeFromTypeNode ( templateParamInstantiationNodes [ i ] , scope , templateTypeReplacements ) ;
2014-06-17 00:10:57 -07:00
instTypeString + = ( instTypeString = = " " ? instType - > toString ( ) : " , " + instType - > toString ( ) ) ;
templateActualTypes . push_back ( instType ) ;
}
std : : cout < < " Size: " < < templateParamInstantiationNodes . size ( ) < < std : : endl ;
std : : string fullyInstantiatedName = functionName + " < " + instTypeString + " > " ;
2014-05-15 17:58:41 -04:00
std : : cout < < " Looking for " < < fullyInstantiatedName < < std : : endl ;
2014-05-19 20:00:35 -04:00
2014-06-17 00:10:57 -07:00
std : : cout < < " Types are : " ;
2014-05-19 20:00:35 -04:00
for ( auto i : types )
std : : cout < < " " < < i . toString ( ) ;
std : : cout < < std : : endl ;
2014-07-18 08:52:15 -07:00
NodeTree < ASTData > * instantiatedFunction = functionLookup ( scope , fullyInstantiatedName , types ) ;
2014-05-15 17:58:41 -04:00
//If it already exists, return it
2014-05-19 20:00:35 -04:00
if ( instantiatedFunction ) {
std : : cout < < fullyInstantiatedName < < " already exists! Returning " < < std : : endl ;
2014-05-15 17:58:41 -04:00
return instantiatedFunction ;
2014-07-28 01:52:15 -07:00
} else {
instantiatedFunction = functionLookup ( topScope , fullyInstantiatedName , types ) ;
if ( instantiatedFunction ) {
std : : cout < < fullyInstantiatedName < < " already exists! Found in TopScope " < < std : : endl ;
return instantiatedFunction ;
}
2014-05-19 20:00:35 -04:00
std : : cout < < fullyInstantiatedName < < " does NOT exist " < < std : : endl ;
}
2014-05-15 17:58:41 -04:00
//Otherwise, we're going to instantiate it
2014-07-18 08:52:15 -07:00
//Find the template definitions
NodeTree < ASTData > * templateDefinition = templateFunctionLookup ( scope , functionName , templateActualTypes , types ) ;
2014-05-19 20:00:35 -04:00
if ( templateDefinition = = NULL ) {
std : : cout < < functionName < < " search turned up null, returing null " < < std : : endl ;
return NULL ;
}
2014-05-15 17:58:41 -04:00
NodeTree < Symbol > * templateSyntaxTree = templateDefinition - > getDataRef ( ) - > valueType - > templateDefinition ;
2014-07-18 08:52:15 -07:00
// Makes a map between the names of the template placeholder parameters and the provided types
std : : map < std : : string , Type * > newTemplateTypeReplacement = makeTemplateFunctionTypeMap ( templateSyntaxTree - > getChildren ( ) [ 0 ] , templateActualTypes ) ;
2014-05-15 17:58:41 -04:00
2014-06-17 00:10:57 -07:00
std : : vector < NodeTree < Symbol > * > templateChildren = templateSyntaxTree - > getChildren ( ) ;
2014-05-15 17:58:41 -04:00
for ( int i = 0 ; i < templateChildren . size ( ) ; i + + )
std : : cout < < " , " < < i < < " : " < < templateChildren [ i ] - > getDataRef ( ) - > getName ( ) ;
std : : cout < < std : : endl ;
2014-07-23 02:23:21 -07:00
instantiatedFunction = new NodeTree < ASTData > ( " function " , ASTData ( function , Symbol ( fullyInstantiatedName , true ) , typeFromTypeNode ( templateChildren [ 1 ] , scope , newTemplateTypeReplacement ) ) ) ;
2014-05-15 17:58:41 -04:00
std : : set < int > skipChildren ;
skipChildren . insert ( 0 ) ;
skipChildren . insert ( 1 ) ;
skipChildren . insert ( 2 ) ;
2014-07-28 01:52:15 -07:00
//scope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction);
2014-05-15 17:58:41 -04:00
instantiatedFunction - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] . push_back ( templateDefinition - > getDataRef ( ) - > scope [ " ~enclosing_scope " ] [ 0 ] ) ; //Instantiated Template Function's scope is it's template's definition's scope
2015-03-11 01:58:10 -04:00
// Arrrrrgh this has a hard time working because the functions will need to see their parameter once they are emitted as C.
// HAHAHAHAHA DOESN'T MATTER ALL ONE C FILE NOW, swap back to old way
auto templateTopScope = getUpperTranslationUnit ( templateDefinition ) ;
templateTopScope - > getDataRef ( ) - > scope [ fullyInstantiatedName ] . push_back ( instantiatedFunction ) ;
templateTopScope - > addChild ( instantiatedFunction ) ; // Add this object the the highest scope's
//topScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction);
//topScope->addChild(instantiatedFunction); //Add this object the the highest scope's
2014-07-28 01:52:15 -07:00
2014-05-15 17:58:41 -04:00
std : : cout < < " About to do children of " < < functionName < < " to " < < fullyInstantiatedName < < std : : endl ;
2014-07-23 02:23:21 -07:00
instantiatedFunction - > addChildren ( transformChildren ( templateSyntaxTree - > getChildren ( ) , skipChildren , instantiatedFunction , std : : vector < Type > ( ) , newTemplateTypeReplacement ) ) ;
2014-05-15 17:58:41 -04:00
std : : cout < < " Fully Instantiated function " < < functionName < < " to " < < fullyInstantiatedName < < std : : endl ;
return instantiatedFunction ;
}