Skip to content

Commit

Permalink
Merge pull request #19 from brwhale/feature/ModulesCompletion
Browse files Browse the repository at this point in the history
Feature/modules completion
  • Loading branch information
brwhale authored Aug 3, 2023
2 parents 2b99847 + f685b55 commit 0c3e9e5
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 66 deletions.
5 changes: 1 addition & 4 deletions src/Library/KataScript.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,14 @@ namespace KataScript {
ScopeRef globalScope = make_shared<Scope>(this);
ScopeRef parseScope = globalScope;
ExpressionRef currentExpression;
ExpressionRef previousExpression;
ValueRef listIndexFunctionVarLocation;
ValueRef identityFunctionVarLocation;

ParseState parseState = ParseState::beginExpression;
vector<string_view> parseStrings;
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;
Expand All @@ -69,7 +67,6 @@ namespace KataScript {
ValueRef getValue(ExpressionRef expr, ScopeRef scope, Class* classs);

void clearParseStacks();
void closeDanglingIfExpression();
void parse(string_view token);

ScopeRef newClassScope(const string& name, ScopeRef scope);
Expand Down
32 changes: 10 additions & 22 deletions src/Library/expressionImplementation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ namespace KataScript {
break;
}
}

if (returnVal) {
return make_shared<Expression>(returnVal.value, returnVal.type == ReturnType::Return ? ExpressionType::Return : ExpressionType::Break);
} else {
Expand All @@ -216,33 +217,20 @@ namespace KataScript {
return get<ValueRef>(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
void 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;
}
}
}

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;
}
Expand Down
6 changes: 6 additions & 0 deletions src/Library/functionImplementation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
39 changes: 30 additions & 9 deletions src/Library/modulesImplementation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,11 +674,21 @@ namespace KataScript {
}
if (args[0]->getType() == Type::String) {
return make_shared<Value>((Int)args[0]->getString().size());
}
} else
if (args[0]->getType() == Type::Array) {
return make_shared<Value>((Int)args[0]->getArray().size());
} else
if (args[0]->getType() == Type::List) {
return make_shared<Value>((Int)args[0]->getList().size());
} else
if (args[0]->getType() == Type::List) {
return make_shared<Value>((Int)args[0]->getList().size());
} else
if (args[0]->getType() == Type::Dictionary) {
return make_shared<Value>((Int)args[0]->getDictionary()->size());
}
return make_shared<Value>((Int)args[0]->getList().size());

return make_shared<Value>();
}},

{"find", [](const List& args) {
Expand Down Expand Up @@ -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<Value>();
}

if (args[0]->getType() == Type::Array) {
if (args[1]->getType() != Type::Int) {
return make_shared<Value>();
}
switch (args[0]->getArray().getType()) {
case Type::Int:
args[0]->getStdVector<Int>().erase(args[0]->getStdVector<Int>().begin() + args[1]->getInt());
Expand All @@ -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<Value>();
}
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<Value>();
}},
Expand Down Expand Up @@ -1118,12 +1136,15 @@ namespace KataScript {
break;
}
return make_shared<Value>(Int(0));
}
auto& list = args[0]->getList();
for (size_t i = 0; i < list.size(); ++i) {
if (*list[i] == *args[1]) {
return make_shared<Value>(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<Value>(Int(1));
}
}
} else if (args[0]->getType() == Type::Dictionary) {
return make_shared<Value>(Int(args[0]->getDictionary()->contains(args[1]->getHash())));
}
return make_shared<Value>(Int(0));
}},
Expand Down
45 changes: 14 additions & 31 deletions src/Library/parsing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,18 +533,12 @@ namespace KataScript {
switch (parseState) {
case ParseState::beginExpression:
{
if (lastTokenEndCurlBraket && lastStatementWasIf) {
if (token != ";" && token != "}" && token != "else") {
lastStatementWasIf = false;
parse(";");
if (lastStatementClosedScope && previousExpression) {
if (token != "else" && token != "if") {
getValue(previousExpression, parseScope, nullptr);
}
}

bool wasElse = false;
bool closedScope = false;
bool closedExpr = false;
bool isEndCurlBracket = false;
lastStatementWasIf = false;

if (token == "fn" || token == "func" || token == "function") {
parseState = ParseState::defineFunc;
Expand Down Expand Up @@ -579,23 +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 == "}") {
wasElse = !currentExpression || currentExpression->type != ExpressionType::IfElse;
lastStatementWasIf = currentExpression && currentExpression->type == ExpressionType::IfElse;
bool wasFreefunc = !currentExpression || (currentExpression->type == ExpressionType::FunctionDef
&& get<FunctionExpression>(currentExpression->expression).function->getFunction()->type == FunctionType::free);
closedExpr = closeCurrentExpression();
if ((!closedExpr && wasFreefunc) || parseScope->name == "__anon") {
if ((!closedExpr) || parseScope->name == "__anon") {
closeScope(parseScope);
}
closedScope = true;
isEndCurlBracket = true;
if (previousExpression && previousExpression->type != ExpressionType::IfElse) {
closedExpr = false;
}
} else if (token == "return") {
parseState = ParseState::returnLine;
} else if (token == "break") {
Expand All @@ -608,18 +599,8 @@ namespace KataScript {
parseState = ParseState::readLine;
parseStrings.push_back(token);
}
if (!closedExpr && (closedScope && lastStatementClosedScope || (!lastStatementWasElse && !wasElse && lastTokenEndCurlBraket))) {
bool wasIfExpr = currentExpression && currentExpression->type == ExpressionType::IfElse;
auto oldExpr = &currentExpression;
closeDanglingIfExpression();
if (closedScope && wasIfExpr && &currentExpression == oldExpr) {
closeCurrentExpression();
closedScope = false;
}
}
lastStatementClosedScope = closedScope;
lastTokenEndCurlBraket = isEndCurlBracket;
lastStatementWasElse = wasElse;

lastStatementClosedScope = closedExpr;
}
break;
case ParseState::loopCall:
Expand Down Expand Up @@ -707,8 +688,10 @@ namespace KataScript {
case ParseState::ifCall:
if (token == ")") {
if (--outerNestLayer <= 0) {
currentExpression->push_back(If());
get<IfElse>(currentExpression->expression).back().testExpression = getExpression(move(parseStrings), parseScope, nullptr);
auto& expx = get<IfElse>(currentExpression->expression);
expx.push_back(If());
expx.back().testExpression = getExpression(move(parseStrings), parseScope, nullptr);

clearParseStacks();
} else {
parseStrings.push_back(token);
Expand Down
1 change: 1 addition & 0 deletions src/Library/value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace KataScript {
// Construct a Value from any underlying type
explicit Value() : value(Null{}) {}
explicit Value(bool a) :value(static_cast<Int>(a)) {}
explicit Value(int a) :value(static_cast<Int>(a)) {}
explicit Value(Int a) : value(a) {}
explicit Value(Float a) : value(a) {}
explicit Value(vec3 a) : value(a) {}
Expand Down
58 changes: 58 additions & 0 deletions src/Tests/KataScriptTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(23), 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;\
Expand Down

0 comments on commit 0c3e9e5

Please sign in to comment.