vlang / v

Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. Supports automatic C => V translation. https://vlang.io
MIT License
35.69k stars 2.15k forks source link

comptime: support `-d ident=value` and `var := $d('ident', 0)` #21685

Closed larpon closed 3 months ago

larpon commented 3 months ago

Updated: Initial suggestion was to use -cv ident=value and $compile_value('ident', <value>), it is now an extension of -d using $d('ident', <value>) as retriever.

This PR adds support for the following:

v -d my_i64=890 -d my_string="five six" run .

const my_i64 = $d('my_i64',4)
const my_string = $d('my_string','five')

fn main() {
    println(my_i64)
    println(my_string)
}

Resulting in:

890
five six

.. and leaving out the -d flags: v run ., outputs:

4
five

Supported types are "pure" literals, and can be used also without const:

my_f64 := $d('my_f64', 1.0)
my_i64 := $d('my_i64', 2)
my_string := $d('my_string', 'three')
my_bool := $d('my_bool', false)
my_char := $d('my_char', `f`)

I'm suggesting this, primarily, because I need to be able to tweak fixed array sizes at compile time - so that they have a default, but so I can decide to let my users tweak the sizes if they have reasons or needs to do so.

As @spytheman mentioned on Discord; It has potential to replace both (current) -d and $env.

I plan on adding support for #flag -I $d('my_flag','flag_value')/xyz and #include "$d('my_include','/usr/include')/stdio.h" when time permits. (DONE)

spytheman commented 3 months ago

It is an excellent and long needed addition. Great work!

larpon commented 3 months ago

Awesome, thanks @spytheman

enghitalo commented 3 months ago

What you guys think about use --compile-values instead of -cv flag? Or using both?

JalonSolov commented 3 months ago

It would be -compile-values - V only uses 1 -.

The longer name would be more explicit, for sure. -cv could be almost anything... Want V to write a Ciriculam Vitae for you? -cv. :-)

larpon commented 3 months ago

What you guys think about use --compile-values instead of -cv flag? Or using both?

Currently most, if not all, v flags is denoted via single dash -. The PR supports both a short and long version: -cv and -compile-value

(and you can even use them multiple times interchangeable: v -cv some_var=4 -compile-value xyz=4.7)

Using the plural version (with "s"; -compile-values) when multiple flags/args can be supplied is not ideal.

medvednikov commented 3 months ago

I like it.

But we do have -d compvar, which does the same thing, so it would probably have to be removed for "one way"?

medvednikov commented 3 months ago

(well, not the same, -d is a subset of this new feature)

larpon commented 3 months ago

If we decide to remove -d it probably needs an extended deprecation period since it's a very "old" and very frequently used feature.

spytheman commented 3 months ago

We can also extend -d ident to support -d ident=value, then it can work as before for the first case (except that $compile_value(ident, false) will be true).

For the second case, it can have the new behavior, that is described here for -cv ident=value.

That way, there will be no need for a deprecation, it will continue to work, while having more functionality.

felipensp commented 3 months ago

We can also extend -d ident to support -d ident=value, then it can work as before for the first case (except that $compile_value(ident, false) will be true).

For the second case, it can have the new behavior, that is described here for -cv ident=value.

That way, there will be no need for a deprecation, it will continue to work, while having more functionality.

+1 on keeping -d parameter.

spytheman commented 3 months ago

gcc/clang's -D option also has 2 forms: -Dname -Dname=value so there is an existing precedent for that.

spytheman commented 3 months ago

It seems to work, but I have to do more tests:

#0 15:56:47 ^ comptime/key-value /v/oo>./v -d dynamic_boehm -keepc -showcc examples/hello_world.v
> C compiler cmd: '/space/v/oo/thirdparty/tcc/tcc.exe' '@/tmp/v_1000/hello_world.tmp.c.rsp'
> C compiler response file "/tmp/v_1000/hello_world.tmp.c.rsp":
  -fwrapv -o "/space/v/oo/examples/hello_world" -D GC_THREADS=1 -I "/usr/local/include" -L "/usr/local/lib" "/tmp/v_1000/hello_world.tmp.c" -std=gnu99 -D_DEFAULT_SOURCE -bt25 -lgc -lpthread -ldl
#0 15:56:52 ^ comptime/key-value /v/oo>./v -keepc -showcc examples/hello_world.v
> C compiler cmd: '/space/v/oo/thirdparty/tcc/tcc.exe' '@/tmp/v_1000/hello_world.tmp.c.rsp'
> C compiler response file "/tmp/v_1000/hello_world.tmp.c.rsp":
  -fwrapv -o "/space/v/oo/examples/hello_world" -D GC_BUILTIN_ATOMIC=1 -D GC_THREADS=1 -I "/space/v/oo/thirdparty/libgc/include" "/tmp/v_1000/hello_world.tmp.c" -std=gnu99 -D_DEFAULT_SOURCE -bt25 "/space/v/oo/thirdparty/tcc/lib/libgc.a" -ldl -lpthread
#0 15:56:59 ^ comptime/key-value /v/oo>
#0 15:57:00 ^ comptime/key-value /v/oo>
#0 15:57:00 ^ comptime/key-value /v/oo>./v -d my_f64=2.0 -d my_int=3 -d my_string='a four' -d my_bool -d my_char=g run ./vlib/v/gen/c/testdata/use_flag_comptime_values.vv
2.0
3
a four
true
g
#0 15:57:04 ^ comptime/key-value /v/oo>
larpon commented 3 months ago

I'm ok with keeping -d but then the name $compile_value will be less fitting IMO. Then maybe $compile_define would be a better name - or simply $define, but that may give too many C associations?

felipensp commented 3 months ago

I'm ok with keeping -d but then the name $compile_value will be less fitting IMO. Then maybe $compile_define would be a better name?

Maybe $get(), $ct_define(), $def(), $define or $compile_define. 👍🏻

JalonSolov commented 3 months ago

Why not just -d name=value and forget about $<anything>?

If -d name continues to work for booleans, and -d name=value works for everything else...

spytheman commented 3 months ago

$define looks nice to me, but it can be indeed mistaken with #define, which we also support.

Perhaps $value('name', 123) ?

Or $d('name', 123) - that will mirror the user side -d name=value ?

larpon commented 3 months ago

Why not just -d name=value and forget about $<anything>?

If -d name continues to work for booleans, and -d name=value works for everything else...

If $<anything> is removed how do we use the value it carries from the -d x=y assignment?

Booleans should be able to be false while being defined IMO.

We need to be able to use it as consts or literals in the code

spytheman commented 3 months ago

$compile_define is also nice, since we already have other $compile_ functions, like $compile_warn etc.

larpon commented 3 months ago

$define looks nice to me, but it can be indeed mistaken with #define, which we also support.

Perhaps $value('name', 123) ?

Or $d('name', 123) - that will mirror the user side -d name=value ?

+1 for $d.

I also thought of that after reading @felipensp s suggestions.

spytheman commented 3 months ago

Why not just -d name=value and forget about $<anything>?

The question is how to access the value in the source.

Currently that is with $compile_value('name', some_default) in this PR.

StunxFS commented 3 months ago

So, $if would remain the same? Or would it be different?

// v run main.v -d say_hi=true

$if say_hi ? {
    println('hi!')
}

// or

$if $compile_value('say_hi', false) {
    println('hi!')
}
JalonSolov commented 3 months ago

When I suggested -d name=value, I actually meant for the command line option. Instead of introducing -cv or -compile-value or -compile-define.

If the code uses $compile_define() or $compile_value(), that's fine by me. I'd be partial to $compile_define since that matches the meaning of -d better.

spytheman commented 3 months ago

The PR is already updated to allow for -d name=value, and if everyone agrees, we can remove the code handling -cv/-compile-value in v.pref.

spytheman commented 3 months ago

So, $if would remain the same? Or would it be different?

The syntax of $if is not affected at all by this PR (and it would be a breaking change if it did). It is still $if name ? {.

The new $compile_value('name', default) syntax allows you to get the actual passed value, which was not possible before.

I think, that it would be too verbose to be used as $if $compile_value('say_hi', false) {, even when that is possible (it currently is not evaluated in that case, which is a bug):

$if $compile_value('say_hi', false) {
        println('say_hi is true')
} $else {
        println('say_hi is false')
}

always prints say_hi is true, even for -d say_hi=false .

felipensp commented 3 months ago

So, $if would remain the same? Or would it be different?

The syntax of $if is not affected at all by this PR (and it would be a breaking change if it did). It is still $if name ? {.

The new $compile_value('name', default) syntax allows you to get the actual passed value, which was not possible before.

I think, that it would be too verbose to be used as $if $compile_value('say_hi', false) {, even when that is possible (it currently is not evaluated in that case, which is a bug):

$if $compile_value('say_hi', false) {
        println('say_hi is true')
} $else {
        println('say_hi is false')
}

always prints say_hi is true, even for -d say_hi=false .

yes, $compile_value() is too verbose on if conditions. We just need to document about using -d to handling conditional code and accessing its values. How retrive value and how use it on conditions.

larpon commented 3 months ago

I'm ok with -d ident=value and like any of $d $define and $compile_value. $d is very nice since it matches -d.

Maybe it will be possible to do: $if name == value ? {...} For comptime logic?

larpon commented 3 months ago

Limited HashStmt support is added in e1be3eb. Currently we only support string values like with $env().

The whole # comptime setup could probably benefit from some proper refactoring at some point.

But now this works similar to $env() in #flag, #include etc.:

#flag -I $d('my_flag','flag_value')/xyz
#include "$d('my_include','/usr/include')/stdio.h"
larpon commented 3 months ago

Resolved conflict with master, hence the merge with master