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

Revert "x64, v2 backends"

This reverts commit 81ae54d9bd.
This commit is contained in:
Alexander Medvednikov 2019-12-31 13:23:12 +01:00
parent 81ae54d9bd
commit da5fb5dcbd
21 changed files with 74 additions and 901 deletions

3
v.v
View File

@ -68,9 +68,6 @@ fn main() {
if v.pref.x64 { if v.pref.x64 {
v.compile_x64() v.compile_x64()
} }
else if v.pref.v2 {
v.compile2()
}
else { else {
v.compile() v.compile()
} }

View File

@ -16,7 +16,7 @@ pub:
} }
// Private function, used by V (`nums := []int`) // 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 } cap_ := if cap == 0 { 1 } else { cap }
arr := array{ arr := array{
len: mylen len: mylen

View File

@ -9,7 +9,7 @@ pub:
} }
// for now off the stack // 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 { arr := array {
len: len len: len
cap: cap cap: cap

View File

@ -7,7 +7,7 @@ import (
os os
strings strings
filepath filepath
//compiler.x64 compiler.x64
// time // time
) )
@ -30,7 +30,7 @@ mut:
prev_tok2 TokenKind // TODO remove these once the tokens are cached prev_tok2 TokenKind // TODO remove these once the tokens are cached
lit string lit string
cgen &CGen cgen &CGen
//x64 &x64.Gen x64 &x64.Gen
table &Table table &Table
import_table ImportTable // Holds imports for just the file being parsed import_table ImportTable // Holds imports for just the file being parsed
pass Pass pass Pass
@ -207,7 +207,7 @@ fn (v mut V) new_parser(scanner &Scanner) Parser {
table: v.table table: v.table
cur_fn: EmptyFn cur_fn: EmptyFn
cgen: v.cgen cgen: v.cgen
//x64: v.x64 x64: v.x64
pref: v.pref pref: v.pref
os: v.os os: v.os
vroot: v.vroot vroot: v.vroot
@ -3095,9 +3095,7 @@ fn (p mut Parser) check_unused_imports() {
} }
// the imports are usually at the start of the file // the imports are usually at the start of the file
//p.production_error_with_token_index('the following imports were never used: $output', 0) //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') p.warn('the following imports were never used: $output')
}
} }
fn (p &Parser) is_expr_fn_call(start_tok_idx int) (bool,string) { 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() { fn todo_remove() {
//x64.new_gen('f') x64.new_gen('f')
} }

View File

@ -356,7 +356,6 @@ fn (p mut Parser) name_expr() string {
} }
// Color.green // Color.green
else if p.peek() == .dot { else if p.peek() == .dot {
is_arr_start := p.prev_tok == .lsbr
enum_type := p.table.find_type(name) enum_type := p.table.find_type(name)
if enum_type.cat != .enum_ { if enum_type.cat != .enum_ {
p.error('`$name` is not an 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) { if !enum_type.has_enum_val(val) {
p.error('enum `$enum_type.name` does not have value `$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 // `if color == .red` is enough
// no need in `if color == Color.red` // no need in `if color == Color.red`
p.warn('`${enum_type.name}.$val` is unnecessary, use `.$val`') p.warn('`${enum_type.name}.$val` is unnecessary, use `.$val`')

View File

@ -434,7 +434,7 @@ fn (p mut Parser) fn_decl() {
// Special case for main() args // Special case for main() args
if f.name == 'main__main' && !has_receiver { if f.name == 'main__main' && !has_receiver {
if p.pref.x64 && !p.first_pass() { if p.pref.x64 && !p.first_pass() {
//p.x64.save_main_fn_addr() p.x64.save_main_fn_addr()
} }
if str_args != '' || typ != 'void' { 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) 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 { if p.pref.x64 {
//p.x64.register_function_address(f.name) p.x64.register_function_address(f.name)
} }
p.statements_no_rcbr() p.statements_no_rcbr()
// p.cgen.nogen = false // p.cgen.nogen = false
@ -574,10 +574,10 @@ fn (p mut Parser) fn_decl() {
p.genln('pthread_mutex_unlock(&live_fn_mutex);') p.genln('pthread_mutex_unlock(&live_fn_mutex);')
} }
if p.pref.x64 && f.name == 'main__main' && !p.first_pass() { 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() { if p.pref.x64 && !p.first_pass() {
//p.x64.ret() p.x64.ret()
} }
// {} closed correctly? scope_level should be 0 // {} closed correctly? scope_level should be 0
if p.mod == 'main' { if p.mod == 'main' {
@ -640,8 +640,7 @@ fn (p mut Parser) check_unused_and_mut_vars() {
if var.name == '' { if var.name == '' {
break break
} }
if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated && if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated && var.name != 'tmpl_res' && p.mod != 'vweb' {
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) 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*' { 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 p.cgen.nogen = true
} }
if p.pref.x64 && !p.first_pass() { 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 p.calling_c = f.is_c
if f.is_c && !p.builtin_mod { 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 // x64 println gen
if p.pref.x64 && i == 0 && f.name == 'println' && p.tok == .str && p.peek() == .rpar { 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() mut typ := p.bool_expression()
// Register an interface type usage: // Register an interface type usage:

View File

@ -12,7 +12,7 @@ fn (p mut Parser) for_st() {
} }
// debug := p.scanner.file_path.contains('r_draw') // debug := p.scanner.file_path.contains('r_draw')
p.open_scope() p.open_scope()
//mut label := 0 mut label := 0
mut to := 0 mut to := 0
if p.tok == .lcbr { if p.tok == .lcbr {
// Infinite loop // Infinite loop
@ -148,7 +148,7 @@ fn (p mut Parser) for_st() {
p.check_types(range_typ, 'int') p.check_types(range_typ, 'int')
range_end = range_expr range_end = range_expr
if p.pref.x64 { 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? // to = range_expr.int() // TODO why empty?
} }
} }
@ -218,8 +218,8 @@ fn (p mut Parser) for_st() {
p.close_scope() p.close_scope()
p.for_expr_cnt-- p.for_expr_cnt--
p.returns = false // TODO handle loops that are guaranteed to return p.returns = false // TODO handle loops that are guaranteed to return
//if label > 0 { if label > 0 {
//p.x64.gen_loop_end(to, label) p.x64.gen_loop_end(to, label)
//} }
} }

View File

@ -8,12 +8,11 @@ import (
os.cmdline os.cmdline
strings strings
filepath filepath
//compiler.x64 compiler.x64
v.gen.x64 //v.table
//v.parser
//v.gen
//v.types //v.types
v.table
v.parser
v.gen
) )
pub const ( 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 .` 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 table &Table // table with types, vars, functions etc
cgen &CGen // C code generator cgen &CGen // C code generator
//x64 &x64.Gen x64 &x64.Gen
pref &Preferences // all the preferences and settings extracted to a struct for reusability pref &Preferences // all the preferences and settings extracted to a struct for reusability
lang_dir string // "~/code/v" lang_dir string // "~/code/v"
out_name string // "program.exe" out_name string // "program.exe"
@ -142,7 +141,6 @@ pub mut:
x64 bool x64 bool
output_cross_c bool output_cross_c bool
prealloc bool prealloc bool
v2 bool
} }
// Should be called by main at the end of the compilation process, to cleanup // 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() v.cc()
} }
/*
pub fn (v mut V) compile2() { pub fn (v mut V) compile2() {
if os.user_os() != 'windows' && v.pref.ccompiler == 'msvc' { if os.user_os() != 'windows' && v.pref.ccompiler == 'msvc' {
verror('Cannot build with msvc on ${os.user_os()}') verror('Cannot build with msvc on ${os.user_os()}')
@ -414,6 +413,7 @@ pub fn (v mut V) compile2() {
v.cc() v.cc()
} }
*/
pub fn (v mut V) compile_x64() { pub fn (v mut V) compile_x64() {
$if !linux { $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.v_files_from_dir(filepath.join(v.pref.vlib_path,'builtin','bare'))
v.files << v.dir 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 { for f in v.files {
v.parse(f, .decl) v.parse(f, .decl)
} }
for f in v.files { for f in v.files {
v.parse(f, .main) v.parse(f, .main)
} }
*/ v.x64.generate_elf_footer()
} }
fn (v mut V) generate_init() { fn (v mut V) generate_init() {
@ -1141,7 +1137,6 @@ pub fn new_v(args []string) &V {
user_mod_path: user_mod_path user_mod_path: user_mod_path
vlib_path: vlib_path vlib_path: vlib_path
vpath: vpath vpath: vpath
v2: '-v2' in args
} }
if pref.is_verbose || pref.is_debug { if pref.is_verbose || pref.is_debug {
println('C compiler=$pref.ccompiler') println('C compiler=$pref.ccompiler')
@ -1163,7 +1158,7 @@ pub fn new_v(args []string) &V {
table: new_table(obfuscate) table: new_table(obfuscate)
out_name_c: out_name_c out_name_c: out_name_c
cgen: new_cgen(out_name_c) cgen: new_cgen(out_name_c)
//x64: x64.new_gen(out_name) x64: x64.new_gen(out_name)
vroot: vroot vroot: vroot
pref: pref pref: pref
mod: mod mod: mod

View File

@ -253,7 +253,7 @@ fn (g mut Gen) mov(reg Register, val int) {
pub fn (g mut Gen) register_function_address(name string) { pub fn (g mut Gen) register_function_address(name string) {
addr := g.pos() addr := g.pos()
//println('reg fn addr $name $addr') println('reg fn addr $name $addr')
g.fn_addr[name] = addr g.fn_addr[name] = addr
} }

View File

@ -21,17 +21,6 @@ fn test_is_leap_year() {
assert time.is_leap_year(2100) == false 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 { fn check_days_in_month(month, year, expected int) bool {
res := time.days_in_month(month, year) or { res := time.days_in_month(month, year) or {
return false return false
@ -59,18 +48,6 @@ fn test_unix() {
assert t.second == 59 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() { fn test_format_ss() {
assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy) assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy)
} }

View File

@ -58,7 +58,6 @@ pub struct StructDecl {
pub: pub:
name string name string
fields []Field fields []Field
is_pub bool
} }
pub struct StructInit { pub struct StructInit {
@ -71,8 +70,8 @@ pub:
// import statement // import statement
pub struct Import { pub struct Import {
pub: pub:
mods []string name string
// expr Expr expr Expr
// imports map[string]string // imports map[string]string
} }
@ -161,7 +160,7 @@ pub:
tok_kind token.Kind tok_kind token.Kind
cond Expr cond Expr
stmts []Stmt stmts []Stmt
else_stmts []Stmt else_ []Stmt
} }
pub struct ForStmt { pub struct ForStmt {

View File

@ -179,13 +179,6 @@ fn (g mut Gen) expr(node ast.Expr) {
g.stmt(stmt) g.stmt(stmt)
} }
g.writeln('}') g.writeln('}')
if it.else_stmts.len > 0 {
g.writeln('else { ')
for stmt in it.else_stmts {
g.stmt(stmt)
}
g.writeln('}')
}
} }
else { else {
println(term.red('cgen.expr(): bad node')) println(term.red('cgen.expr(): bad node'))

View File

@ -40,13 +40,13 @@ fn compare_texts(a, b string) bool {
lines_a := a.trim_space().split_into_lines() lines_a := a.trim_space().split_into_lines()
lines_b := b.trim_space().split_into_lines() lines_b := b.trim_space().split_into_lines()
if lines_a.len != lines_b.len { if lines_a.len != lines_b.len {
println(term.red('different len')) println('different len')
// return false return false
} }
for i, line_a in lines_a { for i, line_a in lines_a {
line_b := lines_b[i] line_b := lines_b[i]
if line_a.trim_space() != line_b.trim_space() { if line_a.trim_space() != line_b.trim_space() {
println(term.red('!' + line_a)) println('!' + line_a)
return false return false
} }
} }

View File

@ -11,15 +11,6 @@ typedef struct {
string name; string name;
} User; } User;
void init_user() {
User user = (User){
.name = tos3("Bob"),
};
}
void puts(string s) {
}
void function2() { void function2() {
int x = 0; int x = 0;
f64 f = 10.1; f64 f = 10.1;
@ -36,18 +27,20 @@ void function2() {
if (false) { if (false) {
foo(1); foo(1);
} }
else {
puts(tos3("else"));
foo(100);
}
while (true) { while (true) {
init_user(); foo(0);
} }
bool e = 1 + 2 > 0; bool e = 1 + 2 > 0;
bool e2 = 1 + 2 < 0; bool e2 = 1 + 2 < 0;
int j = 0; int j = 0;
} }
void init_user() {
User user = (User){
.name = tos3("Bob"),
};
}
void init_array() { void init_array() {
int nums = new_array_from_c_array(3, 3, sizeof(int), { int nums = new_array_from_c_array(3, 3, sizeof(int), {
1, 2, 3, 1, 2, 3,

View File

@ -10,18 +10,9 @@ struct User {
name string name string
} }
fn init_user() {
user := User{
name: 'Bob'
}
}
fn puts(s string) {}
// comment // comment
fn function2() { fn function2() {
mut x := 0 mut x := 0
//mut negative := -1
f := 10.1 f := 10.1
s := 'hi' s := 'hi'
mut m := 10 mut m := 10
@ -38,12 +29,8 @@ fn function2() {
if false { if false {
foo(1) foo(1)
} }
else {
puts('else')
foo(100)
}
for true { for true {
init_user() foo(0)
} }
e := 1 + 2 > 0 e := 1 + 2 > 0
e2 := 1 + 2 < 0 e2 := 1 + 2 < 0
@ -51,6 +38,11 @@ fn function2() {
j := 0 j := 0
} }
fn init_user() {
user := User{
name: 'Bob'
}
}
fn init_array() { fn init_array() {
nums := [1,2,3] nums := [1,2,3]

View File

@ -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')
}

View File

@ -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
})
*/
}

View File

@ -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)
}

View File

@ -15,7 +15,6 @@ import (
struct Parser { struct Parser {
scanner &scanner.Scanner scanner &scanner.Scanner
file_name string
mut: mut:
tok token.Token tok token.Token
peek_tok token.Token peek_tok token.Token
@ -48,9 +47,6 @@ pub fn (p mut Parser) get_type() types.Type {
'string' { 'string' {
return types.string_type return types.string_type
} }
'voidptr' {
return types.voidptr_type
}
else { else {
typ := p.table.types[p.tok.lit] typ := p.table.types[p.tok.lit]
if isnil(typ.name.str) || typ.name == '' { 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 mut files := []ast.File
for path in paths { for path in paths {
mut stmts := []ast.Stmt mut stmts := []ast.Stmt
text := os.read_file(path) or { text := os.read_file(path) or { panic(err) }
panic(err)
}
mut p := Parser{ mut p := Parser{
scanner: scanner.new_scanner(text) scanner: scanner.new_scanner(text)
table: table table: table
file_name: path
} }
p.read_first_token() p.read_first_token()
for { for {
@ -125,7 +118,6 @@ pub fn (p mut Parser) read_first_token() {
} }
pub fn (p mut Parser) parse_block() []ast.Stmt { pub fn (p mut Parser) parse_block() []ast.Stmt {
p.check(.lcbr)
mut stmts := []ast.Stmt mut stmts := []ast.Stmt
for { for {
// res := s.scan() // res := s.scan()
@ -135,7 +127,7 @@ pub fn (p mut Parser) parse_block() []ast.Stmt {
// println('expr at ' + p.tok.str()) // println('expr at ' + p.tok.str())
stmts << p.stmt() stmts << p.stmt()
} }
p.check(.rcbr) p.next()
// println('nr exprs in block = $exprs.len') // println('nr exprs in block = $exprs.len')
return stmts return stmts
} }
@ -178,29 +170,6 @@ pub fn (p mut Parser) stmt() ast.Stmt {
.key_import { .key_import {
return p.import_stmt() 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 { .key_fn {
return p.fn_decl() return p.fn_decl()
} }
@ -251,7 +220,7 @@ pub fn (p mut Parser) assign_stmt() ast.AssignStmt {
} }
pub fn (p &Parser) error(s string) { 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) exit(1)
} }
@ -323,7 +292,6 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
p.check(.colon) p.check(.colon)
// expr,field_type := p.expr(0) // expr,field_type := p.expr(0)
expr,_ := p.expr(0) expr,_ := p.expr(0)
// if !types.check( ,field_type
exprs << expr exprs << expr
} }
node = ast.StructInit{ node = ast.StructInit{
@ -369,17 +337,17 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
} }
else { else {
if p.tok.is_unary() { if p.tok.is_unary() {
pt := p.tok pt := p.tok
p.next() p.next()
expr,t2 := p.expr(token.lowest_prec) expr,t2 := p.expr(token.lowest_prec)
node = ast.UnaryExpr{ node = ast.UnaryExpr{
left: expr left: expr
op: pt.kind op: pt.kind
} }
typ = t2 typ = t2
} }
else { 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 left: node
op: prev_tok.kind op: prev_tok.kind
} }
} } else {
else {
mut expr := ast.Expr{} mut expr := ast.Expr{}
expr,t2 = p.expr(prev_tok.precedence() - 1) expr,t2 = p.expr(prev_tok.precedence() - 1)
if prev_tok.is_relational() { if prev_tok.is_relational() {
typ = types.bool_type typ = types.bool_type
} }
else { else {
typ = t2 typ = t2
} }
// println(t2.name + '222') // println(t2.name + '222')
node = ast.BinaryExpr{ node = ast.BinaryExpr{
left: node left: node
op: prev_tok.kind op: prev_tok.kind
right: expr right: expr
} }
} }
} }
} }
@ -438,6 +405,7 @@ fn (p mut Parser) for_statement() ast.ForStmt {
if !types.check(types.bool_type, typ) { if !types.check(types.bool_type, typ) {
p.error('non-bool used as for condition') p.error('non-bool used as for condition')
} }
p.check(.lcbr)
stmts := p.parse_block() stmts := p.parse_block()
return ast.ForStmt{ return ast.ForStmt{
cond: cond cond: cond
@ -452,17 +420,11 @@ fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
if !types.check(types.bool_type, typ) { if !types.check(types.bool_type, typ) {
p.error('non-bool used as if condition') p.error('non-bool used as if condition')
} }
p.check(.lcbr)
stmts := p.parse_block() 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{ node = ast.IfExpr{
cond: cond cond: cond
stmts: stmts stmts: stmts
else_stmts: else_stmts
} }
return node,types.void_type 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 { fn (p mut Parser) import_stmt() ast.Import {
p.check(.key_import) // p.check(.key_import)
name := p.check_name() p.next()
return ast.Import{ return ast.Import{}
mods: [name]
}
} }
fn (p mut Parser) struct_decl() ast.StructDecl { fn (p mut Parser) struct_decl() ast.StructDecl {
is_pub := p.tok.kind == .key_pub
if is_pub {
p.next()
}
p.check(.key_struct) p.check(.key_struct)
name := p.check_name() name := p.check_name()
p.check(.lcbr) p.check(.lcbr)
mut fields := []ast.Field mut fields := []ast.Field
for p.tok.kind != .rcbr { for p.tok.kind != .rcbr {
if p.tok.kind == .key_pub {
p.check(.key_pub)
p.check(.colon)
}
field_name := p.check_name() field_name := p.check_name()
typ := p.get_type() typ := p.get_type()
fields << ast.Field{ fields << ast.Field{
@ -567,7 +519,6 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
}) })
return ast.StructDecl{ return ast.StructDecl{
name: name name: name
is_pub: is_pub
fields: fields fields: fields
} }
} }
@ -592,9 +543,6 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
typ: typ typ: typ
name: arg_name name: arg_name
} }
if p.tok.kind != .rpar {
p.check(.comma)
}
} }
p.check(.rpar) p.check(.rpar)
// Return type // Return type
@ -603,6 +551,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
typ = p.get_type() typ = p.get_type()
p.return_type = typ p.return_type = typ
} }
p.check(.lcbr)
p.table.register_fn(table.Fn{ p.table.register_fn(table.Fn{
name: name name: name
args: args args: args
@ -653,7 +602,7 @@ fn (p mut Parser) var_decl() ast.VarDecl {
return ast.VarDecl{ return ast.VarDecl{
name: name name: name
expr: expr // p.expr(token.lowest_prec) expr: expr // p.expr(token.lowest_prec)
typ: t typ: t
} }
} }

View File

@ -362,7 +362,7 @@ pub fn (tok Token) is_unary() bool {
pub fn (tok Token) is_left_assoc() bool { pub fn (tok Token) is_left_assoc() bool {
return tok.kind in [ return tok.kind in [
// .number, // .number,
// `++` | `--` // `++` | `--`
.inc, .dec, .inc, .dec,
// `*` | `/` | `%` // `*` | `/` | `%`
.mul, .div, .mod, .mul, .div, .mod,
@ -371,7 +371,7 @@ pub fn (tok Token) is_left_assoc() bool {
// `==` | `!=` // `==` | `!=`
.eq, .ne, .eq, .ne,
// `<` | `<=` | `>` | `>=` // `<` | `<=` | `>` | `>=`
.lt, .le, .gt, .ge, .ne, .eq, .lt, .le, .gt, .ge,
// `,` // `,`
.comma] .comma]
} }
@ -392,5 +392,5 @@ pub fn (tok Token) is_right_assoc() bool {
pub fn (tok Token) is_relational() bool { pub fn (tok Token) is_relational() bool {
return tok.kind in [ return tok.kind in [
// `<` | `<=` | `>` | `>=` // `<` | `<=` | `>` | `>=`
.lt, .le, .gt, .ge, .eq, .ne] .lt, .le, .gt, .ge]
} }

View File

@ -20,8 +20,6 @@ pub const (
'f64',3} 'f64',3}
bool_type = Type{ bool_type = Type{
'bool',4} 'bool',4}
voidptr_type = Type{
'voidptr',5}
) )
pub fn check(got, expected &Type) bool { pub fn check(got, expected &Type) bool {