Skip to content
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
29 changes: 21 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

on:
push:
branches: [main]
branches: [main, dev]
pull_request:
branches: [main]

Expand All @@ -14,14 +14,16 @@ jobs:
steps:
- uses: actions/checkout@v3

# Cache the CMake build outputs
- name: Cache build directory
uses: actions/cache@v4
with:
path: |
build
key: linux-build-${{ hashFiles('CMakeLists.txt', 'src/**') }}
path: build
key: ${{ runner.os }}-build-${{ hashFiles('CMakeLists.txt', 'src/**') }}
restore-keys: |
${{ runner.os }}-build-

- name: Install Dependencies
- name: Install System Dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y build-essential llvm clang cmake python3-pip
Expand All @@ -42,12 +44,23 @@ jobs:
steps:
- uses: actions/checkout@v3

# Cache the CMake build outputs
- name: Cache build directory
uses: actions/cache@v4
with:
path: |
build
key: windows-build-${{ hashFiles('CMakeLists.txt', 'src/**') }}
path: build
key: ${{ runner.os }}-build-${{ hashFiles('CMakeLists.txt', 'src/**') }}
restore-keys: |
${{ runner.os }}-build-

# Cache pip download cache on Windows
- name: Cache pip
uses: actions/cache@v4
with:
path: C:\Users\runneradmin\AppData\Local\pip\Cache
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-

- name: Setup MSVC Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1
Expand Down
2 changes: 1 addition & 1 deletion examples/functions.zz
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ fn factorial(x: uint64_t) -> uint64_t{
if(x <= 1){
return 1;
}else{
return multiply(x, factorial(x - 1));
return multiply(x, factorial(x-1));
}
}

Expand Down
5 changes: 1 addition & 4 deletions src/lexer/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace zust {
if (std::isalpha(static_cast<unsigned char>(c)) || c == '_')
return scanIdentifierOrKeywordOrConditional();

if (std::isdigit(static_cast<unsigned char>(c)) || (c == '-' && std::isdigit((unsigned char)peekChar(1))))
if (std::isdigit(static_cast<unsigned char>(c)))
return scanNumber();

if (c == '"')
Expand Down Expand Up @@ -119,9 +119,6 @@ namespace zust {
size_t startCol = column_;
std::string text;
bool seenDot = false;
if (peekChar() == '-' and isdigit(peekChar(1))) {
text.push_back(advance());
}
while (std::isdigit(static_cast<unsigned char>(peekChar())) || (!seenDot && peekChar() == '.')) {
if (peekChar() == '.')
seenDot = true;
Expand Down
39 changes: 26 additions & 13 deletions src/parser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,15 +180,15 @@ namespace zust {

void Parser::advance() { currentToken = lexer.nextToken(); }

bool Parser::match(Token::Token::Kind kind) {
bool Parser::match(Token::Kind kind) {
if (currentToken.kind == kind) {
advance();
return true;
}
return false;
}

void Parser::expect(Token::Token::Kind kind, const std::string& errMsg) {
void Parser::expect(Token::Kind kind, const std::string& errMsg) {
if (!match(kind)) {
logError({ErrorType::Syntax,
errMsg + " at line " + std::to_string(currentToken.line) +
Expand All @@ -201,7 +201,7 @@ namespace zust {

std::unique_ptr<ASTNode> Parser::parse() {
auto program = ASTNode::makeProgramNode(currentScope);
while (currentToken.kind != Token::Token::Kind::EndOfFile) {
while (currentToken.kind != Token::Kind::EndOfFile) {
auto stmt = parseStatement();
if (stmt)
program->addChild(std::move(stmt));
Expand Down Expand Up @@ -238,9 +238,9 @@ namespace zust {
currentToken.text == "extern") ||
currentToken.kind == Token::Kind::Function)
return parseFunctionDeclaration();
if (match(Token::Token::Kind::Let))
if (match(Token::Kind::Let))
return parseVariableDeclaration();
if (currentToken.kind == Token::Token::Kind::Identifier and lexer.peek().kind == Token::Kind::Equal)
if (currentToken.kind == Token::Kind::Identifier and lexer.peek().kind == Token::Kind::Equal)
return parseVariableReassignment();
if (currentToken.kind == Token::Kind::If ||
currentToken.kind == Token::Kind::ElseIf ||
Expand Down Expand Up @@ -458,8 +458,8 @@ namespace zust {
}

std::unique_ptr<ASTNode> Parser::parseVariableDeclaration() {
if (currentToken.kind != Token::Token::Kind::Identifier)
expect(Token::Token::Kind::Identifier,
if (currentToken.kind != Token::Kind::Identifier)
expect(Token::Kind::Identifier,
"Expected variable name after 'let'");

std::string name = currentToken.text;
Expand Down Expand Up @@ -521,9 +521,9 @@ namespace zust {
std::string name = currentToken.text;
advance();

expect(Token::Token::Kind::Equal, "Expected '=' for variable reassignment");
expect(Token::Kind::Equal, "Expected '=' for variable reassignment");
auto expr = parseExpression();
expect(Token::Token::Kind::SemiColon, "Expected ';' after reassignment");
expect(Token::Kind::SemiColon, "Expected ';' after reassignment");
return ASTNode::makeVariableReassignmentNode(name, std::move(expr),
currentScope);
}
Expand All @@ -538,27 +538,40 @@ namespace zust {
}

std::unique_ptr<ASTNode> Parser::parsePrimary() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider moving all unary minus handling from parsePrimary to parseUnary and using a match overload to reduce duplication and centralize logic.

Here’s one way to pull the “–”‐in‐front‐of‐literal logic out of parsePrimary and into parseUnary, collapse duplication, and keep all existing behavior:

  1. Remove your new “if (currentToken == ‘–’) { … }” block from parsePrimary().
  2. Add an overload of match so you can match on both kind+text:
bool Parser::match(Token::Kind kind, const std::string &txt) {
    if (currentToken.kind == kind && currentToken.text == txt) {
        advance();
        return true;
    }
    return false;
}
  1. Change parseUnary() to handle “–” in one place. If it’s directly in front of a literal you’ll still get a single literal node; if it’s in front of any other expression you get a proper unary‐negate node:
std::unique_ptr<ASTNode> Parser::parseUnary() {
    // special‐case negative literal:
    if (match(Token::Kind::Symbol, "-") &&
        (currentToken.kind == Token::Kind::IntegerLiteral ||
         currentToken.kind == Token::Kind::FloatLiteral))
    {
        // capture "-" + literal text, then let primary do the rest
        std::string txt = "-" + currentToken.text;
        auto kind = currentToken.kind;
        advance();
        return (kind == Token::Kind::IntegerLiteral)
            ? ASTNode::makeIntegerLiteralNode(txt, currentScope)
            : ASTNode::makeFloatLiteralNode    (txt, currentScope);
    }
    // generic unary operator (e.g. negate a sub‐expr)
    if (match(Token::Kind::Symbol, "-")) {
        auto operand = parseUnary();
        return ASTNode::makeUnaryOperatorNode(UnaryOp::Negate,
                                              std::move(operand),
                                              currentScope);
    }
    // fall back to primary
    return parsePrimary();
}

That eliminates the nested if(“-”) in parsePrimary and centralizes all unary‐minus handling in one place.

if (currentToken.kind == Token::Kind::Symbol && currentToken.text == "-") {
advance();
if (currentToken.kind == Token::Kind::FloatLiteral) {
std::string f = currentToken.text;
advance();
return ASTNode::makeFloatLiteralNode("-" + f, currentScope);
}
if (currentToken.kind == Token::Kind::IntegerLiteral) {
std::string val = currentToken.text;
advance();
return ASTNode::makeIntegerLiteralNode("-" + val, currentScope);
}
}
if (currentToken.kind == Token::Kind::BoolLiteral) {
bool val = (currentToken.text == "true");
advance();
return ASTNode::makeBooleanLiteralNode(val, currentScope);
}
if (currentToken.kind == Token::Token::Kind::StringLiteral) {
if (currentToken.kind == Token::Kind::StringLiteral) {
std::string s = currentToken.text;
advance();
return ASTNode::makeStringLiteralNode(s, currentScope);
}
if (currentToken.kind == Token::Token::Kind::FloatLiteral) {
if (currentToken.kind == Token::Kind::FloatLiteral) {
std::string f = currentToken.text;
advance();
return ASTNode::makeFloatLiteralNode(f, currentScope);
}
if (currentToken.kind == Token::Token::Kind::IntegerLiteral) {
if (currentToken.kind == Token::Kind::IntegerLiteral) {
std::string val = currentToken.text;
advance();
return ASTNode::makeIntegerLiteralNode(val, currentScope);
}
if (currentToken.kind == Token::Token::Kind::Identifier) {
if (currentToken.kind == Token::Kind::Identifier) {
std::string name = currentToken.text;
advance();

Expand Down