From 006df5845193d2e42a2b81f917bb9a215b729d5a Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 19 Apr 2022 18:51:03 +0300 Subject: [PATCH] checker, cgen: add support for #insert, to simplify bootstrapping V --- vlib/v/checker/checker.v | 42 +++++++++++++++----- vlib/v/checker/tests/comptime_insert_err.cc | 1 + vlib/v/checker/tests/comptime_insert_err.out | 7 ++++ vlib/v/checker/tests/comptime_insert_err.vv | 10 +++++ vlib/v/gen/c/cgen.v | 14 ++++++- 5 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 vlib/v/checker/tests/comptime_insert_err.cc create mode 100644 vlib/v/checker/tests/comptime_insert_err.out create mode 100644 vlib/v/checker/tests/comptime_insert_err.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index d294e01355..dd399bb58f 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2260,7 +2260,8 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { return } match node.kind { - 'include' { + 'include', 'insert' { + original_flag := node.main mut flag := node.main if flag.contains('@VROOT') { // c.note(checker.vroot_is_deprecated_message, node.pos) @@ -2268,13 +2269,13 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { c.error(err.msg(), node.pos) return } - node.val = 'include $vroot' + node.val = '$node.kind $vroot' node.main = vroot flag = vroot } if flag.contains('@VEXEROOT') { vroot := flag.replace('@VEXEROOT', os.dir(pref.vexe_path())) - node.val = 'include $vroot' + node.val = '$node.kind $vroot' node.main = vroot flag = vroot } @@ -2283,7 +2284,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { c.error(err.msg(), node.pos) return } - node.val = 'include $vroot' + node.val = '$node.kind $vroot' node.main = vroot flag = vroot } @@ -2295,10 +2296,33 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { node.main = env } flag_no_comment := flag.all_before('//').trim_space() - if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"')) - || (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) { - c.error('including C files should use either `"header_file.h"` or `` quoting', - node.pos) + if node.kind == 'include' { + if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"')) + || (flag_no_comment.starts_with('<') && flag_no_comment.ends_with('>'))) { + c.error('including C files should use either `"header_file.h"` or `` quoting', + node.pos) + } + } + if node.kind == 'insert' { + if !(flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"')) { + c.error('inserting .c or .h files, should use `"header_file.h"` quoting', + node.pos) + } + node.main = node.main.trim('"') + if fcontent := os.read_file(node.main) { + node.val = fcontent + } else { + mut missing_message := 'The file $original_flag, needed for insertion by module `$node.mod`,' + if os.is_file(node.main) { + missing_message += ' is not readable.' + } else { + missing_message += ' does not exist.' + } + if node.msg != '' { + missing_message += ' ${node.msg}.' + } + c.error(missing_message, node.pos) + } } } 'pkgconfig' { @@ -2361,7 +2385,7 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { } else { if node.kind != 'define' { - c.error('expected `#define`, `#flag`, `#include` or `#pkgconfig` not $node.val', + c.error('expected `#define`, `#flag`, `#include`, `#insert` or `#pkgconfig` not $node.val', node.pos) } } diff --git a/vlib/v/checker/tests/comptime_insert_err.cc b/vlib/v/checker/tests/comptime_insert_err.cc new file mode 100644 index 0000000000..0438a82f22 --- /dev/null +++ b/vlib/v/checker/tests/comptime_insert_err.cc @@ -0,0 +1 @@ +// just some text diff --git a/vlib/v/checker/tests/comptime_insert_err.out b/vlib/v/checker/tests/comptime_insert_err.out new file mode 100644 index 0000000000..5037a21302 --- /dev/null +++ b/vlib/v/checker/tests/comptime_insert_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/comptime_insert_err.vv:6:1: error: The file "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc", needed for insertion by module `main`, does not exist. + 4 | // some more comments + 5 | + 6 | #insert "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc" + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 7 | + 8 | fn main() { diff --git a/vlib/v/checker/tests/comptime_insert_err.vv b/vlib/v/checker/tests/comptime_insert_err.vv new file mode 100644 index 0000000000..5467309ecd --- /dev/null +++ b/vlib/v/checker/tests/comptime_insert_err.vv @@ -0,0 +1,10 @@ +// The following file exists, so there should not be a checker error for it: +#insert "@VEXEROOT/vlib/v/checker/tests/comptime_insert_err.cc" + +// some more comments + +#insert "@VEXEROOT/vlib/v/checker/tests/Non_Existant_File.cc" + +fn main() { + println('hello') +} diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 84e16e4cba..aa6516e87d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1797,6 +1797,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { g.writeln('goto ${c_name(node.name)};') } ast.HashStmt { + line_nr := node.pos.line_nr + 1 mut ct_condition := '' if node.ct_conds.len > 0 { ct_condition_start := g.out.len @@ -1830,7 +1831,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { } // Objective C code import, include it after V types, so that e.g. `string` is // available there - g.definitions.writeln('// added by module `$node.mod`') + g.definitions.writeln('// added by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:') g.definitions.writeln(guarded_include) if ct_condition.len > 0 { g.definitions.writeln('#endif // \$if $ct_condition') @@ -1841,13 +1842,22 @@ fn (mut g Gen) stmt(node ast.Stmt) { if ct_condition.len > 0 { g.includes.writeln('#if $ct_condition') } - g.includes.writeln('// added by module `$node.mod`') + g.includes.writeln('// added by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:') g.includes.writeln(guarded_include) if ct_condition.len > 0 { g.includes.writeln('#endif // \$if $ct_condition') } g.includes.writeln('\n') } + } else if node.kind == 'insert' { + if ct_condition.len > 0 { + g.includes.writeln('#if $ct_condition') + } + g.includes.writeln('// inserted by module `$node.mod`, file: ${os.file_name(node.source_file)}:$line_nr:') + g.includes.writeln(node.val) + if ct_condition.len > 0 { + g.includes.writeln('#endif // \$if $ct_condition') + } } else if node.kind == 'define' { if ct_condition.len > 0 { g.includes.writeln('#if $ct_condition')