Skip to content

Commit

Permalink
Expanded on modules and added float to string conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
mauro-balades committed Jan 23, 2024
1 parent b2bec5e commit 9b1d8d4
Show file tree
Hide file tree
Showing 19 changed files with 1,566 additions and 44 deletions.
2 changes: 1 addition & 1 deletion app/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ int _main(int argc, char** argv) {
}
return EXIT_FAILURE;
} catch (const std::exception& e) {
Logger::error(FMT("An unexpected error occurred: %s", e.what()));
Logger::error(FMT("\r\nAn unexpected error occurred: %s", e.what()));
return EXIT_FAILURE;
}

Expand Down
1,354 changes: 1,354 additions & 0 deletions compile_commands.json.tmp23c9b

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions src/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@ namespace fs = std::filesystem;
#ifndef __SNOWBALL_COMPILER_H_
#define __SNOWBALL_COMPILER_H_

Check warning on line 16 in src/compiler.h

View workflow job for this annotation

GitHub Actions / cpp-linter

src/compiler.h:16:9 [bugprone-reserved-identifier]

declaration uses identifier '__SNOWBALL_COMPILER_H_', which is a reserved identifier

// It is important that the passes are pointers initialized with "new" and not
// just objects. This is because c++ messes up virtual functions when using
// objects. This is a known bug in c++.
#define SNOWBALL_PASS_EXECUTION_LIST \
std::vector<Syntax::Analyzer> passes = { \
Syntax::DefiniteAssigment(srcInfo)}; \
std::vector<Syntax::Analyzer*> passes = { \
new Syntax::DefiniteAssigment(srcInfo)}; \
for (auto pass : passes) \
pass.run(ast); \
pass->run(ast);

namespace snowball {

Check warning on line 27 in src/compiler.h

View workflow job for this annotation

GitHub Actions / cpp-linter

src/compiler.h:27:11 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'snowball' is non-const and globally accessible, consider making it const

Expand Down
8 changes: 3 additions & 5 deletions src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,15 @@ extern "C" {
(".sn" PATH_SEPARATOR "bin" PATH_SEPARATOR + (os::Driver::getOutputFilename(x, t, s)))

#ifndef _SNOWBALL_ENABLE_INT64
#define _SNOWBALL_ENABLE_INT64 \
0 // if 1 enable snowball_int_t to be a 64bit int (instead of a \
// 32bit int)
#define _SNOWBALL_ENABLE_INT64 1
#endif

#if _SNOWBALL_ENABLE_INT64
typedef int64_t snowball_int_t;
typedef uint64_t snowball_int_t;
#define _SNOWBALL_INT_MAX 9223372036854775807
#define _SNOWBALL_INT_MIN (-_SNOWBALL_INT_MAX - 1LL)
#else
typedef int32_t snowball_int_t;
typedef uint32_t snowball_int_t;
#define _SNOWBALL_INT_MAX 2147483647
#define _SNOWBALL_INT_MIN -2147483648
#endif
Expand Down
14 changes: 14 additions & 0 deletions src/lexer/lexer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,20 @@ void Lexer::tokenize() {
tk.type = TokenType::VALUE_NUMBER;
}

std::string prefix;
if (GET_CHAR(0) == 'u' || GET_CHAR(0) == 'U') {
prefix += "u";
EAT_CHAR(1);
} else if (GET_CHAR(0) == 'i' || GET_CHAR(0) == 'I') {
prefix += "i";
EAT_CHAR(1);
}

if (GET_CHAR(0) == 'l' || GET_CHAR(0) == 'L') {
prefix += "l";
EAT_CHAR(1);
}
tk.value = prefix + tk.value;
tokens.emplace_back(tk);
if (isRange) { // we add '..' if it's a range expr (1..5)
consume(TokenType::SYM_DOT);
Expand Down
4 changes: 2 additions & 2 deletions src/parser/parseClass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,9 @@ Syntax::Statement::DefinedTypeDef* Parser::parseClass() {
case TokenType::KWORD_OVERRIDE: {
auto pk = peek();
if (pk.type != TokenType::KWORD_FUNC && pk.type != TokenType::KWORD_OPERATOR && pk.type != TokenType::KWORD_UNSAFE
&& pk.type != TokenType::KWORD_MUTABLE, pk.type != TokenType::KWORD_VIRTUAL) {
&& pk.type != TokenType::KWORD_MUTABLE && pk.type != TokenType::KWORD_VIRTUAL) {
next();
createError<SYNTAX_ERROR>("expected keyword \"func\" or \"operator\", \"unsafe\" or \"mut\", \"virtual\" "
createError<SYNTAX_ERROR>("expected keyword \"func\" or \"operator\", \"unsafe\", \"mut\" or \"virtual\" "
"after override declaration!");
}
} break;
Expand Down
6 changes: 4 additions & 2 deletions src/parser/parseStructure.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,16 @@ Syntax::Statement::DefinedTypeDef* Parser::parseStructure() {
switch (m_current.type) {
case TokenType::KWORD_PUBLIC:
case TokenType::KWORD_PRIVATE: {
next();
assert_tok<TokenType::KWORD_VAR>("a valid member declaration");
createError<SYNTAX_ERROR>("Cannot declare a member as public or private inside a structure", {
.note = "Structure members are always public"
});
break;
}

case TokenType::KWORD_VAR: {
auto member = parseVariable();
consume<TokenType::SYM_SEMI_COLLON>("';'");
member->setPrivacy(Syntax::Statement::Privacy::PUBLIC);
cls->addVariable(member);
break;
}
Expand Down
1 change: 0 additions & 1 deletion src/visitors/Analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#define __SNOWBALL_ANALYZER_H_

#define ACCEPT(Node) virtual void visit(Node* p_node) override{};
#define SN_ANALYZER_VISIT(Node) void Analyzer::visit(Node* p_node)

namespace snowball {
namespace Syntax {
Expand Down
20 changes: 10 additions & 10 deletions src/visitors/TypeChecker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -754,19 +754,20 @@ void TypeChecker::fixTypes(std::shared_ptr<types::BaseType> ty) {
if (type && type->hasVtable) {
std::vector<types::DefinedType*> parents;
std::vector<std::shared_ptr<ir::Func>> finalVtable;
parents.push_back(type.get());


// add parents from lowest to highest
auto parent = type->getParent();
while (parent) {
parents.push_back(parent);
parent = parent->getParent();
auto tyParent = type->getParent();
while (tyParent) {
parents.insert(parents.begin(), tyParent);
tyParent = tyParent->getParent();
}

parents.push_back(type.get());

// reverse iterate over the parents
for (auto parent = parents.rbegin(); parent != parents.rend(); ++parent) {
for (auto parent : parents) {
int vtableIndex = 0;
auto parentVtable = (*parent)->getVTable();
auto parentVtable = parent->getVTable();
for (auto fn : parentVtable) {
// add it if it's not already in the vtable
// we first check by name and then if the types exist
Expand All @@ -776,14 +777,13 @@ void TypeChecker::fixTypes(std::shared_ptr<types::BaseType> ty) {
});

if (it == finalVtable.end()) {
// TODO: only when "overriding"!!!
fn->setVirtualIndex(vtableIndex++);
finalVtable.push_back(fn);
} else {
// if it's already in the vtable, we need to replace it
// with the new function

if (!fn->hasAttribute(Attributes::OVERRIDE)) {
if (!fn->hasAttribute(Attributes::OVERRIDE) && fn->getParent()->is(type.get())) {
E<SYNTAX_ERROR>(
fn->getDBGInfo(),
FMT("Function '%s' is not marked as 'override'!", fn->getNiceName().c_str()),
Expand Down
12 changes: 6 additions & 6 deletions src/visitors/transform/utils/implementTypes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ void Transformer::implementTypes(
if (!(*classField)->type->is(type)) {
E<TYPE_ERROR>(
ast,
FMT("Field's (%s) type does not match the interface's type!", name.c_str()),
FMT("Field %s type does not match the interface type!", name.c_str()),
{.info = "Type mismatch!",
.note = FMT("Field '%s' declared here with a different type!", name.c_str()),
.help =
FMT("Here it's declared as '%s' but the interface declares it as '%s'!",
FMT("Here its declared as '%s' but the interface declares it as '%s'!",
(*classField)->type->getPrettyName().c_str(),
type->getPrettyName().c_str()),
.tail =
Expand All @@ -81,11 +81,11 @@ void Transformer::implementTypes(
} else if ((*classField)->isMutable != ast->isMutable()) {
E<TYPE_ERROR>(
ast,
FMT("Field's (%s) mutability does not match the interface's mutability!", name.c_str()),
FMT("Field %s mutability does not match the interface mutability!", name.c_str()),
{.info = "Mutability mismatch!",
.note = FMT("Field '%s' declared here with a different mutability!", name.c_str()),
.help =
FMT("Here it's declared as '%s' but the interface declares it as '%s'!",
FMT("Here its declared as '%s' but the interface declares it as '%s'!",
(*classField)->isMutable ? "mutable" : "immutable",
ast->isMutable() ? "mutable" : "immutable"),
.tail = EI<>(
Expand All @@ -100,11 +100,11 @@ void Transformer::implementTypes(
} else if ((*classField)->getPrivacy() != ast->getPrivacy()) {
E<TYPE_ERROR>(
ast,
FMT("Field's (%s) privacy does not match the interface's privacy!", name.c_str()),
FMT("Field (%s) privacy does not match the interface privacy!", name.c_str()),
{.info = "Privacy mismatch!",
.note = FMT("Field '%s' declared here with a different privacy!", name.c_str()),
.help =
FMT("Here it's declared as '%s' but the interface declares it as '%s'!",
FMT("Here its declared as '%s' but the interface declares it as '%s'!",
(*classField)->getPrivacy() == Statement::Privacy::PUBLIC ? "public" : "private",
ast->getPrivacy() == Statement::Privacy::PUBLIC ? "public" : "private"),
.tail = EI<>(
Expand Down
29 changes: 27 additions & 2 deletions src/visitors/transform/visits/Expression/ConstantValue.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ SN_TRANSFORMER_VISIT(Expression::ConstantValue) {
CASE(Number) : {
auto str = p_node->getValue();

bool unsigned_ = false;
bool long_ = false;

if (str[0] == 'u') {
unsigned_ = true;
str = str.substr(1, str.size() - 1);
}

if (str[0] == 'l') {
long_ = true;
str = str.substr(1, str.size() - 1);
}

snowball_int_t n = 0;
if (utils::startsWith(str, "0x") || utils::startsWith(str, "0X")) {
n = std::stoll(str, nullptr, 16);
Expand All @@ -66,11 +79,23 @@ SN_TRANSFORMER_VISIT(Expression::ConstantValue) {
n = std::stoul(str.substr(2, (size_t) (str.size() - 2)), nullptr, 8);
} else {
// TODO: big numbers!
n = std::stoll(str); // We asume the number is correct
n = std::stoull(str);
}

value = getBuilder().createNumberValue(p_node->getDBGInfo(), n);
getBuilder().setType(value, ctx->getInt32Type());
if (unsigned_) {
if (long_) {
value->setType(ctx->getUIntType(64));
} else {
value->setType(ctx->getUIntType(32));
}
} else {
if (long_) {
value->setType(ctx->getInt64Type());
} else {
value->setType(ctx->getInt32Type());
}
}
break;
}

Expand Down
47 changes: 42 additions & 5 deletions stdlib/internal/integers.sn
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,52 @@ class extends IntegerImpl {
}
}

// TODO: this is just a hack, we need to implement a proper
// implementation for to_string for bool and floats
@inline
func to_string(self: bool) String {
// Safety: we know that bool is either 0 or 1
// TODO: See if there is a faster way to do this
if self { return "1" }
if self { return "1"; }
return "0";
}

func to_string(self: f64) String {
let mut n = self;
let mut buffer = ptr::Allocator<?u8>::alloc(16).ptr();
let mut decimals: u16 = 0U as u16;
let mut i: i32 = 16;
let mut units: i32 = 0;
if n < 0 {
units = (-1 * n) as i32;
decimals = ((n * -100000) % 100000) as u16;
} else {
units = n as i32;
decimals = ((n * 100000) % 100000) as u16;
}
unsafe {
i = i - 1;
do {
*(buffer + i) = '0' + (decimals % 10) as u8;
decimals = decimals / 10;
i = i - 1;
} while decimals > 0;
*(buffer + i) = '.';
i = i - 1;
do {
*(buffer + i) = '0' + (units % 10) as u8;
units = units / 10;
i = i - 1;
} while units > 0;
if n < 0 {
*(buffer + i) = '-';
i = i - 1;
}
return String::from(buffer + (i+1), (16-i) - 1);
}
}

@inline
func to_string<>(self: f32) String {
return (self as f64).to_string();
}

/**
* @brief Converts an integer to a hexadecimal string.
*
Expand Down
56 changes: 56 additions & 0 deletions stdlib/rand.sn
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

import std::ptr;
import std::c_bindings;
import std::io;

public class RandomGenerator {
public:
RandomGenerator() {}
virtual func rand_int() u64 {}
}

public class DefaultRNG extends RandomGenerator {
private:
let mut seed: u64 = 0;
public:
DefaultRNG() : super() {}

@inline
override virtual mut func rand_int() u64 {
// We use the linear congruential generator (LCG) algorithm.
if self.seed == 0 {
unsafe {
self.seed = c_bindings::time(ptr::null_ptr<?i32>()) as u64;
}
}
self.seed = (self.seed * 1103515245U + 12345U) & 0x7fffffffU;
return self.seed;
}
}

let mut _global_rng: RandomGenerator = new DefaultRNG() as RandomGenerator;

/**
* @brief It generates a random number between 0 and RAND_MAX.
* @return A random number between 0 and RAND_MAX.
*/
@inline
public func rand_int() u64 {
return _global_rng.rand_int();
}
/**
* @brief It generates a random number between 0 and 1.
* @return A random number between 0 and 1.
*/
@inline
public func rand() f64 {
return _global_rng.rand_int() as f64 / 0x7fffffff as f64;
}
/**
* @brief Set a new random number generator handler.
* @param rng - new random number generator handler
*/
@inline
public func set_rng(rng: RandomGenerator) {
_global_rng = rng;
}
2 changes: 1 addition & 1 deletion tests/lambdas.sn
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func usage_after_lambda2() i32 {
}

struct TestStruct {
public let x: i32;
let x: i32;
}

func lambda_return_struct() Function<func() => TestStruct> {
Expand Down
5 changes: 5 additions & 0 deletions tests/main.sn
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import pkg::strings;
import pkg::enums;
import pkg::json;
import pkg::libs_include;
import pkg::rand;

////import std::io::{{ println }};

Expand All @@ -40,6 +41,8 @@ import std::opt;
import std::tuples;
import std::env as os_env;

import std::rand as random;

//import std::io::{ println };

//import std::json as std_json;
Expand All @@ -50,4 +53,6 @@ public func main() i32 {
//vec.push(true);
//vec.push(false);
//io::println(std_json::serialize(vec));
let a = (-10.0);
io::println(a as f64);
}
Loading

0 comments on commit 9b1d8d4

Please sign in to comment.