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) | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 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 | ||||||
|  | @ -17,6 +17,7 @@ ForStmt | StructDecl | ||||||
| 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: | ||||||
|  | @ -88,6 +96,8 @@ pub: | ||||||
| 	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,8 +92,14 @@ 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()] | ||||||
|  | 		// `a, b, c int`
 | ||||||
|  | 		for p.tok.kind == .comma { | ||||||
|  | 			p.check(.comma) | ||||||
|  | 			arg_names << p.check_name() | ||||||
|  | 		} | ||||||
| 		typ := p.parse_type() | 		typ := p.parse_type() | ||||||
|  | 		for arg_name in arg_names { | ||||||
| 			arg := table.Var{ | 			arg := table.Var{ | ||||||
| 				name: arg_name | 				name: arg_name | ||||||
| 				typ: typ | 				typ: typ | ||||||
|  | @ -80,6 +110,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { | ||||||
| 				typ: typ | 				typ: typ | ||||||
| 				name: arg_name | 				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 { | ||||||
|  | @ -26,6 +28,7 @@ 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