initial commit
This commit is contained in:
11
meson.build
Normal file
11
meson.build
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
project('solstice', 'cpp', version : '0.1.2')
|
||||||
|
|
||||||
|
sources = files(
|
||||||
|
'src/main.cpp',
|
||||||
|
'src/lexer/lexer.cpp',
|
||||||
|
'src/parser/parser.cpp',
|
||||||
|
'src/ir/ir.cpp',
|
||||||
|
'src/compiler/compiler.cpp'
|
||||||
|
)
|
||||||
|
|
||||||
|
executable('solsc', sources)
|
||||||
0
src/compiler/compiler.cpp
Normal file
0
src/compiler/compiler.cpp
Normal file
0
src/compiler/compiler.hpp
Normal file
0
src/compiler/compiler.hpp
Normal file
0
src/ir/ir.cpp
Normal file
0
src/ir/ir.cpp
Normal file
0
src/ir/ir.hpp
Normal file
0
src/ir/ir.hpp
Normal file
258
src/lexer/lexer.cpp
Normal file
258
src/lexer/lexer.cpp
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
#include "lexer.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using TT = Solstice::TokenType;
|
||||||
|
|
||||||
|
namespace Solstice {
|
||||||
|
std::unordered_map<std::string, TT> stringToTokenType = {
|
||||||
|
{"type", TT::Kw_Type},
|
||||||
|
|
||||||
|
{"#cimport", TT::Hash_CImport},
|
||||||
|
{"#effect", TT::Hash_Effect},
|
||||||
|
|
||||||
|
{"::", TT::Assign_Bind},
|
||||||
|
{"=", TT::Assign_Set},
|
||||||
|
{":", TT::Assign_Type},
|
||||||
|
|
||||||
|
{"->", TT::Action_Function},
|
||||||
|
|
||||||
|
{"{", TT::OpenCurly},
|
||||||
|
{"}", TT::CloseCurly},
|
||||||
|
{"(", TT::OpenParen},
|
||||||
|
{")", TT::CloseParen},
|
||||||
|
{"<", TT::OpenSpiky},
|
||||||
|
{">", TT::CloseSpiky},
|
||||||
|
|
||||||
|
{"+", TT::Math_Add},
|
||||||
|
{"-", TT::Math_Subtract},
|
||||||
|
{"*", TT::Math_Multiply},
|
||||||
|
{"/", TT::Math_Divide}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<std::string> Literal::getString() {
|
||||||
|
if (std::holds_alternative<std::string>(data)) {
|
||||||
|
return std::get<std::string>(data);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int64_t> Literal::getInt() {
|
||||||
|
if (std::holds_alternative<int64_t>(data)) {
|
||||||
|
return std::get<int64_t>(data);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<double> Literal::getDouble() {
|
||||||
|
if (std::holds_alternative<double>(data)) {
|
||||||
|
return std::get<double>(data);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<char> Literal::getChar() {
|
||||||
|
if (std::holds_alternative<char>(data)) {
|
||||||
|
return std::get<char>(data);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> Literal::getBool() {
|
||||||
|
if (std::holds_alternative<bool>(data)) {
|
||||||
|
return std::get<bool>(data);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<Literal> Token::getLiteral() {
|
||||||
|
if (std::holds_alternative<Literal>(data)) {
|
||||||
|
return std::get<Literal>(data);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> Token::getIdentifier() {
|
||||||
|
if (std::holds_alternative<std::string>(data)) {
|
||||||
|
return std::get<std::string>(data);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<char> Lexer::peek(std::size_t ahead) {
|
||||||
|
if (current + ahead >= input.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return input[current + ahead];
|
||||||
|
}
|
||||||
|
std::optional<char> Lexer::consume() {
|
||||||
|
if (current + 1 >= input.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return input[current++];
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Lexer::processToken(const std::string& buf) {
|
||||||
|
if (stringToTokenType.find(buf) != stringToTokenType.end()) {
|
||||||
|
return stringToTokenType[buf];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int64_t num = std::stoll(buf);
|
||||||
|
return Token(num);
|
||||||
|
} catch (const std::out_of_range& e) {
|
||||||
|
throw std::runtime_error("Integer is out of range");
|
||||||
|
} catch (const std::invalid_argument& e) {
|
||||||
|
// keep going
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
double num = std::stod(buf);
|
||||||
|
return Token(num);
|
||||||
|
} catch (const std::out_of_range& e) {
|
||||||
|
throw std::runtime_error("Integer is out of range");
|
||||||
|
} catch (const std::invalid_argument& e) {
|
||||||
|
// keep going
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf == "true") {
|
||||||
|
return Token(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf == "false") {
|
||||||
|
return Token(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assume identifier
|
||||||
|
return Token(buf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<Token>& Lexer::lex() {
|
||||||
|
|
||||||
|
std::string buf = "";
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
auto next = consume();
|
||||||
|
if (!next.has_value()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*next) {
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case ' ': {
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '\n': {
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_back(TT::NewLine);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strings
|
||||||
|
case '"': {
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
next = consume();
|
||||||
|
if (!next.has_value()) {
|
||||||
|
throw std::runtime_error("unterminated string");
|
||||||
|
}
|
||||||
|
if (*next == '"') {
|
||||||
|
output.push_back(Literal(buf));
|
||||||
|
buf.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf += *next;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ':': {
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() && *peek() == ':') {
|
||||||
|
output.push_back(TT::Assign_Bind);
|
||||||
|
consume();
|
||||||
|
} else {
|
||||||
|
output.push_back(TT::Assign_Type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case '-': {
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peek() && *peek() == '>') {
|
||||||
|
output.push_back(TT::Action_Function);
|
||||||
|
consume();
|
||||||
|
} else {
|
||||||
|
output.push_back(TT::Math_Subtract);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all the delimiters
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '+':
|
||||||
|
case '*':
|
||||||
|
case '/':
|
||||||
|
{
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
output.push_back(processToken(std::string(1, *next)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
buf.push_back(*next);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the last thingy in the buffer
|
||||||
|
if (!buf.empty()) {
|
||||||
|
output.push_back(processToken(buf));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
125
src/lexer/lexer.hpp
Normal file
125
src/lexer/lexer.hpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Solstice {
|
||||||
|
|
||||||
|
enum class TokenType {
|
||||||
|
None,
|
||||||
|
|
||||||
|
// keywords
|
||||||
|
Kw_Type,
|
||||||
|
|
||||||
|
// hashops
|
||||||
|
Hash_CImport,
|
||||||
|
Hash_Effect,
|
||||||
|
|
||||||
|
// assignment
|
||||||
|
Assign_Bind, // ::
|
||||||
|
Assign_Set, // =
|
||||||
|
Assign_Type, // :
|
||||||
|
|
||||||
|
// actions
|
||||||
|
Action_Function, // ->
|
||||||
|
|
||||||
|
// math
|
||||||
|
Math_Add,
|
||||||
|
Math_Subtract,
|
||||||
|
Math_Multiply,
|
||||||
|
Math_Divide,
|
||||||
|
|
||||||
|
// comparison
|
||||||
|
Comparison_Equal,
|
||||||
|
Comparison_NotEqual,
|
||||||
|
Comparison_GreaterThan,
|
||||||
|
Comparison_LesserThan,
|
||||||
|
|
||||||
|
// structural characters
|
||||||
|
OpenCurly,
|
||||||
|
CloseCurly,
|
||||||
|
OpenParen,
|
||||||
|
CloseParen,
|
||||||
|
OpenSpiky,
|
||||||
|
CloseSpiky,
|
||||||
|
NewLine,
|
||||||
|
|
||||||
|
// other
|
||||||
|
Literal,
|
||||||
|
Identifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class LiteralType {
|
||||||
|
None, String, Int, Double, Char, Bool
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::unordered_map<std::string, TokenType> stringToTokenType;
|
||||||
|
|
||||||
|
class Literal {
|
||||||
|
std::variant<std::string, int64_t, double, char, bool> data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
LiteralType type = LiteralType::None;
|
||||||
|
|
||||||
|
std::optional<std::string> getString();
|
||||||
|
std::optional<int64_t> getInt();
|
||||||
|
std::optional<double> getDouble();
|
||||||
|
std::optional<char> getChar();
|
||||||
|
std::optional<bool> getBool();
|
||||||
|
|
||||||
|
Literal(const std::string& in) : type(LiteralType::String), data(in) {}
|
||||||
|
Literal(int64_t in) : type(LiteralType::Int), data(in) {}
|
||||||
|
Literal(double in) : type(LiteralType::Double), data(in) {}
|
||||||
|
Literal(char in) : type(LiteralType::Char), data(in) {}
|
||||||
|
Literal(bool in) : type(LiteralType::Bool), data(in) {}
|
||||||
|
|
||||||
|
Literal() : type(LiteralType::None) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Token {
|
||||||
|
|
||||||
|
std::variant<Literal, std::string> data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
std::optional<Literal> getLiteral();
|
||||||
|
std::optional<std::string> getIdentifier();
|
||||||
|
|
||||||
|
TokenType type = TokenType::None;
|
||||||
|
|
||||||
|
Token() = delete;
|
||||||
|
Token(TokenType type) : type(type) {}
|
||||||
|
|
||||||
|
Token(const Literal& literal) : type(TokenType::Literal), data(literal) {}
|
||||||
|
Token(const std::string& identifier) : type(TokenType::Identifier), data(identifier) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class Lexer {
|
||||||
|
|
||||||
|
std::string input;
|
||||||
|
std::vector<Token> output;
|
||||||
|
|
||||||
|
std::size_t current = 0;
|
||||||
|
|
||||||
|
std::optional<char> peek(std::size_t ahead = 0);
|
||||||
|
std::optional<char> consume();
|
||||||
|
|
||||||
|
static Token processToken(const std::string& buf);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Lexer() = delete;
|
||||||
|
Lexer(const std::string& input) : input(input) {}
|
||||||
|
|
||||||
|
const std::vector<Token>& lex();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
10
src/main.cpp
Normal file
10
src/main.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include "lexer/lexer.hpp"
|
||||||
|
#include "parser/parser.hpp"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Solstice::Lexer lexer{"2 + 2"};
|
||||||
|
auto lexed = lexer.lex();
|
||||||
|
|
||||||
|
Solstice::Parser parser{lexed};
|
||||||
|
auto parsed = parser.parse();
|
||||||
|
}
|
||||||
190
src/parser/parser.cpp
Normal file
190
src/parser/parser.cpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
#include "parser.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
using TT = Solstice::TokenType;
|
||||||
|
|
||||||
|
namespace Solstice {
|
||||||
|
|
||||||
|
std::unordered_map<TokenType, NodeType> tokToNodeType = {
|
||||||
|
{TT::Math_Add, NodeType::Add},
|
||||||
|
{TT::Math_Subtract, NodeType::Subtract},
|
||||||
|
{TT::Math_Multiply, NodeType::Multiply},
|
||||||
|
{TT::Math_Divide, NodeType::Divide},
|
||||||
|
{TT::Comparison_Equal, NodeType::Equal},
|
||||||
|
{TT::Comparison_NotEqual, NodeType::NotEqual},
|
||||||
|
{TT::Comparison_GreaterThan, NodeType::GreaterThan},
|
||||||
|
{TT::Comparison_LesserThan, NodeType::LesserThan},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<Token> Parser::peek(int64_t ahead) {
|
||||||
|
if (current + ahead >= input.size() || current + ahead < 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return input[current + ahead];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Token> Parser::consume() {
|
||||||
|
if (current >= input.size()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return input[current++];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Node> Parser::getPreviousNode(Node& parent) {
|
||||||
|
if (parent.children.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
Node node = parent.children[parent.children.size() - 1];
|
||||||
|
parent.children.pop_back();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Parser::parseExpr(TT type) {
|
||||||
|
auto left = getPreviousNode(output);
|
||||||
|
if (!left.has_value()) {
|
||||||
|
throw std::runtime_error("Expecting expression on left of '+'");
|
||||||
|
}
|
||||||
|
consume(); // be rid of the +
|
||||||
|
Precedence precedence = getTokenPrecedence(Token(type));
|
||||||
|
auto right = parseOneNode(precedence);
|
||||||
|
if (!right.has_value()) {
|
||||||
|
throw std::runtime_error("Expecting expression on right of '+'");
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeType nodeType;
|
||||||
|
if (tokToNodeType.find(type) == tokToNodeType.end()) {
|
||||||
|
throw std::runtime_error("FIXME couldn't map token type to node type");
|
||||||
|
} else {
|
||||||
|
nodeType = tokToNodeType[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(nodeType, {*left, *right});
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Parser::parseLiteral() {
|
||||||
|
auto current = peek(-1);
|
||||||
|
if (!current.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME couldn't get current token");
|
||||||
|
}
|
||||||
|
auto literal = current->getLiteral();
|
||||||
|
if (!literal.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME token with type literal does not hold a literal");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(*literal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node Parser::parseIdentifier() {
|
||||||
|
auto current = peek(-1);
|
||||||
|
if (!current.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME couldn't get current token");
|
||||||
|
}
|
||||||
|
auto id = current->getIdentifier();
|
||||||
|
if (!id.has_value()) {
|
||||||
|
throw std::runtime_error("FIXME token with type identifier does not hold an identifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Node(*id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Precedence Parser::getTokenPrecedence(const Token& token) {
|
||||||
|
static size_t braceCount = 0;
|
||||||
|
static size_t bracketCount = 0;
|
||||||
|
static size_t spikyBracketCount = 0;
|
||||||
|
switch (token.type) {
|
||||||
|
case TT::OpenCurly: {
|
||||||
|
braceCount++;
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
case TT::CloseCurly: {
|
||||||
|
braceCount--;
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
case TT::OpenSpiky: {
|
||||||
|
spikyBracketCount++;
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
case TT::CloseSpiky: {
|
||||||
|
spikyBracketCount--;
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
case TT::OpenParen: {
|
||||||
|
bracketCount++;
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
case TT::CloseParen: {
|
||||||
|
bracketCount--;
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if (braceCount > 0) {
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
if (bracketCount > 0) {
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
if (spikyBracketCount > 0) {
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
switch (token.type) {
|
||||||
|
case TT::None:
|
||||||
|
case TT::Kw_Type:
|
||||||
|
case TT::Hash_CImport:
|
||||||
|
case TT::Hash_Effect:
|
||||||
|
case TT::Action_Function:
|
||||||
|
return Precedence::Other;
|
||||||
|
case TT::Math_Add:
|
||||||
|
case TT::Math_Subtract:
|
||||||
|
return Precedence::Add;
|
||||||
|
case TT::Math_Multiply:
|
||||||
|
case TT::Math_Divide:
|
||||||
|
return Precedence::Multiply;
|
||||||
|
case TT::Assign_Bind:
|
||||||
|
case TT::Assign_Set:
|
||||||
|
case TT::Assign_Type:
|
||||||
|
return Precedence::Set;
|
||||||
|
case TT::NewLine:
|
||||||
|
return Precedence::NewLine;
|
||||||
|
case TT::Identifier:
|
||||||
|
return Precedence::Identifier;
|
||||||
|
case TT::Literal:
|
||||||
|
return Precedence::Identifier;
|
||||||
|
default:
|
||||||
|
return Precedence::Other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Node> Parser::parseOneNode(Precedence precedence) {
|
||||||
|
auto next = peek();
|
||||||
|
if (!next.has_value()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (getTokenPrecedence(*next) >= precedence) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
consume();
|
||||||
|
switch (next->type) {
|
||||||
|
case TT::None: break;
|
||||||
|
case TT::Identifier:
|
||||||
|
return parseIdentifier();
|
||||||
|
case TT::Literal:
|
||||||
|
return parseLiteral();
|
||||||
|
case TT::Math_Add:
|
||||||
|
case TT::Math_Subtract:
|
||||||
|
case TT::Math_Multiply:
|
||||||
|
case TT::Math_Divide:
|
||||||
|
return parseExpr(next->type);
|
||||||
|
}
|
||||||
|
throw std::runtime_error("FIXME: unimplemented parsing case");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node& Parser::parse() {
|
||||||
|
while (auto node = parseOneNode(Precedence::Root)) {
|
||||||
|
output.children.push_back(*node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/parser/parser.hpp
Normal file
95
src/parser/parser.hpp
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "../lexer/lexer.hpp"
|
||||||
|
|
||||||
|
namespace Solstice {
|
||||||
|
|
||||||
|
enum class NodeType {
|
||||||
|
Root, Literal, Identifier,
|
||||||
|
FunctionBind, Bind, Set,
|
||||||
|
Lambda, FunctionCall,
|
||||||
|
Add, Subtract, Multiply, Divide,
|
||||||
|
Equal, NotEqual, GreaterThan, LesserThan
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Precedence {
|
||||||
|
NewLine,
|
||||||
|
Identifier,
|
||||||
|
If,
|
||||||
|
While,
|
||||||
|
Compare,
|
||||||
|
Set,
|
||||||
|
FunctionCall,
|
||||||
|
Add,
|
||||||
|
Multiply,
|
||||||
|
Other,
|
||||||
|
Root
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::unordered_map<TokenType, NodeType> tokToNodeType;
|
||||||
|
|
||||||
|
class Node {
|
||||||
|
public:
|
||||||
|
NodeType type = NodeType::Root;
|
||||||
|
std::vector<Node> children;
|
||||||
|
std::variant<Literal, std::string> data;
|
||||||
|
|
||||||
|
Node() = delete;
|
||||||
|
Node(NodeType type) : type(type) {}
|
||||||
|
Node(NodeType type, const std::vector<Node>& children) : type(type), children(children) {}
|
||||||
|
Node(const Literal& literal) : type(NodeType::Literal), data(literal) {}
|
||||||
|
Node(const std::string& id) : type(NodeType::Identifier), data(id) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Parser {
|
||||||
|
|
||||||
|
std::vector<Token> input;
|
||||||
|
Node output{NodeType::Root};
|
||||||
|
|
||||||
|
size_t current = 0;
|
||||||
|
|
||||||
|
std::optional<Token> peek(int64_t ahead = 0);
|
||||||
|
std::optional<Token> consume();
|
||||||
|
|
||||||
|
std::optional<Node> getPreviousNode(Node& parent);
|
||||||
|
|
||||||
|
Node parseKwType();
|
||||||
|
|
||||||
|
Node parseHashCimport();
|
||||||
|
Node parseHashEffect();
|
||||||
|
|
||||||
|
Node parseAssignBind();
|
||||||
|
Node parseAssignSet();
|
||||||
|
Node parseAssignType();
|
||||||
|
|
||||||
|
Node parseActionFunction();
|
||||||
|
|
||||||
|
Node parseExpr(TokenType type);
|
||||||
|
|
||||||
|
Node parseOpenCurly();
|
||||||
|
Node parseOpenParen();
|
||||||
|
Node parseOpenSpiky();
|
||||||
|
Node parseCloseCurly();
|
||||||
|
Node parseCloseParen();
|
||||||
|
Node parseCloseSpiky();
|
||||||
|
Node parseNewLine();
|
||||||
|
|
||||||
|
Node parseLiteral();
|
||||||
|
Node parseIdentifier();
|
||||||
|
|
||||||
|
static Precedence getTokenPrecedence(const Token& token);
|
||||||
|
|
||||||
|
// Returns false when finished
|
||||||
|
std::optional<Node> parseOneNode(Precedence precedence = Precedence::Other);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Parser() = delete;
|
||||||
|
Parser(const std::vector<Token>& input) : input(input) {}
|
||||||
|
|
||||||
|
const Node& parse();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user