1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

remove duplication by using a new Preferences struct

This commit is contained in:
Archan Patkar 2019-07-01 01:33:17 +05:30 committed by Alexander Medvednikov
parent 42a622c10f
commit 74d234f8cd
4 changed files with 163 additions and 160 deletions

View File

@ -95,7 +95,7 @@ fn (f mut Fn) clear_vars() {
// vlib header file?
fn (p mut Parser) is_sig() bool {
return (p.build_mode == DEFAULT_MODE || p.build_mode == BUILD) &&
return (p.pref.build_mode == DEFAULT_MODE || p.pref.build_mode == BUILD) &&
(p.file_path.contains(TmpPath))
}
@ -173,8 +173,8 @@ fn (p mut Parser) fn_decl() {
// C function header def? (fn C.NSMakeRect(int,int,int,int))
is_c := f.name == 'C' && p.tok == DOT
// Just fn signature? only builtin.v + default build mode
// is_sig := p.builtin_pkg && p.build_mode == DEFAULT_MODE
// is_sig := p.build_mode == DEFAULT_MODE && (p.builtin_pkg || p.file.contains(LANG_TMP))
// is_sig := p.builtin_pkg && p.pref.build_mode == DEFAULT_MODE
// is_sig := p.pref.build_mode == DEFAULT_MODE && (p.builtin_pkg || p.file.contains(LANG_TMP))
is_sig := p.is_sig()
// println('\n\nfn decl !!is_sig=$is_sig name=$f.name $p.builtin_pkg')
if is_c {
@ -182,7 +182,7 @@ fn (p mut Parser) fn_decl() {
f.name = p.check_name()
f.is_c = true
}
else if !p.translated && !p.file_path.contains('view.v') {
else if !p.pref.translated && !p.file_path.contains('view.v') {
if contains_capital(f.name) {
p.error('function names cannot contain uppercase letters, use snake_case instead')
}
@ -237,7 +237,7 @@ fn (p mut Parser) fn_decl() {
typ = p.get_type()
}
// Translated C code can have empty functions (just definitions)
is_fn_header := !is_c && !is_sig && (p.translated || p.is_test) &&
is_fn_header := !is_c && !is_sig && (p.pref.translated || p.pref.is_test) &&
(p.tok != LCBR)// || (p.tok == NAME && p.peek() != LCBR))
if is_fn_header {
f.is_decl = true
@ -274,10 +274,10 @@ fn (p mut Parser) fn_decl() {
// }
mut fn_name_cgen := p.table.cgen_name(f)
// Start generation of the function body
is_live := p.is_live && f.name != 'main' && f.name != 'reload_so'
skip_main_in_test := f.name == 'main' && p.is_test
is_live := p.pref.is_live && f.name != 'main' && f.name != 'reload_so'
skip_main_in_test := f.name == 'main' && p.pref.is_test
if !is_c && !is_live && !is_sig && !is_fn_header && !skip_main_in_test {
if p.obfuscate {
if p.pref.obfuscate {
p.genln('; // ${f.name}')
}
p.genln('$typ $fn_name_cgen($str_args) {')
@ -332,13 +332,13 @@ fn (p mut Parser) fn_decl() {
}
// Actual fn declaration!
mut fn_decl := '$typ $fn_name_cgen($str_args)'
if p.obfuscate {
if p.pref.obfuscate {
fn_decl += '; // ${f.name}'
}
// Add function definition to the top
if !is_c && f.name != 'main' && p.first_run() {
// TODO hack to make Volt compile without -embed_vlib
if f.name == 'darwin__nsstring' && p.build_mode == DEFAULT_MODE {
if f.name == 'darwin__nsstring' && p.pref.build_mode == DEFAULT_MODE {
return
}
p.cgen.fns << fn_decl + ';'
@ -357,13 +357,13 @@ fn (p mut Parser) fn_decl() {
}
}
// We are in live code reload mode, call the .so loader in bg
if p.is_live {
if p.pref.is_live {
p.genln('
load_so("bounce.so");
pthread_t _thread_so;
pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
}
if p.is_test && !p.scanner.file_path.contains('/volt') {
if p.pref.is_test && !p.scanner.file_path.contains('/volt') {
p.error('tests cannot have function `main`')
}
}
@ -374,14 +374,14 @@ pthread_create(&_thread_so , NULL, &reload_so, NULL); ')
return
}
// We are in profile mode? Start counting at the beginning of the function (save current time).
if p.is_prof && f.name != 'main' && f.name != 'time__ticks' {
if p.pref.is_prof && f.name != 'main' && f.name != 'time__ticks' {
p.genln('double _PROF_START = time__ticks();//$f.name')
cgen_name := p.table.cgen_name(f)
f.defer = ' ${cgen_name}_time += time__ticks() - _PROF_START;'
}
p.statements_no_curly_end()
// Print counting result after all statements in main
if p.is_prof && f.name == 'main' {
if p.pref.is_prof && f.name == 'main' {
p.genln(p.print_prof_counters())
}
// Counting or not, always need to add defer before the end
@ -414,14 +414,14 @@ fn (p mut Parser) check_unused_variables() {
if var.name == '' {
break
}
if !var.is_used && !var.is_arg && !p.translated && var.name != '_' {
if !var.is_used && !var.is_arg && !p.pref.translated && var.name != '_' {
p.scanner.line_nr = var.line_nr - 1
p.error('`$var.name` declared and not used')
}
// Very basic automatic memory management at the end of the function.
// This is inserted right before the final `}`, so if the object is being returned,
// the free method will not be called.
if p.is_test && var.typ.contains('array_') {
if p.pref.is_test && var.typ.contains('array_') {
// p.genln('v_${var.typ}_free($var.name); // !!!! XAXA')
// p.genln('free(${var.name}.data); // !!!! XAXA')
}
@ -500,19 +500,19 @@ fn (p mut Parser) async_fn_call(f Fn, method_ph int, receiver_var, receiver_type
}
fn (p mut Parser) fn_call(f Fn, method_ph int, receiver_var, receiver_type string) {
if !f.is_public && !f.is_c && !p.is_test && f.pkg != p.pkg {
if !f.is_public && !f.is_c && !p.pref.is_test && f.pkg != p.pkg {
p.error('function `$f.name` is private')
}
p.calling_c = f.is_c
is_print := p.is_prod &&// Hide prints only in prod
!p.is_test &&
is_print := p.pref.is_prod &&// Hide prints only in prod
!p.pref.is_test &&
!p.builtin_pkg &&// Allow prints in builtin pkgs
f.is_c && f.name == 'printf'
if !p.cgen.nogen {
p.cgen.nogen = is_print
}
cgen_name := p.table.cgen_name(f)
// if p.is_prof {
// if p.pref.is_prof {
// p.cur_fn.called_fns << cgen_name
// }
// Normal function call
@ -853,4 +853,3 @@ fn (f &Fn) str_args(table *Table) string {
}
return s
}

View File

@ -58,32 +58,38 @@ enum Pass {
main
}
*/
struct Preferences {
mut:
build_mode BuildMode
nofmt bool // disable vfmt
is_test bool // `v test string_test.v`
is_script bool // single file mode (`v program.v`), `fn main(){}` can be skipped
is_live bool // for hot code reloading
is_so bool
is_prof bool // benchmark every function
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
is_prod bool // use "-O2"
is_verbose bool // print extra information with `v.log()`
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
is_play bool // playground mode
is_repl bool
is_run bool
show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c
sanitize bool // use Clang's new "-fsanitize" option
}
struct V {
mut:
build_mode BuildMode
os Os // the OS to build for
nofmt bool // disable vfmt
out_name_c string // name of the temporary C file
files []string // all V files that need to be parsed and compiled
dir string // directory (or file) being compiled (TODO rename to path?)
table *Table // table with types, vars, functions etc
cgen *CGen // C code generator
is_test bool // `v test string_test.v`
is_script bool // single file mode (`v program.v`), `fn main(){}` can be skipped
is_so bool
is_live bool // for hot code reloading
is_prof bool // benchmark every function
translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
obfuscate bool // `v -obf program.v`, renames functions to "f_XXX"
lang_dir string // path to V repo
is_verbose bool // print extra information with `v.log()`
is_run bool // `v run program.v`
is_play bool // playground mode
show_c_cmd bool // `v -show_c_cmd` prints the C command to build program.v.c
sanitize bool // use Clang's new "-fsanitize" option
pref *Preferences // all the prefrences and settings extracted to a struct for reusability
lang_dir string // "~/code/v"
out_name string // "program.exe"
is_prod bool // use "-O2"
is_repl bool
vroot string
}
@ -137,7 +143,7 @@ fn main() {
}
// Construct the V object from command line arguments
mut c := new_v(args)
if c.is_verbose {
if c.pref.is_verbose {
println(args)
}
// Generate the docs and exit
@ -153,7 +159,7 @@ fn (c mut V) compile() {
cgen.genln('// Generated by V')
// Add user files to compile
c.add_user_v_files()
if c.is_verbose {
if c.pref.is_verbose {
println('all .v files:')
println(c.files)
}
@ -164,7 +170,7 @@ fn (c mut V) compile() {
}
// Main pass
cgen.run = RUN_MAIN
if c.is_play {
if c.pref.is_play {
cgen.genln('#define VPLAY (1) ')
}
cgen.genln('
@ -238,23 +244,23 @@ void reload_so();
void init_consts();')
imports_json := c.table.imports.contains('json')
// TODO remove global UI hack
if c.os == MAC && ((c.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) ||
(c.build_mode == BUILD && c.dir.contains('/ui'))) {
if c.os == MAC && ((c.pref.build_mode == EMBED_VLIB && c.table.imports.contains('ui')) ||
(c.pref.build_mode == BUILD && c.dir.contains('/ui'))) {
cgen.genln('id defaultFont = 0; // main.v')
}
// TODO remove ugly .c include once V has its own json parser
// Embed cjson either in embedvlib or in json.o
if imports_json && c.build_mode == EMBED_VLIB ||
(c.build_mode == BUILD && c.out_name.contains('json.o')) {
if imports_json && c.pref.build_mode == EMBED_VLIB ||
(c.pref.build_mode == BUILD && c.out_name.contains('json.o')) {
cgen.genln('#include "cJSON.c" ')
}
// We need the cjson header for all the json decoding user will do in default mode
if c.build_mode == DEFAULT_MODE {
if c.pref.build_mode == DEFAULT_MODE {
if imports_json {
cgen.genln('#include "cJSON.h"')
}
}
if c.build_mode == EMBED_VLIB || c.build_mode == DEFAULT_MODE {
if c.pref.build_mode == EMBED_VLIB || c.pref.build_mode == DEFAULT_MODE {
// If we declare these for all modes, then when running `v a.v` we'll get
// `/usr/bin/ld: multiple definition of 'total_m'`
// TODO
@ -277,7 +283,7 @@ void init_consts();')
p.parse()
// p.g.gen_x64()
// Format all files (don't format automatically generated vlib headers)
if !c.nofmt && !file.contains('/vlib/') {
if !c.pref.nofmt && !file.contains('/vlib/') {
// new vfmt is not ready yet
}
}
@ -292,14 +298,14 @@ void init_consts();')
d.writeln(cgen.fns.join_lines())
d.writeln(cgen.consts.join_lines())
d.writeln(cgen.thread_args.join_lines())
if c.is_prof {
if c.pref.is_prof {
d.writeln('; // Prof counters:')
d.writeln(c.prof_counters())
}
dd := d.str()
cgen.lines.set(defs_pos, dd)// TODO `def.str()` doesn't compile
// if c.build_mode in [.default, .embed_vlib] {
if c.build_mode == DEFAULT_MODE || c.build_mode == EMBED_VLIB {
if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == EMBED_VLIB {
// vlib can't have `init_consts()`
cgen.genln('void init_consts() { g_str_buf=malloc(1000); ${cgen.consts_init.join_lines()} }')
// _STR function can't be defined in vlib
@ -339,10 +345,10 @@ string _STR_TMP(const char *fmt, ...) {
}
// Make sure the main function exists
// Obviously we don't need it in libraries
if c.build_mode != BUILD {
if !c.table.main_exists() && !c.is_test {
if c.pref.build_mode != BUILD {
if !c.table.main_exists() && !c.pref.is_test {
// It can be skipped in single file programs
if c.is_script {
if c.pref.is_script {
//println('Generating main()...')
cgen.genln('int main() { $cgen.fn_main; return 0; }')
}
@ -351,7 +357,7 @@ string _STR_TMP(const char *fmt, ...) {
}
}
// Generate `main` which calls every single test function
else if c.is_test {
else if c.pref.is_test {
cgen.genln('int main() { init_consts();')
for v in c.table.fns {
if v.name.starts_with('test_') {
@ -361,7 +367,7 @@ string _STR_TMP(const char *fmt, ...) {
cgen.genln('return g_test_ok == 0; }')
}
}
if c.is_live {
if c.pref.is_live {
cgen.genln(' int load_so(byteptr path) {
printf("load_so %s\\n", path); dlclose(live_lib); live_lib = dlopen(path, RTLD_LAZY);
if (!live_lib) {puts("open failed"); exit(1); return 0;}
@ -372,13 +378,13 @@ string _STR_TMP(const char *fmt, ...) {
cgen.genln('return 1; }')
}
cgen.save()
if c.is_verbose {
if c.pref.is_verbose {
c.log('flags=')
println(c.table.flags)
}
c.cc()
if c.is_test || c.is_run {
if true || c.is_verbose {
if c.pref.is_test || c.pref.is_run {
if true || c.pref.is_verbose {
println('============ running $c.out_name ============')
}
mut cmd := if c.out_name.starts_with('/') {
@ -405,32 +411,31 @@ string _STR_TMP(const char *fmt, ...) {
}
fn (c mut V) cc() {
ticks := time.ticks()
linux_host := os.user_os() == 'linux'
c.log('cc() isprod=$c.is_prod outname=$c.out_name')
c.log('cc() isprod=$c.pref.is_prod outname=$c.out_name')
mut a := ['-w']// arguments for the C compiler
flags := c.table.flags.join(' ')
/*
mut shared := ''
if c.is_so {
if c.pref.is_so {
a << '-shared'// -Wl,-z,defs'
c.out_name = c.out_name + '.so'
}
*/
if c.is_prod {
if c.pref.is_prod {
a << '-O2'
}
else {
a << '-g'
}
mut libs := ''// builtin.o os.o http.o etc
if c.build_mode == BUILD {
if c.pref.build_mode == BUILD {
a << '-c'
}
else if c.build_mode == EMBED_VLIB {
else if c.pref.build_mode == EMBED_VLIB {
//
}
else if c.build_mode == DEFAULT_MODE {
else if c.pref.build_mode == DEFAULT_MODE {
libs = '$TmpPath/vlib/builtin.o'
if !os.file_exists(libs) {
println('`builtin.o` not found')
@ -453,7 +458,7 @@ mut args := ''
}
}
*/
if c.sanitize {
if c.pref.sanitize {
a << '-fsanitize=leak'
}
// Cross compiling linux
@ -485,11 +490,11 @@ mut args := ''
a << '-x objective-c'
}
// Without these libs compilation will fail on Linux
if c.os == LINUX && c.build_mode != BUILD {
if c.os == LINUX && c.pref.build_mode != BUILD {
a << '-lm -ldl -lpthread'
}
// Find clang executable
fast_clang := 'ff'///usr/local/Cellar/llvm/8.0.0/bin/clang'
fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
args := a.join(' ')
mut cmd := if os.file_exists(fast_clang) {
'$fast_clang $args'
@ -501,7 +506,7 @@ mut args := ''
cmd = 'gcc $args'
}
// Print the C command
if c.show_c_cmd || c.is_verbose {
if c.pref.show_c_cmd || c.pref.is_verbose {
println('\n==========\n$cmd\n=========\n')
}
// Run
@ -512,7 +517,7 @@ mut args := ''
panic('clang error')
}
// Link it if we are cross compiling and need an executable
if c.os == LINUX && !linux_host && c.build_mode != BUILD {
if c.os == LINUX && !linux_host && c.pref.build_mode != BUILD {
c.out_name = c.out_name.replace('.o', '')
obj_file := c.out_name + '.o'
println('linux obj_file=$obj_file out_name=$c.out_name')
@ -531,10 +536,6 @@ mut args := ''
}
println('linux cross compilation done. resulting binary: "$c.out_name"')
}
if c.show_c_cmd {
diff := time.ticks() - ticks
println('cc() took $diff ms ')
}
//os.rm('$TmpPath/$c.out_name_c')
}
@ -546,7 +547,7 @@ fn (c &V) v_files_from_dir(dir string) []string {
panic('$dir isn\'t a directory')
}
mut files := os.ls(dir)
if c.is_verbose {
if c.pref.is_verbose {
println('v_files_from_dir ("$dir")')
}
// println(files.len)
@ -617,7 +618,7 @@ fn (c mut V) add_user_v_files() {
println('No input .v files')
exit(1)
}
if c.is_verbose {
if c.pref.is_verbose {
c.log('user_files:')
println(user_files)
}
@ -627,7 +628,7 @@ fn (c mut V) add_user_v_files() {
p.parse()
}
// Parse lib imports
if c.build_mode == DEFAULT_MODE {
if c.pref.build_mode == DEFAULT_MODE {
for i := 0; i < c.table.imports.len; i++ {
pkg := c.table.imports[i]
vfiles := c.v_files_from_dir('$TmpPath/vlib/$pkg')
@ -652,7 +653,7 @@ fn (c mut V) add_user_v_files() {
}
}
}
if c.is_verbose {
if c.pref.is_verbose {
c.log('imports:')
println(c.table.imports)
}
@ -662,7 +663,7 @@ fn (c mut V) add_user_v_files() {
// If we are in default mode, we don't parse vlib .v files, but header .vh files in
// TmpPath/vlib
// These were generated by vfmt
if c.build_mode == DEFAULT_MODE || c.build_mode == BUILD {
if c.pref.build_mode == DEFAULT_MODE || c.pref.build_mode == BUILD {
module_path = '$TmpPath/vlib/$pkg'
}
vfiles := c.v_files_from_dir(module_path)
@ -695,13 +696,13 @@ fn get_arg(joined_args, arg, def string) string {
}
fn (c &V) log(s string) {
if !c.is_verbose {
if !c.pref.is_verbose {
return
}
println(s)
}
fn new_v(args []string) *V {
fn new_v(args[]string) *V {
mut dir := args.last()
if args.contains('run') {
dir = args[2]
@ -823,7 +824,25 @@ fn new_v(args []string) *V {
files << f
}
}
obfuscate := args.contains('-obf')
obfuscate := args.contains('-obf')
pref := &Preferences {
is_test: is_test
is_script: is_script
is_so: args.contains('-shared')
is_play: args.contains('play')
is_prod: args.contains('-prod')
is_verbose: args.contains('-verbose')
obfuscate: obfuscate
is_prof: args.contains('-prof')
is_live: args.contains('-live')
sanitize: args.contains('-sanitize')
nofmt: args.contains('-nofmt')
show_c_cmd: args.contains('-show_c_cmd')
translated: args.contains('translated')
is_run: args.contains('run')
is_repl: args.contains('-repl')
build_mode: build_mode
}
return &V {
os: _os
out_name: out_name
@ -833,24 +852,9 @@ fn new_v(args []string) *V {
table: new_table(obfuscate)
out_name: out_name
out_name_c: out_name_c
is_test: is_test
is_script: is_script
is_so: args.contains('-shared')
is_play: args.contains('play')
is_prod: args.contains('-prod')
is_verbose: args.contains('-verbose')
obfuscate: args.contains('-obf')
is_prof: args.contains('-prof')
is_live: args.contains('-live')
sanitize: args.contains('-sanitize')
nofmt: args.contains('-nofmt')
show_c_cmd: args.contains('-show_c_cmd')
translated: args.contains('translated')
cgen: new_cgen(out_name_c)
build_mode: build_mode
is_run: args.contains('run')
is_repl: args.contains('-repl')
vroot: lang_dir
pref: pref
}
}

View File

@ -48,19 +48,20 @@ mut:
assigned_type string
tmp_cnt int
// TODO all these options are copy-pasted from the V struct. Create a Settings struct instead?
is_test bool
// is_test bool
is_script bool
is_live bool
is_so bool
is_prof bool
translated bool
is_prod bool
is_verbose bool
obfuscate bool
is_play bool
is_repl bool
pref *Preferences // Setting and Preferences shared from V struct
// is_live bool
// is_so bool
// is_prof bool
// translated bool
// is_prod bool
// is_verbose bool
// obfuscate bool
// is_play bool
// is_repl bool
builtin_pkg bool
build_mode BuildMode
// build_mode BuildMode
vh_lines []string
inside_if_expr bool
is_struct_init bool
@ -90,18 +91,19 @@ fn (c mut V) new_parser(path string, run Pass) Parser {
table: c.table
cur_fn: EmptyFn
cgen: c.cgen
is_test: c.is_test
is_script: (c.is_script && path == c.dir)
is_so: c.is_so
// is_test: c.pref.is_test
is_script: (c.pref.is_script && path == c.dir)
pref: c.pref
// is_so: c.is_so
os: c.os
is_prof: c.is_prof
is_prod: c.is_prod
is_play: c.is_play
translated: c.translated
obfuscate: c.obfuscate
is_verbose: c.is_verbose
build_mode: c.build_mode
is_repl: c.is_repl
// is_prof: c.is_prof
// is_prod: c.is_prod
// is_play: c.is_play
// translated: c.translated
// obfuscate: c.obfuscate
// is_verbose: c.is_verbose
// build_mode: c.build_mode
// is_repl: c.is_repl
run: run
vroot: c.vroot
}
@ -119,7 +121,7 @@ fn (p mut Parser) next() {
}
fn (p &Parser) log(s string) {
if !p.is_verbose {
if !p.pref.is_verbose {
return
}
println(s)
@ -128,7 +130,7 @@ fn (p &Parser) log(s string) {
fn (p mut Parser) parse() {
p.log('\nparse() run=$p.run file=$p.file_name tok=${p.strtok()}')// , "script_file=", script_file)
// `module main` is not required if it's a single file program
if p.is_script || p.is_test {
if p.is_script || p.pref.is_test {
p.pkg = 'main'
// User may still specify `module main`
if p.tok == PACKAGE {
@ -175,7 +177,7 @@ fn (p mut Parser) parse() {
// enum without a name, only allowed in code, translated from C
// it's a very bad practice in C as well, but is used unfortunately (for example, by DOOM)
// such fields are basically int consts
else if p.translated {
else if p.pref.translated {
p.enum_decl('int')
}
else {
@ -207,7 +209,7 @@ fn (p mut Parser) parse() {
// $if, $else
p.comp_time()
case GLOBAL:
if !p.translated && !p.builtin_pkg && !p.building_v() {
if !p.pref.translated && !p.builtin_pkg && !p.building_v() {
p.error('__global is only allowed in translated code')
}
p.next()
@ -230,7 +232,7 @@ fn (p mut Parser) parse() {
p.cgen.consts << g
case EOF:
p.log('end of parse()')
if p.is_script && !p.is_test {
if p.is_script && !p.pref.is_test {
p.cur_fn = MainFn
p.check_unused_variables()
}
@ -242,7 +244,7 @@ fn (p mut Parser) parse() {
return
default:
// no `fn main`, add this "global" statement to cgen.fn_main
if p.is_script && !p.is_test {
if p.is_script && !p.pref.is_test {
// cur_fn is empty since there was no fn main declared
// we need to set it to save and find variables
if p.first_run() {
@ -253,7 +255,7 @@ fn (p mut Parser) parse() {
}
if p.cur_fn.name == '' {
p.cur_fn = MainFn
if p.is_repl {
if p.pref.is_repl {
p.cur_fn.clear_vars()
}
}
@ -324,7 +326,7 @@ fn (p mut Parser) const_decl() {
for p.tok == NAME {
// `Age = 20`
mut name := p.check_name()
if p.is_play && ! (name[0] >= `A` && name[0] <= `Z`) {
if p.pref.is_play && ! (name[0] >= `A` && name[0] <= `Z`) {
p.error('const name must be capitalized')
}
// Imported consts (like GL_TRIANGLES) dont need pkg prepended (gl__GL_TRIANGLES)
@ -407,7 +409,7 @@ fn (p mut Parser) struct_decl() {
// Get type name
p.next()
mut name := p.check_name()
if name.contains('_') && !p.translated {
if name.contains('_') && !p.pref.translated {
p.error('type names cannot contain `_`')
}
if is_interface && !name.ends_with('er') {
@ -521,7 +523,7 @@ fn (p mut Parser) struct_decl() {
is_method: true
receiver_typ: name
}
//println('is interface. field=$field_name run=$p.run')
println('is interface. field=$field_name run=$p.run')
p.fn_args(mut interface_method)
p.fspace()
interface_method.typ = p.get_type()// method return type
@ -670,13 +672,13 @@ fn (p mut Parser) error(s string) {
file_types.close()
file_vars.close()
}
if !p.is_repl {
if !p.pref.is_repl {
println('pass=$p.run fn=`$p.cur_fn.name`')
}
p.cgen.save()
// V git pull hint
cur_path := os.getwd()
if !p.is_repl && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){
if !p.pref.is_repl && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){
println('\n=========================')
println('It looks like you are building V. It is being frequently updated every day.')
println('If you didn\'t modify the compiler\'s code, most likely there was a change that ')
@ -797,7 +799,7 @@ fn (p mut Parser) get_type() string {
typ = p.prepend_pkg(typ)
}
t = p.table.find_type(typ)
if t.name == '' && !p.translated && !p.first_run() && !typ.starts_with('[') {
if t.name == '' && !p.pref.translated && !p.first_run() && !typ.starts_with('[') {
println('get_type() bad type')
// println('all registered types:')
// for q in p.table.types {
@ -837,7 +839,7 @@ fn (p mut Parser) get_type() string {
return 'byte*'
}
if typ == 'voidptr' {
//if !p.builtin_pkg && p.pkg != 'os' && p.pkg != 'gx' && p.pkg != 'gg' && !p.translated {
//if !p.builtin_pkg && p.pkg != 'os' && p.pkg != 'gx' && p.pkg != 'gg' && !p.pref.translated {
//p.error('voidptr can only be used in unsafe code')
//}
return 'void*'
@ -936,7 +938,7 @@ fn (p mut Parser) statement(add_semi bool) string {
switch tok {
case NAME:
next := p.peek()
if p.is_verbose {
if p.pref.is_verbose {
println(next.str())
}
// goto_label:
@ -1028,7 +1030,7 @@ fn (p mut Parser) statement(add_semi bool) string {
fn (p mut Parser) assign_statement(v Var, ph int, is_map bool) {
p.log('assign_statement() name=$v.name tok=')
tok := p.tok
if !v.is_mut && !v.is_arg && !p.translated && !v.is_global{
if !v.is_mut && !v.is_arg && !p.pref.translated && !v.is_global{
p.error('`$v.name` is immutable')
}
is_str := v.typ == 'string'
@ -1202,7 +1204,7 @@ fn (p mut Parser) name_expr() string {
p.next()
}
if deref {
if p.is_play && !p.builtin_pkg {
if p.pref.is_play && !p.builtin_pkg {
p.error('dereferencing is temporarily disabled on the playground, will be fixed soon')
}
}
@ -1428,11 +1430,11 @@ fn (p mut Parser) var_expr(v Var) string {
}
// a++ and a--
if p.tok == INC || p.tok == DEC {
if !v.is_mut && !v.is_arg && !p.translated {
if !v.is_mut && !v.is_arg && !p.pref.translated {
p.error('`$v.name` is immutable')
}
if typ != 'int' {
if !p.translated && !is_number_type(typ) {
if !p.pref.translated && !is_number_type(typ) {
// if T.parent != 'int' {
p.error('cannot ++/-- value of type `$typ`')
}
@ -1441,7 +1443,7 @@ fn (p mut Parser) var_expr(v Var) string {
p.fgen(p.tok.str())
p.next()// ++
// allow a := c++ in translated
if p.translated {
if p.pref.translated {
return p.index_expr(typ, fn_ph)
// return typ
}
@ -1502,14 +1504,14 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
next := p.peek()
modifying := next.is_assign() || next == INC || next == DEC
is_vi := p.fileis('vi')
if !p.builtin_pkg && !p.translated && modifying && !field.is_mut && !is_vi {
if !p.builtin_pkg && !p.pref.translated && modifying && !field.is_mut && !is_vi {
p.error('cannot modify immutable field `$field_name` (type `$typ.name`)')
}
if !p.builtin_pkg && p.pkg != typ.pkg {
}
// if p.is_play && field.access_mod == PRIVATE && !p.builtin_pkg && p.pkg != typ.pkg {
// if p.pref.is_play && field.access_mod == PRIVATE && !p.builtin_pkg && p.pkg != typ.pkg {
// Don't allow `arr.data`
if field.access_mod == PRIVATE && !p.builtin_pkg && !p.translated && p.pkg != typ.pkg {
if field.access_mod == PRIVATE && !p.builtin_pkg && !p.pref.translated && p.pkg != typ.pkg {
// println('$typ.name :: $field.name ')
// println(field.access_mod)
p.error('cannot refer to unexported field `$field_name` (type `$typ.name`)')
@ -1521,7 +1523,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
// println('HOHOH')
// println(next.str())
// }
if !field.is_mut && !p.translated && modifying {
if !field.is_mut && !p.pref.translated && modifying {
p.error('cannot modify public immutable field `$field_name` (type `$typ.name`)')
}
}
@ -1624,7 +1626,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string {
typ = 'void*'
}
// No bounds check in translated from C code
if p.translated {
if p.pref.translated {
// Cast void* to typ*: add (typ*) to the beginning of the assignment :
// ((int*)a.data = ...
p.cgen.set_placeholder(fn_ph, '(($typ*)(')
@ -1705,7 +1707,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string {
return typ
return 'void'
}
// else if p.is_verbose && p.assigned_var != '' {
// else if p.pref.is_verbose && p.assigned_var != '' {
// p.error('didnt assign')
// }
// m[key]. no =, just a getter
@ -1724,7 +1726,7 @@ fn (p mut Parser) index_expr(typ string, fn_ph int) string {
p.cgen.insert_before('$typ $tmp = $def; bool $tmp_ok = map_get($index_expr, & $tmp);')
}
else if is_arr {
if p.translated {
if p.pref.translated {
p.gen('$index_expr ]')
}
else {
@ -1768,7 +1770,7 @@ fn (p mut Parser) expression() string {
// Get the value we are pushing
p.gen(', (')
// Immutable? Can we push?
if !p.expr_var.is_mut && !p.translated {
if !p.expr_var.is_mut && !p.pref.translated {
p.error('`$p.expr_var.name` is immutable (can\'t <<)')
}
p.check_types(p.expression(), tmp_typ)
@ -1833,7 +1835,7 @@ fn (p mut Parser) expression() string {
}
// Vec + Vec
else {
if p.translated {
if p.pref.translated {
p.gen(tok_op.str() + ' /*doom hack*/')// TODO hack to fix DOOM's angle_t
}
else {
@ -1845,7 +1847,7 @@ fn (p mut Parser) expression() string {
p.gen(')')
}
// Make sure operators are used with correct types
if !p.translated && !is_str && !is_num {
if !p.pref.translated && !is_str && !is_num {
T := p.table.find_type(typ)
if tok_op == PLUS {
if T.has_method('+') {
@ -2122,7 +2124,7 @@ fn (p mut Parser) string_expr() {
// println('before format: "$str"')
f := format_str(str)
// println('after format: "$str"')
if p.calling_c || p.translated {
if p.calling_c || p.pref.translated {
p.gen('"$f"')
}
else {
@ -2182,7 +2184,7 @@ fn (p mut Parser) string_expr() {
}
// Don't allocate a new string, just print it. TODO HACK PRINT OPT
cur_line := p.cgen.cur_line.trim_space()
if cur_line.contains('println(') && p.tok != PLUS && !p.is_prod && !cur_line.contains('string_add') {
if cur_line.contains('println(') && p.tok != PLUS && !p.pref.is_prod && !cur_line.contains('string_add') {
p.cgen.cur_line = cur_line.replace('println(', 'printf(')
p.gen('$format\\n$args')
return
@ -2587,10 +2589,10 @@ fn (p mut Parser) chash() {
// p.cgen.nogen = true
}
if hash == 'live' {
if p.is_so {
if p.pref.is_so {
return
}
p.is_live = true
p.pref.is_live = true
return
}
if hash.starts_with('flag ') {
@ -2635,7 +2637,7 @@ fn (p mut Parser) chash() {
else if hash.contains('embed') {
pos := hash.index('embed') + 5
file := hash.right(pos)
if p.build_mode != DEFAULT_MODE {
if p.pref.build_mode != DEFAULT_MODE {
p.genln('#include $file')
}
}
@ -3142,5 +3144,3 @@ fn (p mut Parser) fspace() {
fn (p mut Parser) fgenln(s string) {
//p.scanner.fgenln(s)
}

View File

@ -414,7 +414,7 @@ fn (t &Table) find_type(name string) *Type {
fn (p mut Parser) _check_types(got, expected string, throw bool) bool {
p.log('check types got="$got" exp="$expected" ')
if p.translated {
if p.pref.translated {
return true
}
// Allow ints to be used as floats
@ -443,7 +443,7 @@ fn (p mut Parser) _check_types(got, expected string, throw bool) bool {
// Todo void* allows everything right now
if got=='void*' || expected=='void*' {
// if !p.builtin_pkg {
if p.is_play {
if p.pref.is_play {
return false
}
return true
@ -475,7 +475,7 @@ fn (p mut Parser) _check_types(got, expected string, throw bool) bool {
return true
}
// NsColor* return 0
if !p.is_play {
if !p.pref.is_play {
if expected.ends_with('*') && got == 'int' {
return true
}