class Lexer {
private:
int line;
- std::ifstream &stream;
std::string filename;
- std::string currentLine;
- std::string::iterator start;
- std::string::iterator current;
+ const char *start;
+ const char *current;
public:
bool hadError;
char peekNext() const;
bool isAtEnd() const;
- bool isAtLineEnd() const;
bool isDigit(char ch) const;
bool isAlpha(char ch) const;
bool match(char ch);
public:
- Lexer(std::ifstream &, const std::string &);
+ Lexer(const char*, const std::string &);
int getLine();
int getColumn();
std::unique_ptr<Expr> primary();
public:
- Parser(std::ifstream &file, std::string &filename)
+ Parser(const char *file, const std::string &filename)
: lexer(new Lexer(file, filename)), current(lexer->getNextToken()),
previous(current) {
importedFiles.insert(filename);
}
- Parser(std::ifstream &file, const std::string &filename,
+ Parser(const char *file, const std::string &filename,
std::unordered_set<std::string> &importedFiles)
: importedFiles(importedFiles), lexer(new Lexer(file, filename)),
current(lexer->getNextToken()), previous(current) {}
#include "LBPLTypes.h"
#include "runtime_error.h"
-#include <chrono>
#include <cstddef>
#include <map>
#include <memory>
#include <string>
#include <variant>
-class Timer {
- std::chrono::time_point<std::chrono::high_resolution_clock> m_startTimepoint;
-
-public:
- Timer() { m_startTimepoint = std::chrono::high_resolution_clock::now(); }
-
- ~Timer() { stop(); }
-
- void stop() {
- auto endTimepoint = std::chrono::high_resolution_clock::now();
-
- auto start = std::chrono::time_point_cast<std::chrono::microseconds>(
- m_startTimepoint)
- .time_since_epoch()
- .count();
- auto end =
- std::chrono::time_point_cast<std::chrono::microseconds>(endTimepoint)
- .time_since_epoch()
- .count();
-
- auto duration = end - start;
- auto ms = duration * 0.001;
-
- std::cout << duration << "µs (" << ms << "ms)\n";
- }
-};
void Interpreter::interpret(std::vector<std::unique_ptr<Stmt>> &stmts) {
- std::cout << "\tinterpreter begin\n";
try {
for (auto &&stmt : stmts) {
stmt->accept(this);
LBPLType Interpreter::visitBinaryExpr(BinaryExpr *expr) {
LBPLType left = expr->left->accept(this);
LBPLType right = expr->right->accept(this);
- return performBinaryOperation(expr->op, left, right);
- /* if (std::holds_alternative<int>(left) &&
- * std::holds_alternative<int>(right)) { */
- /* return performBinaryOperation(expr->op.get(), std::get<int>(left), */
- /* std::get<int>(right)); */
- /* } else if (std::holds_alternative<double>(left) && */
- /* std::holds_alternative<double>(right)) { */
- /* return performBinaryOperation(expr->op.get(), std::get<double>(left), */
- /* std::get<double>(right)); */
- /* } else if (std::holds_alternative<double>(left) && */
- /* std::holds_alternative<int>(right)) { */
- /* return performBinaryOperation(expr->op.get(), std::get<double>(left), */
- /* std::get<int>(right)); */
- /* } else if (std::holds_alternative<int>(left) && */
- /* std::holds_alternative<double>(right)) { */
- /* return performBinaryOperation(expr->op.get(), std::get<int>(left), */
- /* std::get<double>(right)); */
- /* } else if ((std::holds_alternative<std::string>(left) || */
- /* std::holds_alternative<std::string>(right)) && */
- /* expr->op->type == TokenType::Plus) { */
- /* if (std::holds_alternative<std::string>(left) && */
- /* std::holds_alternative<std::string>(right)) { */
- /* return std::get<std::string>(left) + */
- /* std::get<std::string>(right); */
- /* } else if (std::holds_alternative<std::string>(left) && */
- /* std::holds_alternative<int>(right)) { */
- /* return std::get<std::string>(left) + */
- /* std::to_string(std::get<int>(right)); */
- /* } else if (std::holds_alternative<int>(left) && */
- /* std::holds_alternative<std::string>(right)) { */
- /* return std::get<std::string>(left) + */
- /* std::to_string(std::get<double>(right)); */
- /* } else if (std::holds_alternative<double>(left) && */
- /* std::holds_alternative<std::string>(right)) { */
- /* return std::to_string(std::get<double>(left)) + */
- /* std::get<std::string>(right); */
- /* } else if (std::holds_alternative<std::string>(left) && */
- /* std::holds_alternative<char>(right)) { */
- /* return std::get<std::string>(left) + std::get<char>(right); */
- /* } else if (std::holds_alternative<char>(left) && */
- /* std::holds_alternative<std::string>(right)) { */
- /* return std::get<char>(left) + std::get<std::string>(right); */
- /* } */
- /* } */
-
- /* throw RuntimeError(expr->op.get(), "Invalid binary operation operand."); */
+ return performBinaryOperation(expr->op, left, right);
}
LBPLType Interpreter::visitBreakExpr(BreakExpr *) { throw BreakException(); }
LBPLType Interpreter::visitSuperExpr(SuperExpr *) { return nullptr; }
LBPLType Interpreter::visitThisExpr(ThisExpr *) { return nullptr; }
+
LBPLType Interpreter::visitCallExpr(FnCallExpr *expr) {
LBPLType callee = expr->callee->accept(this);
LBPLType Interpreter::visitGetFieldExpr(GetFieldExpr *expr) {
LBPLType instance = expr->instance->accept(this);
if (std::holds_alternative<std::shared_ptr<LBPLInstance>>(instance)) {
- return std::get<std::shared_ptr<LBPLInstance>>(instance)->get(expr->field.get());
+ return std::get<std::shared_ptr<LBPLInstance>>(instance)->get(
+ expr->field.get());
}
- throw RuntimeError(expr->instance.get(), "Only instances of classes can have properties");
+ throw RuntimeError(expr->instance.get(),
+ "Only instances of classes can have properties");
}
LBPLType Interpreter::visitSetFieldExpr(SetFieldExpr *expr) {
if (std::holds_alternative<std::shared_ptr<LBPLInstance>>(instance)) {
LBPLType value = expr->value->accept(this);
- std::get<std::shared_ptr<LBPLInstance>>(instance)->set(expr->field.get(), value);
+ std::get<std::shared_ptr<LBPLInstance>>(instance)->set(expr->field.get(),
+ value);
} else {
- throw RuntimeError(expr->instance.get(), "Only instances of classes can have properties");
+ throw RuntimeError(expr->instance.get(),
+ "Only instances of classes can have properties");
}
return nullptr;
left, right);
}
-/* template <typename T, typename G> */
-/* LBPLType Interpreter::performBinaryOperation(const Token *op, const T &left,
- */
-/* const G &right) { */
-/* switch (op->type) { */
-/* case TokenType::EqualEqual: */
-/* return left == right; */
-/* case TokenType::BangEqual: */
-/* return left != right; */
-/* case TokenType::Less: */
-/* return left < right; */
-/* case TokenType::LessEqual: */
-/* return left <= right; */
-/* case TokenType::Greater: */
-/* return left > right; */
-/* case TokenType::GreaterEqual: */
-/* return left >= right; */
-/* case TokenType::Plus: */
-/* return left + right; */
-/* case TokenType::Minus: */
-/* return left - right; */
-/* case TokenType::Star: */
-/* return left * right; */
-/* case TokenType::Slash: */
-/* if (right == T(0)) { */
-/* throw RuntimeError(op, "Division by zero."); */
-/* } */
-/* return left / right; */
-/* case TokenType::ModOp: */
-/* return (int)left % (int)right; */
-/* default: */
-/* throw RuntimeError(op, "Unsupported binary operation."); */
-/* } */
-/* } */
-
void Interpreter::executeBlock(std::vector<std::unique_ptr<Stmt>> &body,
std::shared_ptr<Environment> &&env) {
executeBlock(body, env);
#include "lexer.h"
-Lexer::Lexer(std::ifstream &stream, const std::string &filename)
- : stream(stream), line(1), hadError(false), filename(filename) {
- goToNextLine();
-}
+Lexer::Lexer(const char *stream, const std::string &filename)
+ : line(1), hadError(false), filename(filename), current(stream), start(stream) {}
-bool Lexer::isAtEnd() const { return stream.eof(); }
-bool Lexer::isAtLineEnd() const { return *current == '\0'; }
+bool Lexer::isAtEnd() const { return *current == '\0'; }
bool Lexer::isDigit(char ch) const { return ch >= '0' && ch <= '9'; }
bool Lexer::isAlpha(char ch) const {
return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_';
}
+
bool Lexer::match(char ch) {
- if (isAtLineEnd() || ch != *current) {
+ if (isAtEnd() || ch != *current) {
return false;
}
return true;
}
-void Lexer::goToNextLine() {
- std::getline(stream, currentLine);
- current = currentLine.begin();
- start = currentLine.begin();
-}
-
char Lexer::peek() const { return *current; }
char Lexer::peekNext() const { return *(current + 1); }
-char Lexer::advance() {
- if (isAtLineEnd()) {
- if (isAtEnd()) {
- return '\0';
- }
-
- std::getline(stream, currentLine);
- current = currentLine.begin();
- return *current;
+char Lexer::advance() {
+ if (isAtEnd()) {
+ return '\0';
}
return *(current++);
std::string value) {
if (value != "") {
return std::make_shared<const Token>(type, value, line,
- start - currentLine.begin(), filename);
+ current-start, filename);
}
return std::make_shared<const Token>(type, std::string(start, current), line,
- start - currentLine.begin(), filename);
+ current-start, filename);
}
std::shared_ptr<const Token> Lexer::makeNumberToken() {
std::shared_ptr<const Token> Lexer::makeErrorToken(std::string msg) {
hadError = true;
return std::make_shared<const Token>(TokenType::Error, msg, line,
- start - currentLine.begin(), filename);
+ current-start, filename);
}
void Lexer::skipWhitespace() {
do {
switch (peek()) {
- case '\0':
+ case '\n':
line++;
case ' ':
case '\r':
advance();
break;
case '#':
- while (!isAtLineEnd()) {
+ while (peek() != '\n') {
advance();
}
if (match('|')) {
return makeToken(TokenType::Or);
}
- return makeErrorToken("Invalid operator '|' in: `" + currentLine +
- "`.\n\tDid you mean '|\033[4;32m|\033[0m'?");
+ return makeErrorToken("Invalid token '" + std::to_string(*current) + "'.");
case '-':
return makeToken(TokenType::Minus);
case '+':
if (!match('\'')) {
auto res =
makeErrorToken("A char can't be more then one character long.");
- goToNextLine();
return res;
}
return makeToken(TokenType::Char, val);
case '"': {
std::string lexeme;
- while (peek() != '"' && !isAtLineEnd()) {
+ while (peek() != '"' && !isAtEnd()) {
if (peek() == '\\') {
advance();
}
}
- if (isAtLineEnd()) {
+ if (isAtEnd()) {
return makeErrorToken("Unterminated string.");
}
}
int Lexer::getLine() { return line; }
-int Lexer::getColumn() { return current - currentLine.begin(); }
+int Lexer::getColumn() { return current - start; }
std::string Lexer::getFilename() { return filename; }
#include "main.h"
+#include <fcntl.h>
+#include <iostream>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
int main(const int argc, const char **argv) {
if (argc < 2) {
- std::cerr << "\033[1;31mNot enough arguemnts.\tUsage: lbpl [script]" << std::endl;
+ std::cerr << "\033[1;31mNot enough arguemnts.\tUsage: lbpl [script]"
+ << std::endl;
return 1;
}
- std::ifstream sourceFile(argv[1]);
- std::string filename(argv[1]);
- if (!sourceFile.is_open()) {
- std::cerr << "Error opening the file." << std::endl;
- return 1;
+ int fd = open(argv[1], O_RDONLY, S_IRUSR | S_IWUSR);
+ struct stat sb;
+
+ if (fstat(fd, &sb) == -1) {
+ perror("Couldn't get file size.\n");
}
- Parser *parser = new Parser(sourceFile, filename);
+ char *file_in_memory =
+ (char *)mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ Parser *parser = new Parser(file_in_memory, argv[1]);
std::vector<std::unique_ptr<Stmt>> statements = parser->parse();
// AST_Printer test;
}
delete parser;
- sourceFile.close();
+ munmap(file_in_memory, sb.st_size);
+ close(fd);
}
#include "parser.h"
-
-// static size_t totalMem = 0;
-// void *operator new(size_t size) {
-// totalMem += size;
-// void *ptr = malloc(size + sizeof(size_t));
-// if (ptr) {
-// *((size_t *)ptr) = size;
-// return (char *)ptr + sizeof(size_t);
-// } else {
-// throw std::bad_alloc();
-// }
-// // return malloc(size);
-// }
-
-// void operator delete(void *ptr) noexcept {
-// if (ptr) {
-// size_t *originalPtr = (size_t *)((char *)ptr - sizeof(size_t));
-// size_t size = *originalPtr;
-// totalMem -= size;
-// free(originalPtr);
-// }
-// }
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
std::vector<std::unique_ptr<Stmt>> Parser::parse() {
std::vector<std::unique_ptr<Stmt>> stmts;
- // {
- // Timer timer;
while (!isAtEnd()) {
try {
if (match(TokenType::Import)) {
synchronize();
}
}
- // }
- // std::cout << totalMem << "B\n";
return stmts;
}
}
importedFiles.insert(path->lexeme);
- std::ifstream sourceFile(path->lexeme);
- if (!sourceFile.is_open()) {
- throw SyntaxError(previous.get(), "Error opening file: '" + path->lexeme +
- "'.\nIs the path correct?");
+ int fd = open(path->lexeme.c_str(), O_RDONLY, S_IRUSR | S_IWUSR);
+ struct stat sb;
+
+ if (fstat(fd, &sb) == -1) {
+ perror("Couldn't get file size.\n");
}
+ char *sourceFile =
+ (char *)mmap(nullptr, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ CONSUME_SEMICOLON("import");
+
+ return (new Parser(sourceFile, path->lexeme, importedFiles))->parse();
+
CONSUME_SEMICOLON("import");
return (new Parser(sourceFile, path->lexeme, importedFiles))->parse();