366 lines
15 KiB
C++
366 lines
15 KiB
C++
#include "types.h"
|
|
#include "parsing.h"
|
|
#include "tokens.h"
|
|
|
|
|
|
namespace parsing {
|
|
namespace {
|
|
Result<std::unique_ptr<AST::Expression>, std::string> parse_expression(token::TokenStream& stream);
|
|
|
|
Result<std::shared_ptr<types::Type>, std::string> parse_type(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
try {
|
|
auto token = inner.expect(token::Type::Ident);
|
|
|
|
// TODO eventually make this be potentially more than one word
|
|
std::string type_name = token.content;
|
|
|
|
std::shared_ptr<types::Type> returned{};
|
|
|
|
if (type_name == "int") {
|
|
auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Int };
|
|
returned = std::shared_ptr<types::Type>{ ty };
|
|
}
|
|
else if (type_name == "char") {
|
|
auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Char };
|
|
returned = std::shared_ptr<types::Type>{ ty };
|
|
}
|
|
else if (type_name == "void") {
|
|
auto ty = new types::FundamentalType{ types::FundamentalTypeKind::Void };
|
|
returned = std::shared_ptr<types::Type>{ ty };
|
|
}
|
|
else {
|
|
throw std::runtime_error("Expected type name, got " + type_name);
|
|
}
|
|
|
|
while (inner.peek().type == token::Type::Symbol && inner.peek().content == "*") {
|
|
inner.next();
|
|
auto ty = new types::PointerType{ std::move(returned) };
|
|
returned = std::shared_ptr<types::Type>{ ty };
|
|
}
|
|
|
|
|
|
stream.m_position = inner.m_position;
|
|
|
|
return returned;
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
|
|
Result<std::unique_ptr<AST::Expression>, std::string> parse_plain_expression(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
try {
|
|
auto token = inner.next();
|
|
if (token.type == token::Type::LiteralInt) {
|
|
stream.m_position = inner.m_position;
|
|
|
|
auto expr = new AST::IntLiteralExpression{ token.metadata, std::stoi(token.content) };
|
|
return std::unique_ptr<AST::Expression>{ expr };
|
|
}
|
|
else if (token.type == token::Type::LiteralStr) {
|
|
stream.m_position = inner.m_position;
|
|
|
|
auto expr = new AST::StringLiteralExpression{ token.metadata, token.content };
|
|
return std::unique_ptr<AST::Expression>{ expr };
|
|
}
|
|
else if (token.type == token::Type::Ident) {
|
|
stream.m_position = inner.m_position;
|
|
|
|
auto expr = new AST::ValueReferenceExpression{ token.metadata, token.content };
|
|
return std::unique_ptr<AST::Expression>{ expr };
|
|
}
|
|
else {
|
|
throw std::runtime_error("Expected expression");
|
|
}
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
|
|
Result<std::shared_ptr<types::Type>, std::string> parse_cast(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
try {
|
|
inner.expect(token::Type::Symbol, "(");
|
|
auto ty = parse_type(inner).unwrap();
|
|
inner.expect(token::Type::Symbol, ")");
|
|
|
|
stream.m_position = inner.m_position;
|
|
|
|
return ty;
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
|
|
Result<std::unique_ptr<AST::Expression>, std::string> parse_primary_expression(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
try {
|
|
auto before_meta = inner.metadata();
|
|
|
|
if (auto cast = parse_cast(inner); cast.ok()) {
|
|
auto expr = parse_expression(inner).unwrap();
|
|
stream.m_position = inner.m_position;
|
|
return std::unique_ptr<AST::Expression>{
|
|
new AST::CastExpression{
|
|
before_meta + inner.metadata(),
|
|
cast.unwrap(),
|
|
std::move(expr)
|
|
}
|
|
};
|
|
}
|
|
|
|
auto plain_expr = parse_plain_expression(inner);
|
|
while (inner.peek().content == "(") {
|
|
inner.next();
|
|
|
|
std::vector<std::unique_ptr<AST::Expression>> args{};
|
|
|
|
int counter = 0;
|
|
while (inner.peek().content != ")") {
|
|
if (counter++ > 0)
|
|
inner.expect(token::Type::Symbol, ",");
|
|
args.push_back(parse_expression(inner).unwrap());
|
|
}
|
|
|
|
inner.expect(token::Type::Symbol, ")");
|
|
|
|
auto fn_call = new AST::FunctionCallExpression{ before_meta + inner.metadata(), plain_expr.unwrap(), std::move(args) };
|
|
plain_expr = std::unique_ptr<AST::Expression>{ fn_call };
|
|
}
|
|
|
|
|
|
stream.m_position = inner.m_position;
|
|
return plain_expr;
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
|
|
Result<types::BinOp, std::string> parse_binop(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
try {
|
|
auto token = inner.next();
|
|
if (token.type != token::Type::Symbol) {
|
|
throw std::runtime_error("Expected binop");
|
|
}
|
|
else if (token.content == "=") {
|
|
stream.m_position = inner.m_position;
|
|
return types::BinOp{ types::BinOp::Assignment };
|
|
}
|
|
else if (token.content == "+") {
|
|
stream.m_position = inner.m_position;
|
|
return types::BinOp{ types::BinOp::Add };
|
|
}
|
|
else if (token.content == "-") {
|
|
stream.m_position = inner.m_position;
|
|
return types::BinOp{ types::BinOp::Sub };
|
|
}
|
|
else if (token.content == "<") {
|
|
stream.m_position = inner.m_position;
|
|
return types::BinOp{ types::BinOp::LessThan };
|
|
}
|
|
else if (token.content == ">") {
|
|
stream.m_position = inner.m_position;
|
|
return types::BinOp{ types::BinOp::GreaterThan };
|
|
}
|
|
|
|
throw std::runtime_error("Expected binop");
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<AST::Expression> parse_rhs(
|
|
token::TokenStream& stream, std::unique_ptr<AST::Expression> lhs, int prev_precedence) {
|
|
|
|
auto before = stream.metadata();
|
|
|
|
auto binop_res = parse_binop(stream);
|
|
while (binop_res.ok()) {
|
|
auto binop = binop_res.unwrap();
|
|
auto rhs = parse_primary_expression(stream).unwrap();
|
|
|
|
if (types::operator_precedence(binop) > prev_precedence) {
|
|
rhs = parse_rhs(stream, std::move(rhs), types::operator_precedence(binop));
|
|
}
|
|
|
|
auto binop_expr = new AST::BinaryOperationExpression{ before + stream.metadata(), std::move(lhs), binop, std::move(rhs) };
|
|
lhs = std::unique_ptr<AST::Expression>{ binop_expr };
|
|
|
|
binop_res = parse_binop(stream);
|
|
}
|
|
|
|
return lhs;
|
|
}
|
|
|
|
Result<std::unique_ptr<AST::Expression>, std::string> parse_expression(token::TokenStream& stream) {
|
|
try {
|
|
auto lhs = parse_primary_expression(stream).unwrap();
|
|
return std::unique_ptr{ parse_rhs(stream, std::move(lhs), 0) };
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Result<std::unique_ptr<AST::InitializationStatement>, std::string> parse_init_statement(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
|
|
auto before_meta = inner.metadata();
|
|
|
|
try {
|
|
auto ty = parse_type(inner).unwrap();
|
|
auto name = inner.expect(token::Type::Ident);
|
|
|
|
std::optional<std::unique_ptr<AST::Expression>> expr = {};
|
|
if (inner.peek().type == token::Type::Symbol && inner.peek().content == "=") {
|
|
inner.expect(token::Type::Symbol, "=");
|
|
expr = parse_expression(inner).unwrap();
|
|
}
|
|
|
|
inner.expect(token::Type::Symbol, ";");
|
|
|
|
stream.m_position = inner.m_position;
|
|
auto init = new AST::InitializationStatement{ before_meta + inner.metadata(), std::move(ty), name.content, std::move(expr) };
|
|
return std::unique_ptr<AST::InitializationStatement>{ init };
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
|
|
Result<std::unique_ptr<AST::Statement>, std::string> parse_statement(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
auto before_meta = inner.metadata();
|
|
try {
|
|
if (inner.peek().type == token::Type::ReturnKeyword) {
|
|
inner.next();
|
|
auto expression = parse_expression(inner).unwrap();
|
|
inner.expect(token::Type::Symbol, ";");
|
|
|
|
stream.m_position = inner.m_position;
|
|
|
|
auto ret = new AST::ReturnStatement{ before_meta + stream.metadata(),std::move(expression) };
|
|
return std::unique_ptr<AST::Statement>{ ret };
|
|
}
|
|
else if (inner.peek().type == token::Type::IfKeyword) {
|
|
inner.next();
|
|
inner.expect(token::Type::Symbol, "(");
|
|
auto expression = parse_expression(inner).unwrap();
|
|
inner.expect(token::Type::Symbol, ")");
|
|
|
|
auto then_statement = parse_statement(inner).unwrap();
|
|
std::optional<std::unique_ptr<AST::Statement>> else_statement{};
|
|
if (inner.peek().type == token::Type::ElseKeyword) {
|
|
inner.next();
|
|
else_statement = parse_statement(inner).unwrap();
|
|
}
|
|
|
|
stream.m_position = inner.m_position;
|
|
|
|
auto statement = new AST::IfStatement{
|
|
before_meta + stream.metadata(),
|
|
std::move(expression),
|
|
std::move(then_statement),
|
|
std::move(else_statement)
|
|
};
|
|
return std::unique_ptr<AST::Statement>{ statement };
|
|
}
|
|
else if (auto init = parse_init_statement(inner); init.ok()) {
|
|
stream.m_position = inner.m_position;
|
|
return std::unique_ptr<AST::Statement>{ init.unwrap() };
|
|
}
|
|
else if (auto expr = parse_expression(inner); expr.ok()) {
|
|
stream.m_position = inner.m_position;
|
|
stream.expect(token::Type::Symbol, ";");
|
|
auto expr_statement = new AST::ExpressionStatement{ before_meta + stream.metadata(), expr.unwrap() };
|
|
return std::unique_ptr<AST::Statement>{ expr_statement };
|
|
}
|
|
else {
|
|
throw std::runtime_error("Expected return-keyword");
|
|
}
|
|
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string{ error.what() };
|
|
}
|
|
}
|
|
}
|
|
|
|
Result<std::unique_ptr<AST::TopLevelStatement>, std::string> parse_top_level_statement(token::TokenStream& stream) {
|
|
token::TokenStream inner{ stream };
|
|
auto before_meta = inner.metadata();
|
|
try {
|
|
auto type = parse_type(inner).unwrap();
|
|
auto name_token = inner.expect(token::Type::Ident);
|
|
inner.expect(token::Type::Symbol, "(");
|
|
|
|
std::vector<std::pair<std::optional<std::string>, std::shared_ptr<types::Type>>> params;
|
|
bool is_vararg = false;
|
|
while (inner.peek().content != ")") {
|
|
if (params.size() > 0) {
|
|
inner.expect(token::Type::Symbol, ",");
|
|
}
|
|
|
|
if (inner.peek().content == ".") {
|
|
inner.next();
|
|
inner.expect(token::Type::Symbol, ".");
|
|
inner.expect(token::Type::Symbol, ".");
|
|
is_vararg = true;
|
|
break;
|
|
}
|
|
|
|
auto param_ty = parse_type(inner).unwrap();
|
|
std::optional<std::string> param_name{};
|
|
if (inner.peek().type == token::Type::Ident) {
|
|
param_name = inner.expect(token::Type::Ident).content;
|
|
}
|
|
params.push_back(std::pair(param_name, std::move(param_ty)));
|
|
}
|
|
|
|
inner.expect(token::Type::Symbol, ")");
|
|
|
|
std::optional<std::vector<std::unique_ptr<AST::Statement>>> statements{};
|
|
if (inner.peek().content == "{") {
|
|
inner.expect(token::Type::Symbol, "{");
|
|
|
|
std::vector<std::unique_ptr<AST::Statement>> statement_list{};
|
|
|
|
auto statement = parse_statement(inner);
|
|
while (statement.ok()) {
|
|
statement_list.push_back(statement.unwrap());
|
|
statement = parse_statement(inner);
|
|
}
|
|
|
|
statements = std::optional{ std::move(statement_list) };
|
|
inner.expect(token::Type::Symbol, "}");
|
|
}
|
|
else {
|
|
inner.expect(token::Type::Symbol, ";");
|
|
}
|
|
|
|
stream.m_position = inner.m_position;
|
|
|
|
auto fun = new AST::Function{
|
|
before_meta + stream.metadata(),
|
|
std::move(type),
|
|
std::move(params),
|
|
is_vararg,
|
|
name_token.content,
|
|
std::move(statements)
|
|
};
|
|
return std::unique_ptr<AST::TopLevelStatement>{ fun };
|
|
}
|
|
catch (std::runtime_error& error) {
|
|
return std::string(error.what());
|
|
}
|
|
}
|
|
} |