mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v: forbid function parameter names, shadowing imported module names (#17210)
This commit is contained in:
parent
c16549b6fd
commit
404a9aa442
@ -47,17 +47,6 @@ jobs:
|
||||
../v -prod .
|
||||
cd ..
|
||||
|
||||
- name: Build VEX
|
||||
run: |
|
||||
echo "Install Vex"
|
||||
v install nedpals.vex
|
||||
echo "Compile all of the Vex examples"
|
||||
v should-compile-all ~/.vmodules/nedpals/vex/examples
|
||||
echo "Compile the simple Vex example with -skip-unused"
|
||||
v -skip-unused ~/.vmodules/nedpals/vex/examples/simple_example.v
|
||||
echo "Run Vex Tests"
|
||||
v test ~/.vmodules/nedpals/vex
|
||||
|
||||
- name: Build vlang/pdf
|
||||
run: |
|
||||
v install pdf
|
||||
@ -172,3 +161,15 @@ jobs:
|
||||
v install pcre
|
||||
echo "Execute Tests"
|
||||
cd /tmp/adventofcode && v run verify.v
|
||||
|
||||
|
||||
# - name: Build VEX
|
||||
# run: |
|
||||
# echo "Install Vex"
|
||||
# v install nedpals.vex
|
||||
# echo "Compile all of the Vex examples"
|
||||
# v should-compile-all ~/.vmodules/nedpals/vex/examples
|
||||
# echo "Compile the simple Vex example with -skip-unused"
|
||||
# v -skip-unused ~/.vmodules/nedpals/vex/examples/simple_example.v
|
||||
# echo "Run Vex Tests"
|
||||
# v test ~/.vmodules/nedpals/vex
|
||||
|
@ -19,10 +19,10 @@ fn main() {
|
||||
|
||||
fn process_files(files []string) ! {
|
||||
mut table := ast.new_table()
|
||||
mut pref := pref.new_preferences()
|
||||
pref.is_fmt = true
|
||||
pref.skip_warnings = true
|
||||
pref.output_mode = .silent
|
||||
mut pref_ := pref.new_preferences()
|
||||
pref_.is_fmt = true
|
||||
pref_.skip_warnings = true
|
||||
pref_.output_mode = .silent
|
||||
mut sw := time.new_stopwatch()
|
||||
mut total_us := i64(0)
|
||||
mut total_bytes := i64(0)
|
||||
@ -35,7 +35,7 @@ fn process_files(files []string) ! {
|
||||
continue
|
||||
}
|
||||
// do not measure the scanning, but only the parsing:
|
||||
mut p := new_parser(f, .skip_comments, table, pref)
|
||||
mut p := new_parser(f, .skip_comments, table, pref_)
|
||||
///
|
||||
sw.restart()
|
||||
_ := p.parse()
|
||||
@ -49,12 +49,12 @@ fn process_files(files []string) ! {
|
||||
println('${total_us:10}us ${total_tokens:10} ${total_bytes:10} ${(f64(total_tokens) / total_bytes):7.3} | speed: ${(f64(total_bytes) / total_us):2.5f} MB/s')
|
||||
}
|
||||
|
||||
fn new_parser(path string, comments_mode scanner.CommentsMode, table &ast.Table, pref &pref.Preferences) &parser.Parser {
|
||||
fn new_parser(path string, comments_mode scanner.CommentsMode, table &ast.Table, pref_ &pref.Preferences) &parser.Parser {
|
||||
mut p := &parser.Parser{
|
||||
scanner: scanner.new_scanner_file(path, comments_mode, pref) or { panic(err) }
|
||||
scanner: scanner.new_scanner_file(path, comments_mode, pref_) or { panic(err) }
|
||||
comments_mode: comments_mode
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
scope: &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: table.global_scope
|
||||
|
@ -15,10 +15,10 @@ fn main() {
|
||||
}
|
||||
|
||||
fn process_files(files []string) ! {
|
||||
mut pref := pref.new_preferences()
|
||||
pref.is_fmt = true
|
||||
pref.skip_warnings = true
|
||||
pref.output_mode = .silent
|
||||
mut pref_ := pref.new_preferences()
|
||||
pref_.is_fmt = true
|
||||
pref_.skip_warnings = true
|
||||
pref_.output_mode = .silent
|
||||
mut sw := time.new_stopwatch()
|
||||
mut total_us := i64(0)
|
||||
mut total_bytes := i64(0)
|
||||
@ -31,7 +31,7 @@ fn process_files(files []string) ! {
|
||||
continue
|
||||
}
|
||||
sw.restart()
|
||||
s := scanner.new_scanner_file(f, .skip_comments, pref)!
|
||||
s := scanner.new_scanner_file(f, .skip_comments, pref_)!
|
||||
f_us := sw.elapsed().microseconds()
|
||||
total_us += f_us
|
||||
total_bytes += s.text.len
|
||||
|
@ -108,7 +108,7 @@ fn add_item_to_array(obj &C.cJSON, item &C.cJSON) {
|
||||
C.cJSON_AddItemToArray(obj, item)
|
||||
}
|
||||
|
||||
fn json_print(json &C.cJSON) string {
|
||||
s := C.cJSON_Print(json)
|
||||
fn json_print(json_ &C.cJSON) string {
|
||||
s := C.cJSON_Print(json_)
|
||||
return unsafe { tos3(s) }
|
||||
}
|
||||
|
@ -120,15 +120,15 @@ fn json(file string) string {
|
||||
// use as permissive preferences as possible, so that `v ast`
|
||||
// can print the AST of arbitrary V files, even .vsh or ones
|
||||
// that require globals:
|
||||
mut pref := &pref.Preferences{}
|
||||
pref.fill_with_defaults()
|
||||
pref.enable_globals = true
|
||||
pref.is_fmt = true
|
||||
mut pref_ := &pref.Preferences{}
|
||||
pref_.fill_with_defaults()
|
||||
pref_.enable_globals = true
|
||||
pref_.is_fmt = true
|
||||
//
|
||||
mut t := Tree{
|
||||
root: new_object()
|
||||
table: ast.new_table()
|
||||
pref: pref
|
||||
pref: pref_
|
||||
}
|
||||
// parse file with comment
|
||||
ast_file := parser.parse_file(file, t.table, .parse_comments, t.pref)
|
||||
@ -359,9 +359,9 @@ fn (t Tree) imports(nodes []ast.Import) &Node {
|
||||
return import_array
|
||||
}
|
||||
|
||||
fn (t Tree) errors(errors []errors.Error) &Node {
|
||||
fn (t Tree) errors(errors_ []errors.Error) &Node {
|
||||
mut errs := new_array()
|
||||
for e in errors {
|
||||
for e in errors_ {
|
||||
obj := new_object()
|
||||
obj.add_terse('message', t.string_node(e.message))
|
||||
obj.add_terse('file_path', t.string_node(e.file_path))
|
||||
|
@ -232,9 +232,9 @@ fn (mut foptions FormatOptions) post_process_file(file string, formatted_file_pa
|
||||
}
|
||||
diff_cmd := foptions.find_diff_cmd()
|
||||
foptions.vlog('Using diff command: ${diff_cmd}')
|
||||
diff := diff.color_compare_files(diff_cmd, file, formatted_file_path)
|
||||
if diff.len > 0 {
|
||||
println(diff)
|
||||
diff_ := diff.color_compare_files(diff_cmd, file, formatted_file_path)
|
||||
if diff_.len > 0 {
|
||||
println(diff_)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -301,13 +301,13 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
|
||||
vmod_path := os.join_path(final_module_path, 'v.mod')
|
||||
if os.exists(vmod_path) {
|
||||
data := os.read_file(vmod_path) or { return }
|
||||
vmod := parse_vmod(data) or {
|
||||
vmod_ := parse_vmod(data) or {
|
||||
eprintln(err)
|
||||
return
|
||||
}
|
||||
minfo := mod_name_info(vmod.name)
|
||||
minfo := mod_name_info(vmod_.name)
|
||||
if final_module_path != minfo.final_module_path {
|
||||
println('Relocating module from "${name}" to "${vmod.name}" ( "${minfo.final_module_path}" ) ...')
|
||||
println('Relocating module from "${name}" to "${vmod_.name}" ( "${minfo.final_module_path}" ) ...')
|
||||
if os.exists(minfo.final_module_path) {
|
||||
eprintln('Warning module "${minfo.final_module_path}" already exsits!')
|
||||
eprintln('Removing module "${minfo.final_module_path}" ...')
|
||||
@ -330,10 +330,10 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
|
||||
}
|
||||
continue
|
||||
}
|
||||
println('Module "${name}" relocated to "${vmod.name}" successfully.')
|
||||
println('Module "${name}" relocated to "${vmod_.name}" successfully.')
|
||||
final_module_path = minfo.final_module_path
|
||||
}
|
||||
name = vmod.name
|
||||
name = vmod_.name
|
||||
}
|
||||
resolve_dependencies(name, final_module_path, module_names)
|
||||
}
|
||||
@ -646,13 +646,13 @@ fn resolve_dependencies(name string, module_path string, module_names []string)
|
||||
return
|
||||
}
|
||||
data := os.read_file(vmod_path) or { return }
|
||||
vmod := parse_vmod(data) or {
|
||||
vmod_ := parse_vmod(data) or {
|
||||
eprintln(err)
|
||||
return
|
||||
}
|
||||
mut deps := []string{}
|
||||
// filter out dependencies that were already specified by the user
|
||||
for d in vmod.deps {
|
||||
for d in vmod_.deps {
|
||||
if d !in module_names {
|
||||
deps << d
|
||||
}
|
||||
@ -666,11 +666,11 @@ fn resolve_dependencies(name string, module_path string, module_names []string)
|
||||
|
||||
fn parse_vmod(data string) !Vmod {
|
||||
manifest := vmod.decode(data) or { return error('Parsing v.mod file failed, ${err}') }
|
||||
mut vmod := Vmod{}
|
||||
vmod.name = manifest.name
|
||||
vmod.version = manifest.version
|
||||
vmod.deps = manifest.dependencies
|
||||
return vmod
|
||||
mut vmod_ := Vmod{}
|
||||
vmod_.name = manifest.name
|
||||
vmod_.version = manifest.version
|
||||
vmod_.deps = manifest.dependencies
|
||||
return vmod_
|
||||
}
|
||||
|
||||
fn get_working_server_url() string {
|
||||
|
@ -13,13 +13,13 @@ fn main() {
|
||||
fp.description('\nScan .v source files, and print the V tokens contained in them.')
|
||||
fp.arguments_description('PATH [PATH]...')
|
||||
fp.limit_free_args_to_at_least(1)!
|
||||
pref := pref.new_preferences()
|
||||
pref_ := pref.new_preferences()
|
||||
mut all_paths := fp.remaining_parameters()
|
||||
for path in all_paths {
|
||||
mut scanner := scanner.new_scanner_file(path, .parse_comments, pref)!
|
||||
mut scanner_ := scanner.new_scanner_file(path, .parse_comments, pref_)!
|
||||
mut tok := token.Token{}
|
||||
for tok.kind != .eof {
|
||||
tok = scanner.scan()
|
||||
tok = scanner_.scan()
|
||||
pos := tok.pos()
|
||||
location := '${path}:${pos.line_nr + 1}:${pos.col + 1}:'
|
||||
println('${location:-32} | pos: ${pos.pos:-5} | ${tok.debug()}')
|
||||
|
@ -1,5 +1,5 @@
|
||||
import db.sqlite
|
||||
import db.mysql
|
||||
import db.mysql as sql
|
||||
import db.pg
|
||||
|
||||
[table: 'modules']
|
||||
@ -74,7 +74,7 @@ fn sqlite3_array() {
|
||||
}
|
||||
|
||||
fn mysql_array() {
|
||||
mut db := mysql.Connection{
|
||||
mut db := sql.Connection{
|
||||
host: 'localhost'
|
||||
port: 3306
|
||||
username: 'root'
|
||||
@ -186,7 +186,7 @@ fn sqlite3() {
|
||||
}
|
||||
|
||||
fn mysql() {
|
||||
mut conn := mysql.Connection{
|
||||
mut conn := sql.Connection{
|
||||
host: 'localhost'
|
||||
port: 3306
|
||||
username: 'root'
|
||||
|
@ -1,15 +1,15 @@
|
||||
module deflate
|
||||
|
||||
import compress
|
||||
import compress as compr
|
||||
|
||||
// compresses an array of bytes using deflate and returns the compressed bytes in a new array
|
||||
// Example: compressed := deflate.compress(b)?
|
||||
pub fn compress(data []u8) ![]u8 {
|
||||
return compress.compress(data, 0)
|
||||
return compr.compress(data, 0)
|
||||
}
|
||||
|
||||
// decompresses an array of bytes using deflate and returns the decompressed bytes in a new array
|
||||
// Example: decompressed := deflate.decompress(b)?
|
||||
pub fn decompress(data []u8) ![]u8 {
|
||||
return compress.decompress(data, 0)
|
||||
return compr.decompress(data, 0)
|
||||
}
|
||||
|
@ -3,13 +3,13 @@
|
||||
|
||||
module gzip
|
||||
|
||||
import compress
|
||||
import compress as compr
|
||||
import hash.crc32
|
||||
|
||||
// compresses an array of bytes using gzip and returns the compressed bytes in a new array
|
||||
// Example: compressed := gzip.compress(b)?
|
||||
pub fn compress(data []u8) ![]u8 {
|
||||
compressed := compress.compress(data, 0)!
|
||||
compressed := compr.compress(data, 0)!
|
||||
// header
|
||||
mut result := [
|
||||
u8(0x1f), // magic numbers (1F 8B)
|
||||
@ -139,7 +139,7 @@ pub fn decompress(data []u8, params DecompressParams) ![]u8 {
|
||||
gzip_header := validate(data, params)!
|
||||
header_length := gzip_header.length
|
||||
|
||||
decompressed := compress.decompress(data[header_length..data.len - 8], 0)!
|
||||
decompressed := compr.decompress(data[header_length..data.len - 8], 0)!
|
||||
length_expected := (u32(data[data.len - 4]) << 24) | (u32(data[data.len - 3]) << 16) | (u32(data[data.len - 2]) << 8) | data[data.len - 1]
|
||||
if params.verify_length && decompressed.len != length_expected {
|
||||
return error('length verification failed, got ${decompressed.len}, expected ${length_expected}')
|
||||
|
@ -1,17 +1,17 @@
|
||||
module zlib
|
||||
|
||||
import compress
|
||||
import compress as compr
|
||||
|
||||
// compresses an array of bytes using zlib and returns the compressed bytes in a new array
|
||||
// Example: compressed := zlib.compress(b)?
|
||||
pub fn compress(data []u8) ![]u8 {
|
||||
// flags = TDEFL_WRITE_ZLIB_HEADER (0x01000)
|
||||
return compress.compress(data, 0x01000)
|
||||
return compr.compress(data, 0x01000)
|
||||
}
|
||||
|
||||
// decompresses an array of bytes using zlib and returns the decompressed bytes in a new array
|
||||
// Example: decompressed := zlib.decompress(b)?
|
||||
pub fn decompress(data []u8) ![]u8 {
|
||||
// flags = TINFL_FLAG_PARSE_ZLIB_HEADER (0x1)
|
||||
return compress.decompress(data, 0x1)
|
||||
return compr.decompress(data, 0x1)
|
||||
}
|
||||
|
@ -411,14 +411,14 @@ pub fn (mut rng PRNG) exponential(lambda f64) f64 {
|
||||
// optional and the entire array is shuffled by default. Leave the end as 0 to
|
||||
// shuffle all elements until the end.
|
||||
[direct_array_access]
|
||||
pub fn (mut rng PRNG) shuffle[T](mut a []T, config config.ShuffleConfigStruct) ! {
|
||||
config.validate_for(a)!
|
||||
new_end := if config.end == 0 { a.len } else { config.end }
|
||||
pub fn (mut rng PRNG) shuffle[T](mut a []T, config_ config.ShuffleConfigStruct) ! {
|
||||
config_.validate_for(a)!
|
||||
new_end := if config_.end == 0 { a.len } else { config_.end }
|
||||
|
||||
// We implement the Fisher-Yates shuffle:
|
||||
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
|
||||
|
||||
for i in config.start .. new_end - 2 {
|
||||
for i in config_.start .. new_end - 2 {
|
||||
x := rng.int_in_range(i, new_end) or { i }
|
||||
// swap
|
||||
a_i := a[i]
|
||||
@ -429,9 +429,9 @@ pub fn (mut rng PRNG) shuffle[T](mut a []T, config config.ShuffleConfigStruct) !
|
||||
|
||||
// shuffle_clone returns a random permutation of the elements in `a`.
|
||||
// The permutation is done on a fresh clone of `a`, so `a` remains unchanged.
|
||||
pub fn (mut rng PRNG) shuffle_clone[T](a []T, config config.ShuffleConfigStruct) ![]T {
|
||||
pub fn (mut rng PRNG) shuffle_clone[T](a []T, config_ config.ShuffleConfigStruct) ![]T {
|
||||
mut res := a.clone()
|
||||
rng.shuffle[T](mut res, config)!
|
||||
rng.shuffle[T](mut res, config_)!
|
||||
return res
|
||||
}
|
||||
|
||||
@ -475,10 +475,10 @@ __global default_rng &PRNG
|
||||
|
||||
// new_default returns a new instance of the default RNG. If the seed is not provided, the current time will be used to seed the instance.
|
||||
[manualfree]
|
||||
pub fn new_default(config config.PRNGConfigStruct) &PRNG {
|
||||
pub fn new_default(config_ config.PRNGConfigStruct) &PRNG {
|
||||
mut rng := &wyrand.WyRandRNG{}
|
||||
rng.seed(config.seed_)
|
||||
unsafe { config.seed_.free() }
|
||||
rng.seed(config_.seed_)
|
||||
unsafe { config_.seed_.free() }
|
||||
return &PRNG(rng)
|
||||
}
|
||||
|
||||
@ -680,14 +680,14 @@ pub fn ascii(len int) string {
|
||||
// shuffle randomly permutates the elements in `a`. The range for shuffling is
|
||||
// optional and the entire array is shuffled by default. Leave the end as 0 to
|
||||
// shuffle all elements until the end.
|
||||
pub fn shuffle[T](mut a []T, config config.ShuffleConfigStruct) ! {
|
||||
default_rng.shuffle[T](mut a, config)!
|
||||
pub fn shuffle[T](mut a []T, config_ config.ShuffleConfigStruct) ! {
|
||||
default_rng.shuffle[T](mut a, config_)!
|
||||
}
|
||||
|
||||
// shuffle_clone returns a random permutation of the elements in `a`.
|
||||
// The permutation is done on a fresh clone of `a`, so `a` remains unchanged.
|
||||
pub fn shuffle_clone[T](a []T, config config.ShuffleConfigStruct) ![]T {
|
||||
return default_rng.shuffle_clone[T](a, config)
|
||||
pub fn shuffle_clone[T](a []T, config_ config.ShuffleConfigStruct) ![]T {
|
||||
return default_rng.shuffle_clone[T](a, config_)
|
||||
}
|
||||
|
||||
// choose samples k elements from the array without replacement.
|
||||
@ -716,13 +716,13 @@ pub fn bernoulli(p f64) !bool {
|
||||
|
||||
// normal returns a normally distributed pseudorandom f64 in range `[0, 1)`.
|
||||
// NOTE: Use normal_pair() instead if you're generating a lot of normal variates.
|
||||
pub fn normal(conf config.NormalConfigStruct) !f64 {
|
||||
return default_rng.normal(conf)
|
||||
pub fn normal(config_ config.NormalConfigStruct) !f64 {
|
||||
return default_rng.normal(config_)
|
||||
}
|
||||
|
||||
// normal_pair returns a pair of normally distributed pseudorandom f64 in range `[0, 1)`.
|
||||
pub fn normal_pair(conf config.NormalConfigStruct) !(f64, f64) {
|
||||
return default_rng.normal_pair(conf)
|
||||
pub fn normal_pair(config_ config.NormalConfigStruct) !(f64, f64) {
|
||||
return default_rng.normal_pair(config_)
|
||||
}
|
||||
|
||||
// binomial returns the number of successful trials out of n when the
|
||||
|
@ -29,9 +29,9 @@ const (
|
||||
u64_iter_count = calculate_iterations_for(64)
|
||||
)
|
||||
|
||||
fn calculate_iterations_for(bits int) int {
|
||||
base := bits / sys.rand_bitsize
|
||||
extra := if bits % sys.rand_bitsize == 0 { 0 } else { 1 }
|
||||
fn calculate_iterations_for(bits_ int) int {
|
||||
base := bits_ / sys.rand_bitsize
|
||||
extra := if bits_ % sys.rand_bitsize == 0 { 0 } else { 1 }
|
||||
return base + extra
|
||||
}
|
||||
|
||||
|
@ -160,15 +160,15 @@ fn (mut p Parser) peek(n int) !token.Token {
|
||||
if n <= p.tokens.len {
|
||||
return p.tokens[n - 1]
|
||||
} else {
|
||||
mut token := token.Token{}
|
||||
mut token_ := token.Token{}
|
||||
mut count := n - p.tokens.len
|
||||
util.printdbg(@MOD + '.' + @STRUCT + '.' + @FN, 'buffering ${count} tokens...')
|
||||
for token.kind != .eof && count != 0 {
|
||||
token = p.scanner.scan()!
|
||||
p.tokens << token
|
||||
for token_.kind != .eof && count != 0 {
|
||||
token_ = p.scanner.scan()!
|
||||
p.tokens << token_
|
||||
count--
|
||||
}
|
||||
return token
|
||||
return token_
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,9 +84,9 @@ pub fn parse_file(path string) !Doc {
|
||||
scanner: scanner.new_scanner(scanner_config)!
|
||||
}
|
||||
mut p := parser.new_parser(parser_config)
|
||||
ast := p.parse()!
|
||||
ast_ := p.parse()!
|
||||
return Doc{
|
||||
ast: ast
|
||||
ast: ast_
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,9 +102,9 @@ pub fn parse_text(text string) !Doc {
|
||||
scanner: scanner.new_scanner(scanner_config)!
|
||||
}
|
||||
mut p := parser.new_parser(parser_config)
|
||||
ast := p.parse()!
|
||||
ast_ := p.parse()!
|
||||
return Doc{
|
||||
ast: ast
|
||||
ast: ast_
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,9 +122,9 @@ pub fn parse(toml string) !Doc {
|
||||
scanner: scanner.new_scanner(scanner_config)!
|
||||
}
|
||||
mut p := parser.new_parser(parser_config)
|
||||
ast := p.parse()!
|
||||
ast_ := p.parse()!
|
||||
return Doc{
|
||||
ast: ast
|
||||
ast: ast_
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ a new preference is created:
|
||||
```v
|
||||
import v.pref
|
||||
|
||||
pref := &pref.Preferences{}
|
||||
pref_ := &pref.Preferences{}
|
||||
```
|
||||
|
||||
and a new scope is created:
|
||||
|
@ -28,11 +28,11 @@ struct T08 {
|
||||
}
|
||||
|
||||
fn test_type_size() {
|
||||
mut pref := pref.new_preferences()
|
||||
mut pref_ := pref.new_preferences()
|
||||
$if x64 {
|
||||
pref.m64 = true
|
||||
pref_.m64 = true
|
||||
}
|
||||
mut b := builder.new_builder(pref)
|
||||
mut b := builder.new_builder(pref_)
|
||||
mut files := b.get_builtin_files()
|
||||
b.set_module_lookup_paths()
|
||||
parser.parse_files(files, b.table, b.pref)
|
||||
|
@ -46,22 +46,22 @@ pub mut:
|
||||
executable_exists bool // if the executable already exists, don't remove new executable after `v run`
|
||||
}
|
||||
|
||||
pub fn new_builder(pref &pref.Preferences) Builder {
|
||||
rdir := os.real_path(pref.path)
|
||||
pub fn new_builder(pref_ &pref.Preferences) Builder {
|
||||
rdir := os.real_path(pref_.path)
|
||||
compiled_dir := if os.is_dir(rdir) { rdir } else { os.dir(rdir) }
|
||||
mut table := ast.new_table()
|
||||
table.is_fmt = false
|
||||
if pref.use_color == .always {
|
||||
if pref_.use_color == .always {
|
||||
util.emanager.set_support_color(true)
|
||||
}
|
||||
if pref.use_color == .never {
|
||||
if pref_.use_color == .never {
|
||||
util.emanager.set_support_color(false)
|
||||
}
|
||||
table.pointer_size = if pref.m64 { 8 } else { 4 }
|
||||
table.pointer_size = if pref_.m64 { 8 } else { 4 }
|
||||
mut msvc := MsvcResult{}
|
||||
$if windows {
|
||||
msvc = find_msvc(pref.m64) or {
|
||||
if pref.ccompiler == 'msvc' {
|
||||
msvc = find_msvc(pref_.m64) or {
|
||||
if pref_.ccompiler == 'msvc' {
|
||||
// verror('cannot find MSVC on this OS')
|
||||
}
|
||||
MsvcResult{
|
||||
@ -69,19 +69,19 @@ pub fn new_builder(pref &pref.Preferences) Builder {
|
||||
}
|
||||
}
|
||||
}
|
||||
util.timing_set_should_print(pref.show_timings || pref.is_verbose)
|
||||
if pref.show_callgraph || pref.show_depgraph {
|
||||
util.timing_set_should_print(pref_.show_timings || pref_.is_verbose)
|
||||
if pref_.show_callgraph || pref_.show_depgraph {
|
||||
dotgraph.start_digraph()
|
||||
}
|
||||
mut executable_name := pref.out_name
|
||||
mut executable_name := pref_.out_name
|
||||
$if windows {
|
||||
executable_name += '.exe'
|
||||
}
|
||||
return Builder{
|
||||
pref: pref
|
||||
pref: pref_
|
||||
table: table
|
||||
checker: checker.new_checker(table, pref)
|
||||
transformer: transformer.new_transformer_with_table(table, pref)
|
||||
checker: checker.new_checker(table, pref_)
|
||||
transformer: transformer.new_transformer_with_table(table, pref_)
|
||||
compiled_dir: compiled_dir
|
||||
cached_msvc: msvc
|
||||
executable_exists: os.is_file(executable_name)
|
||||
|
@ -10,10 +10,10 @@ import v.checker
|
||||
|
||||
pub type FnBackend = fn (mut b Builder)
|
||||
|
||||
pub fn compile(command string, pref &pref.Preferences, backend_cb FnBackend) {
|
||||
check_if_output_folder_is_writable(pref)
|
||||
pub fn compile(command string, pref_ &pref.Preferences, backend_cb FnBackend) {
|
||||
check_if_output_folder_is_writable(pref_)
|
||||
// Construct the V object from command line arguments
|
||||
mut b := new_builder(pref)
|
||||
mut b := new_builder(pref_)
|
||||
if b.should_rebuild() {
|
||||
b.rebuild(backend_cb)
|
||||
}
|
||||
@ -23,12 +23,12 @@ pub fn compile(command string, pref &pref.Preferences, backend_cb FnBackend) {
|
||||
b.run_compiled_executable_and_exit()
|
||||
}
|
||||
|
||||
fn check_if_output_folder_is_writable(pref &pref.Preferences) {
|
||||
odir := os.dir(pref.out_name)
|
||||
fn check_if_output_folder_is_writable(pref_ &pref.Preferences) {
|
||||
odir := os.dir(pref_.out_name)
|
||||
// When pref.out_name is just the name of an executable, i.e. `./v -o executable main.v`
|
||||
// without a folder component, just use the current folder instead:
|
||||
mut output_folder := odir
|
||||
if odir.len == pref.out_name.len {
|
||||
if odir.len == pref_.out_name.len {
|
||||
output_folder = os.getwd()
|
||||
}
|
||||
os.ensure_folder_is_writable(output_folder) or {
|
||||
|
@ -7,11 +7,11 @@ import v.dotgraph
|
||||
|
||||
// callgraph.show walks the AST, starting at main() and prints a DOT output describing the calls
|
||||
// that function make transitively
|
||||
pub fn show(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.File) {
|
||||
pub fn show(mut table ast.Table, pref_ &pref.Preferences, ast_files []&ast.File) {
|
||||
mut mapper := &Mapper{
|
||||
pref: pref
|
||||
pref: pref_
|
||||
table: table
|
||||
dg: dotgraph.new('CallGraph', 'CallGraph for ${pref.path}', 'green')
|
||||
dg: dotgraph.new('CallGraph', 'CallGraph for ${pref_.path}', 'green')
|
||||
}
|
||||
// Node14 [shape="box",label="PrivateBase",URL="$classPrivateBase.html"];
|
||||
// Node15 -> Node9 [dir=back,color="midnightblue",fontsize=10,style="solid"];
|
||||
|
@ -312,7 +312,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||
}
|
||||
}
|
||||
// Check if variable name is already registered as imported module symbol
|
||||
if c.file.imports.any(it.mod == left.name) {
|
||||
if c.check_import_sym_conflict(left.name) {
|
||||
c.error('duplicate of an import symbol `${left.name}`', left.pos)
|
||||
}
|
||||
}
|
||||
|
@ -117,16 +117,16 @@ mut:
|
||||
goto_labels map[string]ast.GotoLabel // to check for unused goto labels
|
||||
}
|
||||
|
||||
pub fn new_checker(table &ast.Table, pref &pref.Preferences) &Checker {
|
||||
pub fn new_checker(table &ast.Table, pref_ &pref.Preferences) &Checker {
|
||||
mut timers_should_print := false
|
||||
$if time_checking ? {
|
||||
timers_should_print = true
|
||||
}
|
||||
return &Checker{
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
timers: util.new_timers(should_print: timers_should_print, label: 'checker')
|
||||
match_exhaustive_cutoff_limit: pref.checker_match_exhaustive_cutoff_limit
|
||||
match_exhaustive_cutoff_limit: pref_.checker_match_exhaustive_cutoff_limit
|
||||
}
|
||||
}
|
||||
|
||||
@ -4509,3 +4509,17 @@ fn (mut c Checker) deprecate_old_isreftype_and_sizeof_of_a_guessed_type(is_guess
|
||||
pos)
|
||||
}
|
||||
}
|
||||
|
||||
fn (c &Checker) check_import_sym_conflict(ident string) bool {
|
||||
for import_sym in c.file.imports {
|
||||
// Check if alias exists or not
|
||||
if !import_sym.alias.is_blank() {
|
||||
if import_sym.alias == ident {
|
||||
return true
|
||||
}
|
||||
} else if import_sym.mod == ident {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -249,6 +249,14 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if parameter name is already registered as imported module symbol
|
||||
if c.check_import_sym_conflict(param.name) {
|
||||
c.error('duplicate of an import symbol `${param.name}`', param.pos)
|
||||
}
|
||||
}
|
||||
// Check if function name is already registered as imported module symbol
|
||||
if !node.is_method && c.check_import_sym_conflict(node.short_name) {
|
||||
c.error('duplicate of an import symbol `${node.short_name}`', node.pos)
|
||||
}
|
||||
}
|
||||
if node.language == .v && node.name.after_char(`.`) == 'init' && !node.is_method
|
||||
|
80
vlib/v/checker/tests/fn_param_import_sym_conflict.out
Normal file
80
vlib/v/checker/tests/fn_param_import_sym_conflict.out
Normal file
@ -0,0 +1,80 @@
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:1:8: warning: module 'arrays' is imported but never used
|
||||
1 | import arrays
|
||||
| ~~~~~~
|
||||
2 | import maps
|
||||
3 | import strings as strs
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:2:8: warning: module 'maps' is imported but never used
|
||||
1 | import arrays
|
||||
2 | import maps
|
||||
| ~~~~
|
||||
3 | import strings as strs
|
||||
4 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:3:8: warning: module 'strs (strings)' is imported but never used
|
||||
1 | import arrays
|
||||
2 | import maps
|
||||
3 | import strings as strs
|
||||
| ~~~~~~~
|
||||
4 |
|
||||
5 | // FnDecl
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:6:6: error: duplicate of an import symbol `arrays`
|
||||
4 |
|
||||
5 | // FnDecl
|
||||
6 | fn x(arrays []int) {
|
||||
| ~~~~~~
|
||||
7 | }
|
||||
8 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:9:1: error: duplicate of an import symbol `maps`
|
||||
7 | }
|
||||
8 |
|
||||
9 | fn maps() {
|
||||
| ~~~~~~~~~
|
||||
10 | }
|
||||
11 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:12:9: error: duplicate of an import symbol `arrays`
|
||||
10 | }
|
||||
11 |
|
||||
12 | fn maps(arrays []int) {
|
||||
| ~~~~~~
|
||||
13 | }
|
||||
14 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:18:1: error: duplicate of an import symbol `strs`
|
||||
16 | }
|
||||
17 |
|
||||
18 | fn strs() {
|
||||
| ~~~~~~~~~
|
||||
19 | }
|
||||
20 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:24:5: error: duplicate of an import symbol `arrays`
|
||||
22 | struct Foo {}
|
||||
23 |
|
||||
24 | fn (arrays Foo) x() {
|
||||
| ~~~~~~
|
||||
25 | }
|
||||
26 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:27:5: error: duplicate of an import symbol `arrays`
|
||||
25 | }
|
||||
26 |
|
||||
27 | fn (arrays Foo) y(maps []int) {
|
||||
| ~~~~~~
|
||||
28 | }
|
||||
29 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:30:16: error: duplicate of an import symbol `arrays`
|
||||
28 | }
|
||||
29 |
|
||||
30 | fn (foo Foo) z(arrays []int) {
|
||||
| ~~~~~~
|
||||
31 | }
|
||||
32 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:33:5: error: duplicate of an import symbol `arrays`
|
||||
31 | }
|
||||
32 |
|
||||
33 | fn (arrays Foo) maps() {
|
||||
| ~~~~~~
|
||||
34 | }
|
||||
35 |
|
||||
vlib/v/checker/tests/fn_param_import_sym_conflict.vv:47:11: error: duplicate of an import symbol `arrays`
|
||||
45 | // AnonFn
|
||||
46 | fn y() {
|
||||
47 | _ := fn (arrays []int) {}
|
||||
| ~~~~~~
|
||||
48 | }
|
48
vlib/v/checker/tests/fn_param_import_sym_conflict.vv
Normal file
48
vlib/v/checker/tests/fn_param_import_sym_conflict.vv
Normal file
@ -0,0 +1,48 @@
|
||||
import arrays
|
||||
import maps
|
||||
import strings as strs
|
||||
|
||||
// FnDecl
|
||||
fn x(arrays []int) {
|
||||
}
|
||||
|
||||
fn maps() {
|
||||
}
|
||||
|
||||
fn maps(arrays []int) {
|
||||
}
|
||||
|
||||
fn strings() {
|
||||
}
|
||||
|
||||
fn strs() {
|
||||
}
|
||||
|
||||
// FnDecl with receiver
|
||||
struct Foo {}
|
||||
|
||||
fn (arrays Foo) x() {
|
||||
}
|
||||
|
||||
fn (arrays Foo) y(maps []int) {
|
||||
}
|
||||
|
||||
fn (foo Foo) z(arrays []int) {
|
||||
}
|
||||
|
||||
fn (arrays Foo) maps() {
|
||||
}
|
||||
|
||||
fn (foo Foo) arrays() {
|
||||
}
|
||||
|
||||
fn (foo Foo) strings() {
|
||||
}
|
||||
|
||||
fn (foo Foo) strs() {
|
||||
}
|
||||
|
||||
// AnonFn
|
||||
fn y() {
|
||||
_ := fn (arrays []int) {}
|
||||
}
|
@ -147,12 +147,12 @@ pub mut:
|
||||
pub fn new_vdoc_preferences() &pref.Preferences {
|
||||
// vdoc should be able to parse as much user code as possible
|
||||
// so its preferences should be permissive:
|
||||
mut pref := &pref.Preferences{
|
||||
mut pref_ := &pref.Preferences{
|
||||
enable_globals: true
|
||||
is_fmt: true
|
||||
}
|
||||
pref.fill_with_defaults()
|
||||
return pref
|
||||
pref_.fill_with_defaults()
|
||||
return pref_
|
||||
}
|
||||
|
||||
// new creates a new instance of a `Doc` struct.
|
||||
|
@ -7,10 +7,10 @@ import v.ast
|
||||
import v.pref
|
||||
import v.util
|
||||
|
||||
pub fn new_eval(table &ast.Table, pref &pref.Preferences) Eval {
|
||||
pub fn new_eval(table &ast.Table, pref_ &pref.Preferences) Eval {
|
||||
return Eval{
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,11 +61,11 @@ pub struct FmtOptions {
|
||||
source_text string
|
||||
}
|
||||
|
||||
pub fn fmt(file ast.File, table &ast.Table, pref &pref.Preferences, is_debug bool, options FmtOptions) string {
|
||||
pub fn fmt(file ast.File, table &ast.Table, pref_ &pref.Preferences, is_debug bool, options FmtOptions) string {
|
||||
mut f := Fmt{
|
||||
file: file
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
is_debug: is_debug
|
||||
out: strings.new_builder(1000)
|
||||
out_imports: strings.new_builder(200)
|
||||
|
@ -254,13 +254,13 @@ struct GlobalConstDef {
|
||||
is_precomputed bool // can be declared as a const in C: primitive, and a simple definition
|
||||
}
|
||||
|
||||
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string, string, string, []int) {
|
||||
pub fn gen(files []&ast.File, table &ast.Table, pref_ &pref.Preferences) (string, string, string, []int) {
|
||||
// println('start cgen2')
|
||||
mut module_built := ''
|
||||
if pref.build_mode == .build_module {
|
||||
if pref_.build_mode == .build_module {
|
||||
for file in files {
|
||||
if file.path.contains(pref.path)
|
||||
&& file.mod.short_name == pref.path.all_after_last(os.path_separator).trim_right(os.path_separator) {
|
||||
if file.path.contains(pref_.path)
|
||||
&& file.mod.short_name == pref_.path.all_after_last(os.path_separator).trim_right(os.path_separator) {
|
||||
module_built = file.mod.name
|
||||
break
|
||||
}
|
||||
@ -300,19 +300,19 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string,
|
||||
json_forward_decls: strings.new_builder(100)
|
||||
sql_buf: strings.new_builder(100)
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
fn_decl: 0
|
||||
is_autofree: pref.autofree
|
||||
is_autofree: pref_.autofree
|
||||
indent: -1
|
||||
module_built: module_built
|
||||
timers_should_print: timers_should_print
|
||||
timers: util.new_timers(should_print: timers_should_print, label: 'global_cgen')
|
||||
inner_loop: &ast.empty_stmt
|
||||
field_data_type: ast.Type(table.find_type_idx('FieldData'))
|
||||
is_cc_msvc: pref.ccompiler == 'msvc'
|
||||
use_segfault_handler: !('no_segfault_handler' in pref.compile_defines
|
||||
|| pref.os in [.wasm32, .wasm32_emscripten])
|
||||
static_modifier: if pref.parallel_cc { 'static' } else { '' }
|
||||
is_cc_msvc: pref_.ccompiler == 'msvc'
|
||||
use_segfault_handler: !('no_segfault_handler' in pref_.compile_defines
|
||||
|| pref_.os in [.wasm32, .wasm32_emscripten])
|
||||
static_modifier: if pref_.parallel_cc { 'static' } else { '' }
|
||||
has_reflection: 'v.reflection' in table.modules
|
||||
reflection_funcs: strings.new_builder(100)
|
||||
reflection_others: strings.new_builder(100)
|
||||
@ -330,7 +330,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string,
|
||||
*/
|
||||
// anon fn may include assert and thus this needs
|
||||
// to be included before any test contents are written
|
||||
if pref.is_test {
|
||||
if pref_.is_test {
|
||||
global_g.write_tests_definitions()
|
||||
}
|
||||
|
||||
@ -342,7 +342,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) (string,
|
||||
util.timing_measure('cgen init')
|
||||
global_g.tests_inited = false
|
||||
global_g.file = files.last()
|
||||
if !pref.no_parallel {
|
||||
if !pref_.no_parallel {
|
||||
util.timing_start('cgen parallel processing')
|
||||
mut pp := pool.new_pool_processor(callback: cgen_process_one_file_cb)
|
||||
pp.set_shared_context(global_g) // TODO: make global_g shared
|
||||
|
@ -61,9 +61,9 @@ static inline void __sort_ptr(uintptr_t a[], bool b[], int l) {
|
||||
// Inspired from Chris Wellons's work
|
||||
// https://nullprogram.com/blog/2017/01/08/
|
||||
|
||||
fn c_closure_helpers(pref &pref.Preferences) string {
|
||||
fn c_closure_helpers(pref_ &pref.Preferences) string {
|
||||
mut builder := strings.new_builder(2048)
|
||||
if pref.os != .windows {
|
||||
if pref_.os != .windows {
|
||||
builder.writeln('#include <sys/mman.h>')
|
||||
}
|
||||
|
||||
|
@ -45,10 +45,10 @@ pub mut:
|
||||
nlines int
|
||||
}
|
||||
|
||||
pub fn gen(files []&ast.File, table &ast.Table, out_file string, pref &pref.Preferences) (int, int) {
|
||||
pub fn gen(files []&ast.File, table &ast.Table, out_file string, pref_ &pref.Preferences) (int, int) {
|
||||
mut g := Gen{
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
// is_debug: is_debug
|
||||
out: strings.new_builder(1000)
|
||||
out_imports: strings.new_builder(200)
|
||||
|
@ -100,11 +100,11 @@ fn (mut g JsGen) write_tests_definitions() {
|
||||
g.definitions.writeln('globalThis.g_test_fails = 0;')
|
||||
}
|
||||
|
||||
pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||
pub fn gen(files []&ast.File, table &ast.Table, pref_ &pref.Preferences) string {
|
||||
mut g := &JsGen{
|
||||
definitions: strings.new_builder(100)
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
fn_decl: 0
|
||||
empty_line: true
|
||||
doc: 0
|
||||
@ -115,7 +115,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||
}
|
||||
g.doc = new_jsdoc(g)
|
||||
// TODO: Add '[-no]-jsdoc' flag
|
||||
if pref.is_prod {
|
||||
if g.pref.is_prod {
|
||||
g.enable_doc = false
|
||||
g.is_vlines_enabled = false
|
||||
}
|
||||
|
@ -223,8 +223,8 @@ fn get_backend(arch pref.Arch) !CodeGen {
|
||||
return error('unsupported architecture')
|
||||
}
|
||||
|
||||
pub fn gen(files []&ast.File, table &ast.Table, out_name string, pref &pref.Preferences) (int, int) {
|
||||
exe_name := if pref.os == .windows && !out_name.ends_with('.exe') {
|
||||
pub fn gen(files []&ast.File, table &ast.Table, out_name string, pref_ &pref.Preferences) (int, int) {
|
||||
exe_name := if pref_.os == .windows && !out_name.ends_with('.exe') {
|
||||
out_name + '.exe'
|
||||
} else {
|
||||
out_name
|
||||
@ -233,16 +233,16 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, pref &pref.Pref
|
||||
table: table
|
||||
sect_header_name_pos: 0
|
||||
out_name: exe_name
|
||||
pref: pref
|
||||
pref: pref_
|
||||
files: files
|
||||
// TODO: workaround, needs to support recursive init
|
||||
code_gen: get_backend(pref.arch) or {
|
||||
code_gen: get_backend(pref_.arch) or {
|
||||
eprintln('No available backend for this configuration. Use `-a arm64` or `-a amd64`.')
|
||||
exit(1)
|
||||
}
|
||||
labels: 0
|
||||
structs: []Struct{len: table.type_symbols.len}
|
||||
eval: eval.new_eval(table, pref)
|
||||
eval: eval.new_eval(table, pref_)
|
||||
}
|
||||
g.code_gen.g = g
|
||||
g.generate_header()
|
||||
|
@ -7,7 +7,7 @@ import v.util
|
||||
import v.pref
|
||||
|
||||
// mark_used walks the AST, starting at main() and marks all used fns transitively
|
||||
pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.File) {
|
||||
pub fn mark_used(mut table ast.Table, pref_ &pref.Preferences, ast_files []&ast.File) {
|
||||
mut all_fns, all_consts, all_globals := all_fn_const_and_global(ast_files)
|
||||
util.timing_start(@METHOD)
|
||||
defer {
|
||||
@ -126,7 +126,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
'v.embed_file.find_index_entry_by_path',
|
||||
]
|
||||
|
||||
if pref.is_bare {
|
||||
if pref_.is_bare {
|
||||
all_fn_root_names << [
|
||||
'strlen',
|
||||
'memcmp',
|
||||
@ -137,7 +137,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
]
|
||||
}
|
||||
|
||||
is_noscan_whitelisted := pref.gc_mode in [.boehm_full_opt, .boehm_incr_opt]
|
||||
is_noscan_whitelisted := pref_.gc_mode in [.boehm_full_opt, .boehm_incr_opt]
|
||||
|
||||
for k, mut mfn in all_fns {
|
||||
$if trace_skip_unused_all_fns ? {
|
||||
@ -186,7 +186,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
all_fn_root_names << k
|
||||
continue
|
||||
}
|
||||
if pref.is_prof {
|
||||
if pref_.is_prof {
|
||||
if k.starts_with('time.vpc_now') || k.starts_with('v.profile.') {
|
||||
// needed for -profile
|
||||
all_fn_root_names << k
|
||||
@ -210,7 +210,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
continue
|
||||
}
|
||||
// testing framework:
|
||||
if pref.is_test {
|
||||
if pref_.is_test {
|
||||
if k.starts_with('test_') || k.contains('.test_') {
|
||||
all_fn_root_names << k
|
||||
continue
|
||||
@ -223,7 +223,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
}
|
||||
// public/exported functions can not be skipped,
|
||||
// especially when producing a shared library:
|
||||
if mfn.is_pub && pref.is_shared {
|
||||
if mfn.is_pub && pref_.is_shared {
|
||||
all_fn_root_names << k
|
||||
continue
|
||||
}
|
||||
@ -232,19 +232,19 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
all_fn_root_names << k
|
||||
continue
|
||||
}
|
||||
if pref.prealloc && k.starts_with('prealloc_') {
|
||||
if pref_.prealloc && k.starts_with('prealloc_') {
|
||||
all_fn_root_names << k
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// handle assertions and testing framework callbacks:
|
||||
if pref.is_debug {
|
||||
if pref_.is_debug {
|
||||
all_fn_root_names << 'panic_debug'
|
||||
}
|
||||
all_fn_root_names << 'panic_option_not_set'
|
||||
all_fn_root_names << 'panic_result_not_set'
|
||||
if pref.is_test {
|
||||
if pref_.is_test {
|
||||
all_fn_root_names << 'main.cb_assertion_ok'
|
||||
all_fn_root_names << 'main.cb_assertion_failed'
|
||||
if benched_tests_sym := table.find_sym('main.BenchedTests') {
|
||||
@ -333,7 +333,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
}
|
||||
|
||||
// handle -live main programs:
|
||||
if pref.is_livemain {
|
||||
if pref_.is_livemain {
|
||||
all_fn_root_names << 'v.live.executable.start_reloader'
|
||||
all_fn_root_names << 'v.live.executable.new_live_reload_info'
|
||||
}
|
||||
@ -344,7 +344,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
all_fns: all_fns
|
||||
all_consts: all_consts
|
||||
all_globals: all_globals
|
||||
pref: pref
|
||||
pref: pref_
|
||||
}
|
||||
// println( all_fns.keys() )
|
||||
walker.mark_markused_fns() // tagged with `[markused]`
|
||||
@ -367,7 +367,7 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
|| k.starts_with('map_') {
|
||||
walker.fn_decl(mut mfn)
|
||||
}
|
||||
if pref.gc_mode in [.boehm_full_opt, .boehm_incr_opt] {
|
||||
if pref_.gc_mode in [.boehm_full_opt, .boehm_incr_opt] {
|
||||
if k in ['new_map_noscan_key', 'new_map_noscan_value', 'new_map_noscan_key_value',
|
||||
'new_map_init_noscan_key', 'new_map_init_noscan_value',
|
||||
'new_map_init_noscan_key_value'] {
|
||||
@ -397,10 +397,10 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||
}
|
||||
|
||||
for kcon, con in all_consts {
|
||||
if pref.is_shared && con.is_pub {
|
||||
if pref_.is_shared && con.is_pub {
|
||||
walker.mark_const_as_used(kcon)
|
||||
}
|
||||
if !pref.is_shared && con.is_pub && con.name.starts_with('main.') {
|
||||
if !pref_.is_shared && con.is_pub && con.name.starts_with('main.') {
|
||||
walker.mark_const_as_used(kcon)
|
||||
}
|
||||
}
|
||||
|
@ -126,15 +126,15 @@ pub fn parse_stmt(text string, table &ast.Table, scope &ast.Scope) ast.Stmt {
|
||||
return p.stmt(false)
|
||||
}
|
||||
|
||||
pub fn parse_comptime(tmpl_path string, text string, table &ast.Table, pref &pref.Preferences, scope &ast.Scope) &ast.File {
|
||||
pub fn parse_comptime(tmpl_path string, text string, table &ast.Table, pref_ &pref.Preferences, scope &ast.Scope) &ast.File {
|
||||
$if trace_parse_comptime ? {
|
||||
eprintln('> ${@MOD}.${@FN} text: ${text}')
|
||||
}
|
||||
mut p := Parser{
|
||||
file_name: tmpl_path
|
||||
scanner: scanner.new_scanner(text, .skip_comments, pref)
|
||||
scanner: scanner.new_scanner(text, .skip_comments, pref_)
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
scope: scope
|
||||
errors: []errors.Error{}
|
||||
warnings: []errors.Warning{}
|
||||
@ -144,15 +144,15 @@ pub fn parse_comptime(tmpl_path string, text string, table &ast.Table, pref &pre
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn parse_text(text string, path string, table &ast.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences) &ast.File {
|
||||
pub fn parse_text(text string, path string, table &ast.Table, comments_mode scanner.CommentsMode, pref_ &pref.Preferences) &ast.File {
|
||||
$if trace_parse_text ? {
|
||||
eprintln('> ${@MOD}.${@FN} comments_mode: ${comments_mode:-20} | path: ${path:-20} | text: ${text}')
|
||||
}
|
||||
mut p := Parser{
|
||||
scanner: scanner.new_scanner(text, comments_mode, pref)
|
||||
scanner: scanner.new_scanner(text, comments_mode, pref_)
|
||||
comments_mode: comments_mode
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
scope: &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: table.global_scope
|
||||
@ -222,7 +222,7 @@ pub fn (mut p Parser) set_path(path string) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_file(path string, table &ast.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences) &ast.File {
|
||||
pub fn parse_file(path string, table &ast.Table, comments_mode scanner.CommentsMode, pref_ &pref.Preferences) &ast.File {
|
||||
// Note: when comments_mode == .toplevel_comments,
|
||||
// the parser gives feedback to the scanner about toplevel statements, so that the scanner can skip
|
||||
// all the tricky inner comments. This is needed because we do not have a good general solution
|
||||
@ -231,10 +231,10 @@ pub fn parse_file(path string, table &ast.Table, comments_mode scanner.CommentsM
|
||||
eprintln('> ${@MOD}.${@FN} comments_mode: ${comments_mode:-20} | path: ${path}')
|
||||
}
|
||||
mut p := Parser{
|
||||
scanner: scanner.new_scanner_file(path, comments_mode, pref) or { panic(err) }
|
||||
scanner: scanner.new_scanner_file(path, comments_mode, pref_) or { panic(err) }
|
||||
comments_mode: comments_mode
|
||||
table: table
|
||||
pref: pref
|
||||
pref: pref_
|
||||
scope: &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: table.global_scope
|
||||
@ -248,7 +248,7 @@ pub fn parse_file(path string, table &ast.Table, comments_mode scanner.CommentsM
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn parse_vet_file(path string, table_ &ast.Table, pref &pref.Preferences) (&ast.File, []vet.Error) {
|
||||
pub fn parse_vet_file(path string, table_ &ast.Table, pref_ &pref.Preferences) (&ast.File, []vet.Error) {
|
||||
$if trace_parse_vet_file ? {
|
||||
eprintln('> ${@MOD}.${@FN} path: ${path}')
|
||||
}
|
||||
@ -256,10 +256,10 @@ pub fn parse_vet_file(path string, table_ &ast.Table, pref &pref.Preferences) (&
|
||||
parent: 0
|
||||
}
|
||||
mut p := Parser{
|
||||
scanner: scanner.new_scanner_file(path, .parse_comments, pref) or { panic(err) }
|
||||
scanner: scanner.new_scanner_file(path, .parse_comments, pref_) or { panic(err) }
|
||||
comments_mode: .parse_comments
|
||||
table: table_
|
||||
pref: pref
|
||||
pref: pref_
|
||||
scope: &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: global_scope
|
||||
@ -335,12 +335,12 @@ pub fn (mut p Parser) parse() &ast.File {
|
||||
}
|
||||
p.scope.end_pos = p.tok.pos
|
||||
|
||||
mut errors := p.errors.clone()
|
||||
mut errors_ := p.errors.clone()
|
||||
mut warnings := p.warnings.clone()
|
||||
mut notices := p.notices.clone()
|
||||
|
||||
if p.pref.check_only {
|
||||
errors << p.scanner.errors
|
||||
errors_ << p.scanner.errors
|
||||
warnings << p.scanner.warnings
|
||||
notices << p.scanner.notices
|
||||
}
|
||||
@ -366,7 +366,7 @@ pub fn (mut p Parser) parse() &ast.File {
|
||||
stmts: stmts
|
||||
scope: p.scope
|
||||
global_scope: p.table.global_scope
|
||||
errors: errors
|
||||
errors: errors_
|
||||
warnings: warnings
|
||||
notices: notices
|
||||
global_labels: p.global_labels
|
||||
@ -406,7 +406,7 @@ fn (mut q Queue) run() {
|
||||
}
|
||||
}
|
||||
*/
|
||||
pub fn parse_files(paths []string, table &ast.Table, pref &pref.Preferences) []&ast.File {
|
||||
pub fn parse_files(paths []string, table &ast.Table, pref_ &pref.Preferences) []&ast.File {
|
||||
mut timers := util.new_timers(should_print: false, label: 'parse_files: ${paths}')
|
||||
$if time_parsing ? {
|
||||
timers.should_print = true
|
||||
@ -438,7 +438,7 @@ pub fn parse_files(paths []string, table &ast.Table, pref &pref.Preferences) []&
|
||||
mut files := []&ast.File{cap: paths.len}
|
||||
for path in paths {
|
||||
timers.start('parse_file ${path}')
|
||||
files << parse_file(path, table, .skip_comments, pref)
|
||||
files << parse_file(path, table, .skip_comments, pref_)
|
||||
timers.show('parse_file ${path}')
|
||||
}
|
||||
if codegen_files.len > 0 {
|
||||
|
@ -77,8 +77,8 @@ x := 10
|
||||
table := ast.new_table()
|
||||
vpref := &pref.Preferences{}
|
||||
prog := parse_file(s, table, .skip_comments, vpref)
|
||||
mut checker := checker.new_checker(table, vpref)
|
||||
checker.check(prog)
|
||||
mut checker_ := checker.new_checker(table, vpref)
|
||||
checker_.check(prog)
|
||||
res, _, _, _ := c.gen([prog], table, vpref)
|
||||
println(res)
|
||||
}
|
||||
@ -105,8 +105,8 @@ fn test_one() {
|
||||
scope: scope
|
||||
global_scope: scope
|
||||
}
|
||||
mut checker := checker.new_checker(table, vpref)
|
||||
checker.check(program)
|
||||
mut checker_ := checker.new_checker(table, vpref)
|
||||
checker_.check(program)
|
||||
mut res, _, _, _ := c.gen([program], table, vpref)
|
||||
res = res.replace('\n', '').trim_space().after('#endif')
|
||||
println(res)
|
||||
|
@ -106,19 +106,19 @@ pub enum CommentsMode {
|
||||
}
|
||||
|
||||
// new scanner from file.
|
||||
pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref &pref.Preferences) !&Scanner {
|
||||
pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref_ &pref.Preferences) !&Scanner {
|
||||
if !os.is_file(file_path) {
|
||||
return error('${file_path} is not a .v file')
|
||||
}
|
||||
raw_text := util.read_file(file_path) or { return err }
|
||||
mut s := &Scanner{
|
||||
pref: pref
|
||||
pref: pref_
|
||||
text: raw_text
|
||||
all_tokens: []token.Token{cap: raw_text.len / 3}
|
||||
is_print_line_on_error: true
|
||||
is_print_colored_error: true
|
||||
is_print_rel_paths_on_error: true
|
||||
is_fmt: pref.is_fmt
|
||||
is_fmt: pref_.is_fmt
|
||||
comments_mode: comments_mode
|
||||
file_path: file_path
|
||||
file_base: os.base(file_path)
|
||||
@ -128,15 +128,15 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref &pref
|
||||
}
|
||||
|
||||
// new scanner from string.
|
||||
pub fn new_scanner(text string, comments_mode CommentsMode, pref &pref.Preferences) &Scanner {
|
||||
pub fn new_scanner(text string, comments_mode CommentsMode, pref_ &pref.Preferences) &Scanner {
|
||||
mut s := &Scanner{
|
||||
pref: pref
|
||||
pref: pref_
|
||||
text: text
|
||||
all_tokens: []token.Token{cap: text.len / 3}
|
||||
is_print_line_on_error: true
|
||||
is_print_colored_error: true
|
||||
is_print_rel_paths_on_error: true
|
||||
is_fmt: pref.is_fmt
|
||||
is_fmt: pref_.is_fmt
|
||||
comments_mode: comments_mode
|
||||
file_path: 'internal_memory'
|
||||
file_base: 'internal_memory'
|
||||
|
@ -71,14 +71,14 @@ pub fn run_repl_file(wd string, vexec string, file string) !string {
|
||||
file_expected := '${file}.expected.txt'
|
||||
os.write_file(file_result, result) or { panic(err) }
|
||||
os.write_file(file_expected, output) or { panic(err) }
|
||||
diff := diff_files(file_expected, file_result)
|
||||
diff_ := diff_files(file_expected, file_result)
|
||||
return error('Difference found in REPL file: ${file}
|
||||
====> Expected :
|
||||
|${output}|
|
||||
====> Got :
|
||||
|${result}|
|
||||
====> Diff :
|
||||
${diff}
|
||||
${diff_}
|
||||
')
|
||||
} else {
|
||||
return file.replace('./', '')
|
||||
@ -103,14 +103,14 @@ pub fn run_prod_file(wd string, vexec string, file string) !string {
|
||||
if result != expected_content {
|
||||
file_result := '${file}.result.txt'
|
||||
os.write_file(file_result, result) or { panic(err) }
|
||||
diff := diff_files(file_result, file_expected)
|
||||
diff_ := diff_files(file_result, file_expected)
|
||||
return error('Difference found in test: ${file}
|
||||
====> Got :
|
||||
|${result}|
|
||||
====> Expected :
|
||||
|${expected_content}|
|
||||
====> Diff :
|
||||
${diff}
|
||||
${diff_}
|
||||
')
|
||||
} else {
|
||||
return 'Prod file ${file} is OK'
|
||||
|
@ -171,20 +171,20 @@ fn test_cross_assign_of_big_int() {
|
||||
|
||||
fn test_cross_assign_of_reserved_name_variable() {
|
||||
mut small := 1
|
||||
mut big := 2
|
||||
mut big_ := 2
|
||||
mut sum := 2
|
||||
|
||||
for big < 4_000_000 {
|
||||
small, big = big, small + big
|
||||
if big % 2 == 0 {
|
||||
sum += big
|
||||
for big_ < 4_000_000 {
|
||||
small, big_ = big_, small + big_
|
||||
if big_ % 2 == 0 {
|
||||
sum += big_
|
||||
}
|
||||
}
|
||||
println(small)
|
||||
assert small == 3524578
|
||||
|
||||
println(big)
|
||||
assert big == 5702887
|
||||
println(big_)
|
||||
assert big_ == 5702887
|
||||
|
||||
println(sum)
|
||||
assert sum == 4613732
|
||||
|
@ -1,8 +1,8 @@
|
||||
import time
|
||||
|
||||
struct Game {
|
||||
update fn (mut time.Time) = fn (mut time time.Time) {}
|
||||
draw fn (mut time.Time) = fn (mut time time.Time) {}
|
||||
update fn (mut time.Time) = fn (mut time_ time.Time) {}
|
||||
draw fn (mut time.Time) = fn (mut time_ time.Time) {}
|
||||
mut:
|
||||
time time.Time
|
||||
}
|
||||
|
@ -9,13 +9,13 @@ fn test_main() {
|
||||
}
|
||||
assert 'main' == main.a
|
||||
|
||||
test := test.Test{
|
||||
test_ := test.Test{
|
||||
a: 'test'
|
||||
}
|
||||
assert 'test' == test.a
|
||||
assert 'test' == test_.a
|
||||
|
||||
test2 := test2.Test2{
|
||||
test2_ := test2.Test2{
|
||||
a: 'test2'
|
||||
}
|
||||
assert 'test2' == test2.a
|
||||
assert 'test2' == test2_.a
|
||||
}
|
||||
|
@ -42,14 +42,14 @@ fn server() ! {
|
||||
return true
|
||||
})!
|
||||
|
||||
s.on_message(fn (mut ws ws.Client, msg &RawMessage) ! {
|
||||
s.on_message(fn (mut ws_ ws.Client, msg &RawMessage) ! {
|
||||
mut transport := WsTransport{}
|
||||
mut ws_client := new_ws_client(transport)!
|
||||
_ := ws_client
|
||||
})
|
||||
|
||||
s.on_close(fn (mut ws ws.Client, code int, reason string) ! {
|
||||
println('client (${ws.id}) closed connection')
|
||||
s.on_close(fn (mut ws_ ws.Client, code int, reason string) ! {
|
||||
println('client (${ws_.id}) closed connection')
|
||||
})
|
||||
|
||||
s.listen() or { println('error on server listen: ${err}') }
|
||||
|
@ -13,9 +13,9 @@ mut:
|
||||
is_assert bool
|
||||
}
|
||||
|
||||
pub fn new_transformer(pref &pref.Preferences) &Transformer {
|
||||
pub fn new_transformer(pref_ &pref.Preferences) &Transformer {
|
||||
return &Transformer{
|
||||
pref: pref
|
||||
pref: pref_
|
||||
index: &IndexState{
|
||||
saved_key_vals: [][]KeyVal{cap: 1000}
|
||||
saved_disabled: []bool{cap: 1000}
|
||||
@ -23,8 +23,8 @@ pub fn new_transformer(pref &pref.Preferences) &Transformer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_transformer_with_table(table &ast.Table, pref &pref.Preferences) &Transformer {
|
||||
mut transformer := new_transformer(pref)
|
||||
pub fn new_transformer_with_table(table &ast.Table, pref_ &pref.Preferences) &Transformer {
|
||||
mut transformer := new_transformer(pref_)
|
||||
transformer.table = table
|
||||
return transformer
|
||||
}
|
||||
|
@ -16,22 +16,22 @@ fn trace_qualify(callfn string, mod string, file_path string, kind_res string, r
|
||||
// 2022-01-30 TODO: this seems to always just return `mod` itself, for modules inside the V main folder.
|
||||
// 2022-01-30 It does also return `mod` itself, for stuff installed in ~/.vmodules like `vls` but for
|
||||
// 2022-01-30 other reasons (see res 2 below).
|
||||
pub fn qualify_import(pref &pref.Preferences, mod string, file_path string) string {
|
||||
pub fn qualify_import(pref_ &pref.Preferences, mod string, file_path string) string {
|
||||
// comments are from workdir: /v/vls
|
||||
mut mod_paths := pref.lookup_path.clone()
|
||||
mut mod_paths := pref_.lookup_path.clone()
|
||||
mod_paths << os.vmodules_paths()
|
||||
mod_path := mod.replace('.', os.path_separator)
|
||||
for search_path in mod_paths {
|
||||
try_path := os.join_path_single(search_path, mod_path)
|
||||
if os.is_dir(try_path) {
|
||||
if m1 := mod_path_to_full_name(pref, mod, try_path) {
|
||||
if m1 := mod_path_to_full_name(pref_, mod, try_path) {
|
||||
trace_qualify(@FN, mod, file_path, 'import_res 1', m1, try_path)
|
||||
// > qualify_import: term | file_path: /v/vls/server/diagnostics.v | => import_res 1: term ; /v/cleanv/vlib/term
|
||||
return m1
|
||||
}
|
||||
}
|
||||
}
|
||||
if m1 := mod_path_to_full_name(pref, mod, file_path) {
|
||||
if m1 := mod_path_to_full_name(pref_, mod, file_path) {
|
||||
trace_qualify(@FN, mod, file_path, 'import_res 2', m1, file_path)
|
||||
// > qualify_module: analyzer | file_path: /v/vls/analyzer/store.v | => module_res 2: analyzer ; clean_file_path - getwd == mod
|
||||
// > qualify_import: analyzer.depgraph | file_path: /v/vls/analyzer/store.v | => import_res 2: analyzer.depgraph ; /v/vls/analyzer/store.v
|
||||
@ -51,7 +51,7 @@ pub fn qualify_import(pref &pref.Preferences, mod string, file_path string) stri
|
||||
// 2022-01-30 qualify_module - used by V's parser to find the full module name
|
||||
// 2022-01-30 i.e. when parsing `module textscanner`, inside vlib/strings/textscanner/textscanner.v
|
||||
// 2022-01-30 it will return `strings.textscanner`
|
||||
pub fn qualify_module(pref &pref.Preferences, mod string, file_path string) string {
|
||||
pub fn qualify_module(pref_ &pref.Preferences, mod string, file_path string) string {
|
||||
if mod == 'main' {
|
||||
trace_qualify(@FN, mod, file_path, 'module_res 1', mod, 'main')
|
||||
return mod
|
||||
@ -68,7 +68,7 @@ pub fn qualify_module(pref &pref.Preferences, mod string, file_path string) stri
|
||||
trace_qualify(@FN, mod, file_path, 'module_res 2', mod, 'clean_file_path - getwd == mod, clean_file_path: ${clean_file_path}')
|
||||
return mod
|
||||
}
|
||||
if m1 := mod_path_to_full_name(pref, mod, clean_file_path) {
|
||||
if m1 := mod_path_to_full_name(pref_, mod, clean_file_path) {
|
||||
trace_qualify(@FN, mod, file_path, 'module_res 3', m1, 'm1 == f(${clean_file_path})')
|
||||
// > qualify_module: net | file_path: /v/cleanv/vlib/net/util.v | => module_res 3: net ; m1 == f(/v/cleanv/vlib/net)
|
||||
// > qualify_module: term | file_path: /v/cleanv/vlib/term/control.v | => module_res 3: term ; m1 == f(/v/cleanv/vlib/term)
|
||||
@ -96,11 +96,11 @@ pub fn qualify_module(pref &pref.Preferences, mod string, file_path string) stri
|
||||
// 2022-01-30 just on windows, because while `vlib\v\checker\tests\modules\deprecated_module` works,
|
||||
// 2022-01-30 it leads to path differences, and the / version on windows triggers a module lookip bug,
|
||||
// 2022-01-30 leading to completely different errors)
|
||||
fn mod_path_to_full_name(pref &pref.Preferences, mod string, path string) !string {
|
||||
fn mod_path_to_full_name(pref_ &pref.Preferences, mod string, path string) !string {
|
||||
// TODO: explore using `pref.lookup_path` & `os.vmodules_paths()`
|
||||
// absolute paths instead of 'vlib' & '.vmodules'
|
||||
mut vmod_folders := ['vlib', '.vmodules', 'modules']
|
||||
bases := pref.lookup_path.map(os.base(it))
|
||||
bases := pref_.lookup_path.map(os.base(it))
|
||||
for base in bases {
|
||||
if base !in vmod_folders {
|
||||
vmod_folders << base
|
||||
@ -157,8 +157,8 @@ fn mod_path_to_full_name(pref &pref.Preferences, mod string, path string) !strin
|
||||
}
|
||||
}
|
||||
}
|
||||
if os.is_abs_path(pref.path) && os.is_abs_path(path) && os.is_dir(path) { // && path.contains(mod )
|
||||
rel_mod_path := path.replace(pref.path.all_before_last(os.path_separator) +
|
||||
if os.is_abs_path(pref_.path) && os.is_abs_path(path) && os.is_dir(path) { // && path.contains(mod )
|
||||
rel_mod_path := path.replace(pref_.path.all_before_last(os.path_separator) +
|
||||
os.path_separator, '')
|
||||
if rel_mod_path != path {
|
||||
full_mod_name := rel_mod_path.replace(os.path_separator, '.')
|
||||
|
Loading…
Reference in New Issue
Block a user