Files
BlitzLLVM/code_compiler/source/ast/ast.cpp
T
2025-01-25 19:26:49 +01:00

223 lines
6.4 KiB
C++

// AUTOGENERATED COPYRIGHT HEADER START
// Copyright (C) 2017-2025 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
// AUTOGENERATED COPYRIGHT HEADER END
#include "ast.hpp"
#include <algorithm>
#include <cctype>
#include <cstdlib>
blitz::ast::variable::~variable()
{
/* Variable Parsing
*
* Declaration:
* - 8bit Signed Integer Variable
* Variable:Byte
* Variable:Int8
* - 8bit Unsigned Integer Variable
* Variable:UByte
* Variable:UInt8
* - 16bit Signed Integer Variable
* Variable:Short
* Variable:Int16
* - 16bit Unsigned Integer Variable
* Variable:UShort
* Variable:UInt16
* - 32bit Signed Integer Variable
* Variable
* Variable%
* Variable:Int
* Variable:Int32
* - 32bit Unsigned Integer Variable
* Variable:UInt
* Variable:UInt32
* - 64bit Signed Integer Variable
* Variable%%
* Variable:Long
* Variable:Int64
* - 64bit Unsigned Integer Variable
* Variable:ULong
* Variable:UInt64
* - 32bit Real Variable
* Variable#
* Variable:Float
* Variable:Float32
* Variable:Real
* Variable:Real32
* - 64bit Real Variable
* Variable##
* Variable:Double
* Variable:Float64
* Variable:Real64
* - UTF-8 String Variable
* Variable$
* Variable:String
* - Struct Variable
* Variable.StructName
* Variable:StructName
*
* Access:
* - Struct Access:
* Variable\Key
* - Array Access:
* Variable[IntegerIndex]
* - Dynamic Array Access:
* Variable(IntegerIndex)
* - Direct Access:
* Variable
*/
}
bool blitz::ast::variable::can_parse(std::shared_ptr<blitz::lexer> lexer)
{
return lexer->current().type == blitz::token::variant::TEXT;
}
std::shared_ptr<blitz::ast::node> blitz::ast::variable::try_parse(std::shared_ptr<blitz::lexer> lexer)
{
auto file = lexer->file();
auto name_tk = lexer->current();
if (name_tk.type != blitz::token::variant::TEXT) {
throw blitz::error(file, name_tk.location, name_tk.location, blitz::format("Unexpected %s, expected text.", name_tk.to_string().c_str()));
}
auto node = std::make_shared<blitz::ast::variable>();
node->tokens.push_back(name_tk);
node->type = blitz::types::type::UNKNOWN;
node->name = name_tk.text;
// Check if this has a type definition
auto symbol_tk = lexer->peek();
if (symbol_tk.type != blitz::token::variant::SYMBOL) {
return node;
}
if (symbol_tk.text == ":") {
// :Type
node->tokens.push_back(lexer->next()); // Advance to next token.
auto type_tk = lexer->next();
if (type_tk != blitz::token::variant::TEXT) {
throw blitz::error(file, name_tk.location, type_tk.location, blitz::format("Unexpected %s, expected text.", type_tk.to_string().c_str()));
}
auto type = blitz::types::from_string(type_tk.text);
if (type == blitz::types::type::UNKNOWN) {
throw blitz::error(file, name_tk.location, type_tk.location, blitz::format("Unexpected %s, expected built-in type name.", type_tk.text.c_str()));
}
node->tokens.push_back(type_tk);
node->type = type;
} else if (symbol_tk.text == ".") {
// .Struct
node->tokens.push_back(lexer->next()); // Advance to next token.
auto type_tk = lexer->next();
if (type_tk != blitz::token::variant::TEXT) {
throw blitz::error(file, name_tk.location, type_tk.location, blitz::format("Unexpected %s, expected text.", type_tk.to_string().c_str()));
}
node->tokens.push_back(type_tk);
node->type = blitz::types::type::STRUCT;
node->struct_name = type_tk.text;
} else if (symbol_tk.text == "%") {
// Int32
node->tokens.push_back(lexer->next()); // Advance to next token.
node->type = blitz::types::type::INT32;
} else if (symbol_tk.text == "#") {
// Float
node->tokens.push_back(lexer->next()); // Advance to next token.
node->type = blitz::types::type::FLOAT32;
} else if (symbol_tk.text == "$") {
// String
node->tokens.push_back(lexer->next()); // Advance to next token.
node->type = blitz::types::type::STRING;
}
return node;
}
blitz::ast::value::~value() {}
bool blitz::ast::value::can_parse(std::shared_ptr<blitz::lexer> lexer)
{
auto tk = lexer->current();
switch (tk.type) {
case blitz::token::variant::STRING:
case blitz::token::variant::REAL:
case blitz::token::variant::INTEGER:
return true;
case blitz::token::variant::STRING: {
// We can only parse True, False, Null
std::string text = tk.text;
std::transform(text.cbegin(), text.cend(), text.begin(), [](char from) {
if (from & 0b10000000) { // Exclude Unicode
return from;
}
return (char)std::tolower(from);
});
if (tk.text == "false") {
return true;
} else if (tk.text == "true") {
return true;
} else if (tk.text == "null") {
return true;
}
break;
}
}
return false;
}
std::shared_ptr<blitz::ast::node> blitz::ast::value::try_parse(std::shared_ptr<blitz::lexer> lexer)
{
auto tk = lexer->current();
auto utk = lexer->peek();
auto node = std::make_shared<blitz::ast::value>();
node->type = variant::UNKNOWN;
if (tk.type == blitz::token::variant::STRING) {
node->type = variant::STRING;
node->text = tk.text;
return node;
} else if (tk.type == blitz::token::variant::INTEGER) {
// Figure out which base this integer is in (and where it starts).
int base = 10;
const char* text = tk.text.c_str();
if ((tk.text.length() > 1) && (text[0] == '0')) {
if (text[1] == 'x') { // Base 16
base = 16;
text = text += 2;
} else if (text[1] == 'b') { // Base 2
base = 2;
text = text += 2;
} else if (text[1] == '0') {
base = 8;
text = text += 1;
}
}
if (utk.type == blitz::token::variant::TEXT && utk.text == "u") {
// User specific this is unsigned, so treat it as such.
node->type = variant::UNSIGNED_INTEGER;
node->number.ui = strtoull(text, nullptr, base);
if (errno == ERANGE) {
throw blitz::error(file, tk.location, tk.location, blitz::format("Value '%s' is not representable on this system.", tk.text.c_str()));
}
} else {
// Try and figure out if it is unsigned.
node->number.i = strtoll(text, nullptr, base);
if (errno == ERANGE) {
node->type = variant::UNSIGNED_INTEGER;
node->number.ui = strtoull(text, nullptr, base);
if (errno == ERANGE) {
throw blitz::error(file, tk.location, tk.location, blitz::format("Value '%s' is not representable on this system.", tk.text.c_str()));
}
} else {
node->type = variant::INTEGER;
}
}
}
}