ADD: int literal.
parent
dfd65e5fc3
commit
149f866172
|
@ -0,0 +1,26 @@
|
||||||
|
#include "Factory.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*explicit*/ Factory::Factory(Logger& logger, std::filesystem::path path)
|
||||||
|
: m_logger { logger }
|
||||||
|
, m_path { path }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Factory::~Factory()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Lexer> Factory::make_lexer()
|
||||||
|
{
|
||||||
|
Loc loc {m_path, 1, 0};
|
||||||
|
return std::make_shared<Lexer>(m_logger, loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Parser> Factory::make_parser()
|
||||||
|
{
|
||||||
|
auto lexer = make_lexer();
|
||||||
|
return std::make_shared<Parser>(m_logger, lexer);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef jk_FACTORY_HPP
|
||||||
|
#define jk_FACTORY_HPP
|
||||||
|
|
||||||
|
#include "Lexer.hpp"
|
||||||
|
#include "Parser.hpp"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
class Factory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Factory(Logger& logger, std::filesystem::path path);
|
||||||
|
virtual ~Factory();
|
||||||
|
|
||||||
|
std::shared_ptr<Lexer> make_lexer();
|
||||||
|
std::shared_ptr<Parser> make_parser();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger& m_logger;
|
||||||
|
std::filesystem::path m_path;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,130 @@
|
||||||
|
#include "Lexer.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*explicit*/ Lexer::Lexer(Logger& logger, Loc const& loc)
|
||||||
|
: m_logger { logger }
|
||||||
|
, m_loc { loc }
|
||||||
|
{
|
||||||
|
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Lexer::~Lexer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lexer::scan(std::string const& source)
|
||||||
|
{
|
||||||
|
m_source = source;
|
||||||
|
m_cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Lexer::next()
|
||||||
|
{
|
||||||
|
skip_spaces();
|
||||||
|
|
||||||
|
while (more(m_cursor)
|
||||||
|
&& current(m_cursor) == '#')
|
||||||
|
{
|
||||||
|
while (more(m_cursor)
|
||||||
|
&& current(m_cursor) != '\n')
|
||||||
|
{
|
||||||
|
m_cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_spaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ScanInfo> info;
|
||||||
|
|
||||||
|
for (auto scanner: m_scanners)
|
||||||
|
{
|
||||||
|
auto my_info = scanner();
|
||||||
|
|
||||||
|
if ((!info && my_info)
|
||||||
|
|| (info && my_info
|
||||||
|
&& my_info->cursor > info->cursor))
|
||||||
|
{
|
||||||
|
info = my_info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
m_cursor = info->cursor;
|
||||||
|
return std::make_shared<Node>(info->type, info->repr, m_loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (more(m_cursor))
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
while (more(m_cursor)
|
||||||
|
&& !std::isspace(current(m_cursor)))
|
||||||
|
{
|
||||||
|
text += current(m_cursor);
|
||||||
|
m_cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "unknown text '" << text << "'";
|
||||||
|
m_logger.log<lexical_error>(LOG_ERROR, m_loc, ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Lexer::more(size_t index) const
|
||||||
|
{
|
||||||
|
return index < m_source.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
char Lexer::current(size_t index) const
|
||||||
|
{
|
||||||
|
assert(more(index));
|
||||||
|
|
||||||
|
return m_source[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lexer::skip_spaces()
|
||||||
|
{
|
||||||
|
while (more(m_cursor)
|
||||||
|
&& std::isspace(current(m_cursor)))
|
||||||
|
{
|
||||||
|
if (current(m_cursor) == '\n')
|
||||||
|
{
|
||||||
|
m_loc = Loc {
|
||||||
|
m_loc.path(),
|
||||||
|
m_loc.line() + 1,
|
||||||
|
m_loc.column()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cursor++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ScanInfo> Lexer::scan_int() const
|
||||||
|
{
|
||||||
|
size_t cursor = m_cursor;
|
||||||
|
std::string repr;
|
||||||
|
|
||||||
|
while (more(cursor)
|
||||||
|
&& std::isdigit(current(cursor)))
|
||||||
|
{
|
||||||
|
repr += current(cursor);
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (repr.empty() == false)
|
||||||
|
{
|
||||||
|
return ScanInfo {
|
||||||
|
cursor,
|
||||||
|
NODE_INT,
|
||||||
|
repr
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef jk_LEXER_HPP
|
||||||
|
#define jk_LEXER_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
#include "Node.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
JK_ERROR(lexical_error);
|
||||||
|
|
||||||
|
struct ScanInfo {
|
||||||
|
size_t cursor;
|
||||||
|
NodeType type;
|
||||||
|
std::string repr;
|
||||||
|
};
|
||||||
|
|
||||||
|
using scanner_t = std::function<std::optional<ScanInfo>()>;
|
||||||
|
|
||||||
|
class Lexer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Lexer(Logger& logger, Loc const& loc);
|
||||||
|
virtual ~Lexer();
|
||||||
|
|
||||||
|
void scan(std::string const& source);
|
||||||
|
std::shared_ptr<Node> next();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger& m_logger;
|
||||||
|
Loc m_loc;
|
||||||
|
size_t m_cursor;
|
||||||
|
std::string m_source;
|
||||||
|
std::vector<scanner_t> m_scanners;
|
||||||
|
|
||||||
|
bool more(size_t index) const;
|
||||||
|
char current(size_t index) const;
|
||||||
|
|
||||||
|
void skip_spaces();
|
||||||
|
|
||||||
|
std::optional<ScanInfo> scan_int() const;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include "Loc.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*explicit*/ Loc::Loc(std::filesystem::path path, int line, int column)
|
||||||
|
: m_path { path }
|
||||||
|
, m_line { line }
|
||||||
|
, m_column { column }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Loc::~Loc()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef jk_LOC_HPP
|
||||||
|
#define jk_LOC_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
class Loc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Loc(std::filesystem::path path, int line, int column);
|
||||||
|
virtual ~Loc();
|
||||||
|
|
||||||
|
std::filesystem::path path() const { return m_path; }
|
||||||
|
int line() const { return m_line; }
|
||||||
|
int column() const { return m_column; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::filesystem::path m_path;
|
||||||
|
int m_line;
|
||||||
|
int m_column;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "Logger.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*explicit*/ Logger::Logger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Logger::~Logger()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef jk_LOGGER_HPP
|
||||||
|
#define jk_LOGGER_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "Loc.hpp"
|
||||||
|
|
||||||
|
#define LOG_TYPE(G) \
|
||||||
|
G(LOG_ERROR)
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
JK_ENUM(Log, LOG_TYPE);
|
||||||
|
|
||||||
|
class Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Logger();
|
||||||
|
virtual ~Logger();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void log(LogType type, Loc const& loc, std::string const& what);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Logger::log(LogType type, Loc const& loc, std::string const& what)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << loc.path().string() << ":" << loc.line();
|
||||||
|
ss << " " << (std::string(LogTypeStr[type])
|
||||||
|
.substr(std::string("LOG_").size()));
|
||||||
|
ss << " " << what;
|
||||||
|
|
||||||
|
throw T { ss.str() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include "Node.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*explicit*/ Node::Node(NodeType type,
|
||||||
|
std::string const& repr,
|
||||||
|
Loc const& loc)
|
||||||
|
: m_type { type }
|
||||||
|
, m_repr { repr }
|
||||||
|
, m_loc { loc }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Node::~Node()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::add_child(std::shared_ptr<Node> child)
|
||||||
|
{
|
||||||
|
m_children.push_back(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Node> Node::child(size_t index) const
|
||||||
|
{
|
||||||
|
assert(index < size());
|
||||||
|
return m_children[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Node::string() const
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::string(NodeTypeStr[m_type])
|
||||||
|
.substr(std::string("NODE_").size());
|
||||||
|
|
||||||
|
if (m_repr.empty() == false)
|
||||||
|
{
|
||||||
|
ss << "[" << m_repr << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size() > 0)
|
||||||
|
{
|
||||||
|
ss << "(";
|
||||||
|
|
||||||
|
std::string sep;
|
||||||
|
|
||||||
|
for (auto child: m_children)
|
||||||
|
{
|
||||||
|
ss << sep << child->string();
|
||||||
|
sep = ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
ss << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef jk_NODE_HPP
|
||||||
|
#define jk_NODE_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "Loc.hpp"
|
||||||
|
|
||||||
|
#define NODE_TYPE(G) \
|
||||||
|
G(NODE_PROG), \
|
||||||
|
G(NODE_INT)
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
JK_ENUM(Node, NODE_TYPE);
|
||||||
|
|
||||||
|
class Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Node(NodeType type, std::string const& repr, Loc const& loc);
|
||||||
|
virtual ~Node();
|
||||||
|
|
||||||
|
NodeType type() const { return m_type; }
|
||||||
|
std::string repr() const { return m_repr; }
|
||||||
|
Loc const& loc() const { return m_loc; }
|
||||||
|
size_t size() const { return m_children.size(); }
|
||||||
|
|
||||||
|
void add_child(std::shared_ptr<Node> child);
|
||||||
|
std::weak_ptr<Node> child(size_t index) const;
|
||||||
|
|
||||||
|
std::string string() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NodeType m_type;
|
||||||
|
std::string m_repr;
|
||||||
|
Loc m_loc;
|
||||||
|
std::vector<std::shared_ptr<Node>> m_children;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,19 @@
|
||||||
|
#include "Parser.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*explicit*/ Parser::Parser(Logger& logger, std::shared_ptr<Lexer> lexer)
|
||||||
|
: m_logger { logger }
|
||||||
|
, m_lexer { lexer }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Parser::~Parser()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Node> Parser::parse(std::string const&)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef jk_PARSER_HPP
|
||||||
|
#define jk_PARSER_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
#include "Logger.hpp"
|
||||||
|
#include "Lexer.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
class Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Parser(Logger& logger, std::shared_ptr<Lexer> lexer);
|
||||||
|
virtual ~Parser();
|
||||||
|
|
||||||
|
std::shared_ptr<Node> parse(std::string const& source);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger& m_logger;
|
||||||
|
std::shared_ptr<Lexer> m_lexer;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include "Type.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*explicit*/ Type::Type(TypeType type)
|
||||||
|
: m_type { type }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ Type::~Type()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef jk_TYPE_HPP
|
||||||
|
#define jk_TYPE_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
#define TYPE_TYPE(G) \
|
||||||
|
G(TYPE_NIL), \
|
||||||
|
G(TYPE_INT)
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
JK_ENUM(Type, TYPE_TYPE);
|
||||||
|
|
||||||
|
class Type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Type(TypeType type);
|
||||||
|
virtual ~Type();
|
||||||
|
|
||||||
|
TypeType type() const { return m_type; }
|
||||||
|
private:
|
||||||
|
TypeType m_type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "Value.hpp"
|
||||||
|
#include "Type.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
/*static*/ std::shared_ptr<Value> Value::make_nil()
|
||||||
|
{
|
||||||
|
auto value = std::make_shared<Value>();
|
||||||
|
value->m_type = std::make_shared<Type>(TYPE_NIL);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static*/ std::shared_ptr<Value> Value::make_int(int val)
|
||||||
|
{
|
||||||
|
auto value = std::make_shared<Value>();
|
||||||
|
value->m_type = std::make_shared<Type>(TYPE_INT);
|
||||||
|
value->m_int_val = val;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Type> Value::type() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef jk_VALUE_HPP
|
||||||
|
#define jk_VALUE_HPP
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
namespace jk
|
||||||
|
{
|
||||||
|
class Type;
|
||||||
|
|
||||||
|
class Value
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<Value> make_nil();
|
||||||
|
static std::shared_ptr<Value> make_int(int val);
|
||||||
|
|
||||||
|
explicit Value() = default;
|
||||||
|
virtual ~Value() = default;
|
||||||
|
|
||||||
|
int as_int() const { return *m_int_val; }
|
||||||
|
|
||||||
|
std::weak_ptr<Type> type() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Type> m_type;
|
||||||
|
std::optional<int> m_int_val;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,6 +1,18 @@
|
||||||
#ifndef jk_COMMONS_HPP
|
#ifndef jk_COMMONS_HPP
|
||||||
#define jk_COMMONS_HPP
|
#define jk_COMMONS_HPP
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "mutils.hpp"
|
#include "mutils.hpp"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,18 @@
|
||||||
#ifndef jk_MUTILS_HPP
|
#ifndef jk_MUTILS_HPP
|
||||||
#define jk_MUTILS_HPP
|
#define jk_MUTILS_HPP
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#define ENUM_ENUM(X) X
|
||||||
|
#define ENUM_STRING(X) #X
|
||||||
|
|
||||||
|
#define JK_ENUM(PREFIX, DECL) \
|
||||||
|
enum PREFIX ## Type { DECL(ENUM_ENUM) }; \
|
||||||
|
constexpr char const* PREFIX ## TypeStr [] { DECL(ENUM_STRING) }
|
||||||
|
|
||||||
|
#define JK_ERROR(NAME) \
|
||||||
|
struct NAME : public std::runtime_error { \
|
||||||
|
NAME (std::string const& what): std::runtime_error {what} {} \
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
16
meson.build
16
meson.build
|
@ -21,6 +21,18 @@ configure_file(
|
||||||
joko_lib = static_library(
|
joko_lib = static_library(
|
||||||
'joko',
|
'joko',
|
||||||
sources: [
|
sources: [
|
||||||
|
'lib/Node.cpp',
|
||||||
|
'lib/Loc.cpp',
|
||||||
|
|
||||||
|
'lib/Factory.cpp',
|
||||||
|
|
||||||
|
'lib/Logger.cpp',
|
||||||
|
'lib/Lexer.cpp',
|
||||||
|
'lib/Parser.cpp',
|
||||||
|
|
||||||
|
'lib/Type.cpp',
|
||||||
|
'lib/Value.cpp',
|
||||||
|
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
])
|
])
|
||||||
|
@ -38,7 +50,9 @@ executable('joko',
|
||||||
|
|
||||||
executable('joko-tests',
|
executable('joko-tests',
|
||||||
sources: [
|
sources: [
|
||||||
'tests/main.cpp'
|
'tests/main.cpp',
|
||||||
|
'tests/Lexer.cpp',
|
||||||
|
'tests/Parser.cpp',
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
joko_dep,
|
joko_dep,
|
||||||
|
|
53
src/main.cpp
53
src/main.cpp
|
@ -1,21 +1,26 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
#include "../lib/Lexer.hpp"
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
bool debug_mode = false;
|
||||||
|
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
|
{"debug", no_argument, 0, 'd'},
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
int c = getopt_long(argc, argv, "hv", options, &index);
|
int c = getopt_long(argc, argv, "dhv", options, &index);
|
||||||
|
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
|
case 'd': debug_mode = true; break;
|
||||||
|
|
||||||
case 'h': {
|
case 'h': {
|
||||||
std::cout << "Usage: joko [OPTIONS] source_file" << std::endl;
|
std::cout << "Usage: joko [OPTIONS] source_file" << std::endl;
|
||||||
std::cout << "OPTIONS" << std::endl;
|
std::cout << "OPTIONS" << std::endl;
|
||||||
|
@ -37,5 +42,51 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
jk::Logger logger;
|
||||||
|
jk::Loc loc {argv[optind], 1, 1};
|
||||||
|
|
||||||
|
std::ifstream file { argv[optind] };
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "cannot find file '" << argv[optind] << "'";
|
||||||
|
logger.log<std::runtime_error>(jk::LOG_ERROR, loc, ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string source;
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (std::getline(file, line))
|
||||||
|
{
|
||||||
|
source += line + (file.eof() ? "" : "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
jk::Lexer lexer {logger, loc};
|
||||||
|
lexer.scan(source);
|
||||||
|
|
||||||
|
if (debug_mode)
|
||||||
|
{
|
||||||
|
std::cout << "--- tokens ---" << std::endl;
|
||||||
|
std::shared_ptr<jk::Node> tok;
|
||||||
|
|
||||||
|
std::string sep;
|
||||||
|
while ( (tok = lexer.next()) )
|
||||||
|
{
|
||||||
|
std::cout << sep << tok->string();
|
||||||
|
sep = " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include "../lib/Lexer.hpp"
|
||||||
|
#include "../lib/Factory.hpp"
|
||||||
|
|
||||||
|
class LexerTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit LexerTest() {}
|
||||||
|
virtual ~LexerTest() {}
|
||||||
|
|
||||||
|
void test_next(jk::Lexer& lexer, std::string const& oracle)
|
||||||
|
{
|
||||||
|
auto token = lexer.next();
|
||||||
|
REQUIRE(token);
|
||||||
|
REQUIRE(oracle == token->string());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_end(jk::Lexer& lexer)
|
||||||
|
{
|
||||||
|
auto token = lexer.next();
|
||||||
|
REQUIRE(!token);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
jk::Logger m_logger;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_int")
|
||||||
|
{
|
||||||
|
auto lexer = jk::Factory(m_logger, "tests/lexer").make_lexer();
|
||||||
|
lexer->scan("4 128 333");
|
||||||
|
test_next(*lexer, "INT[4]");
|
||||||
|
test_next(*lexer, "INT[128]");
|
||||||
|
test_next(*lexer, "INT[333]");
|
||||||
|
test_end(*lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_comments")
|
||||||
|
{
|
||||||
|
auto lexer = jk::Factory(m_logger, "tests/lexer").make_lexer();
|
||||||
|
lexer->scan("4 # 128 \n 333");
|
||||||
|
test_next(*lexer, "INT[4]");
|
||||||
|
test_next(*lexer, "INT[333]");
|
||||||
|
test_end(*lexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(LexerTest, "Lexer_error")
|
||||||
|
{
|
||||||
|
auto lexer = jk::Factory(m_logger, "tests/lexer").make_lexer();
|
||||||
|
lexer->scan(" § ");
|
||||||
|
REQUIRE_THROWS_AS(lexer->next(), jk::lexical_error);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include "../lib/Parser.hpp"
|
||||||
|
#include "../lib/Factory.hpp"
|
||||||
|
|
||||||
|
class ParserTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ParserTest() {}
|
||||||
|
virtual ~ParserTest() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
jk::Logger m_logger;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_")
|
||||||
|
{
|
||||||
|
}
|
Reference in New Issue