SelectorExpr; receivers; struct field check; if expression
							parent
							
								
									3c65af8b9a
								
							
						
					
					
						commit
						492dfebd15
					
				
							
								
								
									
										2
									
								
								v2.v
								
								
								
								
							
							
						
						
									
										2
									
								
								v2.v
								
								
								
								
							| 
						 | 
					@ -22,7 +22,7 @@ fn main() {
 | 
				
			||||||
	println('V2 $path')
 | 
						println('V2 $path')
 | 
				
			||||||
	table := table.new_table()
 | 
						table := table.new_table()
 | 
				
			||||||
	program := parser.parse_file(path, table)
 | 
						program := parser.parse_file(path, table)
 | 
				
			||||||
	res := gen.cgen([program])
 | 
						res := gen.cgen([program], table)
 | 
				
			||||||
	mut out := os.create('out.c')?
 | 
						mut out := os.create('out.c')?
 | 
				
			||||||
	out.writeln(cdefs)
 | 
						out.writeln(cdefs)
 | 
				
			||||||
	out.writeln(res)
 | 
						out.writeln(res)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ pub:
 | 
				
			||||||
	element_size int
 | 
						element_size int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Private function, used by V (`nums := []int`)
 | 
					// Internal function, used by V (`nums := []int`)
 | 
				
			||||||
fn new_array(mylen int, cap int, 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{
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ fn new_array(mylen int, cap int, elm_size int) array {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO
 | 
					// TODO
 | 
				
			||||||
pub fn make(len, cap, elm_size int) array {
 | 
					pub fn make(len int, cap int, elm_size int) array {
 | 
				
			||||||
	return new_array(len, cap, elm_size)
 | 
						return new_array(len, cap, elm_size)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,9 @@ fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array {
 | 
				
			||||||
		data: calloc(cap_ * elm_size)
 | 
							data: calloc(cap_ * elm_size)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// TODO Write all memory functions (like memcpy) in V
 | 
						// TODO Write all memory functions (like memcpy) in V
 | 
				
			||||||
	C.memcpy(arr.data, c_array, len * elm_size)
 | 
						C.memcpy(
 | 
				
			||||||
 | 
					arr.data,
 | 
				
			||||||
 | 
					c_array, len * elm_size)
 | 
				
			||||||
	return arr
 | 
						return arr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ import (
 | 
				
			||||||
	v.table
 | 
						v.table
 | 
				
			||||||
	v.parser
 | 
						v.parser
 | 
				
			||||||
	v.gen
 | 
						v.gen
 | 
				
			||||||
 | 
						time
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const (
 | 
					pub const (
 | 
				
			||||||
| 
						 | 
					@ -397,7 +398,7 @@ pub fn (v mut V) compile2() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	table := table.new_table()
 | 
						table := table.new_table()
 | 
				
			||||||
	files := parser.parse_files(v.files, table)
 | 
						files := parser.parse_files(v.files, table)
 | 
				
			||||||
	c := gen.cgen(files)
 | 
						c := gen.cgen(files, table)
 | 
				
			||||||
	println('out: $v.out_name_c')
 | 
						println('out: $v.out_name_c')
 | 
				
			||||||
	os.write_file(v.out_name_c, c)
 | 
						os.write_file(v.out_name_c, c)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -423,9 +424,12 @@ 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	table := &table.Table{}
 | 
						table := &table.new_table()
 | 
				
			||||||
 | 
						ticks := time.ticks()
 | 
				
			||||||
	files := parser.parse_files(v.files, table)
 | 
						files := parser.parse_files(v.files, table)
 | 
				
			||||||
 | 
						println('PARSE: ${time.ticks() - ticks}ms')
 | 
				
			||||||
	x64.gen(files, v.out_name)
 | 
						x64.gen(files, v.out_name)
 | 
				
			||||||
 | 
						println('x64 GEN: ${time.ticks() - ticks}ms')
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	for f in v.files {
 | 
						for f in v.files {
 | 
				
			||||||
		v.parse(f, .decl)
 | 
							v.parse(f, .decl)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,15 +8,16 @@ import (
 | 
				
			||||||
	v.types
 | 
						v.types
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral | 	
 | 
					pub type Expr = BinaryExpr | UnaryExpr | IfExpr | StringLiteral | IntegerLiteral |
 | 
				
			||||||
FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit
 | 
					FloatLiteral | Ident | CallExpr | BoolLiteral | StructInit | ArrayInit | SelectorExpr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt | 	
 | 
					pub type Stmt = VarDecl | FnDecl | Return | Module | Import | ExprStmt | AssignStmt |
 | 
				
			||||||
ForStmt | StructDecl
 | 
					ForStmt | StructDecl
 | 
				
			||||||
// Stand-alone expression in a statement list.
 | 
					// Stand-alone expression in a statement list.
 | 
				
			||||||
pub struct ExprStmt {
 | 
					pub struct ExprStmt {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
	expr Expr
 | 
						expr Expr
 | 
				
			||||||
 | 
						typ  types.Type
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct IntegerLiteral {
 | 
					pub struct IntegerLiteral {
 | 
				
			||||||
| 
						 | 
					@ -40,6 +41,13 @@ pub:
 | 
				
			||||||
	val bool
 | 
						val bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// `foo.bar`
 | 
				
			||||||
 | 
					pub struct SelectorExpr {
 | 
				
			||||||
 | 
					pub:
 | 
				
			||||||
 | 
						expr  Expr
 | 
				
			||||||
 | 
						field string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// module declaration
 | 
					// module declaration
 | 
				
			||||||
pub struct Module {
 | 
					pub struct Module {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
| 
						 | 
					@ -84,10 +92,12 @@ pub:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct FnDecl {
 | 
					pub struct FnDecl {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
	name  string
 | 
						name   string
 | 
				
			||||||
	stmts []Stmt
 | 
						stmts  []Stmt
 | 
				
			||||||
	typ   types.Type
 | 
						typ    types.Type
 | 
				
			||||||
	args  []Arg
 | 
						args   []Arg
 | 
				
			||||||
 | 
						is_pub bool
 | 
				
			||||||
 | 
						receiver Field
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct CallExpr {
 | 
					pub struct CallExpr {
 | 
				
			||||||
| 
						 | 
					@ -164,6 +174,8 @@ pub:
 | 
				
			||||||
	cond       Expr
 | 
						cond       Expr
 | 
				
			||||||
	stmts      []Stmt
 | 
						stmts      []Stmt
 | 
				
			||||||
	else_stmts []Stmt
 | 
						else_stmts []Stmt
 | 
				
			||||||
 | 
						typ        types.Type
 | 
				
			||||||
 | 
						left       Expr // `a` in `a := if ...`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct ForStmt {
 | 
					pub struct ForStmt {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,18 +3,22 @@ module gen
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	strings
 | 
						strings
 | 
				
			||||||
	v.ast
 | 
						v.ast
 | 
				
			||||||
 | 
						v.table
 | 
				
			||||||
 | 
						v.types
 | 
				
			||||||
	term
 | 
						term
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Gen {
 | 
					struct Gen {
 | 
				
			||||||
	out         strings.Builder
 | 
						out         strings.Builder
 | 
				
			||||||
	definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
 | 
						definitions strings.Builder // typedefs, defines etc (everything that goes to the top of the file)
 | 
				
			||||||
 | 
						table       &table.Table
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn cgen(files []ast.File) string {
 | 
					pub fn cgen(files []ast.File, table &table.Table) string {
 | 
				
			||||||
	mut g := Gen{
 | 
						mut g := Gen{
 | 
				
			||||||
		out: strings.new_builder(100)
 | 
							out: strings.new_builder(100)
 | 
				
			||||||
		definitions: strings.new_builder(100)
 | 
							definitions: strings.new_builder(100)
 | 
				
			||||||
 | 
							table: table
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for file in files {
 | 
						for file in files {
 | 
				
			||||||
		for stmt in file.stmts {
 | 
							for stmt in file.stmts {
 | 
				
			||||||
| 
						 | 
					@ -139,6 +143,9 @@ fn (g mut Gen) expr(node ast.Expr) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.BinaryExpr {
 | 
							ast.BinaryExpr {
 | 
				
			||||||
			g.expr(it.left)
 | 
								g.expr(it.left)
 | 
				
			||||||
 | 
								if it.op == .dot {
 | 
				
			||||||
 | 
									println('!! dot')
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			g.write(' $it.op.str() ')
 | 
								g.write(' $it.op.str() ')
 | 
				
			||||||
			g.expr(it.right)
 | 
								g.expr(it.right)
 | 
				
			||||||
			// if typ.name != typ2.name {
 | 
								// if typ.name != typ2.name {
 | 
				
			||||||
| 
						 | 
					@ -184,11 +191,28 @@ fn (g mut Gen) expr(node ast.Expr) {
 | 
				
			||||||
				g.write('false')
 | 
									g.write('false')
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ast.SelectorExpr {
 | 
				
			||||||
 | 
								g.expr(it.expr)
 | 
				
			||||||
 | 
								g.write('.')
 | 
				
			||||||
 | 
								g.write(it.field)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ast.IfExpr {
 | 
							ast.IfExpr {
 | 
				
			||||||
 | 
								// If expression? Assign the value to a temp var.
 | 
				
			||||||
 | 
								// Previously ?: was used, but it's too unreliable.
 | 
				
			||||||
 | 
								mut tmp := ''
 | 
				
			||||||
 | 
								if it.typ.idx != types.void_type.idx {
 | 
				
			||||||
 | 
									tmp = g.table.new_tmp_var()
 | 
				
			||||||
 | 
									// g.writeln('$it.typ.name $tmp;')
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			g.write('if (')
 | 
								g.write('if (')
 | 
				
			||||||
			g.expr(it.cond)
 | 
								g.expr(it.cond)
 | 
				
			||||||
			g.writeln(') {')
 | 
								g.writeln(') {')
 | 
				
			||||||
			for stmt in it.stmts {
 | 
								for i, stmt in it.stmts {
 | 
				
			||||||
 | 
									// Assign ret value
 | 
				
			||||||
 | 
									if i == it.stmts.len - 1 && it.typ.idx != types.void_type.idx {
 | 
				
			||||||
 | 
										// g.writeln('$tmp =')
 | 
				
			||||||
 | 
										println(1)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				g.stmt(stmt)
 | 
									g.stmt(stmt)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			g.writeln('}')
 | 
								g.writeln('}')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,13 +23,14 @@ fn test_c_files() {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		table := &table.new_table()
 | 
							table := &table.new_table()
 | 
				
			||||||
		program := parser.parse_file(path, table)
 | 
							program := parser.parse_file(path, table)
 | 
				
			||||||
		res := gen.cgen([program])
 | 
							res := gen.cgen([program], table)
 | 
				
			||||||
		if compare_texts(res, ctext) {
 | 
							if compare_texts(res, ctext) {
 | 
				
			||||||
			eprintln('${i}... ' + term.green('OK'))
 | 
								eprintln('${i}... ' + term.green('OK'))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			eprintln('${i}... ' + term.red('FAIL'))
 | 
								eprintln('${i}... ' + term.red('FAIL'))
 | 
				
			||||||
			eprintln('expected:\n$ctext\ngot:\n$res')
 | 
								eprintln(path)
 | 
				
			||||||
 | 
								eprintln('got:\n$res')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,11 @@
 | 
				
			||||||
void foo(int a);
 | 
					void foo(int a);
 | 
				
			||||||
 | 
					int get_int(string a);
 | 
				
			||||||
 | 
					int get_int2();
 | 
				
			||||||
 | 
					void myuser();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						int age;
 | 
				
			||||||
 | 
					} User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main() {
 | 
					int main() {
 | 
				
			||||||
int a = 10;
 | 
					int a = 10;
 | 
				
			||||||
| 
						 | 
					@ -10,5 +17,22 @@ return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void foo(int a) {
 | 
					void foo(int a) {
 | 
				
			||||||
 | 
						void n = get_int2();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int get_int(string a) {
 | 
				
			||||||
 | 
						return 10;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int get_int2() {
 | 
				
			||||||
 | 
						string a = tos3("hello");
 | 
				
			||||||
 | 
						return get_int(a);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void myuser() {
 | 
				
			||||||
 | 
						User user = (User){
 | 
				
			||||||
 | 
							.age = 10,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						User age = user.age;
 | 
				
			||||||
 | 
						bool b = age > 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,7 @@
 | 
				
			||||||
 | 
					struct User {
 | 
				
			||||||
 | 
						age int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn main() {
 | 
					fn main() {
 | 
				
			||||||
	a := 10
 | 
						a := 10
 | 
				
			||||||
	a++
 | 
						a++
 | 
				
			||||||
| 
						 | 
					@ -7,5 +11,21 @@ fn main() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn foo(a int) {
 | 
					fn foo(a int) {
 | 
				
			||||||
 | 
						n := get_int2()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_int(a string) int {
 | 
				
			||||||
 | 
						return 10
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_int2() int {
 | 
				
			||||||
 | 
						a := 'hello'
 | 
				
			||||||
 | 
						return get_int(a)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn myuser() {
 | 
				
			||||||
 | 
						user := User{age:10}
 | 
				
			||||||
 | 
						age := user.age
 | 
				
			||||||
 | 
						b := age > 0
 | 
				
			||||||
 | 
						//b2 := user.age > 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					fn foo() {
 | 
				
			||||||
 | 
						a := if true { 1 } else { 2 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,9 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
 | 
				
			||||||
	p.check(.lpar)
 | 
						p.check(.lpar)
 | 
				
			||||||
	mut is_unknown := false
 | 
						mut is_unknown := false
 | 
				
			||||||
	mut args := []ast.Expr
 | 
						mut args := []ast.Expr
 | 
				
			||||||
 | 
						mut return_type := types.void_type
 | 
				
			||||||
	if f := p.table.find_fn(fn_name) {
 | 
						if f := p.table.find_fn(fn_name) {
 | 
				
			||||||
 | 
							return_type = f.return_type
 | 
				
			||||||
		for i, arg in f.args {
 | 
							for i, arg in f.args {
 | 
				
			||||||
			e,typ := p.expr(0)
 | 
								e,typ := p.expr(0)
 | 
				
			||||||
			if !types.check(arg.typ, typ) {
 | 
								if !types.check(arg.typ, typ) {
 | 
				
			||||||
| 
						 | 
					@ -51,16 +53,38 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) {
 | 
				
			||||||
		args: args
 | 
							args: args
 | 
				
			||||||
		is_unknown: is_unknown
 | 
							is_unknown: is_unknown
 | 
				
			||||||
		tok: tok
 | 
							tok: tok
 | 
				
			||||||
 | 
							// typ: return_type
 | 
				
			||||||
 | 
							
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if is_unknown {
 | 
						if is_unknown {
 | 
				
			||||||
		p.table.unknown_calls << node
 | 
							p.table.unknown_calls << node
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return node,types.int_type
 | 
						return node,return_type
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (p mut Parser) fn_decl() ast.FnDecl {
 | 
					fn (p mut Parser) fn_decl() ast.FnDecl {
 | 
				
			||||||
 | 
						is_pub := p.tok.kind == .key_pub
 | 
				
			||||||
 | 
						if is_pub {
 | 
				
			||||||
 | 
							p.next()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	p.table.clear_vars()
 | 
						p.table.clear_vars()
 | 
				
			||||||
	p.check(.key_fn)
 | 
						p.check(.key_fn)
 | 
				
			||||||
 | 
						// Receiver?
 | 
				
			||||||
 | 
						mut rec_name := ''
 | 
				
			||||||
 | 
						mut rec_type := types.void_type
 | 
				
			||||||
 | 
						if p.tok.kind == .lpar {
 | 
				
			||||||
 | 
							p.next()
 | 
				
			||||||
 | 
							rec_name = p.check_name()
 | 
				
			||||||
 | 
							if p.tok.kind == .key_mut {
 | 
				
			||||||
 | 
								p.next()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rec_type = p.parse_type()
 | 
				
			||||||
 | 
							p.table.register_var(table.Var{
 | 
				
			||||||
 | 
								name: rec_name
 | 
				
			||||||
 | 
								typ: rec_type
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							p.check(.rpar)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	name := p.check_name()
 | 
						name := p.check_name()
 | 
				
			||||||
	// println('fn decl $name')
 | 
						// println('fn decl $name')
 | 
				
			||||||
	p.check(.lpar)
 | 
						p.check(.lpar)
 | 
				
			||||||
| 
						 | 
					@ -68,17 +92,24 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
 | 
				
			||||||
	mut args := []table.Var
 | 
						mut args := []table.Var
 | 
				
			||||||
	mut ast_args := []ast.Arg
 | 
						mut ast_args := []ast.Arg
 | 
				
			||||||
	for p.tok.kind != .rpar {
 | 
						for p.tok.kind != .rpar {
 | 
				
			||||||
		arg_name := p.check_name()
 | 
							mut arg_names := [p.check_name()]
 | 
				
			||||||
		typ := p.parse_type()
 | 
							// `a, b, c int`
 | 
				
			||||||
		arg := table.Var{
 | 
							for p.tok.kind == .comma {
 | 
				
			||||||
			name: arg_name
 | 
								p.check(.comma)
 | 
				
			||||||
			typ: typ
 | 
								arg_names << p.check_name()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		args << arg
 | 
							typ := p.parse_type()
 | 
				
			||||||
		p.table.register_var(arg)
 | 
							for arg_name in arg_names {
 | 
				
			||||||
		ast_args << ast.Arg{
 | 
								arg := table.Var{
 | 
				
			||||||
			typ: typ
 | 
									name: arg_name
 | 
				
			||||||
			name: arg_name
 | 
									typ: typ
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								args << arg
 | 
				
			||||||
 | 
								p.table.register_var(arg)
 | 
				
			||||||
 | 
								ast_args << ast.Arg{
 | 
				
			||||||
 | 
									typ: typ
 | 
				
			||||||
 | 
									name: arg_name
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if p.tok.kind != .rpar {
 | 
							if p.tok.kind != .rpar {
 | 
				
			||||||
			p.check(.comma)
 | 
								p.check(.comma)
 | 
				
			||||||
| 
						 | 
					@ -94,6 +125,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
 | 
				
			||||||
	p.table.register_fn(table.Fn{
 | 
						p.table.register_fn(table.Fn{
 | 
				
			||||||
		name: name
 | 
							name: name
 | 
				
			||||||
		args: args
 | 
							args: args
 | 
				
			||||||
 | 
							return_type: typ
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	stmts := p.parse_block()
 | 
						stmts := p.parse_block()
 | 
				
			||||||
	return ast.FnDecl{
 | 
						return ast.FnDecl{
 | 
				
			||||||
| 
						 | 
					@ -101,16 +133,23 @@ fn (p mut Parser) fn_decl() ast.FnDecl {
 | 
				
			||||||
		stmts: stmts
 | 
							stmts: stmts
 | 
				
			||||||
		typ: typ
 | 
							typ: typ
 | 
				
			||||||
		args: ast_args
 | 
							args: ast_args
 | 
				
			||||||
 | 
							is_pub: is_pub
 | 
				
			||||||
 | 
							receiver: ast.Field{
 | 
				
			||||||
 | 
								name: rec_name
 | 
				
			||||||
 | 
								typ: rec_type
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (p &Parser) check_fn_calls() {
 | 
					pub fn (p &Parser) check_fn_calls() {
 | 
				
			||||||
	println('check fn calls')
 | 
						println('check fn calls2')
 | 
				
			||||||
	for call in p.table.unknown_calls {
 | 
						for call in p.table.unknown_calls {
 | 
				
			||||||
		f := p.table.find_fn(call.name) or {
 | 
							f := p.table.find_fn(call.name) or {
 | 
				
			||||||
			p.error_at_line('unknown function `$call.name`', call.tok.line_nr)
 | 
								p.error_at_line('unknown function `$call.name`', call.tok.line_nr)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		println(f.name)
 | 
							println(f.name)
 | 
				
			||||||
 | 
							// println(f.return_type.name)
 | 
				
			||||||
 | 
							// println('IN AST typ=' + call.typ.name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@ mut:
 | 
				
			||||||
	// vars []string
 | 
						// vars []string
 | 
				
			||||||
	table       &table.Table
 | 
						table       &table.Table
 | 
				
			||||||
	return_type types.Type
 | 
						return_type types.Type
 | 
				
			||||||
 | 
						is_c        bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
 | 
					pub fn parse_stmt(text string, table &table.Table) ast.Stmt {
 | 
				
			||||||
| 
						 | 
					@ -74,9 +75,11 @@ pub fn parse_files(paths []string, table &table.Table) []ast.File {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// former get_type()
 | 
					// former get_type()
 | 
				
			||||||
pub fn (p mut Parser) parse_type() types.Type {
 | 
					pub fn (p mut Parser) parse_type() types.Type {
 | 
				
			||||||
	typ := p.table.types[p.tok.lit]
 | 
						typ := p.table.find_type(p.tok.lit) or {
 | 
				
			||||||
	if isnil(typ.name.str) || typ.name == '' {
 | 
							// typ := p.table.types[p.tok.lit]
 | 
				
			||||||
 | 
							// if isnil(typ.name.str) || typ.name == '' {
 | 
				
			||||||
		p.error('undefined type `$p.tok.lit`')
 | 
							p.error('undefined type `$p.tok.lit`')
 | 
				
			||||||
 | 
							exit(0)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.next()
 | 
						p.next()
 | 
				
			||||||
	return typ
 | 
						return typ
 | 
				
			||||||
| 
						 | 
					@ -181,9 +184,10 @@ pub fn (p mut Parser) stmt() ast.Stmt {
 | 
				
			||||||
			return p.for_statement()
 | 
								return p.for_statement()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			expr,_ := p.expr(0)
 | 
								expr,typ := p.expr(0)
 | 
				
			||||||
			return ast.ExprStmt{
 | 
								return ast.ExprStmt{
 | 
				
			||||||
				expr: expr
 | 
									expr: expr
 | 
				
			||||||
 | 
									typ: typ
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -242,7 +246,12 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			*/
 | 
								*/
 | 
				
			||||||
 | 
								if p.tok.lit == 'C' {
 | 
				
			||||||
 | 
									p.is_c = true
 | 
				
			||||||
 | 
									println('is c')
 | 
				
			||||||
 | 
									p.next()
 | 
				
			||||||
 | 
									p.check(.dot)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			// fn call
 | 
								// fn call
 | 
				
			||||||
			if p.peek_tok.kind == .lpar {
 | 
								if p.peek_tok.kind == .lpar {
 | 
				
			||||||
				x,typ2 := p.call_expr() // TODO `node,typ :=` should work
 | 
									x,typ2 := p.call_expr() // TODO `node,typ :=` should work
 | 
				
			||||||
| 
						 | 
					@ -330,6 +339,25 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) {
 | 
				
			||||||
	// left binding power
 | 
						// left binding power
 | 
				
			||||||
	for rbp < p.tok.precedence() {
 | 
						for rbp < p.tok.precedence() {
 | 
				
			||||||
		prev_tok := p.tok
 | 
							prev_tok := p.tok
 | 
				
			||||||
 | 
							if prev_tok.kind == .dot {
 | 
				
			||||||
 | 
								p.warn('dot prev_tok = $prev_tok.str() typ=$typ.name')
 | 
				
			||||||
 | 
								p.next()
 | 
				
			||||||
 | 
								field := p.check_name()
 | 
				
			||||||
 | 
								mut ok := false
 | 
				
			||||||
 | 
								for f in typ.fields {
 | 
				
			||||||
 | 
									if f.name == field {
 | 
				
			||||||
 | 
										ok = true
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									p.error('unknown field `${typ.name}.$field`')
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								node = ast.SelectorExpr{
 | 
				
			||||||
 | 
									expr: node
 | 
				
			||||||
 | 
									field: field
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return node,typ
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		p.next()
 | 
							p.next()
 | 
				
			||||||
		mut t2 := types.Type{}
 | 
							mut t2 := types.Type{}
 | 
				
			||||||
		// left denotation (infix / postfix)
 | 
							// left denotation (infix / postfix)
 | 
				
			||||||
| 
						 | 
					@ -410,23 +438,36 @@ fn (p mut Parser) for_statement() ast.ForStmt {
 | 
				
			||||||
fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
 | 
					fn (p mut Parser) if_expr() (ast.Expr,types.Type) {
 | 
				
			||||||
	mut node := ast.Expr{}
 | 
						mut node := ast.Expr{}
 | 
				
			||||||
	p.check(.key_if)
 | 
						p.check(.key_if)
 | 
				
			||||||
	cond,typ := p.expr(0)
 | 
						cond,cond_type := p.expr(0)
 | 
				
			||||||
	if !types.check(types.bool_type, typ) {
 | 
						if !types.check(types.bool_type, cond_type) {
 | 
				
			||||||
		p.error('non-bool used as if condition')
 | 
							p.error('non-bool used as if condition')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	stmts := p.parse_block()
 | 
						stmts := p.parse_block()
 | 
				
			||||||
	mut else_stmts := []ast.Stmt
 | 
						mut else_stmts := []ast.Stmt
 | 
				
			||||||
	if p.tok.kind == .key_else {
 | 
						if p.tok.kind == .key_else {
 | 
				
			||||||
		println('GOT ELSE')
 | 
							// println('GOT ELSE')
 | 
				
			||||||
		p.check(.key_else)
 | 
							p.check(.key_else)
 | 
				
			||||||
		else_stmts = p.parse_block()
 | 
							else_stmts = p.parse_block()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						mut typ := types.void_type
 | 
				
			||||||
 | 
						// mut left := ast.Expr{}
 | 
				
			||||||
 | 
						match stmts[stmts.len - 1] {
 | 
				
			||||||
 | 
							ast.ExprStmt {
 | 
				
			||||||
 | 
								typ = it.typ
 | 
				
			||||||
 | 
								// return node,it.typ
 | 
				
			||||||
 | 
								// left =
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	node = ast.IfExpr{
 | 
						node = ast.IfExpr{
 | 
				
			||||||
		cond: cond
 | 
							cond: cond
 | 
				
			||||||
		stmts: stmts
 | 
							stmts: stmts
 | 
				
			||||||
		else_stmts: else_stmts
 | 
							else_stmts: else_stmts
 | 
				
			||||||
 | 
							typ: typ
 | 
				
			||||||
 | 
							// left: left
 | 
				
			||||||
 | 
							
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return node,types.void_type
 | 
						return node,typ
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) {
 | 
					fn (p mut Parser) parse_string_literal() (ast.Expr,types.Type) {
 | 
				
			||||||
| 
						 | 
					@ -510,7 +551,8 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
 | 
				
			||||||
	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 ast_fields := []ast.Field
 | 
				
			||||||
 | 
						mut fields := []types.Field
 | 
				
			||||||
	for p.tok.kind != .rcbr {
 | 
						for p.tok.kind != .rcbr {
 | 
				
			||||||
		if p.tok.kind == .key_pub {
 | 
							if p.tok.kind == .key_pub {
 | 
				
			||||||
			p.check(.key_pub)
 | 
								p.check(.key_pub)
 | 
				
			||||||
| 
						 | 
					@ -518,19 +560,24 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		field_name := p.check_name()
 | 
							field_name := p.check_name()
 | 
				
			||||||
		typ := p.parse_type()
 | 
							typ := p.parse_type()
 | 
				
			||||||
		fields << ast.Field{
 | 
							ast_fields << ast.Field{
 | 
				
			||||||
			name: field_name
 | 
								name: field_name
 | 
				
			||||||
			typ: typ
 | 
								typ: typ
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							fields << types.Field{
 | 
				
			||||||
 | 
								name: field_name
 | 
				
			||||||
 | 
								type_idx: typ.idx
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.check(.rcbr)
 | 
						p.check(.rcbr)
 | 
				
			||||||
	p.table.register_type(types.Type{
 | 
						p.table.register_type(types.Type{
 | 
				
			||||||
		name: name
 | 
							name: name
 | 
				
			||||||
 | 
							fields: fields
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	return ast.StructDecl{
 | 
						return ast.StructDecl{
 | 
				
			||||||
		name: name
 | 
							name: name
 | 
				
			||||||
		is_pub: is_pub
 | 
							is_pub: is_pub
 | 
				
			||||||
		fields: fields
 | 
							fields: ast_fields
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@ x := 10
 | 
				
			||||||
'
 | 
					'
 | 
				
			||||||
	table := &table.Table{}
 | 
						table := &table.Table{}
 | 
				
			||||||
	prog := parse_file(s, table)
 | 
						prog := parse_file(s, table)
 | 
				
			||||||
	res := gen.cgen([prog])
 | 
						res := gen.cgen([prog], table)
 | 
				
			||||||
	println(res)
 | 
						println(res)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,7 @@ fn test_parse_expr() {
 | 
				
			||||||
	program := ast.File{
 | 
						program := ast.File{
 | 
				
			||||||
		stmts: e
 | 
							stmts: e
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	res := gen.cgen([program])
 | 
						res := gen.cgen([program], table)
 | 
				
			||||||
	println('========')
 | 
						println('========')
 | 
				
			||||||
	println(res)
 | 
						println(res)
 | 
				
			||||||
	println('========')
 | 
						println('========')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,13 +6,15 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Table {
 | 
					pub struct Table {
 | 
				
			||||||
 | 
						// struct_fields map[string][]string
 | 
				
			||||||
pub mut:
 | 
					pub mut:
 | 
				
			||||||
 | 
						types         map[string]types.Type
 | 
				
			||||||
	local_vars    []Var
 | 
						local_vars    []Var
 | 
				
			||||||
	// fns Hashmap
 | 
						// fns Hashmap
 | 
				
			||||||
	fns           map[string]Fn
 | 
						fns           map[string]Fn
 | 
				
			||||||
	types         map[string]types.Type
 | 
					 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	unknown_calls []ast.CallExpr
 | 
						unknown_calls []ast.CallExpr
 | 
				
			||||||
 | 
						tmp_cnt       int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Var {
 | 
					pub struct Var {
 | 
				
			||||||
| 
						 | 
					@ -24,8 +26,9 @@ pub:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Fn {
 | 
					pub struct Fn {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
	name string
 | 
						name        string
 | 
				
			||||||
	args []Var
 | 
						args        []Var
 | 
				
			||||||
 | 
						return_type types.Type
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn new_table() &Table {
 | 
					pub fn new_table() &Table {
 | 
				
			||||||
| 
						 | 
					@ -109,3 +112,16 @@ pub fn (t mut Table) register_fn(new_fn Fn) {
 | 
				
			||||||
pub fn (t mut Table) register_type(typ types.Type) {
 | 
					pub fn (t mut Table) register_type(typ types.Type) {
 | 
				
			||||||
	t.types[typ.name] = typ
 | 
						t.types[typ.name] = typ
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn (t &Table) find_type(name string) ?types.Type {
 | 
				
			||||||
 | 
						typ := t.types[name]
 | 
				
			||||||
 | 
						if isnil(typ.name.str) || typ.name == '' {
 | 
				
			||||||
 | 
							return none
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return typ
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn (t mut Table) new_tmp_var() string {
 | 
				
			||||||
 | 
						t.tmp_cnt++
 | 
				
			||||||
 | 
						return 'tmp$t.tmp_cnt'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -311,6 +311,9 @@ pub const (
 | 
				
			||||||
// Precedence returns a tokens precedence if defined, otherwise lowest_prec
 | 
					// Precedence returns a tokens precedence if defined, otherwise lowest_prec
 | 
				
			||||||
pub fn (tok Token) precedence() int {
 | 
					pub fn (tok Token) precedence() int {
 | 
				
			||||||
	match tok.kind {
 | 
						match tok.kind {
 | 
				
			||||||
 | 
							.dot {
 | 
				
			||||||
 | 
								return 8
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		// `++` | `--`
 | 
							// `++` | `--`
 | 
				
			||||||
		.inc, .dec {
 | 
							.inc, .dec {
 | 
				
			||||||
			return 7
 | 
								return 7
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,25 +3,51 @@
 | 
				
			||||||
// that can be found in the LICENSE file.
 | 
					// that can be found in the LICENSE file.
 | 
				
			||||||
module types
 | 
					module types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum Kind {
 | 
				
			||||||
 | 
						struct_
 | 
				
			||||||
 | 
						builtin
 | 
				
			||||||
 | 
						enum_
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct Type {
 | 
					pub struct Type {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
	name string
 | 
						name   string
 | 
				
			||||||
	idx  int
 | 
						idx    int
 | 
				
			||||||
 | 
						// kind Kind
 | 
				
			||||||
 | 
						fields []Field
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Field {
 | 
				
			||||||
 | 
					pub:
 | 
				
			||||||
 | 
						name     string
 | 
				
			||||||
 | 
						type_idx int
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const (
 | 
					pub const (
 | 
				
			||||||
	void_type = Type{
 | 
						void_type = Type{
 | 
				
			||||||
		'void',0}
 | 
							name: 'void'
 | 
				
			||||||
 | 
							idx: 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	int_type = Type{
 | 
						int_type = Type{
 | 
				
			||||||
		'int',1}
 | 
							name: 'int'
 | 
				
			||||||
 | 
							idx: 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	string_type = Type{
 | 
						string_type = Type{
 | 
				
			||||||
		'string',2}
 | 
							name: 'string'
 | 
				
			||||||
 | 
							idx: 2
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	f64_type = Type{
 | 
						f64_type = Type{
 | 
				
			||||||
		'f64',3}
 | 
							name: 'f64'
 | 
				
			||||||
 | 
							idx: 3
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	bool_type = Type{
 | 
						bool_type = Type{
 | 
				
			||||||
		'bool',4}
 | 
							name: 'bool'
 | 
				
			||||||
 | 
							idx: 4
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	voidptr_type = Type{
 | 
						voidptr_type = Type{
 | 
				
			||||||
		'voidptr',5}
 | 
							name: 'voidptr'
 | 
				
			||||||
 | 
							idx: 5
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn check(got, expected &Type) bool {
 | 
					pub fn check(got, expected &Type) bool {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue