From d2b06fb5803a97dab78f8f90e897f2341cf9f429 Mon Sep 17 00:00:00 2001 From: Garrett Skelton Date: Sat, 6 May 2023 00:00:34 -0700 Subject: [PATCH 1/7] erase and length implementations for dictionary --- src/Library/modulesImplementation.hpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Library/modulesImplementation.hpp b/src/Library/modulesImplementation.hpp index 092e05e..a3aa4ab 100644 --- a/src/Library/modulesImplementation.hpp +++ b/src/Library/modulesImplementation.hpp @@ -674,11 +674,21 @@ namespace KataScript { } if (args[0]->getType() == Type::String) { return make_shared((Int)args[0]->getString().size()); - } + } else if (args[0]->getType() == Type::Array) { return make_shared((Int)args[0]->getArray().size()); + } else + if (args[0]->getType() == Type::List) { + return make_shared((Int)args[0]->getList().size()); + } else + if (args[0]->getType() == Type::List) { + return make_shared((Int)args[0]->getList().size()); + } else + if (args[0]->getType() == Type::Dictionary) { + return make_shared((Int)args[0]->getDictionary()->size()); } - return make_shared((Int)args[0]->getList().size()); + + return make_shared(); }}, {"find", [](const List& args) { @@ -754,11 +764,14 @@ namespace KataScript { }}, {"erase", [](const List& args) { - if (args.size() < 2 || (int)args[0]->getType() < (int)Type::Array || args[1]->getType() != Type::Int) { + if (args.size() < 2 || (int)args[0]->getType() < (int)Type::Array) { return make_shared(); } if (args[0]->getType() == Type::Array) { + if (args[1]->getType() != Type::Int) { + return make_shared(); + } switch (args[0]->getArray().getType()) { case Type::Int: args[0]->getStdVector().erase(args[0]->getStdVector().begin() + args[1]->getInt()); @@ -778,8 +791,13 @@ namespace KataScript { default: break; } - } else { + } else if (args[0]->getType() == Type::List) { + if (args[1]->getType() != Type::Int) { + return make_shared(); + } args[0]->getList().erase(args[0]->getList().begin() + args[1]->getInt()); + } else if (args[0]->getType() == Type::Dictionary) { + args[0]->getDictionary()->erase(args[1]->getHash()); } return make_shared(); }}, From 992e26279bbbc456489b7e9cce466a1df97b3ae9 Mon Sep 17 00:00:00 2001 From: Garrett Skelton Date: Mon, 19 Jun 2023 21:01:55 -0700 Subject: [PATCH 2/7] add static cast for regular int to wide int --- src/Library/value.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Library/value.hpp b/src/Library/value.hpp index c2fc18c..4abd9f3 100644 --- a/src/Library/value.hpp +++ b/src/Library/value.hpp @@ -25,6 +25,7 @@ namespace KataScript { // Construct a Value from any underlying type explicit Value() : value(Null{}) {} explicit Value(bool a) :value(static_cast(a)) {} + explicit Value(int a) :value(static_cast(a)) {} explicit Value(Int a) : value(a) {} explicit Value(Float a) : value(a) {} explicit Value(vec3 a) : value(a) {} From 515af1725a666b7b5817d95cf667767f6e8e8d06 Mon Sep 17 00:00:00 2001 From: Garrett Skelton Date: Tue, 20 Jun 2023 01:01:00 -0700 Subject: [PATCH 3/7] new failing test case --- src/Tests/KataScriptTests.cpp | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/Tests/KataScriptTests.cpp b/src/Tests/KataScriptTests.cpp index 591cf17..5aca571 100644 --- a/src/Tests/KataScriptTests.cpp +++ b/src/Tests/KataScriptTests.cpp @@ -1927,6 +1927,64 @@ namespace KataScriptTests { Assert::AreEqual(KataScript::Int(8), val->getInt()); } + TEST_METHOD(NestedScopeClearing) { + interpreter.evaluate("var statsDict = dictionary();\ +var currPlayerIndex = 0;\ +class playerStats {\ + var name;\ + var holeNum;\ + var shots;\ + var totalShots;\ + var isComplete;\ + var index;\ +\ + fn playerStats(nm, hole, score) {\ + name = nm;\ + holeNum = hole;\ + shots = score;\ + totalShots = score;\ + isComplete = false;\ + index = currPlayerIndex;\ + ++currPlayerIndex;\ + if (currPlayerIndex > 3) {\ + currPlayerIndex = 0;\ + }\ + }\ +}\ +fn IsFreePlay() { return false; }\ +fn PlayerJoin(playerName, initialHole, initialScore) {\ + statsDict[playerName] = playerStats(playerName, initialHole, initialScore);\ + if (false) {\ + print();\ + }\ +\ + if (!IsFreePlay() && length(statsDict) >= 1) {\ + var furthest = 1;\ + var secondFurthest = 1;\ + foreach (stat; statsDict) {\ + var holeNum = stat.holeNum;\ + if (holeNum != null) {\ + if (holeNum > furthest) {\ + secondFurthest = furthest;\ + furthest = holeNum;\ + } else if (holeNum < furthest && holeNum > secondFurthest) {\ + secondFurthest = holeNum;\ + }\ + }\ + }\ + if (secondFurthest == 1) {\ + secondFurthest = furthest;\ + }\ + return secondFurthest;\ + }\ +return 0;\ +}\ +var asd = PlayerJoin(\"dd\", 23, 4);"); + auto val = interpreter.resolveVariable("asd"s); + Assert::AreEqual(KataScript::Type::Int, val->getType()); + Assert::AreEqual(KataScript::Int(8), val->getInt()); + } + TEST_METHOD(NestedEarlyReturn) { interpreter.evaluate("var dict = dictionary(); dict[1]=1;dict[2]=1;dict[3]=1;fn test(i) {\ var ready = true;\ From 184eceac12d9e93d52d45d91de044769f8da47a3 Mon Sep 17 00:00:00 2001 From: Garrett Skelton Date: Tue, 20 Jun 2023 01:01:24 -0700 Subject: [PATCH 4/7] simplify some parsing code --- src/Library/KataScript.hpp | 2 +- src/Library/expressionImplementation.hpp | 4 +++- src/Library/functionImplementation.hpp | 6 ++++++ src/Library/parsing.hpp | 10 +++------- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Library/KataScript.hpp b/src/Library/KataScript.hpp index 6286df2..8e8f1c5 100644 --- a/src/Library/KataScript.hpp +++ b/src/Library/KataScript.hpp @@ -69,7 +69,7 @@ namespace KataScript { ValueRef getValue(ExpressionRef expr, ScopeRef scope, Class* classs); void clearParseStacks(); - void closeDanglingIfExpression(); + bool closeDanglingIfExpression(); void parse(string_view token); ScopeRef newClassScope(const string& name, ScopeRef scope); diff --git a/src/Library/expressionImplementation.hpp b/src/Library/expressionImplementation.hpp index 21d292d..39f1c15 100644 --- a/src/Library/expressionImplementation.hpp +++ b/src/Library/expressionImplementation.hpp @@ -219,7 +219,7 @@ namespace KataScript { // since the 'else' block in an if/elfe is technically in a different scope // ifelse espressions are not closed immediately and instead left dangling // until the next expression is anything other than an 'else' or the else is unconditional - void KataScriptInterpreter::closeDanglingIfExpression() { + bool KataScriptInterpreter::closeDanglingIfExpression() { if (currentExpression && currentExpression->type == ExpressionType::IfElse) { if (currentExpression->parent) { currentExpression = currentExpression->parent; @@ -227,7 +227,9 @@ namespace KataScript { getValue(currentExpression, parseScope, nullptr); currentExpression = nullptr; } + return true; } + return false; } bool KataScriptInterpreter::closeCurrentExpression() { diff --git a/src/Library/functionImplementation.hpp b/src/Library/functionImplementation.hpp index ad5c668..9b7ab88 100644 --- a/src/Library/functionImplementation.hpp +++ b/src/Library/functionImplementation.hpp @@ -208,10 +208,16 @@ namespace KataScript { while (scope) { auto iter = scope->scopes.find(name); if (iter != scope->scopes.end()) { + if (initialScope != iter->second) { + iter->second->parent = initialScope; + } return iter->second; } else { if (!scope->parent) { if (scope->name == name) { + if (initialScope != scope) { + scope->parent = initialScope; + } return scope; } } diff --git a/src/Library/parsing.hpp b/src/Library/parsing.hpp index df5215b..ff15d31 100644 --- a/src/Library/parsing.hpp +++ b/src/Library/parsing.hpp @@ -535,7 +535,6 @@ namespace KataScript { { if (lastTokenEndCurlBraket && lastStatementWasIf) { if (token != ";" && token != "}" && token != "else") { - lastStatementWasIf = false; parse(";"); } } @@ -586,7 +585,6 @@ namespace KataScript { parseScope = newScope("__anon"s, parseScope); clearParseStacks(); } else if (token == "}") { - wasElse = !currentExpression || currentExpression->type != ExpressionType::IfElse; lastStatementWasIf = currentExpression && currentExpression->type == ExpressionType::IfElse; bool wasFreefunc = !currentExpression || (currentExpression->type == ExpressionType::FunctionDef && get(currentExpression->expression).function->getFunction()->type == FunctionType::free); @@ -608,13 +606,11 @@ namespace KataScript { parseState = ParseState::readLine; parseStrings.push_back(token); } - if (!closedExpr && (closedScope && lastStatementClosedScope || (!lastStatementWasElse && !wasElse && lastTokenEndCurlBraket))) { + if (!closedExpr && !lastStatementWasElse && !wasElse && lastTokenEndCurlBraket) { bool wasIfExpr = currentExpression && currentExpression->type == ExpressionType::IfElse; - auto oldExpr = ¤tExpression; - closeDanglingIfExpression(); - if (closedScope && wasIfExpr && ¤tExpression == oldExpr) { + bool didCloseDangle = closeDanglingIfExpression(); + if (closedScope && wasIfExpr && didCloseDangle) { closeCurrentExpression(); - closedScope = false; } } lastStatementClosedScope = closedScope; From 61007ecc0ef56e3be12d05cb5d25257d1965a743 Mon Sep 17 00:00:00 2001 From: Garrett Skelton Date: Tue, 20 Jun 2023 01:27:34 -0700 Subject: [PATCH 5/7] removing overcomplications --- src/Library/KataScript.hpp | 2 -- src/Library/parsing.hpp | 19 +++++-------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/Library/KataScript.hpp b/src/Library/KataScript.hpp index 8e8f1c5..0a87e5f 100644 --- a/src/Library/KataScript.hpp +++ b/src/Library/KataScript.hpp @@ -53,8 +53,6 @@ namespace KataScript { int outerNestLayer = 0; bool lastStatementClosedScope = false; bool lastStatementWasElse = false; - bool lastTokenEndCurlBraket = false; - bool lastStatementWasIf = false; uint64_t currentLine = 0; ParseState prevState = ParseState::beginExpression; ModulePrivilegeFlags allowedModulePrivileges; diff --git a/src/Library/parsing.hpp b/src/Library/parsing.hpp index ff15d31..0638f8d 100644 --- a/src/Library/parsing.hpp +++ b/src/Library/parsing.hpp @@ -533,7 +533,7 @@ namespace KataScript { switch (parseState) { case ParseState::beginExpression: { - if (lastTokenEndCurlBraket && lastStatementWasIf) { + if (lastStatementClosedScope) { if (token != ";" && token != "}" && token != "else") { parse(";"); } @@ -542,8 +542,6 @@ namespace KataScript { bool wasElse = false; bool closedScope = false; bool closedExpr = false; - bool isEndCurlBracket = false; - lastStatementWasIf = false; if (token == "fn" || token == "func" || token == "function") { parseState = ParseState::defineFunc; @@ -585,15 +583,11 @@ namespace KataScript { parseScope = newScope("__anon"s, parseScope); clearParseStacks(); } else if (token == "}") { - lastStatementWasIf = currentExpression && currentExpression->type == ExpressionType::IfElse; - bool wasFreefunc = !currentExpression || (currentExpression->type == ExpressionType::FunctionDef - && get(currentExpression->expression).function->getFunction()->type == FunctionType::free); + closedScope = currentExpression && currentExpression->type == ExpressionType::IfElse; closedExpr = closeCurrentExpression(); - if ((!closedExpr && wasFreefunc) || parseScope->name == "__anon") { + if ((!closedExpr && !closedScope) || parseScope->name == "__anon") { closeScope(parseScope); } - closedScope = true; - isEndCurlBracket = true; } else if (token == "return") { parseState = ParseState::returnLine; } else if (token == "break") { @@ -606,15 +600,12 @@ namespace KataScript { parseState = ParseState::readLine; parseStrings.push_back(token); } - if (!closedExpr && !lastStatementWasElse && !wasElse && lastTokenEndCurlBraket) { - bool wasIfExpr = currentExpression && currentExpression->type == ExpressionType::IfElse; - bool didCloseDangle = closeDanglingIfExpression(); - if (closedScope && wasIfExpr && didCloseDangle) { + if (!closedExpr && !lastStatementWasElse && !wasElse && lastStatementClosedScope) { + if (closeDanglingIfExpression() && closedScope) { closeCurrentExpression(); } } lastStatementClosedScope = closedScope; - lastTokenEndCurlBraket = isEndCurlBracket; lastStatementWasElse = wasElse; } break; From 9f7f1d856f42795981989160b7b3430bd2696e35 Mon Sep 17 00:00:00 2001 From: Garrett Skelton Date: Tue, 20 Jun 2023 03:03:33 -0700 Subject: [PATCH 6/7] fixed if else implementation --- src/Library/KataScript.hpp | 3 +-- src/Library/expressionImplementation.hpp | 34 +++++++----------------- src/Library/parsing.hpp | 32 ++++++++++------------ src/Tests/KataScriptTests.cpp | 2 +- 4 files changed, 26 insertions(+), 45 deletions(-) diff --git a/src/Library/KataScript.hpp b/src/Library/KataScript.hpp index 0a87e5f..8cad9b0 100644 --- a/src/Library/KataScript.hpp +++ b/src/Library/KataScript.hpp @@ -45,6 +45,7 @@ namespace KataScript { ScopeRef globalScope = make_shared(this); ScopeRef parseScope = globalScope; ExpressionRef currentExpression; + ExpressionRef previousExpression; ValueRef listIndexFunctionVarLocation; ValueRef identityFunctionVarLocation; @@ -52,7 +53,6 @@ namespace KataScript { vector parseStrings; int outerNestLayer = 0; bool lastStatementClosedScope = false; - bool lastStatementWasElse = false; uint64_t currentLine = 0; ParseState prevState = ParseState::beginExpression; ModulePrivilegeFlags allowedModulePrivileges; @@ -67,7 +67,6 @@ namespace KataScript { ValueRef getValue(ExpressionRef expr, ScopeRef scope, Class* classs); void clearParseStacks(); - bool closeDanglingIfExpression(); void parse(string_view token); ScopeRef newClassScope(const string& name, ScopeRef scope); diff --git a/src/Library/expressionImplementation.hpp b/src/Library/expressionImplementation.hpp index 39f1c15..d713359 100644 --- a/src/Library/expressionImplementation.hpp +++ b/src/Library/expressionImplementation.hpp @@ -192,6 +192,7 @@ namespace KataScript { break; } } + if (returnVal) { return make_shared(returnVal.value, returnVal.type == ReturnType::Return ? ExpressionType::Return : ExpressionType::Break); } else { @@ -216,35 +217,20 @@ namespace KataScript { return get(consolidated(exp, scope, classs)->expression); } - // since the 'else' block in an if/elfe is technically in a different scope - // ifelse espressions are not closed immediately and instead left dangling - // until the next expression is anything other than an 'else' or the else is unconditional - bool KataScriptInterpreter::closeDanglingIfExpression() { - if (currentExpression && currentExpression->type == ExpressionType::IfElse) { + bool KataScriptInterpreter::closeCurrentExpression() { + previousExpression = currentExpression; + if (currentExpression) { if (currentExpression->parent) { currentExpression = currentExpression->parent; } else { - getValue(currentExpression, parseScope, nullptr); - currentExpression = nullptr; - } - return true; - } - return false; - } - - bool KataScriptInterpreter::closeCurrentExpression() { - if (currentExpression) { - if (currentExpression->type != ExpressionType::IfElse) { - if (currentExpression->parent) { - currentExpression = currentExpression->parent; - } else { - if (currentExpression->type != ExpressionType::FunctionDef) { - getValue(currentExpression, parseScope, nullptr); - } - currentExpression = nullptr; + if (currentExpression->type != ExpressionType::FunctionDef + && currentExpression->type != ExpressionType::IfElse + ) { + getValue(currentExpression, parseScope, nullptr); } + currentExpression = nullptr; return true; - } + } } return false; } diff --git a/src/Library/parsing.hpp b/src/Library/parsing.hpp index 0638f8d..347e7ed 100644 --- a/src/Library/parsing.hpp +++ b/src/Library/parsing.hpp @@ -533,14 +533,11 @@ namespace KataScript { switch (parseState) { case ParseState::beginExpression: { - if (lastStatementClosedScope) { - if (token != ";" && token != "}" && token != "else") { - parse(";"); + if (lastStatementClosedScope && previousExpression) { + if (token != "else" && token != "if") { + getValue(previousExpression, parseScope, nullptr); } } - - bool wasElse = false; - bool closedScope = false; bool closedExpr = false; if (token == "fn" || token == "func" || token == "function") { @@ -576,18 +573,20 @@ namespace KataScript { } } else if (token == "else") { parseState = ParseState::expectIfEnd; - wasElse = true; + currentExpression = previousExpression; } else if (token == "class") { parseState = ParseState::defineClass; } else if (token == "{") { parseScope = newScope("__anon"s, parseScope); clearParseStacks(); } else if (token == "}") { - closedScope = currentExpression && currentExpression->type == ExpressionType::IfElse; closedExpr = closeCurrentExpression(); - if ((!closedExpr && !closedScope) || parseScope->name == "__anon") { + if ((!closedExpr) || parseScope->name == "__anon") { closeScope(parseScope); } + if (previousExpression && previousExpression->type != ExpressionType::IfElse) { + closedExpr = false; + } } else if (token == "return") { parseState = ParseState::returnLine; } else if (token == "break") { @@ -600,13 +599,8 @@ namespace KataScript { parseState = ParseState::readLine; parseStrings.push_back(token); } - if (!closedExpr && !lastStatementWasElse && !wasElse && lastStatementClosedScope) { - if (closeDanglingIfExpression() && closedScope) { - closeCurrentExpression(); - } - } - lastStatementClosedScope = closedScope; - lastStatementWasElse = wasElse; + + lastStatementClosedScope = closedExpr; } break; case ParseState::loopCall: @@ -694,8 +688,10 @@ namespace KataScript { case ParseState::ifCall: if (token == ")") { if (--outerNestLayer <= 0) { - currentExpression->push_back(If()); - get(currentExpression->expression).back().testExpression = getExpression(move(parseStrings), parseScope, nullptr); + auto& expx = get(currentExpression->expression); + expx.push_back(If()); + expx.back().testExpression = getExpression(move(parseStrings), parseScope, nullptr); + clearParseStacks(); } else { parseStrings.push_back(token); diff --git a/src/Tests/KataScriptTests.cpp b/src/Tests/KataScriptTests.cpp index 5aca571..f36f217 100644 --- a/src/Tests/KataScriptTests.cpp +++ b/src/Tests/KataScriptTests.cpp @@ -1982,7 +1982,7 @@ return 0;\ var asd = PlayerJoin(\"dd\", 23, 4);"); auto val = interpreter.resolveVariable("asd"s); Assert::AreEqual(KataScript::Type::Int, val->getType()); - Assert::AreEqual(KataScript::Int(8), val->getInt()); + Assert::AreEqual(KataScript::Int(23), val->getInt()); } TEST_METHOD(NestedEarlyReturn) { From f685b55e0b6a9c7642327d6b5690f0203fe06cd7 Mon Sep 17 00:00:00 2001 From: Garrett Skelton Date: Fri, 23 Jun 2023 00:13:53 -0700 Subject: [PATCH 7/7] adds contains for dictionary --- src/Library/modulesImplementation.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Library/modulesImplementation.hpp b/src/Library/modulesImplementation.hpp index a3aa4ab..9d870b5 100644 --- a/src/Library/modulesImplementation.hpp +++ b/src/Library/modulesImplementation.hpp @@ -1136,12 +1136,15 @@ namespace KataScript { break; } return make_shared(Int(0)); - } - auto& list = args[0]->getList(); - for (size_t i = 0; i < list.size(); ++i) { - if (*list[i] == *args[1]) { - return make_shared(Int(1)); + } else if (args[0]->getType() == Type::List) { + auto& list = args[0]->getList(); + for (size_t i = 0; i < list.size(); ++i) { + if (*list[i] == *args[1]) { + return make_shared(Int(1)); + } } + } else if (args[0]->getType() == Type::Dictionary) { + return make_shared(Int(args[0]->getDictionary()->contains(args[1]->getHash()))); } return make_shared(Int(0)); }},