MrSmith33 / vox

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

Vox programs on linux will not get the signals with Ctrl+c, Ctrl+z etc. #36

Closed rempas closed 2 years ago

rempas commented 2 years ago

Normally when I run a program, I expect Ctrl+c to stop its execution and Ctrl+z to suspend it (put it in the background). There are probably other signals that you can send but these two are the ones I mostly care about and from what I noticed (don't ask me why I found out about this now, lol) they don't work with Vox

MrSmith33 commented 2 years ago

I don't know much about linux signals yet, but it may be the case that you need to register signal handlers for this to work.

rempas commented 2 years ago

Oh ok! I just wanted to let you know at least and you can see it when you want

MrSmith33 commented 2 years ago

I checked and it worked actually

void main() {
    while(true){}
}
user@PC:~/vox/test_work_dir$ ./vox test2.vx && ./test2
^Z
[1]+  Stopped                 ./test2
user@PC:~/vox/test_work_dir$ fg
./test2
^C
user@PC:~/vox/test_work_dir$
rempas commented 2 years ago

Interesting. It worked for me too with this example. Then something else is the problem with the specific code that I'm having. And it seems that the problem is when compiling code and not in the runtime so nothing with the way that vox generates code. Ok so here is the full code:

void print[T...](u8[] prompt, T... args) {
  u64 psize = 0;
  u64 carg = 0;
  u8 c;
  // TODO: Find if we can for prompt to be known at compile time and use "#foreach" here
  // TODO: After I'm done with this, make a version with "else" labels removed
  while (psize < prompt.length) {
    c = prompt[psize++];
    if (c != '{') {
      // TODO: Make a macro called "add_char" when macros are implemented
      if (stdout_index < STDOUT_BUF_LEN) {
        stdout_buffer[stdout_index++] = c;
        continue;
      } else {
        sys_write(1, stdout_buffer.ptr, stdout_index + 1); // TODO: Remove '+ 1' and see what happens
        stdout_index = 0;
        stdout_buffer[stdout_index++] = c;
        continue;
      }
    } else {
      // TODO: When the #debug is released, make this check only in the #debug version
      if (psize >= prompt.length) // FIXME: psize can never be bigger than prompt.length so maybe only check for equality makes more sense?
        sys_write(2, "Error: Expected the matching '}'\n", 22); // TODO: find how to get the current line number

      // Get the closing '}'
      c = prompt[psize++];
      if (c == '}') { // Format it as its type
        // TODO: When the #debug is released, make this check only in the #debug version
        if (carg >= args.length) { // FIXME: carg can never be bigger than args.length so maybe only check for equality makes more sense?
          sys_write(2, "There are no more argruments to print\n", 27); // TODO: find how to get the current line number
        }

        // TODO FIXME: Change ALL these methods to put the character directly to stdout rather than returning a "u8*"
        #if (T == u8 || T == i8 || T == u16 || T == i16 || T == u32 || T == i32 || T == u64 || T == i64) {
          u8* val = to_str(args[carg++]);
          u64 len = strlen(val);
          for (u64 i = 0; i < len; i++) {
            if (stdout_index < STDOUT_BUF_LEN) {
              stdout_buffer[stdout_index++] = val[i];
              continue;
            } else {
              sys_write(1, stdout_buffer.ptr, stdout_index + 1); // TODO: Remove '+ 1' and see what happens
              stdout_index = 0;
              stdout_buffer[stdout_index++] = val[i];
              continue;
            }
          }
        }
      }
    }
  }
}

void main() {
  print("Hello world!!!");
  exit(0);
}

It's a big code snippet unfortunately. Please ignore any logical errors and comments. So when trying to compile this, it will run for about 2-3 seconds and then I will get the infamous "illegal hardware instruction" error. It seems that #if is causing the error because there are two cases without it.

If you remove the the #if but NOT the code inside it, you will get the following error message:

fe.passes.eval:56: ICE: Cannot evaluate static expression decl_var
- token main.vox:15:3
Stack:
> main.vox:46:30: node.14065 name_resolve expr_index expr_index
  main.vox:46:25: node.14075 name_resolve expr_call to_str
  main.vox:46:9: node.14089 name_resolve decl_var val
  main.vox:39:7: node.14489 name_resolve stmt_if stmt_if
  main.vox:21:5: node.14501 name_resolve stmt_if stmt_if
  main.vox:19:3: node.14513 name_resolve stmt_while stmt_while
  main.vox:13:42: node.14521 name_resolve stmt_block stmt_block
  main.vox:13:1: node.13330 name_resolve decl_function print[]
  main.vox:65:8: node.11161 type_check expr_call print
  main.vox:64:13: node.11201 type_check stmt_block stmt_block
  main.vox:64:1: node.11118 type_check decl_function main
  main.vox:1:1: node.572 type_check decl_module main
context.CompilationException@fe.passes.eval(56)

If you remove the the #if AND the code inside it, you will get the following error message:

fe.ast.expr.member_access:471: ICE: Unexpected node type expr_member
- token main.vox:41:25
- module `main`
- function `print[]`
  - defined at main.vox:13:1
context.CompilationException@fe.ast.expr.member_access(471)
MrSmith33 commented 2 years ago

So, aside from bugs in the code, the T here refers to a $alias[], so you cannot compare it to anything. You also try to index it with runtime variable carg, which is not possible. You can only index it with compile-time variable. Variadic arguments are barely implemented atm, basically you can only do #foreach and indexing on them.

Efficient implementation of prinf is a tricky problem. Ideally it requires compile-time knowledge of the format string, and minimal compile-time cost. In D std lib they workaround the indexing of runtime arguments with the switch (but we don't have the ability to generate cases programmatically in Vox yet)

Also, you allocate memory in to_str, while instead you could write the formatted argument directly into stdout_buffer.

rempas commented 2 years ago

So, aside from bugs in the code, the T here refers to a $alias[], so you cannot compare it to anything.

Whaaaaaaaaa? But you said it yourself here. Wasn't this what you meant or did something changed between then and now? Or did I got it wrong? Can you please show me a small simple example of how to choose types (if it is even available at the moment of course)?

Efficient implementation of prinf is a tricky problem. Ideally it requires compile-time knowledge of the format string, and minimal compile-time cost. In D std lib they workaround the indexing of runtime arguments with the switch (but we don't have the ability to generate cases programmatically in Vox yet)

You know, when I wanted to create a transpiler, I though about having a keyword for variables that will only accept values that can be known at compile time. It wouldn't be a "real" variable just a place to hold a value when compiling. This would be used as a function parameter and I would be able to used with #foreach. What are your thoughts on this idea?

Also, you allocate memory in to_str, while instead you could write the formatted argument directly into stdout_buffer.

Buuuuut I told you to not worry about any logical error :). Just kidding! Thanks for the info, I was planning to do this anyway because it is more efficient and makes more sense but I just wanted to test the function first and then create a different function that does that.

MrSmith33 commented 2 years ago

Whaaaaaaaaa? But you said it yourself here. Wasn't this what you meant or did something changed between then and now? Or did I got it wrong? Can you please show me a small simple example of how to choose types (if it is even available at the moment of course)?

Note the that they are different. Singular T is just a type alias, while T... is type array. Here is an example https://github.com/MrSmith33/voxelman2/blob/master/plugins/core/src/core/utils.vx#L287-L314

You know, when I wanted to create a transpiler, I though about having a keyword for variables that will only accept values that can be known at compile time. It wouldn't be a "real" variable just a place to hold a value when compiling. This would be used as a function parameter and I would be able to used with #foreach. What are your thoughts on this idea?

I thought about this too. It is basically a template parameter. But making it a template parameter is unergonomic, but possible (value template parameters are not yet implemented). The other option is to have something like comptime in Zig. It is exactly what we want, but having 2 ways of defining template parameters doesn't feel good. Third option is macro. Since every macro invocation has direct access to the arguments it can check if the value is a constant. Macros are not easy to implement, and I haven't worked on them yet.

rempas commented 2 years ago

Thanks for the example.

having 2 ways of defining template parameters doesn't feel good

Yeah, that's how I see things two. I like to have one thing to do something (when it comes to features and not problem solving of course) to not blot the language.

Third option is macro

Yeah, that's what I was thinking too! It also makes sense cause the types of functions that are going to use it will probably be variadic and need to get reconstructed anyway so it make sense.

Macros are not easy to implement, and I haven't worked on them yet.

Yes of course they are! There are a lot of decisions you have to make when it comes to design them. Rushing thing is never good. The good things take time as we say here in Greece ;)