MrSmith33 / vox

Vox language compiler. AOT / JIT / Linker. Zero dependencies
Boost Software License 1.0
327 stars 18 forks source link

Wrong results in a function when using a template #32

Closed rempas closed 2 years ago

rempas commented 2 years ago

I have the following code which converts and integral type to a string (u8*):

u8* itostr(i64 num) {
  if (num == 0) return "0";

  i32 digit_count = 0;

  if (num < 0) {
    num = -num;
    digit_count++;
  }

  if (num < 10) digit_count += 1;
  else if (num < 100) digit_count += 2;
  else if (num < 1000) digit_count += 3;
  else if (num < 10000) digit_count += 4;
  else if (num < 100000) digit_count += 5;
  else if (num < 1000000) digit_count += 6;
  else if (num < 10000000) digit_count += 7;
  else if (num < 100000000) digit_count += 8;
  else if (num < 1000000000) digit_count += 9;
  else digit_count += 10;

  u8* str = cast(u8*)sys_mmap(null, cast(u64)digit_count, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
  if (str == null) return "E";

  while (num > 0) {
    --digit_count;
    str[digit_count] = cast(u8)(num % 10 + '0');
    num /= 10;
  }

  if (digit_count == 1) str[0] = '-';
  return str;
}

The result is the expected result but when I use a template the result is not what I was expecting. It actually has a weird behavior where some numbers will get converted normally but some others will return "00" as the result. The full code for the template and the main function is the following: NOTE: Keep in mind that I suppose that you have "write, sys_write, exit, and mmap" from a previous issue, if not, tell me to give them to you.

// SUPOSE THE "itostr" function exists here

u8* to_str[T](T num) {
  #if (T == u8 || T == i8 || T == u16 || T == i16 || T == u32 || T == i32 || T == u64 || T == i64) {
    if (num == 0) return "0";

    i32 digit_count = 0;

  #if (T == i8 || T == i16 || T == i32 || T == i64) { // Unsigned numbers cannot be negative
    if (num < 0) {
      num = -num;
      digit_count++;
    }
  }
    if (num < 10) digit_count += 1;
    else if (num < 100) digit_count += 2;
    else if (num < 1000) digit_count += 3;
    else if (num < 10000) digit_count += 4;
    else if (num < 100000) digit_count += 5;
    else if (num < 1000000) digit_count += 6;
    else if (num < 10000000) digit_count += 7;
    else if (num < 100000000) digit_count += 8;
    else if (num < 1000000000) digit_count += 9;
    else digit_count += 10;

    u8* str = cast(u8*)sys_mmap(null, cast(u64)digit_count, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    if (str == null) return "E";

    while (num > 0) {
      --digit_count;
      str[digit_count] = cast(u8)(num % 10 + '0');
      num /= 10;
    }

    if (digit_count == 1) str[0] = '-';
    return str;
  }

  // TODO: Implement that
  #if (T == f32 || T == f64) {}
}

void main() {
  u8* num;
  num = itostr(32); // Return "32" as expected
  sys_write(1, num, strlen(num));
  write("\n\n"); // Ask this function if you don't have it

  num = to_str(32); // Returns "00"
  sys_write(1, num, strlen(num));
  write("\n\n"); // Ask this function if you don't have it

  num = itostr(-10); // Return "-10" as expected
  sys_write(1, num, strlen(num));
  write("\n\n"); // Ask this function if you don't have it

  num = to_str(-10); // This is right for some reason tho
  sys_write(1, num, strlen(num));
  write("\n"); // Ask this function if you don't have it

  exit(0);
}
MrSmith33 commented 2 years ago

I will check this later, but it may be related to stack alignment bug. I've figured out, that not only syscalls have incorrect stack alignment generated, but regular functions do too on linux.

rempas commented 2 years ago

Oh ok! Don't worry about the time, just take it easy and have fun ;)

MrSmith33 commented 2 years ago

Can you verify that this still doesn't work with master version?

MrSmith33 commented 2 years ago

note that to_str(32) is the same as to_str[u8](32), and to_str(-10) is the same as to_str[i8](-10)

MrSmith33 commented 2 years ago

also, if you are doing zero-terminated strings (which I don't recommend as we have slices in the language), you should allocate an extra byte at the end and set it to 0

MrSmith33 commented 2 years ago

But the actual problem seems to be in cast(u8)(num % 10). For some reason doing remainder on i8 doesn't behave correctly, other types seem ok

MrSmith33 commented 2 years ago

yep, it is a bug with 8bit division. I implemented all sizes the same way, but 8 bits is special

MrSmith33 commented 2 years ago

got caught in a bit of a problem with int literal types

MrSmith33 commented 2 years ago

should be working now. Might need some casts here and there

MrSmith33 commented 2 years ago

10 is i32 now btw

rempas commented 2 years ago

Nice! It works as expected now (at least with this function as I haven't tried anything else at the time of writing this). However, I'm really wondering, as 0df3902 got rejected, how is this fixed? Cause you write that this commit was supposed to fix this problem.

Also something else that has to do with Github in general but I can't seem to find how to fix it. Do you know how I can have notifications appear in my ring bell in the top right corner? I have tried anything and I really can't make this work

MrSmith33 commented 2 years ago

I just forgot to commit some code in that commit, fixed in the next commit.

You can see settings by going to bell -> left bottom -> Manage notifications -> notification settings

rempas commented 2 years ago

Thanks a lot!