mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
x64, v2 backends
This commit is contained in:
parent
907254b9e8
commit
81ae54d9bd
3
v.v
3
v.v
@ -68,6 +68,9 @@ 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()
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ pub:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Private function, used by V (`nums := []int`)
|
// 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 }
|
cap_ := if cap == 0 { 1 } else { cap }
|
||||||
arr := array{
|
arr := array{
|
||||||
len: mylen
|
len: mylen
|
||||||
|
@ -9,7 +9,7 @@ pub:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// for now off the stack
|
// 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 {
|
arr := array {
|
||||||
len: len
|
len: len
|
||||||
cap: cap
|
cap: cap
|
||||||
|
@ -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,8 +3095,10 @@ 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) {
|
||||||
mut expr := p.tokens[start_tok_idx - 1].str()
|
mut expr := p.tokens[start_tok_idx - 1].str()
|
||||||
@ -3132,6 +3134,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')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,6 +356,7 @@ 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')
|
||||||
@ -366,7 +367,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 {
|
if p.expected_type == enum_type.name && !is_arr_start {
|
||||||
// `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`')
|
||||||
|
@ -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,7 +640,8 @@ 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 && 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)
|
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*' {
|
||||||
@ -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
|
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 {
|
||||||
@ -1079,7 +1080,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:
|
||||||
|
@ -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)
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,12 @@ import (
|
|||||||
os.cmdline
|
os.cmdline
|
||||||
strings
|
strings
|
||||||
filepath
|
filepath
|
||||||
compiler.x64
|
//compiler.x64
|
||||||
//v.table
|
v.gen.x64
|
||||||
//v.parser
|
|
||||||
//v.gen
|
|
||||||
//v.types
|
//v.types
|
||||||
|
v.table
|
||||||
|
v.parser
|
||||||
|
v.gen
|
||||||
)
|
)
|
||||||
|
|
||||||
pub const (
|
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 .`
|
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"
|
||||||
@ -141,6 +142,7 @@ 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
|
||||||
@ -378,7 +380,6 @@ 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()}')
|
||||||
@ -413,7 +414,6 @@ 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,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.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() {
|
||||||
@ -1137,6 +1141,7 @@ 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')
|
||||||
@ -1158,7 +1163,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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,17 @@ 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
|
||||||
@ -48,6 +59,18 @@ 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)
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ pub struct StructDecl {
|
|||||||
pub:
|
pub:
|
||||||
name string
|
name string
|
||||||
fields []Field
|
fields []Field
|
||||||
|
is_pub bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StructInit {
|
pub struct StructInit {
|
||||||
@ -70,8 +71,8 @@ pub:
|
|||||||
// import statement
|
// import statement
|
||||||
pub struct Import {
|
pub struct Import {
|
||||||
pub:
|
pub:
|
||||||
name string
|
mods []string
|
||||||
expr Expr
|
// expr Expr
|
||||||
// imports map[string]string
|
// imports map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +161,7 @@ pub:
|
|||||||
tok_kind token.Kind
|
tok_kind token.Kind
|
||||||
cond Expr
|
cond Expr
|
||||||
stmts []Stmt
|
stmts []Stmt
|
||||||
else_ []Stmt
|
else_stmts []Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ForStmt {
|
pub struct ForStmt {
|
||||||
|
@ -179,6 +179,13 @@ 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'))
|
||||||
|
@ -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('different len')
|
println(term.red('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('!' + line_a)
|
println(term.red('!' + line_a))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,15 @@ 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;
|
||||||
@ -27,20 +36,18 @@ void function2() {
|
|||||||
if (false) {
|
if (false) {
|
||||||
foo(1);
|
foo(1);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
puts(tos3("else"));
|
||||||
|
foo(100);
|
||||||
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
foo(0);
|
init_user();
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
@ -10,9 +10,18 @@ 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
|
||||||
@ -29,8 +38,12 @@ fn function2() {
|
|||||||
if false {
|
if false {
|
||||||
foo(1)
|
foo(1)
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
puts('else')
|
||||||
|
foo(100)
|
||||||
|
}
|
||||||
for true {
|
for true {
|
||||||
foo(0)
|
init_user()
|
||||||
}
|
}
|
||||||
e := 1 + 2 > 0
|
e := 1 + 2 > 0
|
||||||
e2 := 1 + 2 < 0
|
e2 := 1 + 2 < 0
|
||||||
@ -38,11 +51,6 @@ 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]
|
||||||
|
100
vlib/v/gen/x64/elf.v
Normal file
100
vlib/v/gen/x64/elf.v
Normal file
@ -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')
|
||||||
|
}
|
||||||
|
|
159
vlib/v/gen/x64/elf_obj.v
Normal file
159
vlib/v/gen/x64/elf_obj.v
Normal file
@ -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
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
457
vlib/v/gen/x64/gen.v
Normal file
457
vlib/v/gen/x64/gen.v
Normal file
@ -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)
|
||||||
|
}
|
@ -15,6 +15,7 @@ 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
|
||||||
@ -47,6 +48,9 @@ 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 == '' {
|
||||||
@ -86,10 +90,13 @@ 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 { panic(err) }
|
text := os.read_file(path) or {
|
||||||
|
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 {
|
||||||
@ -118,6 +125,7 @@ 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()
|
||||||
@ -127,7 +135,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.next()
|
p.check(.rcbr)
|
||||||
// println('nr exprs in block = $exprs.len')
|
// println('nr exprs in block = $exprs.len')
|
||||||
return stmts
|
return stmts
|
||||||
}
|
}
|
||||||
@ -170,6 +178,29 @@ 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()
|
||||||
}
|
}
|
||||||
@ -220,7 +251,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('x.v:$p.tok.line_nr: $s')))
|
println(term.bold(term.red('$p.file_name:$p.tok.line_nr: $s')))
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,6 +323,7 @@ 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{
|
||||||
@ -347,7 +379,7 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
|
|||||||
typ = t2
|
typ = t2
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
verror('!unknown token ' + p.tok.str())
|
p.error('!unknown token ' + p.tok.str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,7 +410,8 @@ 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() {
|
||||||
@ -405,7 +438,6 @@ 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
|
||||||
@ -420,11 +452,17 @@ 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
|
||||||
}
|
}
|
||||||
@ -495,17 +533,27 @@ 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)
|
||||||
p.next()
|
name := p.check_name()
|
||||||
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{
|
||||||
@ -519,6 +567,7 @@ 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -543,6 +592,9 @@ 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
|
||||||
@ -551,7 +603,6 @@ 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
|
||||||
|
@ -371,7 +371,7 @@ pub fn (tok Token) is_left_assoc() bool {
|
|||||||
// `==` | `!=`
|
// `==` | `!=`
|
||||||
.eq, .ne,
|
.eq, .ne,
|
||||||
// `<` | `<=` | `>` | `>=`
|
// `<` | `<=` | `>` | `>=`
|
||||||
.lt, .le, .gt, .ge,
|
.lt, .le, .gt, .ge, .ne, .eq,
|
||||||
// `,`
|
// `,`
|
||||||
.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]
|
.lt, .le, .gt, .ge, .eq, .ne]
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ 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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user