From da5fb5dcbdc561fafdf27bccaba67ce0af6666f1 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 31 Dec 2019 13:23:12 +0100 Subject: [PATCH] Revert "x64, v2 backends" This reverts commit 81ae54d9bd1ee7095bf01eeb1183e2a8bbac2c50. --- v.v | 3 - vlib/builtin/array.v | 2 +- vlib/builtin/bare/array_bare.v | 2 +- vlib/compiler/aparser.v | 10 +- vlib/compiler/expression.v | 3 +- vlib/compiler/fn.v | 15 +- vlib/compiler/for.v | 10 +- vlib/compiler/main.v | 25 +- vlib/compiler/x64/gen.v | 2 +- vlib/time/time_test.v | 23 -- vlib/v/ast/ast.v | 7 +- vlib/v/gen/cgen.v | 7 - vlib/v/gen/cgen_test.v | 6 +- vlib/v/gen/tests/2.c | 21 +- vlib/v/gen/tests/2.vv | 20 +- vlib/v/gen/x64/elf.v | 100 -------- vlib/v/gen/x64/elf_obj.v | 159 ------------ vlib/v/gen/x64/gen.v | 457 --------------------------------- vlib/v/parser/parser.v | 95 ++----- vlib/v/token/token.v | 6 +- vlib/v/types/types.v | 2 - 21 files changed, 74 insertions(+), 901 deletions(-) delete mode 100644 vlib/v/gen/x64/elf.v delete mode 100644 vlib/v/gen/x64/elf_obj.v delete mode 100644 vlib/v/gen/x64/gen.v diff --git a/v.v b/v.v index 22cc88df6b..c98089da43 100644 --- a/v.v +++ b/v.v @@ -68,9 +68,6 @@ fn main() { if v.pref.x64 { v.compile_x64() } - else if v.pref.v2 { - v.compile2() - } else { v.compile() } diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index bcd71e3598..03fbdb4a6d 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -16,7 +16,7 @@ pub: } // Private function, used by V (`nums := []int`) -fn new_array(mylen int, cap int, elm_size int) array { +fn new_array(mylen, cap, elm_size int) array { cap_ := if cap == 0 { 1 } else { cap } arr := array{ len: mylen diff --git a/vlib/builtin/bare/array_bare.v b/vlib/builtin/bare/array_bare.v index e80ec8a53a..e2fc075066 100644 --- a/vlib/builtin/bare/array_bare.v +++ b/vlib/builtin/bare/array_bare.v @@ -9,7 +9,7 @@ pub: } // for now off the stack -fn new_array_from_c_array(len int, cap int, elm_size int, c_array voidptr) array { +fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array { arr := array { len: len cap: cap diff --git a/vlib/compiler/aparser.v b/vlib/compiler/aparser.v index ff5cc8002f..416a07ca0c 100644 --- a/vlib/compiler/aparser.v +++ b/vlib/compiler/aparser.v @@ -7,7 +7,7 @@ import ( os strings filepath - //compiler.x64 + compiler.x64 // time ) @@ -30,7 +30,7 @@ mut: prev_tok2 TokenKind // TODO remove these once the tokens are cached lit string cgen &CGen - //x64 &x64.Gen + x64 &x64.Gen table &Table import_table ImportTable // Holds imports for just the file being parsed pass Pass @@ -207,7 +207,7 @@ fn (v mut V) new_parser(scanner &Scanner) Parser { table: v.table cur_fn: EmptyFn cgen: v.cgen - //x64: v.x64 + x64: v.x64 pref: v.pref os: v.os vroot: v.vroot @@ -3095,9 +3095,7 @@ fn (p mut Parser) check_unused_imports() { } // the imports are usually at the start of the file //p.production_error_with_token_index('the following imports were never used: $output', 0) - if !p.file_path.contains ('vlib/v/') { p.warn('the following imports were never used: $output') - } } fn (p &Parser) is_expr_fn_call(start_tok_idx int) (bool,string) { @@ -3134,6 +3132,6 @@ fn (p mut Parser) skip_block(inside_first_lcbr bool) { } fn todo_remove() { - //x64.new_gen('f') + x64.new_gen('f') } diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index 504f6ce935..ad23e42b55 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -356,7 +356,6 @@ fn (p mut Parser) name_expr() string { } // Color.green else if p.peek() == .dot { - is_arr_start := p.prev_tok == .lsbr enum_type := p.table.find_type(name) if enum_type.cat != .enum_ { p.error('`$name` is not an enum') @@ -367,7 +366,7 @@ fn (p mut Parser) name_expr() string { if !enum_type.has_enum_val(val) { p.error('enum `$enum_type.name` does not have value `$val`') } - if p.expected_type == enum_type.name && !is_arr_start { + if p.expected_type == enum_type.name { // `if color == .red` is enough // no need in `if color == Color.red` p.warn('`${enum_type.name}.$val` is unnecessary, use `.$val`') diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index 8d2ca991d6..3cea04d9b4 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -434,7 +434,7 @@ fn (p mut Parser) fn_decl() { // Special case for main() args if f.name == 'main__main' && !has_receiver { if p.pref.x64 && !p.first_pass() { - //p.x64.save_main_fn_addr() + p.x64.save_main_fn_addr() } if str_args != '' || typ != 'void' { p.error_with_token_index('fn main must have no arguments and no return values', f.fn_name_token_idx) @@ -554,7 +554,7 @@ fn (p mut Parser) fn_decl() { } } if p.pref.x64 { - //p.x64.register_function_address(f.name) + p.x64.register_function_address(f.name) } p.statements_no_rcbr() // p.cgen.nogen = false @@ -574,10 +574,10 @@ fn (p mut Parser) fn_decl() { p.genln('pthread_mutex_unlock(&live_fn_mutex);') } if p.pref.x64 && f.name == 'main__main' && !p.first_pass() { - //p.x64.gen_exit() + p.x64.gen_exit() } if p.pref.x64 && !p.first_pass() { - //p.x64.ret() + p.x64.ret() } // {} closed correctly? scope_level should be 0 if p.mod == 'main' { @@ -640,8 +640,7 @@ fn (p mut Parser) check_unused_and_mut_vars() { if var.name == '' { break } - if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated && - var.name != 'tmpl_res' && p.mod != 'vweb' && var.name != 'it' { + if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated && var.name != 'tmpl_res' && p.mod != 'vweb' { p.production_error_with_token_index('`$var.name` declared and not used', var.token_idx) } if !var.is_changed && var.is_mut && !p.pref.is_repl && !p.pref.translated && var.typ != 'T*' && p.mod != 'ui' && var.typ != 'App*' { @@ -755,7 +754,7 @@ fn (p mut Parser) fn_call(f mut Fn, method_ph int, receiver_var, receiver_type s p.cgen.nogen = true } if p.pref.x64 && !p.first_pass() { - //p.x64.call_fn(f.name) + p.x64.call_fn(f.name) } p.calling_c = f.is_c if f.is_c && !p.builtin_mod { @@ -1080,7 +1079,7 @@ fn (p mut Parser) fn_call_args(f mut Fn, generic_param_types []string) { } // x64 println gen if p.pref.x64 && i == 0 && f.name == 'println' && p.tok == .str && p.peek() == .rpar { - //p.x64.gen_print(p.lit) + p.x64.gen_print(p.lit) } mut typ := p.bool_expression() // Register an interface type usage: diff --git a/vlib/compiler/for.v b/vlib/compiler/for.v index 380ec2f914..b71d79f8a7 100644 --- a/vlib/compiler/for.v +++ b/vlib/compiler/for.v @@ -12,7 +12,7 @@ fn (p mut Parser) for_st() { } // debug := p.scanner.file_path.contains('r_draw') p.open_scope() - //mut label := 0 + mut label := 0 mut to := 0 if p.tok == .lcbr { // Infinite loop @@ -148,7 +148,7 @@ fn (p mut Parser) for_st() { p.check_types(range_typ, 'int') range_end = range_expr if p.pref.x64 { - //label = p.x64.gen_loop_start(expr.int()) + label = p.x64.gen_loop_start(expr.int()) // to = range_expr.int() // TODO why empty? } } @@ -218,8 +218,8 @@ fn (p mut Parser) for_st() { p.close_scope() p.for_expr_cnt-- p.returns = false // TODO handle loops that are guaranteed to return - //if label > 0 { - //p.x64.gen_loop_end(to, label) - //} + if label > 0 { + p.x64.gen_loop_end(to, label) + } } diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 85435ee22f..fb1bc6c302 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -8,12 +8,11 @@ import ( os.cmdline strings filepath - //compiler.x64 - v.gen.x64 + compiler.x64 + //v.table + //v.parser + //v.gen //v.types - v.table - v.parser - v.gen ) pub const ( @@ -71,7 +70,7 @@ pub mut: compiled_dir string // contains os.realpath() of the dir of the final file beeing compiled, or the dir itself when doing `v .` table &Table // table with types, vars, functions etc cgen &CGen // C code generator - //x64 &x64.Gen + x64 &x64.Gen pref &Preferences // all the preferences and settings extracted to a struct for reusability lang_dir string // "~/code/v" out_name string // "program.exe" @@ -142,7 +141,6 @@ pub mut: x64 bool output_cross_c bool prealloc bool - v2 bool } // Should be called by main at the end of the compilation process, to cleanup @@ -380,6 +378,7 @@ pub fn (v mut V) compile() { v.cc() } +/* pub fn (v mut V) compile2() { if os.user_os() != 'windows' && v.pref.ccompiler == 'msvc' { verror('Cannot build with msvc on ${os.user_os()}') @@ -414,6 +413,7 @@ pub fn (v mut V) compile2() { v.cc() } +*/ pub fn (v mut V) compile_x64() { $if !linux { @@ -422,18 +422,14 @@ pub fn (v mut V) compile_x64() { } v.files << v.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare')) v.files << v.dir - - table := &table.Table{} - files := parser.parse_files(v.files, table) - x64.gen(files, v.out_name) - /* + v.x64.generate_elf_header() for f in v.files { v.parse(f, .decl) } for f in v.files { v.parse(f, .main) } - */ + v.x64.generate_elf_footer() } fn (v mut V) generate_init() { @@ -1141,7 +1137,6 @@ pub fn new_v(args []string) &V { user_mod_path: user_mod_path vlib_path: vlib_path vpath: vpath - v2: '-v2' in args } if pref.is_verbose || pref.is_debug { println('C compiler=$pref.ccompiler') @@ -1163,7 +1158,7 @@ pub fn new_v(args []string) &V { table: new_table(obfuscate) out_name_c: out_name_c cgen: new_cgen(out_name_c) - //x64: x64.new_gen(out_name) + x64: x64.new_gen(out_name) vroot: vroot pref: pref mod: mod diff --git a/vlib/compiler/x64/gen.v b/vlib/compiler/x64/gen.v index 279ada855f..ce531f7dff 100644 --- a/vlib/compiler/x64/gen.v +++ b/vlib/compiler/x64/gen.v @@ -253,7 +253,7 @@ fn (g mut Gen) mov(reg Register, val int) { pub fn (g mut Gen) register_function_address(name string) { addr := g.pos() - //println('reg fn addr $name $addr') + println('reg fn addr $name $addr') g.fn_addr[name] = addr } diff --git a/vlib/time/time_test.v b/vlib/time/time_test.v index 461db69e00..3f2b44a89e 100644 --- a/vlib/time/time_test.v +++ b/vlib/time/time_test.v @@ -21,17 +21,6 @@ fn test_is_leap_year() { assert time.is_leap_year(2100) == false } -fn test_now_format() { - /* - t := time.now() - u:=t.uni - println(u) - println(t.format()) - println(time.unix(u).format()) - assert t.format() == time.unix(u).format() - */ -} - fn check_days_in_month(month, year, expected int) bool { res := time.days_in_month(month, year) or { return false @@ -59,18 +48,6 @@ fn test_unix() { assert t.second == 59 } -fn test_unix2() { - /* - println(t.year) - assert t.year == 2019 - assert t.month == 12 - assert t.day == 31 - assert t.hour == 8 - assert t.minute == 9 - assert t.second == 53 - */ -} - fn test_format_ss() { assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy) } diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index c71065c82b..d73d8ed6b4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -58,7 +58,6 @@ pub struct StructDecl { pub: name string fields []Field - is_pub bool } pub struct StructInit { @@ -71,8 +70,8 @@ pub: // import statement pub struct Import { pub: - mods []string - // expr Expr + name string + expr Expr // imports map[string]string } @@ -161,7 +160,7 @@ pub: tok_kind token.Kind cond Expr stmts []Stmt - else_stmts []Stmt + else_ []Stmt } pub struct ForStmt { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 5a8964d078..0c904eab6e 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -179,13 +179,6 @@ fn (g mut Gen) expr(node ast.Expr) { g.stmt(stmt) } g.writeln('}') - if it.else_stmts.len > 0 { - g.writeln('else { ') - for stmt in it.else_stmts { - g.stmt(stmt) - } - g.writeln('}') - } } else { println(term.red('cgen.expr(): bad node')) diff --git a/vlib/v/gen/cgen_test.v b/vlib/v/gen/cgen_test.v index c93eabac82..a86a74ad4e 100644 --- a/vlib/v/gen/cgen_test.v +++ b/vlib/v/gen/cgen_test.v @@ -40,13 +40,13 @@ fn compare_texts(a, b string) bool { lines_a := a.trim_space().split_into_lines() lines_b := b.trim_space().split_into_lines() if lines_a.len != lines_b.len { - println(term.red('different len')) - // return false + println('different len') + return false } for i, line_a in lines_a { line_b := lines_b[i] if line_a.trim_space() != line_b.trim_space() { - println(term.red('!' + line_a)) + println('!' + line_a) return false } } diff --git a/vlib/v/gen/tests/2.c b/vlib/v/gen/tests/2.c index c22c351074..f928d64723 100644 --- a/vlib/v/gen/tests/2.c +++ b/vlib/v/gen/tests/2.c @@ -11,15 +11,6 @@ typedef struct { string name; } User; -void init_user() { - User user = (User){ - .name = tos3("Bob"), - }; -} - -void puts(string s) { -} - void function2() { int x = 0; f64 f = 10.1; @@ -36,18 +27,20 @@ void function2() { if (false) { foo(1); } - else { - puts(tos3("else")); - foo(100); - } while (true) { - init_user(); + foo(0); } bool e = 1 + 2 > 0; bool e2 = 1 + 2 < 0; int j = 0; } +void init_user() { + User user = (User){ + .name = tos3("Bob"), + }; +} + void init_array() { int nums = new_array_from_c_array(3, 3, sizeof(int), { 1, 2, 3, diff --git a/vlib/v/gen/tests/2.vv b/vlib/v/gen/tests/2.vv index 082f6db5cd..60d59c65f3 100644 --- a/vlib/v/gen/tests/2.vv +++ b/vlib/v/gen/tests/2.vv @@ -10,18 +10,9 @@ struct User { name string } -fn init_user() { - user := User{ - name: 'Bob' - } -} - -fn puts(s string) {} - // comment fn function2() { mut x := 0 - //mut negative := -1 f := 10.1 s := 'hi' mut m := 10 @@ -38,12 +29,8 @@ fn function2() { if false { foo(1) } - else { - puts('else') - foo(100) - } for true { - init_user() + foo(0) } e := 1 + 2 > 0 e2 := 1 + 2 < 0 @@ -51,6 +38,11 @@ fn function2() { j := 0 } +fn init_user() { + user := User{ + name: 'Bob' + } +} fn init_array() { nums := [1,2,3] diff --git a/vlib/v/gen/x64/elf.v b/vlib/v/gen/x64/elf.v deleted file mode 100644 index ff018cb784..0000000000 --- a/vlib/v/gen/x64/elf.v +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -module x64 - -import os - -const ( - mag0 = 0x7f - mag1 = `E` - mag2 = `L` - mag3 = `F` - ei_class = 4 - elfclass64 = 2 - elfdata2lsb = 1 - ev_current = 1 - elf_osabi = 0 - // ELF file types - et_rel = 1 - et_exec = 2 - et_dyn = 3 - e_machine = 0x3e - shn_xindex = 0xffff - sht_null = 0 -) - -const ( - segment_start = 0x400000 -) - -pub fn (g mut Gen) generate_elf_header() { - g.buf << [byte(mag0), mag1, mag2, mag3] - g.buf << elfclass64 // file class - g.buf << elfdata2lsb // data encoding - g.buf << ev_current // file version - g.buf << 1 // elf_osabi - g.write64(0) // et_rel) // et_rel for .o - g.write16(2) // e_type - g.write16(e_machine) // - g.write32(ev_current) // e_version - eh_size := 0x40 - phent_size := 0x38 - g.write64(segment_start + eh_size + phent_size) // e_entry - g.write64(0x40) // e_phoff - g.write64(0) // e_shoff - g.write32(0) // e_flags - g.write16(eh_size) // e_ehsize - g.write16(phent_size) // e_phentsize - g.write16(1) // e_phnum - g.write16(0) // e_shentsize - g.write16(0) // e_shnum (number of sections) - g.write16(0) // e_shstrndx - // Elf64_Phdr - g.write32(1) // p_type - g.write32(5) // p_flags - g.write64(0) // p_offset - g.write64(segment_start) // p_vaddr addr:050 - g.write64(segment_start) // - g.file_size_pos = g.buf.len - g.write64(0) // p_filesz PLACEHOLDER, set to file_size later // addr: 060 - g.write64(0) // p_memsz - g.write64(0x1000) // p_align - // user code starts here at - // address: 00070 and a half - g.code_start_pos = g.buf.len - g.call(0) // call main function, it's not guaranteed to be the first -} - -pub fn (g mut Gen) generate_elf_footer() { - // Return 0 - g.mov(.edi, 0) // ret value - g.mov(.eax, 60) - g.syscall() - // Strings table - // Loop thru all strings and set the right addresses - for i, s in g.strings { - g.write64_at(segment_start + g.buf.len, int(g.str_pos[i])) - g.write_string(s) - g.write8(6) - } - // Now we know the file size, set it - file_size := g.buf.len - g.write64_at(file_size, g.file_size_pos) // set file size 64 bit value - g.write64_at(file_size, g.file_size_pos + 8) - // call main function, it's not guaranteed to be the first - // we generated call(0) ("e8 0") - // no need to replace "0" with a relative address of the main function - // +1 is for "e8" - // -5 is for "e8 00 00 00 00" - g.write64_at(int(g.main_fn_addr - g.code_start_pos) - 5, g.code_start_pos + 1) - // Create the binary - mut f := os.create(g.out_name)or{ - panic(err) - } - os.chmod(g.out_name, 0775) - f.write_bytes(g.buf.data, g.buf.len) - f.close() - println('x64 elf binary has been successfully generated') -} - diff --git a/vlib/v/gen/x64/elf_obj.v b/vlib/v/gen/x64/elf_obj.v deleted file mode 100644 index e1f90de6a5..0000000000 --- a/vlib/v/gen/x64/elf_obj.v +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -module x64 -/* -This file is unused right now, since binaries without sections -are generated. - -But it will be necessary once we have dynamic linking. -*/ - - -enum SectionType { - null = 0 - progbits = 1 - symtab = 2 - strtab = 3 - rela = 4 -} - -struct SectionConfig { - name string - typ SectionType - flags i64 - data voidptr - is_saa bool - datalen i64 - link int - info int - align i64 - entsize i64 -} - -fn (g mut Gen) section_header(c SectionConfig) { - g.write32(g.sect_header_name_pos) - g.sect_header_name_pos += c.name.len + 1 - g.write32(int(c.typ)) - g.write64(c.flags) - g.write64(0) // sh_addr - g.write64(g.offset) // offset - g.offset += c.datalen + 1 - g.write64(c.datalen) - g.write32(c.link) - g.write32(c.info) - g.write64(c.align) - g.write64(c.entsize) -} - -fn genobj() { - /* - // SHN_UNDEF - mut g := Gen{} - nr_sections := 7 - g.section_header(SectionConfig{ - name: '' - typ: .null - flags:0 - data: 0 - is_saa: false - link: 0 - info:0 - align:0 - entsize: 0 - }) - - /* - for sect in sections { - g.section_header(SectionConfig{ - name:0 - typ: sect.typ - flags: sect.flags - data: sect.data - is_saa: true - datalen: sect.len - link: 0 - info: 0 - align: sect.align - entsize: sect.entsize - }) - - } - */ - - g.section_header(SectionConfig{ - name: '.DATA' - typ: .progbits - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - - g.section_header(SectionConfig{ - name: '.TEXT' - typ: .progbits - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.shstrtab' - typ: .strtab - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0x22 - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.symtab' - typ: .symtab - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.strtab' - typ: .symtab - flags: 0x2 - //data: sect.data - is_saa: true - datalen: 0xd - link: 0 - info: 0 - align: 1 - entsize: 0 - }) - g.section_header(SectionConfig{ - name: '.rela.TEXT' - typ: .rela - flags: 0x0 - //data: sect.data - is_saa: true - datalen: 0x18 - link: 4 - info: 2 - align: 8 - entsize: 0x18 - }) - */ -} - diff --git a/vlib/v/gen/x64/gen.v b/vlib/v/gen/x64/gen.v deleted file mode 100644 index 0ccf602e38..0000000000 --- a/vlib/v/gen/x64/gen.v +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -module x64 - -import ( - v.ast - term -) - -pub struct Gen { - out_name string -mut: - buf []byte - sect_header_name_pos int - offset i64 - str_pos []i64 - strings []string // TODO use a map and don't duplicate strings - file_size_pos i64 - main_fn_addr i64 - code_start_pos i64 // location of the start of the assembly instructions - fn_addr map[string]i64 - // string_addr map[string]i64 -} - -enum Register { - eax - edi - rax - rdi - rsi - edx - rdx - r12 -} - -enum Size { - _8 - _16 - _32 - _64 -} - -pub fn gen(files []ast.File, out_name string) { - mut g := Gen{ - // out: strings.new_builder(100) - sect_header_name_pos: 0 - buf: [] - out_name: out_name - } - g.generate_elf_header() - for file in files { - for stmt in file.stmts { - g.stmt(stmt) - g.writeln('') - } - } - g.generate_elf_footer() -} - -pub fn new_gen(out_name string) &Gen { - return &Gen{ - sect_header_name_pos: 0 - buf: [] - out_name: out_name - } -} - -pub fn (g &Gen) pos() i64 { - return g.buf.len -} - -fn (g mut Gen) write8(n int) { - // write 1 byte - g.buf << byte(n) -} - -fn (g mut Gen) write16(n int) { - // write 2 bytes - g.buf << byte(n) - g.buf << byte(n>>8) -} - -fn (g mut Gen) write32(n int) { - // write 4 bytes - g.buf << byte(n) - g.buf << byte(n>>8) - g.buf << byte(n>>16) - g.buf << byte(n>>24) -} - -fn (g mut Gen) write64(n i64) { - // write 8 bytes - g.buf << byte(n) - g.buf << byte(n>>8) - g.buf << byte(n>>16) - g.buf << byte(n>>24) - g.buf << byte(n>>32) - g.buf << byte(n>>40) - g.buf << byte(n>>48) - g.buf << byte(n>>56) -} - -fn (g mut Gen) write64_at(n i64, at i64) { - // write 8 bytes - g.buf[at] = byte(n) - g.buf[at + 1] = byte(n>>8) - g.buf[at + 2] = byte(n>>16) - g.buf[at + 3] = byte(n>>24) - g.buf[at + 4] = byte(n>>32) - g.buf[at + 5] = byte(n>>40) - g.buf[at + 6] = byte(n>>48) - g.buf[at + 7] = byte(n>>56) -} - -fn (g mut Gen) write_string(s string) { - for c in s { - g.write8(int(c)) - } -} - -fn (g mut Gen) inc(reg Register) { - g.write16(0xff49) - match reg { - .r12 { - g.write8(0xc4) - } - else { - panic('unhandled inc $reg') - } - } -} - -fn (g mut Gen) cmp(reg Register, size Size, val i64) { - g.write8(0x49) - // Second byte depends on the size of the value - match size { - ._8 { - g.write8(0x83) - } - ._32 { - g.write8(0x81) - } - else { - panic('unhandled cmp') - } - } - // Third byte depends on the register being compared to - match reg { - .r12 { - g.write8(0xfc) - } - else { - panic('unhandled cmp') - } - } - g.write8(int(val)) -} - -fn abs(a i64) i64 { - return if a < 0 { -a } else { a } -} - -fn (g mut Gen) jle(addr i64) { - // Calculate the relative offset to jump to - // (`addr` is absolute address) - offset := 0xff - int(abs(addr - g.buf.len)) - 1 - g.write8(0x7e) - g.write8(offset) -} - -fn (g mut Gen) jl(addr i64) { - offset := 0xff - int(abs(addr - g.buf.len)) - 1 - g.write8(0x7c) - g.write8(offset) -} - -fn (g &Gen) abs_to_rel_addr(addr i64) int { - return int(abs(addr - g.buf.len)) - 1 -} - -fn (g mut Gen) jmp(addr i64) { - offset := 0xff - g.abs_to_rel_addr(addr) - g.write8(0xe9) - g.write8(offset) -} - -fn (g mut Gen) mov64(reg Register, val i64) { - match reg { - .rsi { - g.write8(0x48) - g.write8(0xbe) - } - else { - println('unhandled mov $reg') - } - } - g.write64(val) -} - -fn (g mut Gen) call(addr int) { - // rel := g.abs_to_rel_addr(addr) - // rel := 0xffffffff - int(abs(addr - g.buf.len))-1 - println('call addr=$addr rel_addr=$addr pos=$g.buf.len') - g.write8(0xe8) - g.write32(addr) -} - -fn (g mut Gen) syscall() { - // g.write(0x050f) - g.write8(0x0f) - g.write8(0x05) -} - -pub fn (g mut Gen) ret() { - g.write8(0xc3) -} - -// returns label's relative address -pub fn (g mut Gen) gen_loop_start(from int) int { - g.mov(.r12, from) - label := g.buf.len - g.inc(.r12) - return label -} - -pub fn (g mut Gen) gen_loop_end(to int, label int) { - g.cmp(.r12, ._8, to) - g.jl(label) -} - -pub fn (g mut Gen) save_main_fn_addr() { - g.main_fn_addr = g.buf.len -} - -pub fn (g mut Gen) gen_print(s string) { - g.strings << s + '\n' - // g.string_addr[s] = str_pos - g.mov(.eax, 1) - g.mov(.edi, 1) - str_pos := g.buf.len + 2 - g.str_pos << str_pos - g.mov64(.rsi, 0) // segment_start + 0x9f) // str pos // PLACEHOLDER - g.mov(.edx, s.len + 1) // len - g.syscall() -} - -pub fn (g mut Gen) gen_exit() { - // Return 0 - g.mov(.edi, 0) // ret value - g.mov(.eax, 60) - g.syscall() -} - -fn (g mut Gen) mov(reg Register, val int) { - match reg { - .eax { - g.write8(0xb8) - } - .edi { - g.write8(0xbf) - } - .edx { - g.write8(0xba) - } - .rsi { - g.write8(0x48) - g.write8(0xbe) - } - .r12 { - g.write8(0x41) - g.write8(0xbc) // r11 is 0xbb etc - } - else { - panic('unhandled mov $reg') - } - } - g.write32(val) -} - -pub fn (g mut Gen) register_function_address(name string) { - addr := g.pos() - // println('reg fn addr $name $addr') - g.fn_addr[name] = addr -} - -pub fn (g &Gen) write(s string) {} - -pub fn (g &Gen) writeln(s string) {} - -pub fn (g mut Gen) call_fn(name string) { - if !name.contains('__') { - return - } - addr := g.fn_addr[name] - g.call(int(addr)) - println('call $name $addr') -} - -fn (g mut Gen) stmt(node ast.Stmt) { - match node { - ast.AssignStmt { - g.expr(it.left) - g.write(' $it.op.str() ') - g.expr(it.right) - g.writeln(';') - } - ast.FnDecl { - if it.name == 'main' { - g.write('int ${it.name}(') - } - else { - g.write('$it.typ.name ${it.name}(') - } - for arg in it.args { - g.write(arg.typ.name + ' ' + arg.name) - } - g.writeln(') { ') - for stmt in it.stmts { - g.stmt(stmt) - } - if it.name == 'main' { - g.writeln('return 0;') - } - g.writeln('}') - } - ast.Return { - g.write('return ') - g.expr(it.expr) - g.writeln(';') - } - ast.VarDecl { - g.write('$it.typ.name $it.name = ') - g.expr(it.expr) - g.writeln(';') - } - ast.ForStmt { - g.write('while (') - g.expr(it.cond) - g.writeln(') {') - for stmt in it.stmts { - g.stmt(stmt) - } - g.writeln('}') - } - ast.StructDecl { - g.writeln('typedef struct {') - for field in it.fields { - g.writeln('\t$field.typ.name $field.name;') - } - g.writeln('} $it.name;') - } - ast.ExprStmt { - g.expr(it.expr) - match it.expr { - // no ; after an if expression - ast.IfExpr {} - else { - g.writeln(';') - } - } - } - else { - verror('cgen.stmt(): bad node') - } - } -} - -fn (g mut Gen) expr(node ast.Expr) { - // println('cgen expr()') - match node { - ast.IntegerLiteral { - g.write(it.val.str()) - } - ast.FloatLiteral { - g.write(it.val) - } - ast.UnaryExpr { - g.expr(it.left) - g.write(it.op.str()) - } - ast.StringLiteral { - g.write('tos3("$it.val")') - } - ast.BinaryExpr { - g.expr(it.left) - g.write(' $it.op.str() ') - g.expr(it.right) - // if typ.name != typ2.name { - // verror('bad types $typ.name $typ2.name') - // } - } - // `user := User{name: 'Bob'}` - ast.StructInit { - g.writeln('($it.typ.name){') - for i, field in it.fields { - g.write('\t.$field = ') - g.expr(it.exprs[i]) - g.writeln(', ') - } - g.write('}') - } - ast.CallExpr { - g.write('${it.name}(') - for i, expr in it.args { - g.expr(expr) - if i != it.args.len - 1 { - g.write(', ') - } - } - g.write(')') - } - ast.ArrayInit { - g.writeln('new_array_from_c_array($it.exprs.len, $it.exprs.len, sizeof($it.typ.name), {\t') - for expr in it.exprs { - g.expr(expr) - g.write(', ') - } - g.write('\n})') - } - ast.Ident { - g.write('$it.name') - } - ast.BoolLiteral { - if it.val == true { - g.write('true') - } - else { - g.write('false') - } - } - ast.IfExpr { - g.write('if (') - g.expr(it.cond) - g.writeln(') {') - for stmt in it.stmts { - g.stmt(stmt) - } - g.writeln('}') - if it.else_stmts.len > 0 { - g.writeln('else { ') - for stmt in it.else_stmts { - g.stmt(stmt) - } - g.writeln('}') - } - } - else { - println(term.red('cgen.expr(): bad node')) - } - } -} - -fn verror(s string) { - println(s) - exit(1) -} diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 7fe87f05d5..65eb8b44a8 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -15,7 +15,6 @@ import ( struct Parser { scanner &scanner.Scanner - file_name string mut: tok token.Token peek_tok token.Token @@ -48,9 +47,6 @@ pub fn (p mut Parser) get_type() types.Type { 'string' { return types.string_type } - 'voidptr' { - return types.voidptr_type - } else { typ := p.table.types[p.tok.lit] if isnil(typ.name.str) || typ.name == '' { @@ -90,13 +86,10 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File { mut files := []ast.File for path in paths { mut stmts := []ast.Stmt - text := os.read_file(path) or { - panic(err) - } + text := os.read_file(path) or { panic(err) } mut p := Parser{ scanner: scanner.new_scanner(text) table: table - file_name: path } p.read_first_token() for { @@ -125,7 +118,6 @@ pub fn (p mut Parser) read_first_token() { } pub fn (p mut Parser) parse_block() []ast.Stmt { - p.check(.lcbr) mut stmts := []ast.Stmt for { // res := s.scan() @@ -135,7 +127,7 @@ pub fn (p mut Parser) parse_block() []ast.Stmt { // println('expr at ' + p.tok.str()) stmts << p.stmt() } - p.check(.rcbr) + p.next() // println('nr exprs in block = $exprs.len') return stmts } @@ -178,29 +170,6 @@ pub fn (p mut Parser) stmt() ast.Stmt { .key_import { return p.import_stmt() } - .key_pub { - match p.peek_tok.kind { - .key_fn { - return p.fn_decl() - } - .key_struct, .key_union, .key_interface { - return p.struct_decl() - } - else { - p.error('wrong pub keyword usage') - return ast.Stmt{} - } - } - // .key_const { - // return p.const_decl() - // } - // .key_enum { - // return p.enum_decl() - // } - // .key_type { - // return p.type_decl() - // } - } .key_fn { return p.fn_decl() } @@ -251,7 +220,7 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt { } pub fn (p &Parser) error(s string) { - println(term.bold(term.red('$p.file_name:$p.tok.line_nr: $s'))) + println(term.bold(term.red('x.v:$p.tok.line_nr: $s'))) exit(1) } @@ -323,7 +292,6 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { p.check(.colon) // expr,field_type := p.expr(0) expr,_ := p.expr(0) - // if !types.check( ,field_type exprs << expr } node = ast.StructInit{ @@ -369,17 +337,17 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { } else { if p.tok.is_unary() { - pt := p.tok - p.next() - expr,t2 := p.expr(token.lowest_prec) - node = ast.UnaryExpr{ - left: expr - op: pt.kind - } - typ = t2 + pt := p.tok + p.next() + expr,t2 := p.expr(token.lowest_prec) + node = ast.UnaryExpr{ + left: expr + op: pt.kind + } + typ = t2 } else { - p.error('!unknown token ' + p.tok.str()) + verror('!unknown token ' + p.tok.str()) } } } @@ -410,22 +378,21 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { left: node op: prev_tok.kind } - } - else { + } else { mut expr := ast.Expr{} expr,t2 = p.expr(prev_tok.precedence() - 1) if prev_tok.is_relational() { typ = types.bool_type } else { - typ = t2 + typ = t2 } // println(t2.name + '222') node = ast.BinaryExpr{ left: node op: prev_tok.kind right: expr - } + } } } } @@ -438,6 +405,7 @@ fn (p mut Parser) for_statement() ast.ForStmt { if !types.check(types.bool_type, typ) { p.error('non-bool used as for condition') } + p.check(.lcbr) stmts := p.parse_block() return ast.ForStmt{ cond: cond @@ -452,17 +420,11 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) { if !types.check(types.bool_type, typ) { p.error('non-bool used as if condition') } + p.check(.lcbr) stmts := p.parse_block() - mut else_stmts := []ast.Stmt - if p.tok.kind == .key_else { - println('GOT ELSE') - p.check(.key_else) - else_stmts = p.parse_block() - } node = ast.IfExpr{ cond: cond stmts: stmts - else_stmts: else_stmts } return node,types.void_type } @@ -533,27 +495,17 @@ fn (p mut Parser) module_decl() ast.Module { } fn (p mut Parser) import_stmt() ast.Import { - p.check(.key_import) - name := p.check_name() - return ast.Import{ - mods: [name] - } + // p.check(.key_import) + p.next() + return ast.Import{} } fn (p mut Parser) struct_decl() ast.StructDecl { - is_pub := p.tok.kind == .key_pub - if is_pub { - p.next() - } p.check(.key_struct) name := p.check_name() p.check(.lcbr) mut fields := []ast.Field for p.tok.kind != .rcbr { - if p.tok.kind == .key_pub { - p.check(.key_pub) - p.check(.colon) - } field_name := p.check_name() typ := p.get_type() fields << ast.Field{ @@ -567,7 +519,6 @@ fn (p mut Parser) struct_decl() ast.StructDecl { }) return ast.StructDecl{ name: name - is_pub: is_pub fields: fields } } @@ -592,9 +543,6 @@ fn (p mut Parser) fn_decl() ast.FnDecl { typ: typ name: arg_name } - if p.tok.kind != .rpar { - p.check(.comma) - } } p.check(.rpar) // Return type @@ -603,6 +551,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { typ = p.get_type() p.return_type = typ } + p.check(.lcbr) p.table.register_fn(table.Fn{ name: name args: args @@ -653,7 +602,7 @@ fn (p mut Parser) var_decl() ast.VarDecl { return ast.VarDecl{ name: name expr: expr // p.expr(token.lowest_prec) - + typ: t } } diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 1d26318481..783e2cad94 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -362,7 +362,7 @@ pub fn (tok Token) is_unary() bool { pub fn (tok Token) is_left_assoc() bool { return tok.kind in [ // .number, - // `++` | `--` + // `++` | `--` .inc, .dec, // `*` | `/` | `%` .mul, .div, .mod, @@ -371,7 +371,7 @@ pub fn (tok Token) is_left_assoc() bool { // `==` | `!=` .eq, .ne, // `<` | `<=` | `>` | `>=` - .lt, .le, .gt, .ge, .ne, .eq, + .lt, .le, .gt, .ge, // `,` .comma] } @@ -392,5 +392,5 @@ pub fn (tok Token) is_right_assoc() bool { pub fn (tok Token) is_relational() bool { return tok.kind in [ // `<` | `<=` | `>` | `>=` - .lt, .le, .gt, .ge, .eq, .ne] + .lt, .le, .gt, .ge] } diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v index 609ac95d0a..34e5cc5283 100644 --- a/vlib/v/types/types.v +++ b/vlib/v/types/types.v @@ -20,8 +20,6 @@ pub const ( 'f64',3} bool_type = Type{ 'bool',4} - voidptr_type = Type{ - 'voidptr',5} ) pub fn check(got, expected &Type) bool {