From e3aa531856f940c25e1c4187377c8adbb7d96225 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Fri, 10 Apr 2015 00:37:31 -0400 Subject: [PATCH] Wooo actual scoping and better C interop --- include/ASTData.h | 3 +- include/CGenerator.h | 1 + krakenGrammer.kgm | 9 +++-- src/ASTData.cpp | 6 ++++ src/ASTTransformation.cpp | 21 ++++++++--- src/CGenerator.cpp | 30 ++++++++++++++-- src/Importer.cpp | 3 +- stdlib/math.krak | 16 ++++----- stdlib/mem.krak | 8 ++--- tests/c_passthrough_diff.krak | 10 ++++-- tests/sameNameOne.krak | 7 ++++ tests/sameNameTwo.krak | 6 ++++ tests/test_c_passthrough.expected_results | 1 + tests/test_c_passthrough.krak | 13 +++++-- tests/test_negative_number_unary.krak | 14 -------- .../test_negative_number_unary.krak.c | 10 ++++++ .../test_negative_number_unary.krak.h | 27 ++++++++++++++ .../test_negative_number_unary.krak.results | 0 .../test_negative_number_unary.krak.sh | 2 ++ tests/test_sameName.expected_results | 9 +++++ tests/test_sameName.krak | 36 +++++++++++++++++++ tests/test_trigTest.expected_results | 1 + .../TrigTest.krak => tests/test_trigTest.krak | 7 ++-- 23 files changed, 194 insertions(+), 46 deletions(-) create mode 100644 tests/sameNameOne.krak create mode 100644 tests/sameNameTwo.krak delete mode 100644 tests/test_negative_number_unary.krak create mode 100644 tests/test_negative_number_unary.krak/test_negative_number_unary.krak.c create mode 100644 tests/test_negative_number_unary.krak/test_negative_number_unary.krak.h create mode 100644 tests/test_negative_number_unary.krak/test_negative_number_unary.krak.results create mode 100755 tests/test_negative_number_unary.krak/test_negative_number_unary.krak.sh create mode 100644 tests/test_sameName.expected_results create mode 100644 tests/test_sameName.krak create mode 100644 tests/test_trigTest.expected_results rename ChrisTest/TrigTest.krak => tests/test_trigTest.krak (95%) diff --git a/include/ASTData.h b/include/ASTData.h index 5ff182b..daa744a 100644 --- a/include/ASTData.h +++ b/include/ASTData.h @@ -16,7 +16,8 @@ class Type; enum ASTType {undef, translation_unit, interpreter_directive, import, identifier, type_def, function, code_block, typed_parameter, expression, boolean_expression, statement, if_statement, while_loop, for_loop, return_statement, assignment_statement, declaration_statement, - if_comp, simple_passthrough, passthrough_params, function_call, value}; + if_comp, simple_passthrough, passthrough_params, in_passthrough_params, out_passthrough_params, + opt_string, param_assign, function_call, value}; class ASTData { public: diff --git a/include/CGenerator.h b/include/CGenerator.h index d45d522..c70ceac 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -35,6 +35,7 @@ class CGenerator { std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype); NodeTree* getMethodsObjectType(NodeTree* scope, std::string functionName); std::string generatorString; + std::string linkerString; private: std::string tabs(); int tabLevel; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index a5fe94d..57e4455 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -15,7 +15,7 @@ template_param = identifier WS traits | identifier ; import = "import" WS identifier WS SEMI | "import" WS identifier WS ":" WS "\*" WS SEMI | "import" WS identifier WS ":" WS import_list WS SEMI ; import_list = identifier | identifier WS "," WS import_list ; -# all for optional semicolons k k +# all for optional semicolons line_break = " +" ; actual_white = "( | )+" | line_break | line_break actual_white | "( | )+" actual_white ; @@ -28,9 +28,12 @@ SEMI = ";" | line_break | cpp_comment ; if_comp = "__if_comp__" WS identifier WS if_comp_pred ; if_comp_pred = code_block | simple_passthrough ; simple_passthrough = "simple_passthrough" WS passthrough_params WS triple_quoted_string ; -passthrough_params = "\(" WS opt_param_assign_list WS ":" WS opt_param_assign_list WS ":" WS opt_string WS "\)" | ; +passthrough_params = "\(" WS in_passthrough_params WS ":" WS out_passthrough_params WS ":" WS opt_string WS "\)" | ; +in_passthrough_params = opt_param_assign_list ; +out_passthrough_params = opt_param_assign_list ; opt_param_assign_list = param_assign_list | ; -param_assign_list = identifier WS "=" WS identifier | identifier WS "=" WS identifier WS "," WS param_assign_list ; +param_assign_list = param_assign WS "," WS param_assign_list | param_assign ; +param_assign = identifier WS "=" WS identifier ; opt_string = string | ; triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| diff --git a/src/ASTData.cpp b/src/ASTData.cpp index 0869448..8dd84ff 100644 --- a/src/ASTData.cpp +++ b/src/ASTData.cpp @@ -68,6 +68,12 @@ std::string ASTData::ASTTypeToString(ASTType type) { return "simple_passthrough"; case passthrough_params: return "passthrough_params"; + case in_passthrough_params: + return "out_passthrough_params"; + case param_assign: + return "param_assign"; + case opt_string: + return "opt_string"; case function_call: return "function_call"; case value: diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 13bcebb..6a605e0 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -56,6 +56,8 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTreegetChildren()[0]); NodeTree* firstDec = addToScope("~enclosing_scope", translationUnit, new NodeTree("type_def", ASTData(type_def, Symbol(name, true, name)))); + addToScope(name, firstDec, translationUnit); + translationUnit->addChild(firstDec); //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. @@ -71,9 +73,6 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTreegetData().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); - translationUnit->addChild(firstDec); - translationUnit->getDataRef()->scope[name].push_back(firstDec); - firstDec->getDataRef()->scope["~enclosing_scope"].push_back(translationUnit); } else if (i->getDataRef()->getName() == "if_comp") { std::cout << "IF COMP" << std::endl; NodeTree* newNode = addToScope("~enclosing_scope", translationUnit, new NodeTree(i->getDataRef()->getName(), ASTData(if_comp))); @@ -154,7 +153,9 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "type") { Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map()); 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 + // only put in scope if it has a definition, that is it is not an aliased primitive + if (aliasedType->typeDefinition) + 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 // std::cout << name << " alias's to " << aliasedType->typeDefinition << std::endl; // std::cout << "that is " << aliasedType->typeDefinition->getDataRef()->toString() << std::endl; continue; @@ -629,6 +630,18 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "passthrough_params") { newNode = new NodeTree(name, ASTData(passthrough_params)); addToScope("~enclosing_scope", scope, newNode); + } else if (name == "in_passthrough_params") { + newNode = new NodeTree(name, ASTData(in_passthrough_params)); + addToScope("~enclosing_scope", scope, newNode); + } else if (name == "out_passthrough_params") { + newNode = new NodeTree(name, ASTData(out_passthrough_params)); + addToScope("~enclosing_scope", scope, newNode); + } else if (name == "opt_string") { + newNode = new NodeTree(name, ASTData(opt_string)); + addToScope("~enclosing_scope", scope, newNode); + } else if (name == "param_assign") { + newNode = new NodeTree(name, ASTData(param_assign)); + addToScope("~enclosing_scope", scope, newNode); } else if (name == "function_call") { std::string functionCallName = concatSymbolTree(children[0]); newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 7e4b474..70f0164 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -27,6 +27,7 @@ void CGenerator::generateCompSet(std::map*> ASTs, outputCFile.close(); outputHFile.close(); + buildString += linkerString; buildString += "-o " + outputName; std::ofstream outputBuild; outputBuild.open(outputName + "/" + split(outputName, '/').back() + ".sh"); @@ -191,7 +192,7 @@ std::pair CGenerator::generateTranslationUnit(std::str parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], nullptr); nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); } - functionPrototypes += scopePrefix(declaration) + + functionPrototypes += ((declarationData.symbol.getName() == "main") ? "" : scopePrefix(declaration)) + CifyName(declarationData.symbol.getName() + nameDecoration) + "(" + parameters + "); /*func*/\n"; // generate function @@ -295,7 +296,9 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc parameters += ValueTypeToCType(children[j]->getData().valueType) + " " + generate(children[j], enclosingObject); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); } - output += scopePrefix(from) + CifyName(data.symbol.getName() + nameDecoration) + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); + + output += ((data.symbol.getName() == "main") ? "" : scopePrefix(from)) + + CifyName(data.symbol.getName() + nameDecoration) + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); return output; } case code_block: @@ -379,7 +382,28 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc return generate(children[1], enclosingObject); return ""; case simple_passthrough: - return strSlice(generate(children[0], enclosingObject), 3, -4); + { + // Stuff is bit more interesting now! XXX + std::string pre_passthrough, post_passthrough; + // Handle input/output parameters + if (children.front()->getDataRef()->type == passthrough_params) { + auto optParamAssignLists = children.front()->getChildren(); + for (auto in_or_out : optParamAssignLists) { + for (auto assign : in_or_out->getChildren()) { + auto assignChildren = assign->getChildren(); + if (in_or_out->getDataRef()->type == in_passthrough_params) + pre_passthrough += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType) + " " + assignChildren[1]->getDataRef()->symbol.getName() + " = " + generate(assignChildren[0], enclosingObject) + ";\n"; + else if (in_or_out->getDataRef()->type == out_passthrough_params) + post_passthrough += generate(assignChildren[0], enclosingObject) + " = " + assignChildren[1]->getDataRef()->symbol.getName() + ";\n"; + else + linkerString += " " + strSlice(generate(in_or_out, enclosingObject), 1, -2) + " "; + } + } + } + // The actual passthrough string is the last child now, as we might + // have passthrough_params be the first child + return pre_passthrough + strSlice(generate(children.back(), enclosingObject), 3, -4) + post_passthrough; + } case function_call: { //NOTE: The first (0th) child of a function call node is the declaration of the function diff --git a/src/Importer.cpp b/src/Importer.cpp index 79f9f1e..c4c7fe9 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -36,7 +36,8 @@ Importer::Importer(Parser* parserIn, std::vector includePaths, std: removeSymbols.push_back(Symbol("template", true)); removeSymbols.push_back(Symbol("\\|", true)); //collapseSymbols.push_back(Symbol("scoped_identifier", false)); - collapseSymbols.push_back(Symbol("opt_param_assign_list", false)); + collapseSymbols.push_back(Symbol("opt_param_assign_list", false)); + collapseSymbols.push_back(Symbol("param_assign_list", false)); collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_import_list", false)); diff --git a/stdlib/math.krak b/stdlib/math.krak index a530215..5f0b315 100644 --- a/stdlib/math.krak +++ b/stdlib/math.krak @@ -1,4 +1,4 @@ -__if_comp__ __C__ simple_passthrough """ +__if_comp__ __C__ simple_passthrough(::"-lm") """ #include """ @@ -16,7 +16,7 @@ __if_comp__ __C__ simple_passthrough """ { |double| ans = 0; __if_comp__ __C__{ - simple_passthrough(arg = arg : ans = ans :) """ + simple_passthrough(arg = arg, ans = ans : ans = ans :) """ ans = atan(arg); """ }//end C wrapper @@ -28,7 +28,7 @@ __if_comp__ __C__ simple_passthrough """ { |double| ans = 0; __if_comp__ __C__{ - simple_passthrough(x = x, y = y : ans = ans :) """ + simple_passthrough(x = x, y = y, ans = ans : ans = ans :) """ ans = atan2(x,y); """ }//end C wrapper @@ -40,7 +40,7 @@ __if_comp__ __C__ simple_passthrough """ { |double| ans = 0; __if_comp__ __C__{ - simple_passthrough(arg = arg : ans = ans :) """ + simple_passthrough(arg = arg, ans = ans : ans = ans :) """ ans = acos(arg); """ }//end C wrapper @@ -52,7 +52,7 @@ __if_comp__ __C__ simple_passthrough """ { |double| ans = 0; __if_comp__ __C__{ - simple_passthrough(arg = arg : ans = ans :) """ + simple_passthrough(arg = arg, ans = ans : ans = ans :) """ ans = asin(arg); """ }//end C wrapper @@ -64,7 +64,7 @@ __if_comp__ __C__ simple_passthrough """ { |double| ans = 0; __if_comp__ __C__{ - simple_passthrough(arg = arg : ans = ans :) """ + simple_passthrough(arg = arg, ans = ans : ans = ans :) """ ans = tan(arg); """ }//end C wrapper @@ -76,7 +76,7 @@ __if_comp__ __C__ simple_passthrough """ { |double| ans = 0; __if_comp__ __C__{ - simple_passthrough(arg = arg : ans = ans :) """ + simple_passthrough(arg = arg, ans = ans : ans = ans :) """ ans = cos(arg); """ }//end C wrapper @@ -88,7 +88,7 @@ __if_comp__ __C__ simple_passthrough """ { |double| ans = 0; __if_comp__ __C__{ - simple_passthrough(arg = arg : ans = ans :) """ + simple_passthrough(arg = arg, ans = ans : ans = ans :) """ ans = sin(arg); """ }//end C wrapper diff --git a/stdlib/mem.krak b/stdlib/mem.krak index a8d87ce..a799bb2 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -5,9 +5,9 @@ __if_comp__ __C__ simple_passthrough """ /* we have a template versions so we don't have to cast (because we don't have that yet) */ template |T*| malloc(|int| size) { - |T*| memPtr = 0; + |T*| memPtr; __if_comp__ __C__ { - simple_passthrough( size = size : memPtr = memPtr :) """ + simple_passthrough( size = size, memPtr = memPtr : memPtr = memPtr :) """ memPtr = malloc(size); """ } @@ -23,11 +23,11 @@ template |void| free(|T*| memPtr) { } template |int| sizeof() { - |int| result = 0; |T| testObj; + |int| result; __if_comp__ __C__ { simple_passthrough(testObj = testObj : result = result:) """ - result = sizeof(testObj); + int result = sizeof(testObj); """ } return result; diff --git a/tests/c_passthrough_diff.krak b/tests/c_passthrough_diff.krak index a491b85..394d730 100644 --- a/tests/c_passthrough_diff.krak +++ b/tests/c_passthrough_diff.krak @@ -1,11 +1,17 @@ -__if_comp__ __C__ __simple_passthrough__ """ +__if_comp__ __C__ simple_passthrough """ #include int diff = 7; """ |void| print_it() { - __if_comp__ __C__ __simple_passthrough__ """ + __if_comp__ __C__ simple_passthrough """ printf("diff_file: %d\n", diff); """ } + +|void| print_it(|int| i) { + __if_comp__ __C__ simple_passthrough(i = i::) """ + printf("diff_file: %d\n", i); + """ +} diff --git a/tests/sameNameOne.krak b/tests/sameNameOne.krak new file mode 100644 index 0000000..192552f --- /dev/null +++ b/tests/sameNameOne.krak @@ -0,0 +1,7 @@ + +|int| sameVar; +|int| sameFun() { return 5; } +typedef classTester { + |int| method() { return 8; } +} + diff --git a/tests/sameNameTwo.krak b/tests/sameNameTwo.krak new file mode 100644 index 0000000..0b0d15c --- /dev/null +++ b/tests/sameNameTwo.krak @@ -0,0 +1,6 @@ + +|int| sameVar; +|int| sameFun() { return 6; } +typedef classTester { + |int| method() { return 9; } +} diff --git a/tests/test_c_passthrough.expected_results b/tests/test_c_passthrough.expected_results index 1822295..4a70708 100644 --- a/tests/test_c_passthrough.expected_results +++ b/tests/test_c_passthrough.expected_results @@ -1,2 +1,3 @@ same_file: 5 diff_file: 7 +diff_file: 13 diff --git a/tests/test_c_passthrough.krak b/tests/test_c_passthrough.krak index 589939a..b79a748 100644 --- a/tests/test_c_passthrough.krak +++ b/tests/test_c_passthrough.krak @@ -1,17 +1,24 @@ import c_passthrough_diff -__if_comp__ __C__ __simple_passthrough__ """ +__if_comp__ __C__ simple_passthrough """ #include int same = 5; """ |int| main() { - __if_comp__ __C__ __simple_passthrough__ """ + __if_comp__ __C__ simple_passthrough """ printf("same_file: %d\n", same); """ - c_passthrough_diff::print_it() + + c_passthrough_diff::print_it(); + |int| i = 7; + |int| j = 6; + __if_comp__ __C__ simple_passthrough(i = i, j = j : j = j:) """ + j = i + j; + """ + c_passthrough_diff::print_it(j) return 0 } diff --git a/tests/test_negative_number_unary.krak b/tests/test_negative_number_unary.krak deleted file mode 100644 index 7f1a2e3..0000000 --- a/tests/test_negative_number_unary.krak +++ /dev/null @@ -1,14 +0,0 @@ -import io:* - -|int| main() { - |int| a = -1 - println(a) - println(-a) - println(+a); // this is still -1! (as C has it, anyway) (darn comment/semicolon interaction) - - |int| b = 7 - println(b) - println(-b) - - return 0; -} diff --git a/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.c b/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.c new file mode 100644 index 0000000..8200aba --- /dev/null +++ b/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.c @@ -0,0 +1,10 @@ +#include "test_negative_number_unary.krak.h" + +/** + * Variable Declarations + */ + +/** + * Function Definitions + */ + diff --git a/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.h b/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.h new file mode 100644 index 0000000..34251d0 --- /dev/null +++ b/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.h @@ -0,0 +1,27 @@ +#include +#include +#include +/** + * Plain Typedefs + */ + +/** + * Import Includes + */ + +/** + * Top Level C Passthrough + */ + +/** + * Extern Variable Declarations + */ + +/** + * Class Structs + */ + +/** + * Function Prototypes + */ + diff --git a/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.results b/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.results new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.sh b/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.sh new file mode 100755 index 0000000..9673afa --- /dev/null +++ b/tests/test_negative_number_unary.krak/test_negative_number_unary.krak.sh @@ -0,0 +1,2 @@ +#!/bin/sh +cc -std=c99 test_negative_number_unary.krak.c -o test_negative_number_unary.krak \ No newline at end of file diff --git a/tests/test_sameName.expected_results b/tests/test_sameName.expected_results new file mode 100644 index 0000000..0719398 --- /dev/null +++ b/tests/test_sameName.expected_results @@ -0,0 +1,9 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/tests/test_sameName.krak b/tests/test_sameName.krak new file mode 100644 index 0000000..a75470e --- /dev/null +++ b/tests/test_sameName.krak @@ -0,0 +1,36 @@ +import io:* +import sameNameOne +import sameNameTwo + +|int| sameVar; +|int| sameFun() { return 4; } + +typedef classTester { + |int| method() { + return 7 + } +} + +|int| main() { + sameVar = 1 + sameNameOne::sameVar = 2 + sameNameTwo::sameVar = 3 + + |classTester| class1; + |sameNameOne::classTester| class2; + |sameNameTwo::classTester| class3; + + println(sameVar) + println(sameNameOne::sameVar) + println(sameNameTwo::sameVar) + + println(sameFun()) + println(sameNameOne::sameFun()) + println(sameNameTwo::sameFun()) + + println(class1.method()) + println(class2.method()) + println(class3.method()) + + return 0 +} diff --git a/tests/test_trigTest.expected_results b/tests/test_trigTest.expected_results new file mode 100644 index 0000000..f92ee1f --- /dev/null +++ b/tests/test_trigTest.expected_results @@ -0,0 +1 @@ +3.141593 diff --git a/ChrisTest/TrigTest.krak b/tests/test_trigTest.krak similarity index 95% rename from ChrisTest/TrigTest.krak rename to tests/test_trigTest.krak index 4674134..51811c8 100644 --- a/ChrisTest/TrigTest.krak +++ b/tests/test_trigTest.krak @@ -5,7 +5,8 @@ import math:*; { |double| ans; |double| STD_PI = 4.0*atan(1.0); - + println(STD_PI); + /* ans = 4.0*atan(1.0); print("atan = "); @@ -18,11 +19,11 @@ import math:*; ans = acos(1.0); print("acos = "); println(ans); - + ans = 2.0 * asin(1.0); print("asin = "); println(ans); - + ans = tan(STD_PI / 4.0); print("tan = "); println(ans);