@@ -258,6 +258,10 @@ fn (b &Builder) imports_headers_stamp_path() string {
258258 return cache_path_join (b.core_cache_dir (), '${imports_cache_name} .vh.stamp' )
259259}
260260
261+ fn (b &Builder) v2compiler_headers_stamp_path () string {
262+ return cache_path_join (b.core_cache_dir (), '${v2compiler_cache_name} .vh.stamp' )
263+ }
264+
261265fn (b &Builder) imports_manifest_path () string {
262266 return cache_path_join (b.core_cache_dir (), '${imports_cache_name} .manifest' )
263267}
@@ -298,6 +302,14 @@ fn (b &Builder) cached_header_paths() []string {
298302 return paths
299303}
300304
305+ fn (b &Builder) v2compiler_header_paths () []string {
306+ mut paths := []string {cap: v2 compiler_cached_module_names.len}
307+ for module_name in v2 compiler_cached_module_names {
308+ paths << b.core_header_path (module_name)
309+ }
310+ return paths
311+ }
312+
301313fn cached_header_module_paths () []string {
302314 mut paths := core_cached_module_paths.clone ()
303315 for module_path in veb_cached_module_paths {
@@ -848,19 +860,34 @@ fn (b &Builder) virtuals_header_stamp_for_modules(groups []CachedVirtualModule)
848860 return lines.join ('\n ' )
849861}
850862
863+ fn stamp_tracked_file_line (line string ) (string , string , bool ) {
864+ mut path_start := - 1
865+ for prefix in ['entry:' , 'source:' , 'compiler:' , 'emit:' , 'compiler_exe:' ] {
866+ if line.starts_with (prefix) {
867+ path_start = prefix.len
868+ break
869+ }
870+ }
871+ if path_start < 0 {
872+ if line.starts_with ('/' ) || line.starts_with ('./' ) || line.starts_with ('../' ) {
873+ path_start = 0
874+ } else {
875+ return '' , '' , false
876+ }
877+ }
878+ colon_idx := line.last_index (':' ) or { return '' , '' , false }
879+ if colon_idx < = path_start {
880+ return '' , '' , false
881+ }
882+ return line[path_start..colon_idx], line[colon_idx + 1 ..], true
883+ }
884+
851885fn stamp_file_lines_are_fresh (stamp string ) bool {
852886 for line in stamp.split_into_lines () {
853- if ! (line. starts_with ( 'entry:' ) || line. starts_with ( 'source:' )
854- || line. starts_with ( 'compiler:' )) {
887+ file , expected_mtime , tracked := stamp_tracked_file_line (line )
888+ if ! tracked {
855889 continue
856890 }
857- colon_idx := line.last_index (':' ) or { return false }
858- path_idx := line.index (':' ) or { return false }
859- if colon_idx < = path_idx {
860- return false
861- }
862- file := line[path_idx + 1 ..colon_idx]
863- expected_mtime := line[colon_idx + 1 ..]
864891 if ! os.exists (file) {
865892 return false
866893 }
@@ -987,6 +1014,37 @@ fn (b &Builder) can_use_cached_import_headers_for_parse() bool {
9871014 return false
9881015}
9891016
1017+ fn (b &Builder) can_use_cached_v2compiler_headers_for_parse () bool {
1018+ if ! b.is_cmd_v2_self_build () || b.pref.no_cache || b.pref.skip_builtin {
1019+ return false
1020+ }
1021+ if ! b.ensure_core_cache_dir () {
1022+ return false
1023+ }
1024+ if ! b.can_use_cached_module_bundle_for_parse (v2 compiler_cache_name, false ) {
1025+ return false
1026+ }
1027+ expected_stamp := b.header_stamp_for_modules (v2 compiler_cached_module_paths)
1028+ current_stamp := os.read_file (b.v2compiler_headers_stamp_path ()) or { return false }
1029+ if current_stamp != expected_stamp || ! stamp_file_lines_are_fresh (current_stamp) {
1030+ return false
1031+ }
1032+ for header_path in b.v2compiler_header_paths () {
1033+ if ! os.exists (header_path) || os.file_size (header_path) == 0 {
1034+ return false
1035+ }
1036+ }
1037+ return true
1038+ }
1039+
1040+ // v2compiler_headers_consumed_for_parse reports whether the generated v2compiler .vh module
1041+ // headers can ever be read back by the parser. v2compiler header parse-reuse is currently
1042+ // disabled (the generated headers are not yet complete/safe), so generating them is dead work on
1043+ // a cold self-build. Set V2_V2COMPILER_VH=1 to re-enable generation while iterating on that path.
1044+ fn (b &Builder) v2compiler_headers_consumed_for_parse () bool {
1045+ return os.getenv ('V2_V2COMPILER_VH' ) != ''
1046+ }
1047+
9901048fn (b &Builder) can_use_cached_virtual_headers_for_parse (groups []CachedVirtualModule) bool {
9911049 if groups.len == 0 || b.pref.no_cache || b.pref.skip_builtin {
9921050 return false
@@ -1071,6 +1129,21 @@ fn (b &Builder) cached_import_parse_path(module_path string) ?string {
10711129 }
10721130 return header_path
10731131 }
1132+ if b.can_use_cached_v2compiler_headers_for_parse () {
1133+ for i, cached_module_path in v2 compiler_cached_module_paths {
1134+ if module_path != cached_module_path {
1135+ continue
1136+ }
1137+ if i > = v2 compiler_cached_module_names.len {
1138+ return none
1139+ }
1140+ header_path := b.core_header_path (v2 compiler_cached_module_names[i])
1141+ if ! os.exists (header_path) || os.file_size (header_path) == 0 {
1142+ return none
1143+ }
1144+ return header_path
1145+ }
1146+ }
10741147 return none
10751148}
10761149
@@ -1253,6 +1326,69 @@ fn (mut b Builder) ensure_import_module_headers(module_names []string) {
12531326 os.write_file (b.imports_headers_stamp_path (), expected_stamp) or {}
12541327}
12551328
1329+ fn (mut b Builder) ensure_v2compiler_module_headers () {
1330+ if ! b.is_cmd_v2_self_build () || ! b.ensure_core_cache_dir () {
1331+ return
1332+ }
1333+ expected_stamp := b.header_stamp_for_modules (v2 compiler_cached_module_paths)
1334+ mut has_headers := true
1335+ for header_path in b.v2compiler_header_paths () {
1336+ if ! os.exists (header_path) || os.file_size (header_path) == 0 {
1337+ has_headers = false
1338+ break
1339+ }
1340+ }
1341+ if has_headers {
1342+ current_stamp := os.read_file (b.v2compiler_headers_stamp_path ()) or { '' }
1343+ if current_stamp == expected_stamp {
1344+ return
1345+ }
1346+ }
1347+ header_source_files := b.v2compiler_header_source_files ()
1348+ source_fn_returns := b.source_fn_return_types (v2 compiler_cached_module_paths)
1349+ for module_name in v2 compiler_cached_module_names {
1350+ header_ast := b.build_module_header_ast (header_source_files, module_name) or { return }
1351+ mut gen := v.new_gen (b.pref)
1352+ gen.gen (header_ast)
1353+ mut header_source := sanitize_header_source (gen.output_string (), source_fn_returns)
1354+ source_struct_fields := b.source_struct_field_types_for_module (module_name)
1355+ header_source = repair_missing_struct_field_types (header_source, source_struct_fields)
1356+ if header_source.len == 0 {
1357+ for cleanup_name in v2 compiler_cached_module_names {
1358+ os.rm (b.core_header_path (cleanup_name)) or {}
1359+ }
1360+ os.rm (b.v2compiler_headers_stamp_path ()) or {}
1361+ return
1362+ }
1363+ if ! header_source.ends_with ('\n ' ) {
1364+ header_source + = '\n '
1365+ }
1366+ os.write_file (b.core_header_path (module_name), header_source) or { return }
1367+ }
1368+ os.write_file (b.v2compiler_headers_stamp_path (), expected_stamp) or {}
1369+ }
1370+
1371+ fn (mut b Builder) v2compiler_header_source_files () []ast.File {
1372+ mut needed := map [string ]bool {}
1373+ for module_name in v2 compiler_cached_module_names {
1374+ needed[module_name] = true
1375+ }
1376+ mut found := map [string ]bool {}
1377+ for file in b.files {
1378+ if file.name == '' || file.name.ends_with ('.vh' ) {
1379+ continue
1380+ }
1381+ module_name := ast_file_module_name (file)
1382+ if module_name in needed {
1383+ found[module_name] = true
1384+ }
1385+ }
1386+ if found.len == needed.len {
1387+ return b.files
1388+ }
1389+ return b.parse_module_source_files_for_headers (v2 compiler_cached_module_paths)
1390+ }
1391+
12561392fn (mut b Builder) ensure_virtual_module_headers (groups []CachedVirtualModule) {
12571393 if groups.len == 0 || ! b.ensure_core_cache_dir () {
12581394 return
@@ -2018,9 +2154,15 @@ fn (b &Builder) header_const_type_expr(module_name string, field ast.FieldInit)
20182154
20192155fn header_const_value_is_safe (expr ast.Expr) bool {
20202156 return match expr {
2021- ast.BasicLiteral, ast.StringLiteral, ast.StringInterLiteral, ast. Ident {
2157+ ast.BasicLiteral, ast.Ident {
20222158 true
20232159 }
2160+ ast.StringLiteral {
2161+ ! expr.value.contains ('\n ' ) && ! expr.value.contains ('\r ' )
2162+ }
2163+ ast.StringInterLiteral {
2164+ expr.values.all (! it .contains ('\n ' ) && ! it .contains ('\r ' ))
2165+ }
20242166 ast.SelectorExpr {
20252167 header_const_selector_lhs_is_safe (expr.lhs)
20262168 }
0 commit comments