Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/modules completion #19

Merged
merged 7 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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