Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
amanuel2 committed Jun 28, 2024
1 parent f451059 commit 070dbfd
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 36 deletions.
9 changes: 9 additions & 0 deletions include/scanner/scanner.hh
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ namespace rift
inline bool isAlphaNumeric(char c) { return std::isalnum(c); }
inline bool isIdentifier(char c) { return std::isalnum(c) || c == '_'; }

void twoChar(Type t1, Type t2, char c) {
if (peek(c)) {
addToken(t2);
advance();
} else {
addToken(t1);
}
}

#pragma mark - Token Scanners

/// @brief Scans a string literal
Expand Down
11 changes: 8 additions & 3 deletions include/scanner/tokens.hh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ namespace rift
SEMICOLON,
SLASH,
STAR,
QUESTION,
COLON,

// One or two character tokens
BANG,
Expand All @@ -49,17 +51,21 @@ namespace rift
LESS_EQUAL,
SEPARATOR,
WHITESPACE,

// Operators
OPERATOR,
TERNARY,
NULLISH_COAL,
LOG_AND,
LOG_OR,
BIT_AND,
BIT_OR,

// Literals
IDENTIFIER,
STRINGLITERAL,
NUMERICLITERAL,

// Keywords
AND,
CLASS,
FALSE,
FUN,
Expand All @@ -68,7 +74,6 @@ namespace rift
ELSE,
ELIF,
NIL,
OR,
PRINT,
RETURN,
SUPER,
Expand Down
67 changes: 46 additions & 21 deletions lib/ast/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,25 +116,48 @@ namespace rift

Token Visitor::visit_binary(const Binary& expr) const
{
Token left = expr.left.get()->accept(*this);
Token right = expr.right.get()->accept(*this);

/* resolve identifiers */
if (left.type == TokenType::IDENTIFIER) {
auto tmp = Token(left);
left = rift::ast::Environment::getInstance().getEnv(castString(left));
if (left.type == TokenType::NIL) rift::error::runTimeError("Undefined variable '" + castString(tmp) + "'");
}
if (right.type == TokenType::IDENTIFIER) {
auto tmp = Token(right);
right = rift::ast::Environment::getInstance().getEnv(castString(right));
if (right.type == TokenType::NIL) rift::error::runTimeError("Undefined variable '" + castString(tmp) + "'");
}
Token left;
Token right;

string l_s, r_s;
any resAny;
bool resBool;

// Operators that can't evaulate yet
switch (expr.op.type) {
case NULLISH_COAL:
left = expr.left.get()->accept(*this);
if (left.type == TokenType::NIL) {
right = expr.right.get()->accept(*this);
return right;
}
return left;
case LOG_AND:
left = expr.left.get()->accept(*this);
if(truthy(left)) {
if(truthy(expr.right.get()->accept(*this)))
return Token(TokenType::TRUE, "true", "true", expr.op.line);
return Token(TokenType::FALSE, "false", "false", expr.op.line);
}
return Token();
case LOG_OR:
left = expr.left.get()->accept(*this);
if (truthy(left)) {
right = expr.right.get()->accept(*this);
return Token(TokenType::TRUE, "true", "true", expr.op.line);
} else {
right = expr.left.get()->accept(*this);
if (truthy(right)) return Token(TokenType::TRUE, "true", "true", expr.op.line);
return Token(TokenType::FALSE, "false", "false", expr.op.line);
}
default:
break;
}

left = expr.left.get()->accept(*this);
right = expr.right.get()->accept(*this);

// Operators which depend on evaluation of both
switch (expr.op.type) {
/* arthimetic ops */
case TokenType::MINUS:
Expand Down Expand Up @@ -169,7 +192,6 @@ namespace rift
rift::error::runTimeError("Expected a number for '*' operator");
resAny = any_arithmetic(left, right, expr.op);
return Token(TokenType::NUMERICLITERAL, castNumberString(resAny), resAny, expr.op.line);

/* comparison ops */
case TokenType::GREATER:
if(strcmp(castString(left).c_str(),castString(right).c_str())>0)
Expand Down Expand Up @@ -206,12 +228,6 @@ namespace rift
Token Visitor::visit_unary(const Unary& expr) const
{
Token right = expr.expr.get()->accept(*this);
// if (right.type == TokenType::IDENTIFIER) {
// auto tmp = Token(right);
// right = rift::ast::Environment::getInstance().getEnv(castString(right));
// if (right.type == TokenType::NIL) rift::error::runTimeError("Undefined variable '" + castString(tmp) + "'");
// }

bool res = false;
any resAny;

Expand Down Expand Up @@ -239,6 +255,15 @@ namespace rift
return Token();
}

Token Visitor::visit_ternary(const Ternary& expr) const
{
Token cond = expr.condition->accept(*this);

if(truthy(cond))
return Token(expr.left->accept(*this));
return Token(expr.right->accept(*this));
}

#pragma mark - Stmt Visitors

Token Visitor::visit_expr_stmt(const StmtExpr& stmt) const
Expand Down
17 changes: 12 additions & 5 deletions lib/ast/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ namespace rift
{
auto expr = comparison();

while (match({Token(TokenType::BANG_EQUAL, "!=", "", line)}) || match({Token(TokenType::EQUAL_EQUAL, "==", "", line)})) {
if (match({Token(TokenType::BANG_EQUAL, "!=", "", line)}) || match({Token(TokenType::EQUAL_EQUAL, "==", "", line)}) ||
match({Token(TokenType::NULLISH_COAL, "??", "", line)}) || match({Token(TokenType::LOG_AND, "&&", "", line)}) ) {
auto op = peekPrev();
auto right = comparison();
if (expr == nullptr) rift::error::report(line, "equality", "Expected expression before equality operator", op, ParserException("Expected expression before equality operator"));
Expand All @@ -148,10 +149,16 @@ namespace rift

std::unique_ptr<Expr> Parser::ternary()
{
if (peekNext() == Token(TokenType::TERNARY, "?:", "", line)) {
auto expr = equality();

auto expr = equality();

if (match({Token(TokenType::QUESTION, "?", "", line)})) {
auto left = equality();
consume(Token(TokenType::COLON, ":", "", line), std::unique_ptr<ParserException>(new ParserException("Expected a colon while expecting a ternary operator")));
auto right = equality();
return std::unique_ptr<Ternary>(new Ternary(std::move(expr),std::move(left),std::move(right)));
}

return expr;
}

std::unique_ptr<Expr> Parser::assignment()
Expand Down Expand Up @@ -181,7 +188,7 @@ namespace rift
}
}

return equality();
return ternary();
}

std::unique_ptr<Expr> Parser::expression()
Expand Down
10 changes: 8 additions & 2 deletions lib/scanner/scanner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace rift
this->tokens = std::vector<Token>();

keywords = std::unordered_map<std::string, Type>();
keywords["and"] = Type::AND;
keywords["and"] = Type::LOG_AND;
keywords["class"] = Type::CLASS;
keywords["false"] = Type::FALSE;
keywords["for"] = Type::FOR;
Expand All @@ -42,7 +42,7 @@ namespace rift
keywords["else"] = Type::ELSE;
keywords["elif"] = Type::ELIF;
keywords["nil"] = Type::NIL;
keywords["or"] = Type::OR;
keywords["or"] = Type::LOG_OR;
keywords["print"] = Type::PRINT;
keywords["return"] = Type::RETURN;
keywords["super"] = Type::SUPER;
Expand Down Expand Up @@ -148,6 +148,12 @@ namespace rift
case '\t': break;
case '\n': line++; break;

case '?': twoChar(Type::QUESTION, Type::NULLISH_COAL, c); break;
case ':': addToken(TokenType::COLON, ":");break;

case '&': twoChar(Type::BIT_AND, Type::LOG_AND, c); break;
case '|': twoChar(Type::BIT_OR, Type::LOG_OR, c); break;

default:
if (isDigit(c)) num();
else if (keyword()) return;
Expand Down
19 changes: 14 additions & 5 deletions lib/scanner/tokens.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,15 @@ std::string Token::convertTypeString(TokenType type) {
case SEPARATOR: return "SEPARATOR";
case WHITESPACE: return "WHITESPACE";
case OPERATOR: return "OPERATOR";
case TERNARY: return "TERNARY";
case QUESTION: return "QUESTION";
case COLON: return "COLON";
case NULLISH_COAL: return "NULLISH_COAL";
case IDENTIFIER: return "IDENTIFIER";
case STRINGLITERAL: return "STRINGLITERAL";
case NUMERICLITERAL: return "NUMERICLITERAL";
case AND: return "AND";
case BIT_AND: return "BIT_AND";
case BIT_OR: return "BIT_OR";
case LOG_AND: return "LOG_AND";
case CLASS: return "CLASS";
case ELSE: return "ELSE";
case ELIF: return "ELIF";
Expand All @@ -57,7 +60,7 @@ std::string Token::convertTypeString(TokenType type) {
case FOR: return "FOR";
case IF: return "IF";
case NIL: return "NIL";
case OR: return "OR";
case LOG_OR: return "LOG_OR";
case PRINT: return "PRINT";
case RETURN: return "RETURN";
case SUPER: return "SUPER";
Expand Down Expand Up @@ -165,6 +168,14 @@ std::any Token::getLiteral() const
return std::any{std::string(lexeme)};
} else if (type == IDENTIFIER) {
return std::any{std::string(lexeme)};
} else if (type == NUMERICLITERAL) {
return std::any{std::stod(lexeme)};
} else if (type == TRUE) {
return std::any{true};
} else if (type == FALSE) {
return std::any{false};
} else if (type == NIL) {
return std::any{nullptr};
}

if (isInteger(lexeme.c_str()))
Expand All @@ -191,8 +202,6 @@ std::any Token::getLiteral() const
return std::any{std::string(lexeme.substr(1, lexeme.length() - 2))};
if (isChar(lexeme.c_str()))
return std::any{char(lexeme[1])};
if (lexeme == "nil")
return std::any{nullptr};

rift::error::report(line, "getLiteral", "Unknown Literal Type", Token(), std::exception());
return std::any(); // should never hit
Expand Down
3 changes: 3 additions & 0 deletions lib/utils/literals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ namespace rift

std::string castAnyString(const Token& tok)
{
if (tok.type == TokenType::TRUE) return "true";
if (tok.type == TokenType::FALSE) return "false";
if (tok.type == TokenType::NIL) return "nil";
std::string str = castNumberString(tok.getLiteral(), false);
if (str.empty()) {
str = castString(tok, false);
Expand Down

0 comments on commit 070dbfd

Please sign in to comment.