Skip to content

Commit d24dce8

Browse files
authored
parser,checker: support $compile_error('message') and $compile_warn('message') (vlang#14320)
1 parent 4400f98 commit d24dce8

6 files changed

Lines changed: 78 additions & 28 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
-*Not yet released, changelog is not full*
33
- Introduce `isize` and `usize` types, deprecate `size_t` in favor of `usize`.
44
- Add `datatypes` and `datatypes.fsm` modules.
5+
- Add `compile_error` and `compile_warn` comptime functions.
56

67
-## V 0.2.4
78
-*Not yet released, changelog is not full*

doc/docs.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5433,9 +5433,6 @@ numbers: [1, 2, 3]
54335433
3
54345434
```
54355435

5436-
5437-
5438-
54395436
#### `$env`
54405437

54415438
```v
@@ -5451,6 +5448,34 @@ V can bring in values at compile time from environment variables.
54515448
`$env('ENV_VAR')` can also be used in top-level `#flag` and `#include` statements:
54525449
`#flag linux -I $env('JAVA_HOME')/include`.
54535450

5451+
#### `$compile_error` and `$compile_warn`
5452+
5453+
These two comptime functions are very useful for displaying custom errors/warnings during
5454+
compile time.
5455+
5456+
Both receive as their only argument a string literal that contains the message to display:
5457+
5458+
```v failcompile nofmt
5459+
// x.v
5460+
module main
5461+
5462+
$if linux {
5463+
$compile_error('Linux is not supported')
5464+
}
5465+
5466+
fn main() {
5467+
}
5468+
5469+
$ v run x.v
5470+
x.v:4:5: error: Linux is not supported
5471+
2 |
5472+
3 | $if linux {
5473+
4 | $compile_error('Linux is not supported')
5474+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5475+
5 | }
5476+
6 |
5477+
```
5478+
54545479
### Environment specific files
54555480

54565481
If a file has an environment-specific suffix, it will only be compiled for that environment.

vlib/v/checker/comptime.v

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ import v.pkgconfig
1010

1111
fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
1212
node.left_type = c.expr(node.left)
13+
if node.method_name == 'compile_error' {
14+
c.error(node.args_var, node.pos)
15+
return ast.void_type
16+
} else if node.method_name == 'compile_warn' {
17+
c.warn(node.args_var, node.pos)
18+
return ast.void_type
19+
}
1320
if node.is_env {
1421
env_value := util.resolve_env_value("\$env('$node.args_var')", false) or {
1522
c.error(err.msg(), node.env_pos)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
vlib/v/checker/tests/compile_error.vv:4:5: error: Only Serenity is supported
2+
2 |
3+
3 | $if !serenity {
4+
4 | $compile_error('Only Serenity is supported')
5+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6+
5 | }
7+
6 |
8+
vlib/v/checker/tests/compile_error.vv:8:5: error: On non Vinix this warning should be shown
9+
6 |
10+
7 | $if !vinix {
11+
8 | $compile_warn('On non Vinix this warning should be shown')
12+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13+
9 | }
14+
10 |
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module main
2+
3+
$if !serenity {
4+
$compile_error('Only Serenity is supported')
5+
}
6+
7+
$if !vinix {
8+
$compile_warn('On non Vinix this warning should be shown')
9+
}
10+
11+
fn main() {
12+
println('Hello from Serenity')
13+
}
14+
15+

vlib/v/parser/comptime.v

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import v.pref
99
import v.token
1010

1111
const (
12-
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig']
12+
supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig', 'compile_error',
13+
'compile_warn']
1314
comptime_types = ['Map', 'Array', 'Int', 'Float', 'Struct', 'Interface', 'Enum',
1415
'Sumtype']
1516
)
@@ -85,9 +86,9 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
8586
err_node := ast.ComptimeCall{
8687
scope: 0
8788
}
89+
start_pos := p.tok.pos()
8890
p.check(.dollar)
89-
start_pos := p.prev_tok.pos()
90-
error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()` and `\$vweb.html()` comptime functions are supported right now'
91+
error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()` and `\$compile_warn()` comptime functions are supported right now'
9192
if p.peek_tok.kind == .dot {
9293
name := p.check_name() // skip `vweb.html()` TODO
9394
if name != 'vweb' {
@@ -96,7 +97,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
9697
}
9798
p.check(.dot)
9899
}
99-
method_name := p.check_name() // (.name)
100+
method_name := p.check_name()
100101
if method_name !in parser.supported_comptime_calls {
101102
p.error(error_msg)
102103
return err_node
@@ -105,31 +106,18 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
105106
is_html := method_name == 'html'
106107
// $env('ENV_VAR_NAME')
107108
p.check(.lpar)
108-
spos := p.tok.pos()
109-
if method_name == 'env' {
110-
s := p.tok.lit
111-
p.check(.string)
112-
p.check(.rpar)
113-
return ast.ComptimeCall{
114-
scope: 0
115-
method_name: method_name
116-
args_var: s
117-
is_env: true
118-
env_pos: spos
119-
pos: spos.extend(p.prev_tok.pos())
120-
}
121-
}
122-
if method_name == 'pkgconfig' {
109+
if method_name in ['env', 'pkgconfig', 'compile_error', 'compile_warn'] {
123110
s := p.tok.lit
124111
p.check(.string)
125112
p.check(.rpar)
126113
return ast.ComptimeCall{
127114
scope: 0
128115
method_name: method_name
129116
args_var: s
130-
is_pkgconfig: true
131-
env_pos: spos
132-
pos: spos.extend(p.prev_tok.pos())
117+
is_env: method_name == 'env'
118+
is_pkgconfig: method_name == 'pkgconfig'
119+
env_pos: start_pos
120+
pos: start_pos.extend(p.prev_tok.pos())
133121
}
134122
}
135123
literal_string_param := if is_html { '' } else { p.tok.lit }
@@ -152,7 +140,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
152140
// Validate that the epath exists, and that it is actually a file.
153141
if epath == '' {
154142
p.error_with_pos('supply a valid relative or absolute file path to the file to embed',
155-
spos)
143+
start_pos)
156144
return err_node
157145
}
158146
if !p.pref.is_fmt {
@@ -163,12 +151,12 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
163151
epath = os.real_path(os.join_path_single(os.dir(p.file_name), epath))
164152
if !os.exists(epath) {
165153
p.error_with_pos('"$epath" does not exist so it cannot be embedded',
166-
spos)
154+
start_pos)
167155
return err_node
168156
}
169157
if !os.is_file(epath) {
170158
p.error_with_pos('"$epath" is not a file so it cannot be embedded',
171-
spos)
159+
start_pos)
172160
return err_node
173161
}
174162
} else {

0 commit comments

Comments
 (0)