2013-11-01 02:52:18 -04:00
# include "CGenerator.h"
2013-12-22 01:34:59 -06:00
CGenerator : : CGenerator ( ) : generatorString ( " __C__ " ) {
2013-11-01 02:52:18 -04:00
tabLevel = 0 ;
}
CGenerator : : ~ CGenerator ( ) {
}
2014-12-30 01:22:09 -05:00
// Note the use of std::pair to hold two strings - the running string for the header file and the running string for the c file.
2014-01-01 17:29:19 -06:00
void CGenerator : : generateCompSet ( std : : map < std : : string , NodeTree < ASTData > * > ASTs , std : : string outputName ) {
//Generate an entire set of files
std : : string buildString = " #!/bin/sh \n cc -std=c99 " ;
2014-12-30 01:22:09 -05:00
std : : cout < < " \n \n =====GENERATE PASS===== \n \n " < < std : : endl ;
if ( mkdir ( ( " ./ " + outputName ) . c_str ( ) , 0755 ) ) {
2015-03-14 02:42:07 -04:00
std : : cerr < < " \n \n =====GENERATE PASS===== \n \n " < < std : : endl ;
std : : cerr < < " Could not make directory " < < outputName < < std : : endl ;
2014-12-30 01:22:09 -05:00
//throw "could not make directory ";
}
2015-03-11 01:58:10 -04:00
std : : cout < < " \n \n Generate pass for: " < < outputName < < std : : endl ;
buildString + = outputName + " .c " ;
std : : ofstream outputCFile , outputHFile ;
outputCFile . open ( outputName + " / " + outputName + " .c " ) ;
outputHFile . open ( outputName + " / " + outputName + " .h " ) ;
if ( outputCFile . is_open ( ) | | outputHFile . is_open ( ) ) {
// Prequel common to all files
auto chPair = generateTranslationUnit ( outputName , ASTs ) ;
outputHFile < < " #include <stdbool.h> \n #include <stdlib.h> \n #include <stdio.h> \n " < < chPair . first ;
outputCFile < < " #include \" " + outputName + " .h \" \n \n " < < chPair . second ;
} else {
2015-03-14 02:42:07 -04:00
std : : cerr < < " Cannot open file " < < outputName < < " .c/h " < < std : : endl ;
2015-03-11 01:58:10 -04:00
}
outputCFile . close ( ) ;
outputHFile . close ( ) ;
2014-01-01 17:29:19 -06:00
buildString + = " -o " + outputName ;
std : : ofstream outputBuild ;
2014-12-30 01:22:09 -05:00
outputBuild . open ( outputName + " / " + split ( outputName , ' / ' ) . back ( ) + " .sh " ) ;
2014-01-01 17:29:19 -06:00
outputBuild < < buildString ;
outputBuild . close ( ) ;
}
2013-11-01 02:52:18 -04:00
std : : string CGenerator : : tabs ( ) {
std : : string returnTabs ;
for ( int i = 0 ; i < tabLevel ; i + + )
returnTabs + = " \t " ;
return returnTabs ;
}
2014-07-28 01:52:15 -07:00
std : : string CGenerator : : generateClassStruct ( NodeTree < ASTData > * from ) {
auto data = from - > getData ( ) ;
auto children = from - > getChildren ( ) ;
std : : string objectString = " struct __struct_dummy_ " + CifyName ( data . symbol . getName ( ) ) + " __ { \n " ;
tabLevel + + ;
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
std : : cout < < children [ i ] - > getName ( ) < < std : : endl ;
if ( children [ i ] - > getName ( ) ! = " function " )
objectString + = tabs ( ) + generate ( children [ i ] , nullptr ) + " \n " ;
}
tabLevel - - ;
objectString + = " }; " ;
return objectString ;
}
// This method recurseivly generates all aliases of some definition
2015-03-11 01:58:10 -04:00
std : : string CGenerator : : generateAliasChains ( std : : map < std : : string , NodeTree < ASTData > * > ASTs , NodeTree < ASTData > * definition ) {
2014-07-28 01:52:15 -07:00
std : : string output ;
2015-03-11 01:58:10 -04:00
for ( auto trans : ASTs ) {
for ( auto i = trans . second - > getDataRef ( ) - > scope . begin ( ) ; i ! = trans . second - > getDataRef ( ) - > scope . end ( ) ; i + + ) {
for ( auto declaration : i - > second ) {
auto declarationData = declaration - > getDataRef ( ) ;
if ( declarationData - > type = = type_def
& & declarationData - > valueType - > typeDefinition ! = declaration
& & declarationData - > valueType - > typeDefinition = = definition ) {
output + = " typedef " + CifyName ( definition - > getDataRef ( ) - > symbol . getName ( ) ) + " " + CifyName ( declarationData - > symbol . getName ( ) ) + " ; \n " ;
// Recursively add the ones that depend on this one
output + = generateAliasChains ( ASTs , declaration ) ;
}
2014-07-28 01:52:15 -07:00
}
}
}
return output ;
}
2014-12-30 01:22:09 -05:00
bool CGenerator : : isUnderTranslationUnit ( NodeTree < ASTData > * from , NodeTree < ASTData > * node ) {
auto scope = from - > getDataRef ( ) - > scope ;
for ( auto i : scope )
for ( auto j : i . second )
if ( j = = node )
return true ;
auto upper = scope . find ( " ~enclosing_scope " ) ;
if ( upper ! = scope . end ( ) )
return isUnderTranslationUnit ( upper - > second [ 0 ] , node ) ;
return false ;
}
NodeTree < ASTData > * CGenerator : : highestScope ( NodeTree < ASTData > * node ) {
auto it = node - > getDataRef ( ) - > scope . find ( " ~enclosing_scope " ) ;
while ( it ! = node - > getDataRef ( ) - > scope . end ( ) ) {
node = it - > second [ 0 ] ;
it = node - > getDataRef ( ) - > scope . find ( " ~enclosing_scope " ) ;
}
return node ;
}
// We do translation units in their own function so they can do the pariwise h/c stuff and regualr in function body generation does not
2015-03-11 01:58:10 -04:00
std : : pair < std : : string , std : : string > CGenerator : : generateTranslationUnit ( std : : string name , std : : map < std : : string , NodeTree < ASTData > * > ASTs ) {
// We now pass in the entire map of ASTs and loop through them so that we generate out into a single file
2014-12-30 01:22:09 -05:00
std : : string cOutput , hOutput ;
// Ok, so we've got to do this in passes to preserve mututally recursive definitions.
//
// First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;".
// Also, other typedefs follow after their naming.
// Second Pass: All top level variable declarations
// Third Pass: Define all actual structs of a class, in correct order (done with posets)
// Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too).
// (this includes object methods)
// Fifth Pass: Define all functions (including object methods).
2014-07-28 01:52:15 -07:00
2014-12-30 01:22:09 -05:00
// However, most of these do not actually have to be done as separate passes. First, second, fourth, and fifth
// are done simultanously, but append to different strings that are then concatinated properly, in order.
2014-07-28 01:52:15 -07:00
2014-12-30 01:22:09 -05:00
std : : string importIncludes = " /** \n * Import Includes \n */ \n \n " ;
std : : string variableExternDeclarations = " /** \n * Extern Variable Declarations \n */ \n \n " ;
std : : string plainTypedefs = " /** \n * Plain Typedefs \n */ \n \n " ;
std : : string variableDeclarations = " /** \n * Variable Declarations \n */ \n \n " ;
std : : string classStructs = " /** \n * Class Structs \n */ \n \n " ;
std : : string functionPrototypes = " /** \n * Function Prototypes \n */ \n \n " ;
std : : string functionDefinitions = " /** \n * Function Definitions \n */ \n \n " ;
2014-07-28 01:52:15 -07:00
2014-12-30 01:22:09 -05:00
// And get the correct order for emiting classes, but not if they're not in our file, then they will get included
// Note that this is not sufsticated enough for some multiple file mutually recursive types, but I want to get this simple version working first
Poset < NodeTree < ASTData > * > typedefPoset ;
2015-03-11 01:58:10 -04:00
for ( auto trans : ASTs ) {
auto children = trans . second - > getChildren ( ) ;
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
if ( children [ i ] - > getDataRef ( ) - > type = = type_def ) {
// If we're an alias type, continue. We handle those differently
if ( children [ i ] - > getDataRef ( ) - > valueType - > typeDefinition ! = children [ i ] )
continue ;
2014-05-21 13:14:16 -04:00
2015-03-11 01:58:10 -04:00
typedefPoset . addVertex ( children [ i ] ) ; // We add this definition by itself just in case there are no dependencies.
// If it has dependencies, there's no harm in adding it here
// Go through every child in the class looking for declaration statements. For each of these that is not a primitive type
// we will add a dependency from this definition to that definition in the poset.
std : : vector < NodeTree < ASTData > * > classChildren = children [ i ] - > getChildren ( ) ;
for ( auto j : classChildren ) {
if ( j - > getDataRef ( ) - > type = = declaration_statement ) {
Type * decType = j - > getChildren ( ) [ 0 ] - > getDataRef ( ) - > valueType ; // Type of the declaration
if ( decType - > typeDefinition & & decType - > getIndirection ( ) = = 0 ) // If this is a custom type and not a pointer
typedefPoset . addRelationship ( children [ i ] , decType - > typeDefinition ) ; // Add a dependency
}
2014-12-30 01:22:09 -05:00
}
}
}
}
//Now generate the typedef's in the correct, topological order
for ( NodeTree < ASTData > * i : typedefPoset . getTopoSort ( ) )
classStructs + = generateClassStruct ( i ) + " \n " ;
2014-07-28 01:52:15 -07:00
2015-03-11 01:58:10 -04:00
// Declare everything in translation unit scope here (now for ALL translation units). (allows stuff from other files, automatic forward declarations)
2014-12-30 01:22:09 -05:00
// Also, everything in all of the import's scopes
2015-03-11 01:58:10 -04:00
for ( auto trans : ASTs ) {
for ( auto i = trans . second - > getDataRef ( ) - > scope . begin ( ) ; i ! = trans . second - > getDataRef ( ) - > scope . end ( ) ; i + + ) {
for ( auto declaration : i - > second ) {
std : : vector < NodeTree < ASTData > * > decChildren = declaration - > getChildren ( ) ;
ASTData declarationData = declaration - > getData ( ) ;
switch ( declarationData . type ) {
case identifier :
variableDeclarations + = ValueTypeToCType ( declarationData . valueType ) + " " + declarationData . symbol . getName ( ) + " ; /*identifier*/ \n " ;
variableExternDeclarations + = " extern " + ValueTypeToCType ( declarationData . valueType ) + " " + declarationData . symbol . getName ( ) + " ; /*extern identifier*/ \n " ;
break ;
case function :
{
if ( declarationData . valueType - > baseType = = template_type )
functionPrototypes + = " /* template function " + declarationData . symbol . toString ( ) + " */ \n " ;
else if ( decChildren . size ( ) = = 0 ) //Not a real function, must be a built in passthrough
functionPrototypes + = " /* built in function: " + declarationData . symbol . toString ( ) + " */ \n " ;
else {
functionPrototypes + = " \n " + ValueTypeToCType ( declarationData . valueType ) + " " ;
std : : string nameDecoration , parameters ;
for ( int j = 0 ; j < decChildren . size ( ) - 1 ; j + + ) {
if ( j > 0 )
parameters + = " , " ;
parameters + = ValueTypeToCType ( decChildren [ j ] - > getData ( ) . valueType ) + " " + generate ( decChildren [ j ] , nullptr ) ;
nameDecoration + = " _ " + ValueTypeToCTypeDecoration ( decChildren [ j ] - > getData ( ) . valueType ) ;
}
functionPrototypes + = CifyName ( declarationData . symbol . getName ( ) + nameDecoration ) + " ( " + parameters + " ); /*func*/ \n " ;
// generate function
std : : cout < < " Generating " < < CifyName ( declarationData . symbol . getName ( ) ) < < std : : endl ;
2014-12-30 01:22:09 -05:00
functionDefinitions + = generate ( declaration , nullptr ) ;
2015-03-11 01:58:10 -04:00
}
2014-12-30 01:22:09 -05:00
}
2015-03-11 01:58:10 -04:00
break ;
case type_def :
//type
plainTypedefs + = " /*typedef " + declarationData . symbol . getName ( ) + " */ \n " ;
2014-12-30 01:22:09 -05:00
2015-03-11 01:58:10 -04:00
if ( declarationData . valueType - > baseType = = template_type ) {
plainTypedefs + = " /* non instantiated template " + declarationData . symbol . getName ( ) + " */ " ;
} else if ( declarationData . valueType - > typeDefinition ! = declaration ) {
if ( declarationData . valueType - > typeDefinition )
continue ; // Aliases of objects are done with the thing it alises
// Otherwise, we're actually a renaming of a primitive, can generate here
plainTypedefs + = " typedef " + ValueTypeToCType ( declarationData . valueType ) + " " + CifyName ( declarationData . symbol . getName ( ) ) + " ; \n " ;
plainTypedefs + = generateAliasChains ( ASTs , declaration ) ;
} else {
plainTypedefs + = " typedef struct __struct_dummy_ " + CifyName ( declarationData . symbol . getName ( ) ) + " __ " + CifyName ( declarationData . symbol . getName ( ) ) + " ; \n " ;
functionPrototypes + = " /* Method Prototypes for " + declarationData . symbol . getName ( ) + " */ \n " ;
// We use a seperate string for this because we only include it if this is the file we're defined in
std : : string objectFunctionDefinitions = " /* Method Definitions for " + declarationData . symbol . getName ( ) + " */ \n " ;
for ( int j = 0 ; j < decChildren . size ( ) ; j + + ) {
std : : cout < < decChildren [ j ] - > getName ( ) < < std : : endl ;
if ( decChildren [ j ] - > getName ( ) = = " function " ) //If object method
objectFunctionDefinitions + = generateObjectMethod ( declaration , decChildren [ j ] , & functionPrototypes ) + " \n " ;
}
// Add all aliases to the plain typedefs. This will add any alias that aliases to this object, and any alias that aliases to that, and so on
plainTypedefs + = generateAliasChains ( ASTs , declaration ) ;
functionPrototypes + = " /* Done with " + declarationData . symbol . getName ( ) + " */ \n " ;
// include methods
2014-12-30 01:22:09 -05:00
functionDefinitions + = objectFunctionDefinitions + " /* Done with " + declarationData . symbol . getName ( ) + " */ \n " ;
2015-03-11 01:58:10 -04:00
}
break ;
default :
//std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl;
cOutput + = " /*unknown declaration named " + declaration - > getName ( ) + " */ \n " ;
hOutput + = " /*unknown declaration named " + declaration - > getName ( ) + " */ \n " ;
}
2014-12-30 01:22:09 -05:00
}
}
}
hOutput + = plainTypedefs + importIncludes + variableExternDeclarations + classStructs + functionPrototypes ;
cOutput + = variableDeclarations + functionDefinitions ;
return std : : make_pair ( hOutput , cOutput ) ;
}
//The enclosing object is for when we're generating the inside of object methods. They allow us to check scope lookups against the object we're in
std : : string CGenerator : : generate ( NodeTree < ASTData > * from , NodeTree < ASTData > * enclosingObject ) {
ASTData data = from - > getData ( ) ;
std : : vector < NodeTree < ASTData > * > children = from - > getChildren ( ) ;
std : : string output ;
switch ( data . type ) {
case translation_unit :
{
// Should not happen! We do this in it's own function now!
2015-03-14 02:42:07 -04:00
std : : cerr < < " Trying to normal generate a translation unit! That's a nono! ( " < < from - > getDataRef ( ) - > toString ( ) < < " ) " < < std : : endl ;
2014-12-30 01:22:09 -05:00
throw " That's not gonna work " ;
2014-05-21 13:14:16 -04:00
}
2013-11-01 02:52:18 -04:00
break ;
case interpreter_directive :
//Do nothing
break ;
case import :
2014-12-30 01:22:09 -05:00
return " /* never reached import? */ \n " ;
//return "include \"" + data.symbol.getName() + ".h\" //woo importing!\n";
2013-12-22 01:34:59 -06:00
//return "#include <" + data.symbol.getName() + ">\n";
2013-11-01 02:52:18 -04:00
case identifier :
2014-02-03 11:41:25 -05:00
{
2014-06-26 01:45:44 -07:00
//but first, if we're this, we should just emit. (assuming enclosing object) (note that technically this would fall through, but for errors)
2015-03-11 01:58:10 -04:00
if ( data . symbol . getName ( ) = = " this " ) {
2014-06-26 01:45:44 -07:00
if ( enclosingObject )
return " this " ;
else
2015-03-14 02:42:07 -04:00
std : : cerr < < " Error: this used in non-object scope " < < std : : endl ;
2015-03-11 01:58:10 -04:00
}
2014-06-26 01:45:44 -07:00
//If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the this reference.
2014-03-06 13:13:40 -05:00
std : : string preName ;
if ( enclosingObject & & enclosingObject - > getDataRef ( ) - > scope . find ( data . symbol . getName ( ) ) ! = enclosingObject - > getDataRef ( ) - > scope . end ( ) )
2014-06-26 01:45:44 -07:00
preName + = " this-> " ;
2014-05-10 19:28:36 -04:00
return preName + CifyName ( data . symbol . getName ( ) ) ; //Cifying does nothing if not an operator overload
2014-02-03 11:41:25 -05:00
}
2013-11-01 02:52:18 -04:00
case function :
2014-03-06 13:13:40 -05:00
{
2014-05-15 17:58:41 -04:00
if ( data . valueType - > baseType = = template_type )
return " /* template function: " + data . symbol . getName ( ) + " */ " ;
2014-03-06 13:13:40 -05:00
output + = " \n " + ValueTypeToCType ( data . valueType ) + " " ;
std : : string nameDecoration , parameters ;
for ( int j = 0 ; j < children . size ( ) - 1 ; j + + ) {
if ( j > 0 )
parameters + = " , " ;
parameters + = ValueTypeToCType ( children [ j ] - > getData ( ) . valueType ) + " " + generate ( children [ j ] , enclosingObject ) ;
2014-03-07 14:17:07 -05:00
nameDecoration + = " _ " + ValueTypeToCTypeDecoration ( children [ j ] - > getData ( ) . valueType ) ;
2013-11-01 02:52:18 -04:00
}
2014-06-10 00:53:30 -07:00
output + = CifyName ( data . symbol . getName ( ) + nameDecoration ) + " ( " + parameters + " ) \n " + generate ( children [ children . size ( ) - 1 ] , enclosingObject ) ;
2013-11-01 02:52:18 -04:00
return output ;
2014-03-06 13:13:40 -05:00
}
2013-11-01 02:52:18 -04:00
case code_block :
2014-06-28 08:31:33 -07:00
{
2013-11-07 22:19:33 -05:00
output + = " { \n " ;
2014-06-28 08:31:33 -07:00
std : : string destructorString = " " ;
tabLevel + + ;
2014-02-03 11:41:25 -05:00
for ( int i = 0 ; i < children . size ( ) ; i + + ) {
2014-03-06 13:13:40 -05:00
//std::cout << "Line " << i << std::endl;
2014-02-03 11:41:25 -05:00
std : : string line = generate ( children [ i ] , enclosingObject ) ;
2014-03-06 13:13:40 -05:00
//std::cout << line << std::endl;
2014-02-03 11:41:25 -05:00
output + = line ;
2014-06-28 08:31:33 -07:00
if ( children [ i ] - > getChildren ( ) . size ( ) & & children [ i ] - > getChildren ( ) [ 0 ] - > getDataRef ( ) - > type = = declaration_statement ) {
NodeTree < ASTData > * identifier = children [ i ] - > getChildren ( ) [ 0 ] - > getChildren ( ) [ 0 ] ;
2014-07-28 01:52:15 -07:00
Type * declarationType = identifier - > getDataRef ( ) - > valueType ;
if ( declarationType - > getIndirection ( ) )
continue ;
NodeTree < ASTData > * typeDefinition = declarationType - > typeDefinition ;
2014-06-28 08:31:33 -07:00
if ( ! typeDefinition )
continue ;
if ( typeDefinition - > getDataRef ( ) - > scope . find ( " destruct " ) = = typeDefinition - > getDataRef ( ) - > scope . end ( ) )
continue ;
destructorString + = tabs ( ) + CifyName ( typeDefinition - > getDataRef ( ) - > symbol . getName ( ) )
+ " __ " + " destruct " + " (& " + generate ( identifier , enclosingObject ) + " ); \n " ; //Call the destructor
}
}
output + = destructorString ;
tabLevel - - ;
2013-11-01 02:52:18 -04:00
output + = tabs ( ) + " } " ;
return output ;
2014-06-28 08:31:33 -07:00
}
case expression :
2013-11-01 02:52:18 -04:00
output + = " " + data . symbol . getName ( ) + " , " ;
case boolean_expression :
output + = " " + data . symbol . getName ( ) + " " ;
case statement :
2014-02-03 11:41:25 -05:00
return tabs ( ) + generate ( children [ 0 ] , enclosingObject ) + " ; \ n " ;
2013-11-01 02:52:18 -04:00
case if_statement :
2014-02-03 11:41:25 -05:00
output + = " if ( " + generate ( children [ 0 ] , enclosingObject ) + " ) \n \t " + generate ( children [ 1 ] , enclosingObject ) ;
2013-11-01 02:52:18 -04:00
if ( children . size ( ) > 2 )
2014-02-03 11:41:25 -05:00
output + = " else " + generate ( children [ 2 ] , enclosingObject ) ;
2013-11-01 02:52:18 -04:00
return output ;
2013-12-18 18:05:21 -06:00
case while_loop :
2014-02-03 11:41:25 -05:00
output + = " while ( " + generate ( children [ 0 ] , enclosingObject ) + " ) \n \t " + generate ( children [ 1 ] , enclosingObject ) ;
2013-12-18 18:05:21 -06:00
return output ;
case for_loop :
2013-12-28 21:54:22 -05:00
//The strSlice's are there to get ride of an unwanted return and an unwanted semicolon(s)
2014-02-03 11:41:25 -05:00
output + = " for ( " + strSlice ( generate ( children [ 0 ] , enclosingObject ) , 0 , - 3 ) + generate ( children [ 1 ] , enclosingObject ) + " ; " + strSlice ( generate ( children [ 2 ] , enclosingObject ) , 0 , - 3 ) + " ) \n \t " + generate ( children [ 3 ] , enclosingObject ) ;
2013-12-18 18:05:21 -06:00
return output ;
2013-11-01 02:52:18 -04:00
case return_statement :
2013-12-22 01:34:59 -06:00
if ( children . size ( ) )
2014-02-03 11:41:25 -05:00
return " return " + generate ( children [ 0 ] , enclosingObject ) ;
2013-12-22 01:34:59 -06:00
else
return " return " ;
2013-11-01 02:52:18 -04:00
case assignment_statement :
2014-02-03 11:41:25 -05:00
return generate ( children [ 0 ] , enclosingObject ) + " = " + generate ( children [ 1 ] , enclosingObject ) ;
2013-11-01 02:52:18 -04:00
case declaration_statement :
2014-01-07 13:14:58 -05:00
if ( children . size ( ) = = 1 )
2014-02-03 11:41:25 -05:00
return ValueTypeToCType ( children [ 0 ] - > getData ( ) . valueType ) + " " + generate ( children [ 0 ] , enclosingObject ) + " ; " ;
2014-06-26 01:45:44 -07:00
else if ( children [ 1 ] - > getChildren ( ) . size ( ) & & children [ 1 ] - > getChildren ( ) [ 0 ] - > getChildren ( ) . size ( ) > 1
& & children [ 1 ] - > getChildren ( ) [ 0 ] - > getChildren ( ) [ 1 ] = = children [ 0 ] ) {
//That is, if we're a declaration with an init position call (Object a.construct())
//We can tell if our function call (children[1])'s access operation([0])'s lhs ([1]) is the thing we just declared (children[0])
return ValueTypeToCType ( children [ 0 ] - > getData ( ) . valueType ) + " " + generate ( children [ 0 ] , enclosingObject ) + " ; " + generate(children[1]) + " /*Init Position Call*/ " ;
} else
2014-02-03 11:41:25 -05:00
return ValueTypeToCType ( children [ 0 ] - > getData ( ) . valueType ) + " " + generate ( children [ 0 ] , enclosingObject ) + " = " + generate ( children [ 1 ] , enclosingObject ) + " ; " ;
2013-12-22 01:34:59 -06:00
case if_comp :
2014-02-03 11:41:25 -05:00
if ( generate ( children [ 0 ] , enclosingObject ) = = generatorString )
return generate ( children [ 1 ] , enclosingObject ) ;
2013-12-22 01:34:59 -06:00
return " " ;
case simple_passthrough :
2014-02-03 11:41:25 -05:00
return strSlice ( generate ( children [ 0 ] , enclosingObject ) , 3 , - 4 ) ;
2013-11-01 02:52:18 -04:00
case function_call :
{
2013-12-27 13:05:07 -06:00
//NOTE: The first (0th) child of a function call node is the declaration of the function
2013-11-01 02:52:18 -04:00
//Handle operators specially for now. Will later replace with
//Inlined functions in the standard library
2014-02-03 11:41:25 -05:00
// std::string name = data.symbol.getName();
// std::cout << name << " == " << children[0]->getData().symbol.getName() << std::endl;
std : : string name = children [ 0 ] - > getDataRef ( ) - > symbol . getName ( ) ;
ASTType funcType = children [ 0 ] - > getDataRef ( ) - > type ;
std : : cout < < " Doing function: " < < name < < std : : endl ;
//Test for specail functions only if what we're testing is, indeed, the definition, not a function call that returns a callable function pointer
if ( funcType = = function ) {
if ( name = = " ++ " | | name = = " -- " )
return generate ( children [ 1 ] , enclosingObject ) + name ;
2014-07-28 01:52:15 -07:00
if ( ( name = = " * " | | name = = " & " | | name = = " ! " ) & & children . size ( ) = = 2 ) //Is dereference, not multiplication, address-of, or other unary operator
2014-05-06 13:54:53 -04:00
return name + " ( " + generate ( children [ 1 ] , enclosingObject ) + " ) " ;
if ( name = = " [] " )
return " ( " + generate ( children [ 1 ] , enclosingObject ) + " )[ " + generate ( children [ 2 ] , enclosingObject ) + " ] " ;
2014-02-03 11:41:25 -05:00
if ( name = = " + " | | name = = " - " | | name = = " * " | | name = = " / " | | name = = " == " | | name = = " >= " | | name = = " <= " | | name = = " != "
| | name = = " < " | | name = = " > " | | name = = " % " | | name = = " += " | | name = = " -= " | | name = = " *= " | | name = = " /= " | | name = = " || "
2014-07-28 01:52:15 -07:00
| | name = = " && " )
2014-02-03 11:41:25 -05:00
return " (( " + generate ( children [ 1 ] , enclosingObject ) + " ) " + name + " ( " + generate ( children [ 2 ] , enclosingObject ) + " )) " ;
else if ( name = = " . " | | name = = " -> " ) {
if ( children . size ( ) = = 1 )
return " /*dot operation with one child*/ " + generate ( children [ 0 ] , enclosingObject ) + " /*end one child*/ " ;
2014-02-18 21:55:00 -05:00
//If this is accessing an actual function, find the function in scope and take the appropriate action. Probabally an object method
if ( children [ 2 ] - > getDataRef ( ) - > type = = function ) {
std : : string functionName = children [ 2 ] - > getDataRef ( ) - > symbol . getName ( ) ;
NodeTree < ASTData > * possibleObjectType = children [ 1 ] - > getDataRef ( ) - > valueType - > typeDefinition ;
//If is an object method, generate it like one. Needs extension/modification for inheritence
2014-06-10 23:59:39 -07:00
if ( possibleObjectType ) {
NodeTree < ASTData > * unaliasedTypeDef = getMethodsObjectType ( possibleObjectType , functionName ) ;
if ( unaliasedTypeDef ) { //Test to see if the function's a member of this type_def, or if this is an alias, of the original type. Get this original type if it exists.
std : : string nameDecoration ;
std : : vector < NodeTree < ASTData > * > functionDefChildren = children [ 2 ] - > getChildren ( ) ; //The function def is the rhs of the access operation
std : : cout < < " Decorating (in access-should be object) " < < name < < " " < < functionDefChildren . size ( ) < < std : : endl ;
for ( int i = 0 ; i < ( functionDefChildren . size ( ) > 0 ? functionDefChildren . size ( ) - 1 : 0 ) ; i + + )
nameDecoration + = " _ " + ValueTypeToCTypeDecoration ( functionDefChildren [ i ] - > getData ( ) . valueType ) ;
/*HERE*/ return CifyName ( unaliasedTypeDef - > getDataRef ( ) - > symbol . getName ( ) ) + " __ " + CifyName ( functionName + nameDecoration ) + " ( " + ( name = = " . " ? " & " : " " ) + generate ( children [ 1 ] , enclosingObject ) + " , " ;
//The comma lets the upper function call know we already started the param list
//Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses
} else {
std : : cout < < " Is not in scope or not type " < < std : : endl ;
return " (( " + generate ( children [ 1 ] , enclosingObject ) + " ) " + name + functionName + " ) " ;
}
} else {
std : : cout < < " Is not in scope or not type " < < std : : endl ;
return " (( " + generate ( children [ 1 ] , enclosingObject ) + " ) " + name + functionName + " ) " ;
2014-02-18 21:55:00 -05:00
}
} else {
2014-03-09 03:13:08 -04:00
//return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")";
return " (( " + generate ( children [ 1 ] , enclosingObject ) + " ) " + name + generate ( children [ 2 ] ) + " ) " ;
2014-02-18 21:55:00 -05:00
}
} else {
2014-03-07 14:17:07 -05:00
//It's a normal function call, not a special one or a method or anything. Name decorate.
std : : vector < NodeTree < ASTData > * > functionDefChildren = children [ 0 ] - > getChildren ( ) ;
std : : cout < < " Decorating (none-special) " < < name < < " " < < functionDefChildren . size ( ) < < std : : endl ;
std : : string nameDecoration ;
for ( int i = 0 ; i < ( functionDefChildren . size ( ) > 0 ? functionDefChildren . size ( ) - 1 : 0 ) ; i + + )
nameDecoration + = " _ " + ValueTypeToCTypeDecoration ( functionDefChildren [ i ] - > getData ( ) . valueType ) ;
2014-03-08 16:13:09 -05:00
//Check to see if we're inside of an object and this is a method call
bool isSelfObjectMethod = enclosingObject & & contains ( enclosingObject - > getChildren ( ) , children [ 0 ] ) ;
if ( isSelfObjectMethod )
2014-07-28 01:52:15 -07:00
output + = CifyName ( enclosingObject - > getDataRef ( ) - > symbol . getName ( ) ) + " __ " ;
2014-06-10 00:53:30 -07:00
/*HERE*/ output + = CifyName ( name + nameDecoration ) + " ( " ;
2014-03-08 16:13:09 -05:00
if ( isSelfObjectMethod )
2014-06-26 01:45:44 -07:00
output + = children . size ( ) > 1 ? " this, " : " this " ;
2014-02-03 11:41:25 -05:00
}
} else {
2014-03-07 14:17:07 -05:00
//This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function)
//It's probabally the result of an access function call (. or ->) to access an object method.
2014-02-18 21:55:00 -05:00
std : : string functionCallSource = generate ( children [ 0 ] , enclosingObject ) ;
if ( functionCallSource [ functionCallSource . size ( ) - 1 ] = = ' , ' ) //If it's a member method, it's already started the parameter list.
output + = children . size ( ) > 1 ? functionCallSource : functionCallSource . substr ( 0 , functionCallSource . size ( ) - 1 ) ;
else
output + = functionCallSource + " ( " ;
2014-02-03 11:41:25 -05:00
}
2013-12-27 13:05:07 -06:00
for ( int i = 1 ; i < children . size ( ) ; i + + ) //children[0] is the declaration
2013-11-01 02:52:18 -04:00
if ( i < children . size ( ) - 1 )
2014-02-03 11:41:25 -05:00
output + = generate ( children [ i ] , enclosingObject ) + " , " ;
2014-03-06 13:13:40 -05:00
else
output + = generate ( children [ i ] , enclosingObject ) ;
2013-11-01 02:52:18 -04:00
output + = " ) " ;
return output ;
}
case value :
return data . symbol . getName ( ) ;
default :
std : : cout < < " Nothing! " < < std : : endl ;
}
for ( int i = 0 ; i < children . size ( ) ; i + + )
2014-02-03 11:41:25 -05:00
output + = generate ( children [ i ] , enclosingObject ) ;
return output ;
}
2014-06-10 23:59:39 -07:00
NodeTree < ASTData > * CGenerator : : getMethodsObjectType ( NodeTree < ASTData > * scope , std : : string functionName ) {
//check the thing
while ( scope ! = scope - > getDataRef ( ) - > valueType - > typeDefinition ) //type is an alias, follow it to the definition
scope = scope - > getDataRef ( ) - > valueType - > typeDefinition ;
return ( scope - > getDataRef ( ) - > scope . find ( functionName ) ! = scope - > getDataRef ( ) - > scope . end ( ) ) ? scope : NULL ;
}
2014-07-28 01:52:15 -07:00
// Returns the function prototype in the out param and the full definition normally
std : : string CGenerator : : generateObjectMethod ( NodeTree < ASTData > * enclosingObject , NodeTree < ASTData > * from , std : : string * functionPrototype ) {
2014-02-03 11:41:25 -05:00
ASTData data = from - > getData ( ) ;
2014-02-18 21:55:00 -05:00
Type enclosingObjectType = * ( enclosingObject - > getDataRef ( ) - > valueType ) ; //Copy a new type so we can turn it into a pointer if we need to
2014-05-19 20:00:35 -04:00
enclosingObjectType . increaseIndirection ( ) ;
2014-02-03 11:41:25 -05:00
std : : vector < NodeTree < ASTData > * > children = from - > getChildren ( ) ;
2014-03-07 14:17:07 -05:00
std : : string nameDecoration , parameters ;
for ( int i = 0 ; i < children . size ( ) - 1 ; i + + ) {
parameters + = " , " + ValueTypeToCType ( children [ i ] - > getData ( ) . valueType ) + " " + generate ( children [ i ] ) ;
nameDecoration + = " _ " + ValueTypeToCTypeDecoration ( children [ i ] - > getData ( ) . valueType ) ;
}
2014-07-28 01:52:15 -07:00
std : : string functionSignature = " \n " + ValueTypeToCType ( data . valueType ) + " " + CifyName ( enclosingObject - > getDataRef ( ) - > symbol . getName ( ) ) + " __ "
2014-05-10 19:28:36 -04:00
+ CifyName ( data . symbol . getName ( ) ) + nameDecoration + " ( " + ValueTypeToCType ( & enclosingObjectType )
2014-07-28 01:52:15 -07:00
+ " this " + parameters + " ) " ;
* functionPrototype + = functionSignature + " ; \n " ;
return functionSignature + " \n " + generate ( children [ children . size ( ) - 1 ] , enclosingObject ) ; //Pass in the object so we can properly handle access to member stuff
2013-11-01 02:52:18 -04:00
}
2015-03-11 01:58:10 -04:00
2014-12-30 01:22:09 -05:00
std : : string CGenerator : : ValueTypeToCType ( Type * type ) { return ValueTypeToCTypeThingHelper ( type , " * " ) ; }
std : : string CGenerator : : ValueTypeToCTypeDecoration ( Type * type ) { return ValueTypeToCTypeThingHelper ( type , " _P__ " ) ; }
std : : string CGenerator : : ValueTypeToCTypeThingHelper ( Type * type , std : : string ptrStr ) {
2014-03-06 13:13:40 -05:00
std : : string return_type ;
switch ( type - > baseType ) {
case none :
if ( type - > typeDefinition )
2014-07-28 01:52:15 -07:00
return_type = CifyName ( type - > typeDefinition - > getDataRef ( ) - > symbol . getName ( ) ) ;
2014-03-06 13:13:40 -05:00
else
return_type = " none " ;
break ;
case void_type :
return_type = " void " ;
break ;
case boolean :
return_type = " bool " ;
break ;
case integer :
return_type = " int " ;
break ;
case floating :
return_type = " float " ;
break ;
case double_percision :
return_type = " double " ;
break ;
case character :
return_type = " char " ;
break ;
default :
return_type = " unknown_ValueType " ;
break ;
}
2014-05-19 20:00:35 -04:00
for ( int i = 0 ; i < type - > getIndirection ( ) ; i + + )
2014-12-30 01:22:09 -05:00
return_type + = ptrStr ;
2014-03-06 13:13:40 -05:00
return return_type ;
}
2014-03-07 14:17:07 -05:00
2014-05-10 19:28:36 -04:00
std : : string CGenerator : : CifyName ( std : : string name ) {
2014-03-14 15:55:45 -04:00
std : : string operatorsToReplace [ ] = { " + " , " plus " ,
" - " , " minus " ,
" * " , " star " ,
" / " , " div " ,
" % " , " mod " ,
" ^ " , " carat " ,
" & " , " amprsd " ,
" | " , " pipe " ,
" ~ " , " tilde " ,
" ! " , " exclamationpt " ,
" , " , " comma " ,
" = " , " equals " ,
" ++ " , " doubleplus " ,
" -- " , " doubleminus " ,
" << " , " doubleleft " ,
" >> " , " doubleright " ,
2014-12-30 01:22:09 -05:00
" :: " , " scopeop " ,
2014-03-14 15:55:45 -04:00
" == " , " doubleequals " ,
" != " , " notequals " ,
" && " , " doubleamprsnd " ,
" || " , " doublepipe " ,
" += " , " plusequals " ,
" -= " , " minusequals " ,
" /= " , " divequals " ,
" %= " , " modequals " ,
" ^= " , " caratequals " ,
" &= " , " amprsdequals " ,
" |= " , " pipeequals " ,
" *= " , " starequals " ,
" <<= " , " doublerightequals " ,
2014-05-10 19:28:36 -04:00
" < " , " lessthan " ,
" > " , " greaterthan " ,
2014-03-14 15:55:45 -04:00
" >>= " , " doubleleftequals " ,
2014-07-18 08:52:15 -07:00
" ( " , " openparen " ,
" ) " , " closeparen " ,
" [ " , " openbracket " ,
" ] " , " closebracket " ,
" " , " space " ,
2015-03-11 01:58:10 -04:00
" . " , " dot " ,
2014-03-14 15:55:45 -04:00
" -> " , " arrow " } ;
int length = sizeof ( operatorsToReplace ) / sizeof ( std : : string ) ;
//std::cout << "Length is " << length << std::endl;
for ( int i = 0 ; i < length ; i + = 2 ) {
size_t foundPos = name . find ( operatorsToReplace [ i ] ) ;
while ( foundPos ! = std : : string : : npos ) {
name = strSlice ( name , 0 , foundPos ) + " _ " + operatorsToReplace [ i + 1 ] + " _ " + strSlice ( name , foundPos + operatorsToReplace [ i ] . length ( ) , - 1 ) ;
foundPos = name . find ( operatorsToReplace [ i ] ) ;
}
}
return name ;
}