Break, continue, and DEFER statements! Woooo
This commit is contained in:
@@ -15,9 +15,9 @@ class Type;
|
|||||||
|
|
||||||
enum ASTType {undef, translation_unit, interpreter_directive, import, identifier, type_def,
|
enum ASTType {undef, translation_unit, interpreter_directive, import, identifier, type_def,
|
||||||
function, code_block, typed_parameter, expression, boolean_expression, statement,
|
function, code_block, typed_parameter, expression, boolean_expression, statement,
|
||||||
if_statement, while_loop, for_loop, return_statement, assignment_statement, declaration_statement,
|
if_statement, while_loop, for_loop, return_statement, break_statement, continue_statement, defer_statement,
|
||||||
if_comp, simple_passthrough, passthrough_params, in_passthrough_params, out_passthrough_params,
|
assignment_statement, declaration_statement, if_comp, simple_passthrough, passthrough_params,
|
||||||
opt_string, param_assign, function_call, value};
|
in_passthrough_params, out_passthrough_params, opt_string, param_assign, function_call, value};
|
||||||
|
|
||||||
class ASTData {
|
class ASTData {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <stack>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "NodeTree.h"
|
#include "NodeTree.h"
|
||||||
@@ -34,10 +35,13 @@ class CGenerator {
|
|||||||
static std::string scopePrefix(NodeTree<ASTData>* from);
|
static std::string scopePrefix(NodeTree<ASTData>* from);
|
||||||
std::string generateObjectMethod(NodeTree<ASTData>* enclosingObject, NodeTree<ASTData>* from, std::string *functionPrototype);
|
std::string generateObjectMethod(NodeTree<ASTData>* enclosingObject, NodeTree<ASTData>* from, std::string *functionPrototype);
|
||||||
NodeTree<ASTData>* getMethodsObjectType(NodeTree<ASTData>* scope, std::string functionName);
|
NodeTree<ASTData>* getMethodsObjectType(NodeTree<ASTData>* scope, std::string functionName);
|
||||||
|
std::string tabs();
|
||||||
|
|
||||||
|
int tabLevel;
|
||||||
std::string generatorString;
|
std::string generatorString;
|
||||||
std::string linkerString;
|
std::string linkerString;
|
||||||
|
std::vector<std::vector<NodeTree<ASTData>*>> deferDoubleStack;
|
||||||
|
std::stack<int> loopDeferStackDepth;
|
||||||
private:
|
private:
|
||||||
std::string tabs();
|
|
||||||
int tabLevel;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -87,7 +87,10 @@ return_statement = "return" | "return" WS boolean_expression ;
|
|||||||
code_block = "{" WS statement_list WS "}" | "{" WS "}" ;
|
code_block = "{" WS statement_list WS "}" | "{" WS "}" ;
|
||||||
|
|
||||||
statement_list = statement_list WS statement | statement ;
|
statement_list = statement_list WS statement | statement ;
|
||||||
statement = if_statement | while_loop | for_loop | return_statement line_end | boolean_expression line_end | assignment_statement line_end | declaration_statement line_end | code_block | if_comp | simple_passthrough ;
|
statement = if_statement | while_loop | for_loop | return_statement line_end | boolean_expression line_end | assignment_statement line_end | declaration_statement line_end | code_block | if_comp | simple_passthrough | break_statement | continue_statement | defer_statement ;
|
||||||
|
break_statement = "break" ;
|
||||||
|
continue_statement = "continue" ;
|
||||||
|
defer_statement = "defer" WS statement ;
|
||||||
function_call = unarad "\(" WS opt_parameter_list WS "\)" ;
|
function_call = unarad "\(" WS opt_parameter_list WS "\)" ;
|
||||||
|
|
||||||
boolean_expression = boolean_expression WS "\|\|" WS and_boolean_expression | and_boolean_expression ;
|
boolean_expression = boolean_expression WS "\|\|" WS and_boolean_expression | and_boolean_expression ;
|
||||||
|
|||||||
@@ -58,6 +58,12 @@ std::string ASTData::ASTTypeToString(ASTType type) {
|
|||||||
return "for_loop";
|
return "for_loop";
|
||||||
case return_statement:
|
case return_statement:
|
||||||
return "return_statement";
|
return "return_statement";
|
||||||
|
case break_statement:
|
||||||
|
return "break_statement";
|
||||||
|
case continue_statement:
|
||||||
|
return "continue_statement";
|
||||||
|
case defer_statement:
|
||||||
|
return "defer_statement";
|
||||||
case assignment_statement:
|
case assignment_statement:
|
||||||
return "assignment_statement";
|
return "assignment_statement";
|
||||||
case declaration_statement:
|
case declaration_statement:
|
||||||
|
|||||||
@@ -586,6 +586,12 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
|||||||
newNode = new NodeTree<ASTData>(name, ASTData(for_loop));
|
newNode = new NodeTree<ASTData>(name, ASTData(for_loop));
|
||||||
} else if (name == "return_statement") {
|
} else if (name == "return_statement") {
|
||||||
newNode = new NodeTree<ASTData>(name, ASTData(return_statement));
|
newNode = new NodeTree<ASTData>(name, ASTData(return_statement));
|
||||||
|
} else if (name == "break_statement") {
|
||||||
|
newNode = new NodeTree<ASTData>(name, ASTData(break_statement));
|
||||||
|
} else if (name == "continue_statement") {
|
||||||
|
newNode = new NodeTree<ASTData>(name, ASTData(continue_statement));
|
||||||
|
} else if (name == "defer_statement") {
|
||||||
|
newNode = new NodeTree<ASTData>(name, ASTData(defer_statement));
|
||||||
} else if (name == "assignment_statement") {
|
} else if (name == "assignment_statement") {
|
||||||
newNode = new NodeTree<ASTData>(name, ASTData(assignment_statement));
|
newNode = new NodeTree<ASTData>(name, ASTData(assignment_statement));
|
||||||
std::string assignFuncName = concatSymbolTree(children[1]);
|
std::string assignFuncName = concatSymbolTree(children[1]);
|
||||||
@@ -609,16 +615,9 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
|||||||
return newNode;
|
return newNode;
|
||||||
} else if (name == "declaration_statement") {
|
} else if (name == "declaration_statement") {
|
||||||
newNode = new NodeTree<ASTData>(name, ASTData(declaration_statement));
|
newNode = new NodeTree<ASTData>(name, ASTData(declaration_statement));
|
||||||
|
|
||||||
// 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[0]);
|
std::string newIdentifierStr = concatSymbolTree(children[0]);
|
||||||
NodeTree<Symbol>* typeSyntaxNode = getNode("type", children);
|
NodeTree<Symbol>* typeSyntaxNode = getNode("type", children);
|
||||||
Type* identifierType = typeSyntaxNode ? typeFromTypeNode(typeSyntaxNode, scope, templateTypeReplacements) : nullptr;
|
Type* identifierType = typeSyntaxNode ? typeFromTypeNode(typeSyntaxNode, scope, templateTypeReplacements) : nullptr;
|
||||||
//if (children.size() > 1 && concatSymbolTree(children[1]) == ".")
|
|
||||||
//identifierType = typeFromTypeNode(children.back(), scope, templateTypeReplacements);
|
|
||||||
//else
|
|
||||||
//identifierType = typeFromTypeNode(children[2], scope, templateTypeReplacements);
|
|
||||||
|
|
||||||
if (identifierType)
|
if (identifierType)
|
||||||
std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl;
|
std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl;
|
||||||
@@ -652,9 +651,6 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
|||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
//skipChildren.insert(0); //These, the type and the identifier, have been taken care of.
|
|
||||||
//skipChildren.insert(2);
|
|
||||||
//auto transChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements);
|
|
||||||
auto boolExp = getNode("boolean_expression", children);
|
auto boolExp = getNode("boolean_expression", children);
|
||||||
NodeTree<ASTData>* toAssign = boolExp ? transform(boolExp, scope, types, templateTypeReplacements) : nullptr;
|
NodeTree<ASTData>* toAssign = boolExp ? transform(boolExp, scope, types, templateTypeReplacements) : nullptr;
|
||||||
// for type inferencing
|
// for type inferencing
|
||||||
@@ -673,7 +669,6 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
|||||||
newNode->addChild(newIdentifier);
|
newNode->addChild(newIdentifier);
|
||||||
if (toAssign)
|
if (toAssign)
|
||||||
newNode->addChild(toAssign);
|
newNode->addChild(toAssign);
|
||||||
//newNode->addChildren(transChildren);
|
|
||||||
return newNode;
|
return newNode;
|
||||||
} else if (name == "if_comp") {
|
} else if (name == "if_comp") {
|
||||||
newNode = new NodeTree<ASTData>(name, ASTData(if_comp));
|
newNode = new NodeTree<ASTData>(name, ASTData(if_comp));
|
||||||
|
|||||||
@@ -304,31 +304,15 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
|||||||
case code_block:
|
case code_block:
|
||||||
{
|
{
|
||||||
output += "{\n";
|
output += "{\n";
|
||||||
std::string destructorString = "";
|
|
||||||
tabLevel++;
|
tabLevel++;
|
||||||
for (int i = 0; i < children.size(); i++) {
|
// we push on a new vector to hold deferred statements
|
||||||
//std::cout << "Line " << i << std::endl;
|
deferDoubleStack.push_back(std::vector<NodeTree<ASTData>*>());
|
||||||
std::string line = generate(children[i], enclosingObject);
|
for (int i = 0; i < children.size(); i++)
|
||||||
//std::cout << line << std::endl;
|
output += generate(children[i], enclosingObject);
|
||||||
output += line;
|
// we pop off the vector and go through them in reverse emitting them
|
||||||
if (children[i]->getChildren().size() && children[i]->getChildren()[0]->getDataRef()->type == declaration_statement) {
|
for (auto iter = deferDoubleStack.back().rbegin(); iter != deferDoubleStack.back().rend(); iter++)
|
||||||
NodeTree<ASTData> *identifier = children[i]->getChildren()[0]->getChildren()[0];
|
output += generate(*iter, enclosingObject);
|
||||||
Type* declarationType = identifier->getDataRef()->valueType;
|
deferDoubleStack.pop_back();
|
||||||
if (declarationType->getIndirection())
|
|
||||||
continue;
|
|
||||||
NodeTree<ASTData> *typeDefinition = declarationType->typeDefinition;
|
|
||||||
if (!typeDefinition)
|
|
||||||
continue;
|
|
||||||
if (typeDefinition->getDataRef()->scope.find("destruct") == typeDefinition->getDataRef()->scope.end())
|
|
||||||
continue;
|
|
||||||
// ***************************************************************************************
|
|
||||||
// I've decided not to do the destructor thing. This will come back soon for defer though!
|
|
||||||
// ***************************************************************************************
|
|
||||||
//destructorString += tabs() + scopePrefix(from) + CifyName(typeDefinition->getDataRef()->symbol.getName())
|
|
||||||
//+ "__" + "destruct" + "(&" + generate(identifier, enclosingObject) + ");\n";//Call the destructor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output += destructorString;
|
|
||||||
tabLevel--;
|
tabLevel--;
|
||||||
output += tabs() + "}";
|
output += tabs() + "}";
|
||||||
return output;
|
return output;
|
||||||
@@ -348,24 +332,59 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
|||||||
std::cout << "Then statement is a block, emitting the block not the statement so no trailing semicolon" << std::endl;
|
std::cout << "Then statement is a block, emitting the block not the statement so no trailing semicolon" << std::endl;
|
||||||
output += generate(children[1]->getChildren()[0], enclosingObject);
|
output += generate(children[1]->getChildren()[0], enclosingObject);
|
||||||
} else {
|
} else {
|
||||||
|
// ALSO we always emit blocks now, to handle cases like defer when several statements need to be
|
||||||
|
// run in C even though it is a single Kraken statement
|
||||||
std::cout << "Then statement is a simple statement, regular emitting the statement so trailing semicolon" << std::endl;
|
std::cout << "Then statement is a simple statement, regular emitting the statement so trailing semicolon" << std::endl;
|
||||||
output += generate(children[1], enclosingObject);
|
output += "{ " + generate(children[1], enclosingObject) + " }";
|
||||||
}
|
}
|
||||||
|
// Always emit blocks here too
|
||||||
if (children.size() > 2)
|
if (children.size() > 2)
|
||||||
output += " else " + generate(children[2], enclosingObject);
|
output += " else { " + generate(children[2], enclosingObject) + " }";
|
||||||
return output;
|
return output;
|
||||||
case while_loop:
|
case while_loop:
|
||||||
|
// keep track of the current size of the deferDoubleStack so that statements that
|
||||||
|
// break or continue inside this loop can correctly emit all of the defers through
|
||||||
|
// all of the inbetween scopes
|
||||||
|
loopDeferStackDepth.push(deferDoubleStack.size());
|
||||||
output += "while (" + generate(children[0], enclosingObject) + ")\n\t" + generate(children[1], enclosingObject);
|
output += "while (" + generate(children[0], enclosingObject) + ")\n\t" + generate(children[1], enclosingObject);
|
||||||
|
// and pop it off again
|
||||||
|
loopDeferStackDepth.pop();
|
||||||
return output;
|
return output;
|
||||||
case for_loop:
|
case for_loop:
|
||||||
|
// keep track of the current size of the deferDoubleStack so that statements that
|
||||||
|
// break or continue inside this loop can correctly emit all of the defers through
|
||||||
|
// all of the inbetween scopes
|
||||||
|
loopDeferStackDepth.push(deferDoubleStack.size());
|
||||||
//The strSlice's are there to get ride of an unwanted return and an unwanted semicolon(s)
|
//The strSlice's are there to get ride of an unwanted return and an unwanted semicolon(s)
|
||||||
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);
|
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);
|
||||||
|
// and pop it off again
|
||||||
|
loopDeferStackDepth.pop();
|
||||||
return output;
|
return output;
|
||||||
case return_statement:
|
case return_statement:
|
||||||
|
// we pop off the vector and go through them in reverse emitting them, going
|
||||||
|
// through all of both arrays, as return will go through all scopes
|
||||||
|
for (auto topItr = deferDoubleStack.rbegin(); topItr != deferDoubleStack.rend(); topItr++)
|
||||||
|
for (auto iter = (*topItr).rbegin(); iter != (*topItr).rend(); iter++)
|
||||||
|
output += generate(*iter, enclosingObject);
|
||||||
if (children.size())
|
if (children.size())
|
||||||
return "return " + generate(children[0], enclosingObject);
|
return "return " + generate(children[0], enclosingObject);
|
||||||
else
|
else
|
||||||
return "return";
|
return "return";
|
||||||
|
case break_statement:
|
||||||
|
// handle everything that's been deferred all the way back to the loop's scope
|
||||||
|
for (int i = deferDoubleStack.size()-1; i >= loopDeferStackDepth.top(); i--)
|
||||||
|
for (auto iter = deferDoubleStack[i].rbegin(); iter != deferDoubleStack[i].rend(); iter++)
|
||||||
|
output += generate(*iter, enclosingObject);
|
||||||
|
return output + "break";
|
||||||
|
case continue_statement:
|
||||||
|
// handle everything that's been deferred all the way back to the loop's scope
|
||||||
|
for (int i = deferDoubleStack.size()-1; i >= loopDeferStackDepth.top(); i--)
|
||||||
|
for (auto iter = deferDoubleStack[i].rbegin(); iter != deferDoubleStack[i].rend(); iter++)
|
||||||
|
output += generate(*iter, enclosingObject);
|
||||||
|
return output + "continue";
|
||||||
|
case defer_statement:
|
||||||
|
deferDoubleStack.back().push_back(children[0]);
|
||||||
|
return "/*defer " + generate(children[0], enclosingObject) + "*/";
|
||||||
case assignment_statement:
|
case assignment_statement:
|
||||||
return generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject);
|
return generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject);
|
||||||
case declaration_statement:
|
case declaration_statement:
|
||||||
|
|||||||
16
tests/test_break_continue_defer.expected_results
Normal file
16
tests/test_break_continue_defer.expected_results
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
1
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
3
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
5
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
7
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
happens every time, even when breaking or continueing
|
||||||
|
first
|
||||||
|
last
|
||||||
|
deferred
|
||||||
20
tests/test_break_continue_defer.krak
Normal file
20
tests/test_break_continue_defer.krak
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import io:*
|
||||||
|
|
||||||
|
fun main():int {
|
||||||
|
for (var i = 1; i < 10; i++;) {
|
||||||
|
{
|
||||||
|
defer println("happens every time, even when breaking or continueing")
|
||||||
|
if (i % 2 == 0)
|
||||||
|
continue
|
||||||
|
if (i == 9)
|
||||||
|
break
|
||||||
|
println(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
println("first")
|
||||||
|
defer println("deferred")
|
||||||
|
println("last")
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user