diff --git a/vlib/v/builder/builder.v b/vlib/v/builder/builder.v index 9aa5d79626..aecad70c50 100644 --- a/vlib/v/builder/builder.v +++ b/vlib/v/builder/builder.v @@ -36,7 +36,7 @@ pub fn new_builder(pref &pref.Preferences) Builder { pub fn (b mut Builder) gen_c(v_files []string) string { t0 := time.ticks() - b.parsed_files = parser.parse_files(v_files, b.table) + b.parsed_files = parser.parse_files(v_files, b.table, b.pref) b.parse_imports() t1 := time.ticks() parse_time := t1 - t0 @@ -71,7 +71,7 @@ pub fn (b mut Builder) build_c(v_files []string, out_file string) { pub fn (b mut Builder) build_x64(v_files []string, out_file string) { t0 := time.ticks() - b.parsed_files = parser.parse_files(v_files, b.table) + b.parsed_files = parser.parse_files(v_files, b.table, b.pref) b.parse_imports() t1 := time.ticks() parse_time := t1 - t0 @@ -109,7 +109,7 @@ pub fn (b mut Builder) parse_imports() { panic('cannot import module "$mod" (no .v files in "$import_path")') } // Add all imports referenced by these libs - parsed_files := parser.parse_files(v_files, b.table) + parsed_files := parser.parse_files(v_files, b.table, b.pref) for file in parsed_files { if file.mod.name != mod { // v.parsers[pidx].error_with_token_index('bad module definition: ${v.parsers[pidx].file_path} imports module "$mod" but $file is defined as module `$p_mod`', 1 diff --git a/vlib/v/doc/doc.v b/vlib/v/doc/doc.v index 6eb0f419c0..348add4abe 100644 --- a/vlib/v/doc/doc.v +++ b/vlib/v/doc/doc.v @@ -45,7 +45,7 @@ pub fn doc(mod string, table &table.Table) string { if file.ends_with('_test.v') || file.ends_with('_windows.v') || file.ends_with('_macos.v') { continue } - file_ast := parser.parse_file(os.join_path(path,file), table, .skip_comments) + file_ast := parser.parse_file(os.join_path(path,file), table, .skip_comments, &pref.Preferences{}) d.stmts << file_ast.stmts } if d.stmts.len == 0 { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 79a4fb87c0..fa6bff07d3 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -295,28 +295,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { g.const_decl(it) } ast.CompIf { - ifdef := comp_if_to_ifdef(it.val) - if it.is_not { - g.writeln('\n#ifndef ' + ifdef) - g.writeln('// #if not $it.val') - } - else { - g.writeln('\n#ifdef ' + ifdef) - g.writeln('// #if $it.val') - } - // NOTE: g.defer_ifdef is needed for defers called witin an ifdef - // in v1 this code would be completely excluded - g.defer_ifdef = if it.is_not { '#ifndef ' + ifdef } else { '#ifdef ' + ifdef } - // println('comp if stmts $g.file.path:$it.pos.line_nr') - g.stmts(it.stmts) - g.defer_ifdef = '' - if it.has_else { - g.writeln('#else') - g.defer_ifdef = if it.is_not { '#ifdef ' + ifdef } else { '#ifndef ' + ifdef } - g.stmts(it.else_stmts) - g.defer_ifdef = '' - } - g.writeln('#endif') + g.comp_if(it) } ast.DeferStmt { mut defer_stmt := *it @@ -2494,3 +2473,28 @@ pub fn (g mut Gen) write_tests_main() { fn (g &Gen) is_importing_os() bool { return 'os' in g.table.imports } + +fn (g mut Gen) comp_if(it ast.CompIf) { + ifdef := comp_if_to_ifdef(it.val) + if it.is_not { + g.writeln('\n#ifndef ' + ifdef) + g.writeln('// #if not $it.val') + } + else { + g.writeln('\n#ifdef ' + ifdef) + g.writeln('// #if $it.val') + } + // NOTE: g.defer_ifdef is needed for defers called witin an ifdef + // in v1 this code would be completely excluded + g.defer_ifdef = if it.is_not { '#ifndef ' + ifdef } else { '#ifdef ' + ifdef } + // println('comp if stmts $g.file.path:$it.pos.line_nr') + g.stmts(it.stmts) + g.defer_ifdef = '' + if it.has_else { + g.writeln('#else') + g.defer_ifdef = if it.is_not { '#ifdef ' + ifdef } else { '#ifndef ' + ifdef } + g.stmts(it.else_stmts) + g.defer_ifdef = '' + } + g.writeln('#endif') +} diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index b7fb521a68..68da656cd9 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -2,9 +2,15 @@ module parser import ( v.ast + v.pref ) -pub fn (p mut Parser) comp_if() ast.CompIf { +const ( + supported_platforms = ['windows', 'mac', 'macos', 'linux', 'freebsd', 'openbsd', 'netbsd', + 'dragonfly', 'android', 'js', 'solaris', 'haiku', 'linux_or_macos'] +) + +fn (p mut Parser) comp_if() ast.CompIf { pos := p.tok.position() p.next() p.check(.key_if) @@ -13,14 +19,51 @@ pub fn (p mut Parser) comp_if() ast.CompIf { p.next() } val := p.check_name() + mut stmts := []ast.Stmt + mut skip_os := false + if val in supported_platforms { + os := os_from_string(val) + // `$if os {` for a different target, skip everything inside + // to avoid compilation errors (like including or calling WinAPI fns + // on non-Windows systems) + if ((!is_not && os != p.pref.os) || (is_not && os == p.pref.os)) && !p.pref.output_cross_c { + skip_os = true + p.check(.lcbr) + p.warn('SKIPPING $val os=$os p.pref.os=$p.pref.os') + mut stack := 1 + for { + if p.tok.kind == .key_return { + p.returns = true + } + if p.tok.kind == .lcbr { + stack++ + } + else if p.tok.kind == .rcbr { + stack-- + } + if p.tok.kind == .eof { + break + } + if stack <= 0 && p.tok.kind == .rcbr { + // p.warn('exiting $stack') + p.next() + break + } + p.next() + } + } + } if p.tok.kind == .question { p.next() } + if !skip_os { + stmts = p.parse_block() + } mut node := ast.CompIf{ is_not: is_not - stmts: p.parse_block() pos: pos val: val + stmts: stmts } if p.tok.kind == .dollar && p.peek_tok.kind == .key_else { p.next() @@ -30,3 +73,56 @@ pub fn (p mut Parser) comp_if() ast.CompIf { } return node } + +fn os_from_string(os string) pref.OS { + match os { + 'linux' { + return .linux + } + 'windows' { + return .windows + } + 'mac' { + return .mac + } + 'macos' { + return .mac + } + 'freebsd' { + return .freebsd + } + 'openbsd' { + return .openbsd + } + 'netbsd' { + return .netbsd + } + 'dragonfly' { + return .dragonfly + } + 'js' { + return .js + } + 'solaris' { + return .solaris + } + 'android' { + return .android + } + 'msvc' { + // notice that `-os msvc` became `-cc msvc` + verror('use the flag `-cc msvc` to build using msvc') + } + 'haiku' { + return .haiku + } + 'linux_or_macos' { + return .linux + } + else { + panic('bad os $os') + } + } + // println('bad os $os') // todo panic? + return .linux +} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index a8245a6a8d..9bb7362c68 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -40,6 +40,7 @@ mut: imports map[string]string ast_imports []ast.Import is_amp bool + returns bool } // for tests @@ -51,14 +52,14 @@ pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt { pref: &pref.Preferences{} scope: scope // scope: &ast.Scope{start_pos: 0, parent: 0} - + } p.init_parse_fns() p.read_first_token() return p.stmt() } -pub fn parse_file(path string, table &table.Table, comments_mode scanner.CommentsMode) ast.File { +pub fn parse_file(path string, table &table.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences) ast.File { // println('parse_file("$path")') // text := os.read_file(path) or { // panic(err) @@ -69,13 +70,13 @@ pub fn parse_file(path string, table &table.Table, comments_mode scanner.Comment scanner: scanner.new_scanner_file(path, comments_mode) table: table file_name: path - pref: &pref.Preferences{} + pref: pref //&pref.Preferences{} scope: &ast.Scope{ start_pos: 0 parent: 0 } // comments_mode: comments_mode - + } p.read_first_token() // p.scope = &ast.Scope{start_pos: p.tok.position(), parent: 0} @@ -141,7 +142,7 @@ fn (q mut Queue) run() { */ -pub fn parse_files(paths []string, table &table.Table) []ast.File { +pub fn parse_files(paths []string, table &table.Table, pref &pref.Preferences) []ast.File { /* println('\n\n\nparse_files()') println(paths) @@ -162,7 +163,7 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File { mut files := []ast.File for path in paths { // println('parse_files $path') - files << parse_file(path, table, .skip_comments) + files << parse_file(path, table, .skip_comments, pref) } return files } @@ -686,7 +687,7 @@ pub fn (p mut Parser) name_expr() ast.Expr { p.expr_mod = '' return ast.EnumVal{ enum_name: enum_name // lp.prepend_mod(enum_name) - + val: val pos: p.tok.position() mod: mod @@ -776,7 +777,7 @@ pub fn (p mut Parser) expr(precedence int) ast.Expr { node = ast.SizeOf{ typ: sizeof_type // type_name: type_name - + } } .key_typeof { @@ -1044,7 +1045,7 @@ fn (p mut Parser) infix_expr(left ast.Expr) ast.Expr { left: left right: right // right_type: typ - + op: op pos: pos } @@ -1449,7 +1450,7 @@ fn (p mut Parser) const_decl() ast.ConstDecl { fields << ast.Field{ name: name // typ: typ - + } exprs << expr // TODO: once consts are fixed reg here & update in checker