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') | ||||
| 	table := table.new_table() | ||||
| 	program := parser.parse_file(path, table) | ||||
| 	res := gen.cgen([program]) | ||||
| 	res := gen.cgen([program], table) | ||||
| 	mut out := os.create('out.c')? | ||||
| 	out.writeln(cdefs) | ||||
| 	out.writeln(res) | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ pub: | |||
| 	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 { | ||||
| 	cap_ := if cap == 0 { 1 } else { cap } | ||||
| 	arr := array{ | ||||
|  | @ -28,7 +28,7 @@ fn new_array(mylen int, cap int, elm_size int) array { | |||
| } | ||||
| 
 | ||||
| // 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) | ||||
| } | ||||
| 
 | ||||
|  | @ -42,7 +42,9 @@ fn new_array_from_c_array(len, cap, elm_size int, c_array voidptr) array { | |||
| 		data: calloc(cap_ * elm_size) | ||||
| 	} | ||||
| 	// 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 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ import ( | |||
| 	v.table | ||||
| 	v.parser | ||||
| 	v.gen | ||||
| 	time | ||||
| ) | ||||
| 
 | ||||
| pub const ( | ||||
|  | @ -397,7 +398,7 @@ pub fn (v mut V) compile2() { | |||
| 	} | ||||
| 	table := table.new_table() | ||||
| 	files := parser.parse_files(v.files, table) | ||||
| 	c := gen.cgen(files) | ||||
| 	c := gen.cgen(files, table) | ||||
| 	println('out: $v.out_name_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.dir | ||||
| 
 | ||||
| 	table := &table.Table{} | ||||
| 	table := &table.new_table() | ||||
| 	ticks := time.ticks() | ||||
| 	files := parser.parse_files(v.files, table) | ||||
| 	println('PARSE: ${time.ticks() - ticks}ms') | ||||
| 	x64.gen(files, v.out_name) | ||||
| 	println('x64 GEN: ${time.ticks() - ticks}ms') | ||||
| 	/* | ||||
| 	for f in v.files { | ||||
| 		v.parse(f, .decl) | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ import ( | |||
| ) | ||||
| 
 | ||||
| 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 | | ||||
| ForStmt | StructDecl | ||||
|  | @ -17,6 +17,7 @@ ForStmt | StructDecl | |||
| pub struct ExprStmt { | ||||
| pub: | ||||
| 	expr Expr | ||||
| 	typ  types.Type | ||||
| } | ||||
| 
 | ||||
| pub struct IntegerLiteral { | ||||
|  | @ -40,6 +41,13 @@ pub: | |||
| 	val bool | ||||
| } | ||||
| 
 | ||||
| // `foo.bar`
 | ||||
| pub struct SelectorExpr { | ||||
| pub: | ||||
| 	expr  Expr | ||||
| 	field string | ||||
| } | ||||
| 
 | ||||
| // module declaration
 | ||||
| pub struct Module { | ||||
| pub: | ||||
|  | @ -88,6 +96,8 @@ pub: | |||
| 	stmts  []Stmt | ||||
| 	typ    types.Type | ||||
| 	args   []Arg | ||||
| 	is_pub bool | ||||
| 	receiver Field | ||||
| } | ||||
| 
 | ||||
| pub struct CallExpr { | ||||
|  | @ -164,6 +174,8 @@ pub: | |||
| 	cond       Expr | ||||
| 	stmts      []Stmt | ||||
| 	else_stmts []Stmt | ||||
| 	typ        types.Type | ||||
| 	left       Expr // `a` in `a := if ...`
 | ||||
| } | ||||
| 
 | ||||
| pub struct ForStmt { | ||||
|  |  | |||
|  | @ -3,18 +3,22 @@ module gen | |||
| import ( | ||||
| 	strings | ||||
| 	v.ast | ||||
| 	v.table | ||||
| 	v.types | ||||
| 	term | ||||
| ) | ||||
| 
 | ||||
| struct Gen { | ||||
| 	out         strings.Builder | ||||
| 	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{ | ||||
| 		out: strings.new_builder(100) | ||||
| 		definitions: strings.new_builder(100) | ||||
| 		table: table | ||||
| 	} | ||||
| 	for file in files { | ||||
| 		for stmt in file.stmts { | ||||
|  | @ -139,6 +143,9 @@ fn (g mut Gen) expr(node ast.Expr) { | |||
| 		} | ||||
| 		ast.BinaryExpr { | ||||
| 			g.expr(it.left) | ||||
| 			if it.op == .dot { | ||||
| 				println('!! dot') | ||||
| 			} | ||||
| 			g.write(' $it.op.str() ') | ||||
| 			g.expr(it.right) | ||||
| 			// if typ.name != typ2.name {
 | ||||
|  | @ -184,11 +191,28 @@ fn (g mut Gen) expr(node ast.Expr) { | |||
| 				g.write('false') | ||||
| 			} | ||||
| 		} | ||||
| 		ast.SelectorExpr { | ||||
| 			g.expr(it.expr) | ||||
| 			g.write('.') | ||||
| 			g.write(it.field) | ||||
| 		} | ||||
| 		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.expr(it.cond) | ||||
| 			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.writeln('}') | ||||
|  |  | |||
|  | @ -23,13 +23,14 @@ fn test_c_files() { | |||
| 		} | ||||
| 		table := &table.new_table() | ||||
| 		program := parser.parse_file(path, table) | ||||
| 		res := gen.cgen([program]) | ||||
| 		res := gen.cgen([program], table) | ||||
| 		if compare_texts(res, ctext) { | ||||
| 			eprintln('${i}... ' + term.green('OK')) | ||||
| 		} | ||||
| 		else { | ||||
| 			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); | ||||
| int get_int(string a); | ||||
| int get_int2(); | ||||
| void myuser(); | ||||
| 
 | ||||
| typedef struct { | ||||
| 	int age; | ||||
| } User; | ||||
| 
 | ||||
| int main() { | ||||
| int a = 10; | ||||
|  | @ -10,5 +17,22 @@ return 0; | |||
| } | ||||
| 
 | ||||
| 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() { | ||||
| 	a := 10 | ||||
| 	a++ | ||||
|  | @ -7,5 +11,21 @@ fn main() { | |||
| } | ||||
| 
 | ||||
| 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) | ||||
| 	mut is_unknown := false | ||||
| 	mut args := []ast.Expr | ||||
| 	mut return_type := types.void_type | ||||
| 	if f := p.table.find_fn(fn_name) { | ||||
| 		return_type = f.return_type | ||||
| 		for i, arg in f.args { | ||||
| 			e,typ := p.expr(0) | ||||
| 			if !types.check(arg.typ, typ) { | ||||
|  | @ -51,16 +53,38 @@ pub fn (p mut Parser) call_expr() (ast.CallExpr,types.Type) { | |||
| 		args: args | ||||
| 		is_unknown: is_unknown | ||||
| 		tok: tok | ||||
| 		// typ: return_type
 | ||||
| 		 | ||||
| 	} | ||||
| 	if is_unknown { | ||||
| 		p.table.unknown_calls << node | ||||
| 	} | ||||
| 	return node,types.int_type | ||||
| 	return node,return_type | ||||
| } | ||||
| 
 | ||||
| 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.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() | ||||
| 	// println('fn decl $name')
 | ||||
| 	p.check(.lpar) | ||||
|  | @ -68,8 +92,14 @@ fn (p mut Parser) fn_decl() ast.FnDecl { | |||
| 	mut args := []table.Var | ||||
| 	mut ast_args := []ast.Arg | ||||
| 	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() | ||||
| 		for arg_name in arg_names { | ||||
| 			arg := table.Var{ | ||||
| 				name: arg_name | ||||
| 				typ: typ | ||||
|  | @ -80,6 +110,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { | |||
| 				typ: typ | ||||
| 				name: arg_name | ||||
| 			} | ||||
| 		} | ||||
| 		if p.tok.kind != .rpar { | ||||
| 			p.check(.comma) | ||||
| 		} | ||||
|  | @ -94,6 +125,7 @@ fn (p mut Parser) fn_decl() ast.FnDecl { | |||
| 	p.table.register_fn(table.Fn{ | ||||
| 		name: name | ||||
| 		args: args | ||||
| 		return_type: typ | ||||
| 	}) | ||||
| 	stmts := p.parse_block() | ||||
| 	return ast.FnDecl{ | ||||
|  | @ -101,16 +133,23 @@ fn (p mut Parser) fn_decl() ast.FnDecl { | |||
| 		stmts: stmts | ||||
| 		typ: typ | ||||
| 		args: ast_args | ||||
| 		is_pub: is_pub | ||||
| 		receiver: ast.Field{ | ||||
| 			name: rec_name | ||||
| 			typ: rec_type | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (p &Parser) check_fn_calls() { | ||||
| 	println('check fn calls') | ||||
| 	println('check fn calls2') | ||||
| 	for call in p.table.unknown_calls { | ||||
| 		f := p.table.find_fn(call.name) or { | ||||
| 			p.error_at_line('unknown function `$call.name`', call.tok.line_nr) | ||||
| 			return | ||||
| 		} | ||||
| 		println(f.name) | ||||
| 		// println(f.return_type.name)
 | ||||
| 		// println('IN AST typ=' + call.typ.name)
 | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ mut: | |||
| 	// vars []string
 | ||||
| 	table       &table.Table | ||||
| 	return_type types.Type | ||||
| 	is_c        bool | ||||
| } | ||||
| 
 | ||||
| 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()
 | ||||
| pub fn (p mut Parser) parse_type() types.Type { | ||||
| 	typ := p.table.types[p.tok.lit] | ||||
| 	if isnil(typ.name.str) || typ.name == '' { | ||||
| 	typ := p.table.find_type(p.tok.lit) or { | ||||
| 		// typ := p.table.types[p.tok.lit]
 | ||||
| 		// if isnil(typ.name.str) || typ.name == '' {
 | ||||
| 		p.error('undefined type `$p.tok.lit`') | ||||
| 		exit(0) | ||||
| 	} | ||||
| 	p.next() | ||||
| 	return typ | ||||
|  | @ -181,9 +184,10 @@ pub fn (p mut Parser) stmt() ast.Stmt { | |||
| 			return p.for_statement() | ||||
| 		} | ||||
| 		else { | ||||
| 			expr,_ := p.expr(0) | ||||
| 			expr,typ := p.expr(0) | ||||
| 			return ast.ExprStmt{ | ||||
| 				expr: expr | ||||
| 				typ: typ | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -242,7 +246,12 @@ pub fn (p mut Parser) expr(rbp int) (ast.Expr,types.Type) { | |||
| 				return | ||||
| 			} | ||||
| 			*/ | ||||
| 
 | ||||
| 			if p.tok.lit == 'C' { | ||||
| 				p.is_c = true | ||||
| 				println('is c') | ||||
| 				p.next() | ||||
| 				p.check(.dot) | ||||
| 			} | ||||
| 			// fn call
 | ||||
| 			if p.peek_tok.kind == .lpar { | ||||
| 				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
 | ||||
| 	for rbp < p.tok.precedence() { | ||||
| 		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() | ||||
| 		mut t2 := types.Type{} | ||||
| 		// 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) { | ||||
| 	mut node := ast.Expr{} | ||||
| 	p.check(.key_if) | ||||
| 	cond,typ := p.expr(0) | ||||
| 	if !types.check(types.bool_type, typ) { | ||||
| 	cond,cond_type := p.expr(0) | ||||
| 	if !types.check(types.bool_type, cond_type) { | ||||
| 		p.error('non-bool used as if condition') | ||||
| 	} | ||||
| 	stmts := p.parse_block() | ||||
| 	mut else_stmts := []ast.Stmt | ||||
| 	if p.tok.kind == .key_else { | ||||
| 		println('GOT ELSE') | ||||
| 		// println('GOT ELSE')
 | ||||
| 		p.check(.key_else) | ||||
| 		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{ | ||||
| 		cond: cond | ||||
| 		stmts: 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) { | ||||
|  | @ -510,7 +551,8 @@ fn (p mut Parser) struct_decl() ast.StructDecl { | |||
| 	p.check(.key_struct) | ||||
| 	name := p.check_name() | ||||
| 	p.check(.lcbr) | ||||
| 	mut fields := []ast.Field | ||||
| 	mut ast_fields := []ast.Field | ||||
| 	mut fields := []types.Field | ||||
| 	for p.tok.kind != .rcbr { | ||||
| 		if p.tok.kind == .key_pub { | ||||
| 			p.check(.key_pub) | ||||
|  | @ -518,19 +560,24 @@ fn (p mut Parser) struct_decl() ast.StructDecl { | |||
| 		} | ||||
| 		field_name := p.check_name() | ||||
| 		typ := p.parse_type() | ||||
| 		fields << ast.Field{ | ||||
| 		ast_fields << ast.Field{ | ||||
| 			name: field_name | ||||
| 			typ: typ | ||||
| 		} | ||||
| 		fields << types.Field{ | ||||
| 			name: field_name | ||||
| 			type_idx: typ.idx | ||||
| 		} | ||||
| 	} | ||||
| 	p.check(.rcbr) | ||||
| 	p.table.register_type(types.Type{ | ||||
| 		name: name | ||||
| 		fields: fields | ||||
| 	}) | ||||
| 	return ast.StructDecl{ | ||||
| 		name: name | ||||
| 		is_pub: is_pub | ||||
| 		fields: fields | ||||
| 		fields: ast_fields | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ x := 10 | |||
| ' | ||||
| 	table := &table.Table{} | ||||
| 	prog := parse_file(s, table) | ||||
| 	res := gen.cgen([prog]) | ||||
| 	res := gen.cgen([prog], table) | ||||
| 	println(res) | ||||
| } | ||||
| 
 | ||||
|  | @ -79,7 +79,7 @@ fn test_parse_expr() { | |||
| 	program := ast.File{ | ||||
| 		stmts: e | ||||
| 	} | ||||
| 	res := gen.cgen([program]) | ||||
| 	res := gen.cgen([program], table) | ||||
| 	println('========') | ||||
| 	println(res) | ||||
| 	println('========') | ||||
|  |  | |||
|  | @ -6,13 +6,15 @@ import ( | |||
| ) | ||||
| 
 | ||||
| pub struct Table { | ||||
| 	// struct_fields map[string][]string
 | ||||
| pub mut: | ||||
| 	types         map[string]types.Type | ||||
| 	local_vars    []Var | ||||
| 	// fns Hashmap
 | ||||
| 	fns           map[string]Fn | ||||
| 	types         map[string]types.Type | ||||
| 	//
 | ||||
| 	unknown_calls []ast.CallExpr | ||||
| 	tmp_cnt       int | ||||
| } | ||||
| 
 | ||||
| pub struct Var { | ||||
|  | @ -26,6 +28,7 @@ pub struct Fn { | |||
| pub: | ||||
| 	name        string | ||||
| 	args        []Var | ||||
| 	return_type types.Type | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	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
 | ||||
| pub fn (tok Token) precedence() int { | ||||
| 	match tok.kind { | ||||
| 		.dot { | ||||
| 			return 8 | ||||
| 		} | ||||
| 		// `++` | `--`
 | ||||
| 		.inc, .dec { | ||||
| 			return 7 | ||||
|  |  | |||
|  | @ -3,25 +3,51 @@ | |||
| // that can be found in the LICENSE file.
 | ||||
| module types | ||||
| 
 | ||||
| pub enum Kind { | ||||
| 	struct_ | ||||
| 	builtin | ||||
| 	enum_ | ||||
| } | ||||
| 
 | ||||
| pub struct Type { | ||||
| pub: | ||||
| 	name   string | ||||
| 	idx    int | ||||
| 	// kind Kind
 | ||||
| 	fields []Field | ||||
| } | ||||
| 
 | ||||
| pub struct Field { | ||||
| pub: | ||||
| 	name     string | ||||
| 	type_idx int | ||||
| } | ||||
| 
 | ||||
| pub const ( | ||||
| 	void_type = Type{ | ||||
| 		'void',0} | ||||
| 		name: 'void' | ||||
| 		idx: 0 | ||||
| 	} | ||||
| 	int_type = Type{ | ||||
| 		'int',1} | ||||
| 		name: 'int' | ||||
| 		idx: 1 | ||||
| 	} | ||||
| 	string_type = Type{ | ||||
| 		'string',2} | ||||
| 		name: 'string' | ||||
| 		idx: 2 | ||||
| 	} | ||||
| 	f64_type = Type{ | ||||
| 		'f64',3} | ||||
| 		name: 'f64' | ||||
| 		idx: 3 | ||||
| 	} | ||||
| 	bool_type = Type{ | ||||
| 		'bool',4} | ||||
| 		name: 'bool' | ||||
| 		idx: 4 | ||||
| 	} | ||||
| 	voidptr_type = Type{ | ||||
| 		'voidptr',5} | ||||
| 		name: 'voidptr' | ||||
| 		idx: 5 | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| pub fn check(got, expected &Type) bool { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue