From 4d31d5882d517dee8195788940c55101a8e19096 Mon Sep 17 00:00:00 2001
From: Alexander Medvednikov <alexander@medvednikov.com>
Date: Tue, 31 Dec 2019 19:42:16 +0100
Subject: [PATCH] x64, v2 backends

---
 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, 901 insertions(+), 74 deletions(-)
 create mode 100644 vlib/v/gen/x64/elf.v
 create mode 100644 vlib/v/gen/x64/elf_obj.v
 create mode 100644 vlib/v/gen/x64/gen.v

diff --git a/v.v b/v.v
index c98089da43..22cc88df6b 100644
--- a/v.v
+++ b/v.v
@@ -68,6 +68,9 @@ 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 03fbdb4a6d..bcd71e3598 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, cap, elm_size int) array {
+fn new_array(mylen int, cap int, 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 e2fc075066..e80ec8a53a 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, cap, elm_size int, c_array voidptr) array {
+fn new_array_from_c_array(len int, cap int, 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 ce0489f09e..85757deb92 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
@@ -3098,7 +3098,9 @@ 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) {
@@ -3135,6 +3137,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 ad23e42b55..504f6ce935 100644
--- a/vlib/compiler/expression.v
+++ b/vlib/compiler/expression.v
@@ -356,6 +356,7 @@ 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')
@@ -366,7 +367,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 {
+			if p.expected_type == enum_type.name && !is_arr_start {
 				// `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 3cea04d9b4..8d2ca991d6 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,7 +640,8 @@ 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' {
+		if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated &&
+			var.name != 'tmpl_res' && p.mod != 'vweb' && var.name != 'it' {
 			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*' {
@@ -754,7 +755,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 {
@@ -1079,7 +1080,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 b71d79f8a7..380ec2f914 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 fb1bc6c302..85435ee22f 100644
--- a/vlib/compiler/main.v
+++ b/vlib/compiler/main.v
@@ -8,11 +8,12 @@ import (
 	os.cmdline
 	strings
 	filepath
-	compiler.x64
-	//v.table
-	//v.parser
-	//v.gen
+	//compiler.x64
+	v.gen.x64
 	//v.types
+	v.table
+	v.parser
+	v.gen
 )
 
 pub const (
@@ -70,7 +71,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"
@@ -141,6 +142,7 @@ 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
@@ -378,7 +380,6 @@ 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()}')
@@ -413,7 +414,6 @@ pub fn (v mut V) compile2() {
 	v.cc()
 
 }
-*/
 
 pub fn (v mut V) compile_x64() {
 	$if !linux {
@@ -422,14 +422,18 @@ 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
-	v.x64.generate_elf_header()
+
+	table := &table.Table{}
+	files := parser.parse_files(v.files, table)
+	x64.gen(files, v.out_name)
+	/*
 	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() {
@@ -1137,6 +1141,7 @@ 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')
@@ -1158,7 +1163,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 ce531f7dff..279ada855f 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 46d639d5f6..7d71174237 100644
--- a/vlib/time/time_test.v
+++ b/vlib/time/time_test.v
@@ -21,6 +21,17 @@ 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
@@ -80,6 +91,18 @@ fn test_unix() {
 	assert t5.second == 7
 }
 
+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 d73d8ed6b4..c71065c82b 100644
--- a/vlib/v/ast/ast.v
+++ b/vlib/v/ast/ast.v
@@ -58,6 +58,7 @@ pub struct StructDecl {
 pub:
 	name   string
 	fields []Field
+	is_pub bool
 }
 
 pub struct StructInit {
@@ -70,8 +71,8 @@ pub:
 // import statement
 pub struct Import {
 pub:
-	name string
-	expr Expr
+	mods []string
+	// expr Expr
 	// imports map[string]string
 }
 
@@ -160,7 +161,7 @@ pub:
 	tok_kind token.Kind
 	cond     Expr
 	stmts    []Stmt
-	else_    []Stmt
+	else_stmts []Stmt
 }
 
 pub struct ForStmt {
diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v
index 0c904eab6e..5a8964d078 100644
--- a/vlib/v/gen/cgen.v
+++ b/vlib/v/gen/cgen.v
@@ -179,6 +179,13 @@ 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 a86a74ad4e..c93eabac82 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('different len')
-		return false
+		println(term.red('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('!' + line_a)
+			println(term.red('!' + line_a))
 			return false
 		}
 	}
diff --git a/vlib/v/gen/tests/2.c b/vlib/v/gen/tests/2.c
index f928d64723..c22c351074 100644
--- a/vlib/v/gen/tests/2.c
+++ b/vlib/v/gen/tests/2.c
@@ -11,6 +11,15 @@ 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;
@@ -27,20 +36,18 @@ void function2() {
 	if (false) {
 		foo(1);
 	}
+	else {
+		puts(tos3("else"));
+		foo(100);
+	}
 	while (true) {
-		foo(0);
+		init_user();
 	}
 	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 60d59c65f3..082f6db5cd 100644
--- a/vlib/v/gen/tests/2.vv
+++ b/vlib/v/gen/tests/2.vv
@@ -10,9 +10,18 @@ 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
@@ -29,8 +38,12 @@ fn function2() {
 	if false {
 		foo(1)
 	}
+	else {
+		puts('else')
+		foo(100)
+	}
 	for true {
-		foo(0)
+		init_user()
 	}
 	e := 1 + 2 > 0
 	e2 := 1 + 2 < 0
@@ -38,11 +51,6 @@ 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
new file mode 100644
index 0000000000..ff018cb784
--- /dev/null
+++ b/vlib/v/gen/x64/elf.v
@@ -0,0 +1,100 @@
+// 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
new file mode 100644
index 0000000000..e1f90de6a5
--- /dev/null
+++ b/vlib/v/gen/x64/elf_obj.v
@@ -0,0 +1,159 @@
+// 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
new file mode 100644
index 0000000000..0ccf602e38
--- /dev/null
+++ b/vlib/v/gen/x64/gen.v
@@ -0,0 +1,457 @@
+// 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 65eb8b44a8..7fe87f05d5 100644
--- a/vlib/v/parser/parser.v
+++ b/vlib/v/parser/parser.v
@@ -15,6 +15,7 @@ import (
 
 struct Parser {
 	scanner     &scanner.Scanner
+	file_name   string
 mut:
 	tok         token.Token
 	peek_tok    token.Token
@@ -47,6 +48,9 @@ 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 == '' {
@@ -86,10 +90,13 @@ 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 {
@@ -118,6 +125,7 @@ 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()
@@ -127,7 +135,7 @@ pub fn (p mut Parser) parse_block() []ast.Stmt {
 		// println('expr at ' + p.tok.str())
 		stmts << p.stmt()
 	}
-	p.next()
+	p.check(.rcbr)
 	// println('nr exprs in block = $exprs.len')
 	return stmts
 }
@@ -170,6 +178,29 @@ 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()
 		}
@@ -220,7 +251,7 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt {
 }
 
 pub fn (p &Parser) error(s string) {
-	println(term.bold(term.red('x.v:$p.tok.line_nr: $s')))
+	println(term.bold(term.red('$p.file_name:$p.tok.line_nr: $s')))
 	exit(1)
 }
 
@@ -292,6 +323,7 @@ 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{
@@ -337,17 +369,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 {
-				verror('!unknown token ' + p.tok.str())
+				p.error('!unknown token ' + p.tok.str())
 			}
 		}
 	}
@@ -378,21 +410,22 @@ 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
-				}	
+				}
 			}
 		}
 	}
@@ -405,7 +438,6 @@ 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
@@ -420,11 +452,17 @@ 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
 }
@@ -495,17 +533,27 @@ fn (p mut Parser) module_decl() ast.Module {
 }
 
 fn (p mut Parser) import_stmt() ast.Import {
-	// p.check(.key_import)
-	p.next()
-	return ast.Import{}
+	p.check(.key_import)
+	name := p.check_name()
+	return ast.Import{
+		mods: [name]
+	}
 }
 
 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{
@@ -519,6 +567,7 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
 	})
 	return ast.StructDecl{
 		name: name
+		is_pub: is_pub
 		fields: fields
 	}
 }
@@ -543,6 +592,9 @@ 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
@@ -551,7 +603,6 @@ 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
@@ -602,7 +653,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 783e2cad94..1d26318481 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,
+	.lt, .le, .gt, .ge, .ne, .eq,
 	// `,`
 	.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]
+	.lt, .le, .gt, .ge, .eq, .ne]
 }
diff --git a/vlib/v/types/types.v b/vlib/v/types/types.v
index 34e5cc5283..609ac95d0a 100644
--- a/vlib/v/types/types.v
+++ b/vlib/v/types/types.v
@@ -20,6 +20,8 @@ pub const (
 		'f64',3}
 	bool_type = Type{
 		'bool',4}
+	voidptr_type = Type{
+		'voidptr',5}
 )
 
 pub fn check(got, expected &Type) bool {