-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3fe7afc
commit c5280e0
Showing
16 changed files
with
469 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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))); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.