v / cmd / tools / vast2 / vast2.v
156 lines · 141 sloc · 4.34 KB · 6c1b1f3a7f45190c5334b8594779c248db72a471
Raw
1// Copyright (c) 2020-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module main
5
6import os
7import v2.ast
8import v2.ast_dump
9import v2.parser
10import v2.pref
11import v2.token
12import v2.transformer
13import v2.types
14
15fn main() {
16 args := os.args[1..]
17
18 if args.len == 0 {
19 eprintln('Usage: vast <file.v>')
20 eprintln('Dumps AST to <file>_ast.json and <file>_ast_transformed.json')
21 exit(1)
22 }
23
24 files := get_files(args)
25 if files.len == 0 {
26 eprintln('Usage: vast <file.v>')
27 eprintln('Dumps AST to <file>_ast.json and <file>_ast_transformed.json')
28 exit(1)
29 }
30
31 // Get base name for output files
32 input_file := files[0]
33 base_name := if input_file.ends_with('.v') {
34 input_file[..input_file.len - 2]
35 } else {
36 input_file
37 }
38
39 prefs := pref.new_preferences()
40 mut file_set := token.FileSet.new()
41 mut p := parser.Parser.new(&prefs)
42
43 // Parse builtin and dependencies first
44 mut ast_files := []ast.File{}
45 ast_files << p.parse_files(get_v_files_from_dir(prefs.get_vlib_module_path('builtin')), mut
46 file_set)
47 ast_files << p.parse_files(get_v_files_from_dir(prefs.get_vlib_module_path('strconv')), mut
48 file_set)
49 ast_files << p.parse_files(get_v_files_from_dir(prefs.get_vlib_module_path('strings')), mut
50 file_set)
51 ast_files << p.parse_files(get_v_files_from_dir(prefs.get_vlib_module_path('hash')), mut
52 file_set)
53 ast_files << p.parse_files(get_v_files_from_dir(prefs.get_vlib_module_path('math.bits')), mut
54 file_set)
55
56 // Parse the user file(s)
57 ast_files << p.parse_files(files, mut file_set)
58
59 // Write pre-transformation AST (only user files, not builtin)
60 user_files := ast_files.filter(it.name in files)
61 ast_json := ast_dump.dump_files(user_files)
62 ast_file := '${base_name}_ast.json'
63 os.write_file(ast_file, ast_json) or {
64 eprintln('Failed to write ${ast_file}: ${err}')
65 exit(1)
66 }
67 println('Wrote ${ast_file}')
68
69 // Type check
70 env := types.Environment.new()
71 mut checker := types.Checker.new(&prefs, file_set, env)
72 checker.check_files(ast_files)
73
74 // Transform
75 mut trans := transformer.Transformer.new_with_pref(env, &prefs)
76 transformed_files := trans.transform_files(ast_files)
77
78 // Write post-transformation AST (only user files)
79 transformed_user_files := transformed_files.filter(it.name in files)
80 transformed_json := ast_dump.dump_files(transformed_user_files)
81 transformed_file := '${base_name}_ast_transformed.json'
82 os.write_file(transformed_file, transformed_json) or {
83 eprintln('Failed to write ${transformed_file}: ${err}')
84 exit(1)
85 }
86 println('Wrote ${transformed_file}')
87}
88
89// get_files extracts source files from args, excluding options and their values
90fn get_files(args []string) []string {
91 options_with_values := ['-o', '-output']
92 mut files := []string{}
93 mut skip_next := false
94 for arg in args {
95 if skip_next {
96 skip_next = false
97 continue
98 }
99 if arg.starts_with('-') {
100 if arg in options_with_values {
101 skip_next = true
102 }
103 continue
104 }
105 files << arg
106 }
107 return files
108}
109
110fn get_v_files_from_dir(dir string) []string {
111 mut v_files := []string{}
112 all_files := os.ls(dir) or { return v_files }
113 for file in all_files {
114 if file.ends_with('.v') && !file.ends_with('_test.v') {
115 // Skip platform-specific files that don't match current platform
116 if should_include_file(file) {
117 v_files << os.join_path(dir, file)
118 }
119 }
120 }
121 return v_files
122}
123
124fn should_include_file(filename string) bool {
125 // Skip test files (including _test.c.v)
126 if filename.contains('_test.') {
127 return false
128 }
129 // Skip JavaScript backend files
130 if filename.ends_with('.js.v') {
131 return false
132 }
133 // Handle platform-specific files
134 current_os := os.user_os()
135 // Check for OS-specific suffixes like _linux.v, _windows.v, _macos.v
136 os_suffixes := ['_linux.v', '_windows.v', '_macos.v', '_darwin.v', '_freebsd.v', '_openbsd.v',
137 '_netbsd.v', '_solaris.v', '_haiku.v', '_android.v']
138 for suffix in os_suffixes {
139 if filename.ends_with(suffix) {
140 // Include only if it matches current OS
141 if suffix == '_darwin.v' || suffix == '_macos.v' {
142 return current_os == 'macos'
143 } else if suffix == '_linux.v' {
144 return current_os == 'linux'
145 } else if suffix == '_windows.v' {
146 return current_os == 'windows'
147 }
148 return false
149 }
150 }
151 // Check for "not this OS" files like _nix.v (not windows)
152 if filename.ends_with('_nix.v') {
153 return current_os != 'windows'
154 }
155 return true
156}
157