Skip to content

Commit

Permalink
Basic interpreter set up
Browse files Browse the repository at this point in the history
  • Loading branch information
Samathingamajig committed Feb 15, 2021
1 parent 3fe7afc commit c5280e0
Show file tree
Hide file tree
Showing 16 changed files with 469 additions and 28 deletions.
30 changes: 23 additions & 7 deletions BarkScript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#include <memory>
#include "lexer.h"
#include "parser.h"
#include "object.h"
#include "interpreter.h"

const std::string bsversion = "0.0.6";
const std::string bsversion = "0.0.7";

int main() {
std::cout << "BarkScript version " << bsversion << std::endl;
Expand All @@ -24,12 +26,26 @@ int main() {
for (Token token : mlr.tokenized) {
std::cout << token.to_string() << std::endl;
}
std::cout << std::endl;
Parser parser = Parser(mlr.tokenized);
ParseResult abSyTree = parser.parse();
if (!abSyTree.hasError())
std::cout << abSyTree.node->to_string() << std::endl;
else std::cout << abSyTree.error->to_string() << std::endl;
if (mlr.tokenized.size() != 1) {
std::cout << std::endl;
Parser parser = Parser(mlr.tokenized);
ParseResult abSyTree = parser.parse();
if (abSyTree.hasError()) {
std::cout << abSyTree.error->to_string() << std::endl;
} else {
std::cout << abSyTree.node->to_string() << std::endl;
std::cout << std::endl;

Interpreter interpreter;
spContext context = std::make_shared<Context>(Context("<main>"));
RuntimeResult rt = interpreter.visit(abSyTree.node, context);
if (rt.hasError()) {
std::cout << rt.error->to_string() << std::endl;
} else {
std::cout << rt.object->to_string() << std::endl;
}
}
}
std::cout << "--------------------------" << std::endl;
}
}
5 changes: 5 additions & 0 deletions BarkScript.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,18 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="BarkScript.cpp" />
<ClCompile Include="Interpreter.cpp" />
<ClCompile Include="Lexer.cpp" />
<ClCompile Include="Object.cpp" />
<ClCompile Include="Parser.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ast.h" />
<ClInclude Include="context.h" />
<ClInclude Include="error.h" />
<ClInclude Include="interpreter.h" />
<ClInclude Include="lexer.h" />
<ClInclude Include="object.h" />
<ClInclude Include="parser.h" />
<ClInclude Include="position.h" />
<ClInclude Include="strings_with_arrows.h" />
Expand Down
15 changes: 15 additions & 0 deletions BarkScript.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
<ClCompile Include="Parser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Interpreter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="tokens.h">
Expand Down Expand Up @@ -51,5 +57,14 @@
<ClInclude Include="strings_with_arrows.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="interpreter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="context.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
96 changes: 96 additions & 0 deletions Interpreter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include "interpreter.h"
#include <iostream>
#include <string>
#include <stdexcept>
#include "ast.h"
#include "object.h"

bool RuntimeResult::hasError() { return error != nullptr; }

spObject RuntimeResult::registerRT(spObject object) {
return object;
}

spObject RuntimeResult::registerRT(RuntimeResult rt) {
if (rt.hasError()) {
this->error = rt.error;
}
return rt.object;
}

RuntimeResult RuntimeResult::success(spObject object) {
this->object = object;
return *this;
}

RuntimeResult RuntimeResult::failure(spError error) {
this->error = error;
return *this;
}

RuntimeResult Interpreter::visit(spNode node, spContext context) {
std::string type = node->nodeType;

if (type == nodetypes::Number) {
return visitNumberNode(node, context);
} else if (type == nodetypes::BinaryOperator) {
return visitBinaryOperatorNode(node, context);
} else if (type == nodetypes::UnaryOperator) {
return visitUnaryOperatorNode(node, context);
} else {
std::cout << "Error: node type " + type + " does not have a visit method!" << std::endl;
}
}

RuntimeResult Interpreter::visitNumberNode(spNode node, spContext context) {
spObject number = makeSharedObject(Number(node->token.value));
number->setContext(context);
number->setPosition(node->positionStart, node->positionEnd);
return RuntimeResult().success(number);
}

RuntimeResult Interpreter::visitBinaryOperatorNode(spNode node, spContext context) {
RuntimeResult rt;
spObject left = rt.registerRT(visit(node->leftNode, context));
if (rt.hasError()) return rt;
spObject right = rt.registerRT(visit(node->rightNode, context));
if (rt.hasError()) return rt;

RuntimeResult result;

std::string optoken = node->token.type;
if (optoken == tokens::PLUS) {
result = left->binary_plus(right);
} else if (optoken == tokens::MINUS) {
result = left->binary_minus(right);
} else if (optoken == tokens::ASTERISK) {
result = left->binary_asterisk(right);
} else if (optoken == tokens::F_SLASH) {
result = left->binary_f_slash(right);
}

if (result.hasError()) return rt.failure(result.error);

result.object->setPosition(node->positionStart, node->positionEnd);
return rt.success(result.object);
}

RuntimeResult Interpreter::visitUnaryOperatorNode(spNode node, spContext context) {
RuntimeResult rt;
spObject object = rt.registerRT(visit(node->rightNode, context));
if (rt.hasError()) return rt;

RuntimeResult result;

std::string optoken = node->token.type;
if (optoken == tokens::PLUS) {
result = object->unary_plus();
} else if (optoken == tokens::MINUS) {
result = object->unary_minus();
}

if (result.hasError()) return rt.failure(result.error);

result.object->setPosition(node->positionStart, node->positionEnd);
return rt.success(result.object);
}
6 changes: 5 additions & 1 deletion Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ SingleLexResult Lexer::nextToken() {
if (isNumeric(current)) {
std::string value = std::string(1, current);
Position positionStart = position.copy();
while (isNumeric(peekChar())) {
bool period = false;
while (isNumeric(peekChar()) || (peekChar() == '.' && !period)) {
value += peekChar();
if (peekChar() == '.') {
period = true;
}
readChar();
}
token = Token(tokens::NUMBER, value, positionStart, position);
Expand Down
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
barkscript : BarkScript.cpp Lexer.cpp Parser.cpp
windowsvs : BarkScript.cpp Lexer.cpp Parser.cpp Object.cpp Interpreter.cpp
.\build.bat

linuxgpp : BarkScript.cpp Lexer.cpp Parser.cpp Object.cpp Interpreter.cpp
g++ -o ./build/BarkScript -O2 -Wall BarkScript.cpp Lexer.cpp Parser.cpp Object.cpp Interpreter.cpp

cleanobj :
rm BarkScript.obj Lexer.obj Parser.obj
rm BarkScript.obj Lexer.obj Parser.obj Object.obj Interpreter.obj

cleanobjcmd :
del BarkScript.obj Lexer.obj Parser.obj
del BarkScript.obj Lexer.obj Parser.obj Object.obj Interpreter.obj
129 changes: 129 additions & 0 deletions Object.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "object.h"
#include "interpreter.h"
void Object::setPosition(Position positionStart, Position positionEnd) {
this->positionStart = positionStart;
this->positionEnd = positionEnd;
}

void Object::setContext(spContext context) {
this->context = context;
}

std::string Object::to_string() {
return "Not implemented! " + type;
}

Number::Number(double value, bool sign) {
this->type = "Number";
this->doubleValue = value;
if (value < 0.0) this->sign = -0;
if (value == 0) this->isPureZero = true;
}

Number::Number(std::string value, bool sign) {
this->type = "Number";
this->sign = sign;
if (value == "Infinity") {
this->isInfinity = true;
} else if (value == "NaN") {
this->isNaN = true;
} else {
try {
this->doubleValue = std::stod(value);
if (this->doubleValue == 0) this->isPureZero = true;
} catch (const std::out_of_range&) {
this->isInfinity = true;
}
}
}

std::string Number::to_string() {
// https://stackoverflow.com/a/16606128/12101554
if (isInfinity) {
std::string sign;
if (this->sign == -0) sign += "-";
return sign + "Infinity";
} else if (isNaN) {
return "NaN";
}
std::ostringstream out;
out.precision(16);
out << doubleValue;
return out.str();
}

RuntimeResult Number::binary_plus(spObject object) {
RuntimeResult rt;

if (this->isNaN || object->isNaN) return rt.success(makeSharedObject(Number("NaN")));
if (this->isInfinity || object->isInfinity) {
if (this->sign == object->sign) {
return rt.success(makeSharedObject(Number("Infinity", this->sign)));
} else {
// Infinity + -Infinity, and -Infinity + Infinity, are both proven impossible
// so we need to return NaN
return rt.success(makeSharedObject(Number("NaN", 0)));
}
}
return rt.success(makeSharedObject(Number(this->doubleValue + object->doubleValue)));
}

RuntimeResult Number::binary_minus(spObject object) {
RuntimeResult rt;

if (this->isNaN || object->isNaN) return rt.success(makeSharedObject(Number("NaN")));
if (this->isInfinity || object->isInfinity) {
if (this->sign != object->sign) {
return rt.success(makeSharedObject(Number("Infinity", this->sign)));
} else {
// Infinity - Infinity, and -Infinity - -Infinity, are both proven impossible
// so we need to return NaN
return rt.success(makeSharedObject(Number("NaN")));
}
}
return rt.success(makeSharedObject(Number(this->doubleValue - object->doubleValue)));
}

RuntimeResult Number::binary_asterisk(spObject object) {
RuntimeResult rt;

if (this->isNaN || object->isNaN) return rt.success(makeSharedObject(Number("NaN")));
if (this->isInfinity || object->isInfinity) {
if (this->isPureZero || object->isPureZero) return rt.success(makeSharedObject(Number("NaN")));
// a == b is the same as !(a ^ b)
// this->sign == object->sign
// 0 == 0 -> 1
// 0 == 1 -> 0
// 1 == 0 -> 0
// 1 == 1 -> 1
return rt.success(makeSharedObject(Number("Infinity", this->sign == object->sign)));
}
return rt.success(makeSharedObject(Number(this->doubleValue * object->doubleValue)));
}

RuntimeResult Number::binary_f_slash(spObject object) {
RuntimeResult rt;

if (this->isNaN || object->isNaN) return rt.success(makeSharedObject(Number("NaN")));
if (this->isInfinity && object->isInfinity) return rt.success(makeSharedObject(Number("NaN")));
if (object->isPureZero) return rt.failure(makeSharedError(RuntimeError(object->positionStart, object->positionEnd, "Division by 0", this->context)));
if (object->isInfinity) return rt.success(makeSharedObject(Number(0, this->sign == object->sign)));
if (this->isInfinity) return rt.success(makeSharedObject(Number("Infinity", this->sign == object->sign)));
return rt.success(makeSharedObject(Number(this->doubleValue / object->doubleValue)));
}

RuntimeResult Number::unary_plus() {
RuntimeResult rt;

if (isNaN) return rt.success(makeSharedObject(Number("NaN")));
else if (isInfinity) return rt.success(makeSharedObject(Number("Infinity", sign)));
return rt.success(makeSharedObject(Number(this->doubleValue)));
}

RuntimeResult Number::unary_minus() {
RuntimeResult rt;

if (isNaN) return rt.success(makeSharedObject(Number("NaN")));
else if (isInfinity) return rt.success(makeSharedObject(Number("Infinity", !sign)));
return rt.success(makeSharedObject(Number(this->doubleValue * -1)));
}
6 changes: 1 addition & 5 deletions Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Parser::Parser(std::vector<Token> tokens) {

Token Parser::nextToken() {
tokenIndex++;
if (tokenIndex < tokens.size()) {
if ((unsigned) tokenIndex < tokens.size()) {
currentToken = tokens[tokenIndex];
}
return currentToken;
Expand Down Expand Up @@ -62,10 +62,6 @@ ParseResult Parser::expr() {
}

ParseResult Parser::parse() {
if (currentToken.type == tokens::EEOF) {
ParseResult pr;
return pr.success(makeSharedNode(Node()));
}
ParseResult pr = expr();
if (!pr.hasError() && currentToken.type != tokens::EEOF) {
return pr.failure(makeSharedError(InvalidSyntaxError(currentToken.positionStart, currentToken.positionEnd, "Expected +, -, *, /")));
Expand Down
Loading

0 comments on commit c5280e0

Please sign in to comment.