-
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
Daan Posthuma
authored and
Daan Posthuma
committed
Dec 14, 2023
1 parent
da74eca
commit 362f44b
Showing
9 changed files
with
271 additions
and
132 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,16 @@ | ||
# CMakeList.txt : Top-level CMake project file, do global configuration | ||
# and include sub-projects here. | ||
# | ||
cmake_minimum_required (VERSION 3.8) | ||
cmake_minimum_required (VERSION 3.8) | ||
|
||
project ("lox") | ||
|
||
# Enable Hot Reload for MSVC compilers if supported. | ||
if (POLICY CMP0141) | ||
cmake_policy(SET CMP0141 NEW) | ||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>") | ||
endif() | ||
|
||
project ("lox") | ||
set(CMAKE_CXX_STANDARD 23) | ||
set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
set(CMAKE_CXX_EXTENSIONS OFF) | ||
|
||
# Include sub-projects. | ||
add_subdirectory ("lox") | ||
|
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,5 +1,21 @@ | ||
add_executable (lox "Expr.cpp" "Environment.cpp" "ExprToString.cpp" "Interpreter.cpp" "Lox.cpp" "Object.cpp" "Parser.cpp" "Scanner.cpp" "Stmt.cpp" "Token.cpp" "TokenType.cpp" "LoxCallable.cpp" "Resolver.cpp") | ||
add_library(loxlib | ||
Environment.cpp | ||
Expr.cpp | ||
ExprToString.cpp | ||
Interpreter.cpp | ||
Lox.cpp | ||
LoxCallable.cpp | ||
Object.cpp | ||
Parser.cpp | ||
Resolver.cpp | ||
Scanner.cpp | ||
Stmt.cpp | ||
Token.cpp | ||
TokenType.cpp | ||
) | ||
|
||
if (CMAKE_VERSION VERSION_GREATER 3.25) | ||
set_property(TARGET lox PROPERTY CXX_STANDARD 26) | ||
endif() | ||
add_executable (lox Main.cpp) | ||
|
||
target_link_libraries(lox loxlib) | ||
|
||
add_subdirectory ("tests") |
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,121 @@ | ||
#include "Scanner.h" | ||
#include "Token.h" | ||
#include "Lox.h" | ||
#include "Parser.h" | ||
#include "Interpreter.h" | ||
#include "Environment.h" | ||
#include "LoxCallable.h" | ||
#include "Resolver.h" | ||
#include <iostream> | ||
#include <fstream> | ||
#include <algorithm> | ||
#include <chrono> | ||
|
||
using namespace std::string_literals; | ||
|
||
namespace { | ||
|
||
void addNativeFunctionsToGlobalEnvironment() { | ||
Lox::globals.define("clock", LoxCallable([](std::vector<Object> const&) { | ||
return static_cast<double>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()); | ||
}, 0, "clock (native)")); | ||
|
||
Lox::globals.define("monkey", LoxCallable([](std::vector<Object> const&) { | ||
return " __ \n w c(..)o ( \n \\__(-) __) \n /\\ ( \n /(_)___) \n w /| \n | \\ \n m m "s; | ||
}, 0, "monkey (native)")); | ||
|
||
Lox::globals.define("readString", LoxCallable([](std::vector<Object> const&) { | ||
std::string s; | ||
std::cin >> s; | ||
return s; | ||
}, 0, "readString (native)")); | ||
|
||
Lox::globals.define("subString", LoxCallable([](std::vector<Object> const& arguments) { | ||
auto const string = static_cast<std::string>(arguments[0]); | ||
auto const offd = static_cast<double>(arguments[1]); | ||
auto const countd = static_cast<double>(arguments[2]); | ||
auto const off = static_cast<int>(offd); | ||
auto const count = static_cast<int>(countd); | ||
return string.substr(off, count); | ||
}, 3, "subString (native)")); | ||
|
||
} | ||
|
||
void run(std::string source) { | ||
|
||
auto const tScanTokensStart = std::chrono::high_resolution_clock::now(); | ||
auto const tokens = scanTokens(source); | ||
auto const tScanTokensEnd = std::chrono::high_resolution_clock::now(); | ||
|
||
if (Lox::debugEnabled) { | ||
std::cout << "Tokens: "; | ||
std::ranges::for_each(tokens, [first = true](Token const& token) mutable { std::cout << (first ? "" : ", ") << "[" << token.toString() << "]"; first = false; }); | ||
std::cout << std::endl; | ||
} | ||
|
||
auto const tParseStart = std::chrono::high_resolution_clock::now(); | ||
auto const statements = parse(tokens); | ||
auto const tParseEnd = std::chrono::high_resolution_clock::now(); | ||
|
||
if (Lox::debugEnabled) { | ||
std::cout << "Num statements: " << statements.size() << std::endl; | ||
} | ||
|
||
auto const tResolveStart = std::chrono::high_resolution_clock::now(); | ||
auto const locals = Lox::hadError ? ResolvedLocals() : resolve(statements); | ||
auto const tResolveEnd = std::chrono::high_resolution_clock::now(); | ||
|
||
auto const tInterpretStart = std::chrono::high_resolution_clock::now(); | ||
auto const result = Lox::hadError ? Object{} : interpret(statements, locals); | ||
auto const tInterpretEnd = std::chrono::high_resolution_clock::now(); | ||
|
||
if (!result.isNil()) { | ||
std::cout << result.toString() << std::endl; | ||
} | ||
|
||
if (Lox::debugEnabled) { | ||
std::cout << "Scanner: " << std::chrono::duration_cast<std::chrono::microseconds>(tScanTokensEnd - tScanTokensStart) << std::endl; | ||
std::cout << "Parser: " << std::chrono::duration_cast<std::chrono::microseconds>(tParseEnd - tParseStart) << std::endl; | ||
std::cout << "Resolver: " << std::chrono::duration_cast<std::chrono::microseconds>(tResolveEnd - tResolveStart) << std::endl; | ||
std::cout << "Interpreter: " << std::chrono::duration_cast<std::chrono::microseconds>(tInterpretEnd - tInterpretStart) << std::endl; | ||
} | ||
} | ||
|
||
void runFile(std::string fileName) { | ||
std::ifstream t(fileName); | ||
std::stringstream buffer; | ||
buffer << t.rdbuf(); | ||
run(buffer.str()); | ||
} | ||
|
||
void runPrompt() { | ||
while (true) { | ||
std::cout << "> "; | ||
std::string line; | ||
getline(std::cin, line); | ||
if (line == "exit" || line == "q") return; | ||
run(line); | ||
Lox::hadError = false; | ||
} | ||
} | ||
} | ||
|
||
int main(int argc, char* argv[]) | ||
{ | ||
std::cout << std::boolalpha; | ||
|
||
addNativeFunctionsToGlobalEnvironment(); | ||
|
||
if (argc > 2) { | ||
std::cerr << "Usage: lox [script]" << std::endl; | ||
return EXIT_FAILURE; | ||
} | ||
else if (argc == 2) { | ||
runFile(argv[1]); | ||
} | ||
else { | ||
runPrompt(); | ||
} | ||
|
||
return 0; | ||
} |
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,12 @@ | ||
include(FetchContent) | ||
FetchContent_Declare( | ||
catch2 | ||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git | ||
GIT_TAG v3.5.0 | ||
) | ||
FetchContent_MakeAvailable(Catch2) | ||
|
||
include_directories(..) | ||
|
||
add_executable(tests TestScanner.cpp TestParser.cpp TestResolver.cpp) | ||
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain loxlib) |
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,36 @@ | ||
#include "Token.h" | ||
#include "TokenType.h" | ||
#include "Object.h" | ||
#include "Parser.h" | ||
#include "Stmt.h" | ||
#include "Lox.h" | ||
#include <catch2/catch_test_macros.hpp> | ||
|
||
namespace lox::parser { | ||
|
||
auto const tSEMICOLON = Token(TokenType::SEMICOLON, ";", Object(), 0); | ||
auto const tEND_OF_FILE = Token(TokenType::END_OF_FILE, "", Object(), 0); | ||
|
||
auto const tPRINT = Token(TokenType::PRINT, "print", Object(), 0); | ||
auto const tNUMBER = Token(TokenType::NUMBER, "3", Object(3.0), 0); | ||
|
||
auto const tVAR = Token(TokenType::VAR, "print", Object(), 0); | ||
auto const tIDENTIFIER = Token(TokenType::IDENTIFIER, "test", Object(), 0); | ||
auto const tEQUAL = Token(TokenType::EQUAL, "=", Object(), 0); | ||
auto const tSTRING = Token(TokenType::STRING, "Test", Object("Test"), 0); | ||
|
||
TEST_CASE("Parser produces print statement", "[lox.parser.print]") { | ||
auto const printNumber = parse({ tPRINT, tNUMBER, tSEMICOLON, tEND_OF_FILE }); | ||
REQUIRE(!Lox::hadError); | ||
REQUIRE(printNumber.size() == 1); | ||
REQUIRE(dynamic_cast<PrintStmt const*>(printNumber.front())); | ||
} | ||
|
||
TEST_CASE("Parser produces var statement", "[lox.parser.var]") { | ||
auto const printNumber = parse({ tVAR, tIDENTIFIER, tEQUAL, tSTRING, tSEMICOLON, tEND_OF_FILE }); | ||
REQUIRE(!Lox::hadError); | ||
REQUIRE(printNumber.size() == 1); | ||
REQUIRE(dynamic_cast<VarStmt const*>(printNumber.front())); | ||
} | ||
|
||
} |
Oops, something went wrong.