Added "Init Position Call" (takes the place of implicit constructors) and the this keyword! This was the structure needed for more sensable memory management. At least delete will need some updating before it becomes very usable, though. (Figuring out the types for function template instantiation) Anyway, good progress here!

This commit is contained in:
Nathan Braswell
2014-06-26 01:45:44 -07:00
parent 82d8a15de0
commit 63d9ec66e1
7 changed files with 134 additions and 50 deletions

View File

@@ -45,7 +45,8 @@ class ASTTransformation: public NodeTransformation<Symbol,ASTData> {
NodeTree<ASTData>* findOrInstantiateFunctionTemplate(std::vector<NodeTree<Symbol>*> children, NodeTree<ASTData>* scope, std::vector<Type> types, std::map<std::string, Type*> templateTypeReplacements);
private:
Importer * importer;
std::map<std::string, std::vector<NodeTree<ASTData>*>> languageLevelScope;
std::map<std::string, std::vector<NodeTree<ASTData>*>> languageLevelReservedWords;
std::map<std::string, std::vector<NodeTree<ASTData>*>> languageLevelOperators;
NodeTree<ASTData>* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated
};

View File

@@ -81,7 +81,7 @@ number = integer | float | double ;
access_operation = unarad "." identifier | unarad "->" identifier ;
assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression ;
declaration_statement = type WS identifier WS "=" WS boolean_expression | type WS identifier ;
declaration_statement = type WS identifier WS "=" WS boolean_expression | type WS identifier | type WS identifier WS "." WS identifier WS "\(" WS opt_parameter_list WS "\)" ;
alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ;
hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ;

View File

@@ -3,30 +3,34 @@
ASTTransformation::ASTTransformation(Importer *importerIn) {
importer = importerIn;
topScope = NULL;
//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)
//Note the NULL type
languageLevelScope["+"].push_back( new NodeTree<ASTData>("function", ASTData(function, Symbol("+", true), NULL)));
languageLevelScope["-"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("-", true), NULL)));
languageLevelScope["*"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("*", true), NULL)));
languageLevelScope["/"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("/", true), NULL)));
languageLevelScope["%"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("%", true), NULL)));
languageLevelScope["&"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("&", true), NULL)));
languageLevelScope["--"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("--", true), NULL)));
languageLevelScope["++"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("++", true), NULL)));
languageLevelScope["=="].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("==", true), NULL)));
languageLevelScope["<="].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("<=", true), NULL)));
languageLevelScope[">="].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol(">=", true), NULL)));
languageLevelScope["<"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("<", true), NULL)));
languageLevelScope[">"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol(">", true), NULL)));
languageLevelScope["&&"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("&&", true), NULL)));
languageLevelScope["||"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("||", true), NULL)));
languageLevelScope["!"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("!", true), NULL)));
languageLevelScope["*="].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("*=", true), NULL)));
languageLevelScope["+="].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("+=", true), NULL)));
languageLevelScope["-="].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("-=", true), NULL)));
languageLevelScope["."].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol(".", true), NULL)));
languageLevelScope["->"].push_back(new NodeTree<ASTData>("function", ASTData(function, Symbol("->", true), NULL)));
languageLevelScope["[]"].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)));
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)));
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)));
}
ASTTransformation::~ASTTransformation() {
@@ -132,6 +136,7 @@ void ASTTransformation::secondPassDoClassInsides(NodeTree<ASTData>* typeDef, std
//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) {
//Check here for method call (an error here)
NodeTree<ASTData>* decStmt = new NodeTree<ASTData>("declaration_statement", ASTData(declaration_statement));
std::string newIdentifierStr = concatSymbolTree(from->getChildren()[1]);
Type* identifierType = typeFromTypeNode(from->getChildren()[0], scope, templateTypeReplacements, false);
@@ -576,8 +581,32 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope);
newNode->addChild(newIdentifier);
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);
std::vector<NodeTree<ASTData>*> initPositionFuncParams = transformChildren(sliced, std::set<int>(), scope, types, templateTypeReplacements, instantiateTemplates);
NodeTree<ASTData>* rhs = transform(children[3], identifierType->typeDefinition, mapNodesToTypes(initPositionFuncParams), templateTypeReplacements, instantiateTemplates); //If an access operation, then the right side will be in the lhs's type's scope
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;
}
skipChildren.insert(0); //These, the type and the identifier, have been taken care of.
skipChildren.insert(1);
newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates));
return newNode;
} else if (name == "if_comp") {
newNode = new NodeTree<ASTData>(name, ASTData(if_comp));
newNode->addChild(new NodeTree<ASTData>("identifier", ASTData(identifier, Symbol(concatSymbolTree(children[0]),true))));
@@ -627,15 +656,7 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
}
//Do all children but the ones we skip
for (int i = 0; i < children.size(); i++) {
if (skipChildren.find(i) == skipChildren.end()) {
NodeTree<ASTData>* transChild = transform(children[i], scope, types, templateTypeReplacements, instantiateTemplates);
if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData.
newNode->addChild(transChild);
else
delete transChild;
}
}
newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates));
return newNode;
}
@@ -680,9 +701,9 @@ std::string ASTTransformation::concatSymbolTree(NodeTree<Symbol>* root) {
//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) {
auto LLElementIterator = languageLevelScope.find(lookup);
auto LLElementIterator = languageLevelOperators.find(lookup);
NodeTree<ASTData>* newNode;
if (LLElementIterator != languageLevelScope.end()) {
if (LLElementIterator != languageLevelOperators.end()) {
std::cout << "Checking for early method level operator overload" << std::endl;
std::string lookupOp = "operator" + lookup;
for (auto i : nodes)
@@ -697,7 +718,7 @@ NodeTree<ASTData>* ASTTransformation::doFunction(NodeTree<ASTData>* scope, std::
//return operatorMethod;
NodeTree<ASTData>* newNode = new NodeTree<ASTData>(lookupOp, ASTData(function_call, Symbol(lookupOp, true)));
NodeTree<ASTData>* dotFunctionCall = new NodeTree<ASTData>(".", ASTData(function_call, Symbol(".", true)));
dotFunctionCall->addChild(languageLevelScope["."][0]); //function definition
dotFunctionCall->addChild(languageLevelOperators["."][0]); //function definition
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
@@ -740,9 +761,15 @@ NodeTree<ASTData>* ASTTransformation::doFunction(NodeTree<ASTData>* scope, std::
//Search recursively through levels of scope (each ASTData, that is, every node, has its own scope)
//We pass in types so that if we're searching for a function we can find the right overloaded one
NodeTree<ASTData>* ASTTransformation::scopeLookup(NodeTree<ASTData>* scope, std::string lookup, std::vector<Type> types) {
//We first search the languageLevelScope to see if it's an operator. If so, we modifiy the lookup with a preceding "operator"
auto LLElementIterator = languageLevelScope.find(lookup);
if (LLElementIterator != languageLevelScope.end())
//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())
lookup = "operator" + lookup;
//Search the map
auto scopeMap = scope->getDataRef()->scope;
@@ -802,7 +829,7 @@ NodeTree<ASTData>* ASTTransformation::scopeLookup(NodeTree<ASTData>* scope, std:
std::cout << "could not find " << lookup << " in standard scope, checking for operator" << std::endl;
//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
//Also, we've already searched for the element because this is also how we keep track of operator overloading
if (LLElementIterator != languageLevelScope.end()) {
if (LLElementIterator != languageLevelOperators.end()) {
std::cout << "found it at language level as operator." << std::endl;
return LLElementIterator->second[0];
}

View File

@@ -49,7 +49,7 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
Poset<NodeTree<ASTData>*> typedefPoset;
for (int i = 0; i < children.size(); i++) {
if (children[i]->getDataRef()->type == type_def) {
typedefPoset.addVertex(children[i]); //We add this definition by itself just in case there are no dependencies.
typedefPoset.addVertex(children[i]); //We add this definition by itthis 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.
@@ -129,10 +129,16 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
//return "#include <" + data.symbol.getName() + ">\n";
case identifier:
{
//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 self reference.
//but first, if we're this, we should just emit. (assuming enclosing object) (note that technically this would fall through, but for errors)
if (data.symbol.getName() == "this")
if (enclosingObject)
return "this";
else
std::cout << "Error: this used in non-object scope" << std::endl;
//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.
std::string preName;
if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end())
preName += "self->";
preName += "this->";
if (false)
for (int j = 0; j < children.size()-1; j++)
preName += ValueTypeToCType(children[j]->getData().valueType) + "_";
@@ -213,7 +219,12 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
case declaration_statement:
if (children.size() == 1)
return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + ";";
else
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
return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject) + ";";
case if_comp:
if (generate(children[0], enclosingObject) == generatorString)
@@ -288,7 +299,7 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
output += enclosingObject->getDataRef()->symbol.getName() +"__";
/*HERE*/ output += CifyName(name + nameDecoration) + "(";
if (isSelfObjectMethod)
output += children.size() > 1 ? "self," : "self";
output += children.size() > 1 ? "this," : "this";
}
} else {
//This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function)
@@ -337,7 +348,7 @@ std::string CGenerator::generateObjectMethod(NodeTree<ASTData>* enclosingObject,
}
output += "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__"
+ CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType)
+ " self" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff
+ " this" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff
return output;
}

View File

@@ -11,6 +11,11 @@ void print(char* toPrint) {
return;
}
void println(char* toPrint) {
print(toPrint);
print("\n");
}
void print(int toPrint) {
__if_comp__ __C__ {
__simple_passthrough__ """
@@ -20,6 +25,11 @@ void print(int toPrint) {
return;
}
void println(int toPrint) {
print(toPrint);
print("\n");
}
void print(float toPrint) {
__if_comp__ __C__ {
__simple_passthrough__ """
@@ -28,3 +38,9 @@ void print(float toPrint) {
}
return;
}
void println(float toPrint) {
print(toPrint);
print("\n");
}

View File

@@ -0,0 +1,3 @@
4
8
11

View File

@@ -0,0 +1,26 @@
import io;
import mem;
typedef ClassWithConstructor {
int data;
ClassWithConstructor* construct(int inData) {
data = inData;
return this;
}
void printData() {
println(data);
}
};
int main() {
ClassWithConstructor object.construct(4);
//ClassWithConstructor object;
//object.construct(4);
object.printData();
int a = 8;
println(a);
ClassWithConstructor* objPtr = new<ClassWithConstructor>()->construct(11);
objPtr->printData();
delete<ClassWithConstructor>(objPtr);
return 0;
}