parser,checker: support `$compile_error('message')` and `$compile_warn('message')` (#14320)
parent
4400f9891e
commit
d24dce8eb3
|
@ -2,6 +2,7 @@
|
||||||
-*Not yet released, changelog is not full*
|
-*Not yet released, changelog is not full*
|
||||||
- Introduce `isize` and `usize` types, deprecate `size_t` in favor of `usize`.
|
- Introduce `isize` and `usize` types, deprecate `size_t` in favor of `usize`.
|
||||||
- Add `datatypes` and `datatypes.fsm` modules.
|
- Add `datatypes` and `datatypes.fsm` modules.
|
||||||
|
- Add `compile_error` and `compile_warn` comptime functions.
|
||||||
|
|
||||||
-## V 0.2.4
|
-## V 0.2.4
|
||||||
-*Not yet released, changelog is not full*
|
-*Not yet released, changelog is not full*
|
||||||
|
|
31
doc/docs.md
31
doc/docs.md
|
@ -5433,9 +5433,6 @@ numbers: [1, 2, 3]
|
||||||
3
|
3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### `$env`
|
#### `$env`
|
||||||
|
|
||||||
```v
|
```v
|
||||||
|
@ -5451,6 +5448,34 @@ V can bring in values at compile time from environment variables.
|
||||||
`$env('ENV_VAR')` can also be used in top-level `#flag` and `#include` statements:
|
`$env('ENV_VAR')` can also be used in top-level `#flag` and `#include` statements:
|
||||||
`#flag linux -I $env('JAVA_HOME')/include`.
|
`#flag linux -I $env('JAVA_HOME')/include`.
|
||||||
|
|
||||||
|
#### `$compile_error` and `$compile_warn`
|
||||||
|
|
||||||
|
These two comptime functions are very useful for displaying custom errors/warnings during
|
||||||
|
compile time.
|
||||||
|
|
||||||
|
Both receive as their only argument a string literal that contains the message to display:
|
||||||
|
|
||||||
|
```v failcompile nofmt
|
||||||
|
// x.v
|
||||||
|
module main
|
||||||
|
|
||||||
|
$if linux {
|
||||||
|
$compile_error('Linux is not supported')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
|
|
||||||
|
$ v run x.v
|
||||||
|
x.v:4:5: error: Linux is not supported
|
||||||
|
2 |
|
||||||
|
3 | $if linux {
|
||||||
|
4 | $compile_error('Linux is not supported')
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
5 | }
|
||||||
|
6 |
|
||||||
|
```
|
||||||
|
|
||||||
### Environment specific files
|
### Environment specific files
|
||||||
|
|
||||||
If a file has an environment-specific suffix, it will only be compiled for that environment.
|
If a file has an environment-specific suffix, it will only be compiled for that environment.
|
||||||
|
|
|
@ -10,6 +10,13 @@ import v.pkgconfig
|
||||||
|
|
||||||
fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
||||||
node.left_type = c.expr(node.left)
|
node.left_type = c.expr(node.left)
|
||||||
|
if node.method_name == 'compile_error' {
|
||||||
|
c.error(node.args_var, node.pos)
|
||||||
|
return ast.void_type
|
||||||
|
} else if node.method_name == 'compile_warn' {
|
||||||
|
c.warn(node.args_var, node.pos)
|
||||||
|
return ast.void_type
|
||||||
|
}
|
||||||
if node.is_env {
|
if node.is_env {
|
||||||
env_value := util.resolve_env_value("\$env('$node.args_var')", false) or {
|
env_value := util.resolve_env_value("\$env('$node.args_var')", false) or {
|
||||||
c.error(err.msg(), node.env_pos)
|
c.error(err.msg(), node.env_pos)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
vlib/v/checker/tests/compile_error.vv:4:5: error: Only Serenity is supported
|
||||||
|
2 |
|
||||||
|
3 | $if !serenity {
|
||||||
|
4 | $compile_error('Only Serenity is supported')
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
5 | }
|
||||||
|
6 |
|
||||||
|
vlib/v/checker/tests/compile_error.vv:8:5: error: On non Vinix this warning should be shown
|
||||||
|
6 |
|
||||||
|
7 | $if !vinix {
|
||||||
|
8 | $compile_warn('On non Vinix this warning should be shown')
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
9 | }
|
||||||
|
10 |
|
|
@ -0,0 +1,15 @@
|
||||||
|
module main
|
||||||
|
|
||||||
|
$if !serenity {
|
||||||
|
$compile_error('Only Serenity is supported')
|
||||||
|
}
|
||||||
|
|
||||||
|
$if !vinix {
|
||||||
|
$compile_warn('On non Vinix this warning should be shown')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println('Hello from Serenity')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,8 @@ import v.pref
|
||||||
import v.token
|
import v.token
|
||||||
|
|
||||||
const (
|
const (
|
||||||
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig']
|
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig', 'compile_error',
|
||||||
|
'compile_warn']
|
||||||
comptime_types = ['Map', 'Array', 'Int', 'Float', 'Struct', 'Interface', 'Enum',
|
comptime_types = ['Map', 'Array', 'Int', 'Float', 'Struct', 'Interface', 'Enum',
|
||||||
'Sumtype']
|
'Sumtype']
|
||||||
)
|
)
|
||||||
|
@ -85,9 +86,9 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
err_node := ast.ComptimeCall{
|
err_node := ast.ComptimeCall{
|
||||||
scope: 0
|
scope: 0
|
||||||
}
|
}
|
||||||
|
start_pos := p.tok.pos()
|
||||||
p.check(.dollar)
|
p.check(.dollar)
|
||||||
start_pos := p.prev_tok.pos()
|
error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()` and `\$compile_warn()` comptime functions are supported right now'
|
||||||
error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()` and `\$vweb.html()` comptime functions are supported right now'
|
|
||||||
if p.peek_tok.kind == .dot {
|
if p.peek_tok.kind == .dot {
|
||||||
name := p.check_name() // skip `vweb.html()` TODO
|
name := p.check_name() // skip `vweb.html()` TODO
|
||||||
if name != 'vweb' {
|
if name != 'vweb' {
|
||||||
|
@ -96,7 +97,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
}
|
}
|
||||||
p.check(.dot)
|
p.check(.dot)
|
||||||
}
|
}
|
||||||
method_name := p.check_name() // (.name)
|
method_name := p.check_name()
|
||||||
if method_name !in parser.supported_comptime_calls {
|
if method_name !in parser.supported_comptime_calls {
|
||||||
p.error(error_msg)
|
p.error(error_msg)
|
||||||
return err_node
|
return err_node
|
||||||
|
@ -105,8 +106,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
is_html := method_name == 'html'
|
is_html := method_name == 'html'
|
||||||
// $env('ENV_VAR_NAME')
|
// $env('ENV_VAR_NAME')
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
spos := p.tok.pos()
|
if method_name in ['env', 'pkgconfig', 'compile_error', 'compile_warn'] {
|
||||||
if method_name == 'env' {
|
|
||||||
s := p.tok.lit
|
s := p.tok.lit
|
||||||
p.check(.string)
|
p.check(.string)
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
|
@ -114,22 +114,10 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
scope: 0
|
scope: 0
|
||||||
method_name: method_name
|
method_name: method_name
|
||||||
args_var: s
|
args_var: s
|
||||||
is_env: true
|
is_env: method_name == 'env'
|
||||||
env_pos: spos
|
is_pkgconfig: method_name == 'pkgconfig'
|
||||||
pos: spos.extend(p.prev_tok.pos())
|
env_pos: start_pos
|
||||||
}
|
pos: start_pos.extend(p.prev_tok.pos())
|
||||||
}
|
|
||||||
if method_name == 'pkgconfig' {
|
|
||||||
s := p.tok.lit
|
|
||||||
p.check(.string)
|
|
||||||
p.check(.rpar)
|
|
||||||
return ast.ComptimeCall{
|
|
||||||
scope: 0
|
|
||||||
method_name: method_name
|
|
||||||
args_var: s
|
|
||||||
is_pkgconfig: true
|
|
||||||
env_pos: spos
|
|
||||||
pos: spos.extend(p.prev_tok.pos())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
literal_string_param := if is_html { '' } else { p.tok.lit }
|
literal_string_param := if is_html { '' } else { p.tok.lit }
|
||||||
|
@ -152,7 +140,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
// Validate that the epath exists, and that it is actually a file.
|
// Validate that the epath exists, and that it is actually a file.
|
||||||
if epath == '' {
|
if epath == '' {
|
||||||
p.error_with_pos('supply a valid relative or absolute file path to the file to embed',
|
p.error_with_pos('supply a valid relative or absolute file path to the file to embed',
|
||||||
spos)
|
start_pos)
|
||||||
return err_node
|
return err_node
|
||||||
}
|
}
|
||||||
if !p.pref.is_fmt {
|
if !p.pref.is_fmt {
|
||||||
|
@ -163,12 +151,12 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
epath = os.real_path(os.join_path_single(os.dir(p.file_name), epath))
|
epath = os.real_path(os.join_path_single(os.dir(p.file_name), epath))
|
||||||
if !os.exists(epath) {
|
if !os.exists(epath) {
|
||||||
p.error_with_pos('"$epath" does not exist so it cannot be embedded',
|
p.error_with_pos('"$epath" does not exist so it cannot be embedded',
|
||||||
spos)
|
start_pos)
|
||||||
return err_node
|
return err_node
|
||||||
}
|
}
|
||||||
if !os.is_file(epath) {
|
if !os.is_file(epath) {
|
||||||
p.error_with_pos('"$epath" is not a file so it cannot be embedded',
|
p.error_with_pos('"$epath" is not a file so it cannot be embedded',
|
||||||
spos)
|
start_pos)
|
||||||
return err_node
|
return err_node
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue