From e7a49bf2e5c49dd2e846c1334097babb028451c7 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sat, 14 Nov 2015 19:05:28 -0500 Subject: [PATCH] Match statements work with ADTs! (still no object stuff or anything though) --- include/ASTData.h | 6 +++--- krakenGrammer.kgm | 6 +++++- src/ASTTransformation.cpp | 24 ++++++++++++++++++++++++ src/CGenerator.cpp | 29 +++++++++++++++++++++++++++++ src/Importer.cpp | 3 ++- tests/test_adt.krak | 15 +++++++++++++++ 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/include/ASTData.h b/include/ASTData.h index 12bf354..ac3a328 100644 --- a/include/ASTData.h +++ b/include/ASTData.h @@ -16,9 +16,9 @@ class Type; enum ASTType {undef, translation_unit, interpreter_directive, import, identifier, type_def, adt_def, function, code_block, typed_parameter, expression, boolean_expression, statement, - if_statement, while_loop, for_loop, return_statement, break_statement, continue_statement, defer_statement, - assignment_statement, declaration_statement, if_comp, simple_passthrough, passthrough_params, - in_passthrough_params, out_passthrough_params, opt_string, param_assign, function_call, value}; + if_statement, match_statement, case_statement, while_loop, for_loop, return_statement, break_statement, + continue_statement, defer_statement, assignment_statement, declaration_statement, 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/krakenGrammer.kgm b/krakenGrammer.kgm index 122ae4c..ad918cc 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -95,6 +95,10 @@ adt_option = identifier | identifier WS dec_type ; if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement | "if" WS "\(" WS boolean_expression WS "\)" WS statement WS "else" WS statement ; +match_statement = "match" WS "\(" WS boolean_expression WS "\)" WS "{" WS case_statement_list WS "}" ; +case_statement_list = case_statement WS case_statement_list | case_statement ; +case_statement = scoped_identifier WS "\(" WS identifier WS "\)" WS statement | scoped_identifier WS "\(" WS "\)" WS statement ; + while_loop = "while" WS boolean_expression WS statement ; for_loop = "for" WS "\(" WS statement WS boolean_expression line_end WS statement WS "\)" WS statement ; @@ -104,7 +108,7 @@ return_statement = "return" | "return" WS boolean_expression ; code_block = "{" WS statement_list WS "}" | "{" WS "}" ; 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 | break_statement | continue_statement | defer_statement ; +statement = if_statement | match_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 ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 3718315..a3e22d7 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -662,6 +662,30 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(name, ASTData(statement)); } else if (name == "if_statement") { newNode = new NodeTree(name, ASTData(if_statement)); + } else if (name == "match_statement") { + newNode = new NodeTree(name, ASTData(match_statement)); + } else if (name == "case_statement") { + newNode = new NodeTree(name, ASTData(case_statement)); + std::string adtOptionStr = concatSymbolTree(getNodes("scoped_identifier", children)[0]); + auto optionDefPoss = scopeLookup(scope, adtOptionStr); + auto optionDef = optionDefPoss[0]; + //auto adtDef = optionDef->getDataRef()->scope["~enclosing_scope"][0]; + + addToScope("~enclosing_scope", scope, newNode); + newNode->addChild(optionDef); + + // we have a destructure + auto newIdentifierSymbolNodes = getNodes("identifier", children); + if (newIdentifierSymbolNodes.size()) { + std::string newIdentifierStr = concatSymbolTree(newIdentifierSymbolNodes[0]); + NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), optionDef->getDataRef()->valueType)); + addToScope(newIdentifierStr, newIdentifier, newNode); + addToScope("~enclosing_scope", newNode, newIdentifier); + newNode->addChild(newIdentifier); + } + + newNode->addChild(transform(getNode("statement",children), newNode, types, limitToFunction, templateTypeReplacements)); + return newNode; } else if (name == "while_loop") { newNode = new NodeTree(name, ASTData(while_loop)); } else if (name == "for_loop") { diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 75fc8eb..2d34410 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -526,6 +526,35 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc if (children.size() > 2) output += " else { " + generate(children[2], enclosingObject, justFuncName, enclosingFunction).oneString() + " }"; return output; + case match_statement: + { + output += "/* match_statement */\n"; + CCodeTriple thingToMatch = generate(children[0], enclosingObject, false, enclosingFunction); + output.preValue += thingToMatch.preValue; + output.postValue += thingToMatch.postValue; + for (auto case_stmt : slice(children, 1, -1)) { + auto case_children = case_stmt->getChildren(); + std::string option = generate(case_children[0], enclosingObject, false, enclosingFunction).oneString(); + output += "/* case " + option + " if " + thingToMatch.value + " */\n"; + output += tabs() + "if (" + thingToMatch.value + ".flag == " + option + ") {\n"; + tabLevel++; + if (case_children.size() > 2) { + output += tabs() + ValueTypeToCType(case_children[1]->getData().valueType, generate(case_children[1], enclosingObject, false, enclosingFunction).oneString()) + + " = " + thingToMatch.value + "." + option + ";\n"; + output += generate(case_children[2], enclosingObject, false, enclosingFunction).oneString(); + } else { + output += generate(case_children[1], enclosingObject, false, enclosingFunction).oneString(); + } + tabLevel--; + output += "}\n"; + } + return output; + } + break; + case case_statement: + output += "/* case_statement */"; + throw "case statement isn't actually used, but is generated in match"; + break; case while_loop: { // we push on a new vector to hold while stuff that might need a destructor call diff --git a/src/Importer.cpp b/src/Importer.cpp index 34af861..5ddf49a 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -45,7 +45,8 @@ Importer::Importer(Parser* parserIn, std::vector includePaths, std: removeSymbols.push_back(Symbol("adt_nonterm", false)); removeSymbols.push_back(Symbol("template", true)); removeSymbols.push_back(Symbol("\\|", true)); - //collapseSymbols.push_back(Symbol("scoped_identifier", false)); + //removeSymbols.push_back(Symbol("match", true)); + collapseSymbols.push_back(Symbol("case_statement_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)); diff --git a/tests/test_adt.krak b/tests/test_adt.krak index f07a450..6ac908e 100644 --- a/tests/test_adt.krak +++ b/tests/test_adt.krak @@ -53,6 +53,21 @@ fun main():int { println("equality false works!") else println("equality false fails!") + + match (maybe_int::an_int(11)) { + maybe_int::an_int(the_int) { + print("matched an int:") + print(the_int) + println(" correctly!") + } + maybe_int::no_int() { + println("matched no int incorrectly!") + } + } + match (maybe_int::no_int()) { + maybe_int::an_int(the_int) println("matched an int incorrectly!") + maybe_int::no_int() println("matched no int correctly!") + } return 0 }