checker/parser: check & gen stmts for ForIn & fix key, val vars
							parent
							
								
									e37fed437d
								
							
						
					
					
						commit
						4262ff76c3
					
				|  | @ -319,6 +319,11 @@ pub fn (c mut Checker) method_call_expr(method_call_expr mut ast.MethodCallExpr) | |||
| 		method_call_expr.return_type = method.return_type | ||||
| 		return method.return_type | ||||
| 	} | ||||
| 	// TODO: str methods
 | ||||
| 	if typ_sym.kind in [.map] && name == 'str' { | ||||
| 		method_call_expr.return_type = table.string_type | ||||
| 		return table.string_type | ||||
| 	} | ||||
| 	c.error('type `$typ_sym.name` has no method `$name`', method_call_expr.pos) | ||||
| 	return table.void_type | ||||
| } | ||||
|  | @ -530,9 +535,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { | |||
| 		ast.FnDecl { | ||||
| 			c.expected_type = table.void_type | ||||
| 			c.fn_return_type = it.return_type | ||||
| 			for stmt in it.stmts { | ||||
| 				c.stmt(stmt) | ||||
| 			} | ||||
| 			c.stmts(it.stmts) | ||||
| 		} | ||||
| 		ast.ForStmt { | ||||
| 			typ := c.expr(it.cond) | ||||
|  | @ -541,22 +544,47 @@ fn (c mut Checker) stmt(node ast.Stmt) { | |||
| 			} | ||||
| 			// TODO: update loop var type
 | ||||
| 			// how does this work currenly?
 | ||||
| 			for stmt in it.stmts { | ||||
| 				c.stmt(stmt) | ||||
| 			} | ||||
| 			c.stmts(it.stmts) | ||||
| 		} | ||||
| 		ast.ForCStmt { | ||||
| 			c.stmt(it.init) | ||||
| 			c.expr(it.cond) | ||||
| 			// c.stmt(it.inc)
 | ||||
| 			c.expr(it.inc) | ||||
| 			for stmt in it.stmts { | ||||
| 				c.stmt(stmt) | ||||
| 			} | ||||
| 			c.stmts(it.stmts) | ||||
| 		} | ||||
| 		ast.ForInStmt { | ||||
| 			c.expr(it.cond) | ||||
| 			c.expr(it.high) | ||||
| 			typ := c.expr(it.cond) | ||||
| 			if it.is_range { | ||||
| 				c.expr(it.high) | ||||
| 			} | ||||
| 			else { | ||||
| 				mut scope := c.file.scope.innermost(it.pos.pos) | ||||
| 				if it.key_var.len > 0 { | ||||
| 					sym := c.table.get_type_symbol(typ) | ||||
| 					key_type := match sym.kind { | ||||
| 						.map{ | ||||
| 							sym.map_info().key_type | ||||
| 						} | ||||
| 						else { | ||||
| 							table.int_type} | ||||
| 	} | ||||
| 					scope.override_var(ast.Var{ | ||||
| 						name: it.key_var | ||||
| 						typ: key_type | ||||
| 					}) | ||||
| 				} | ||||
| 				value_type := c.table.value_type(typ) | ||||
| 				if value_type == table.void_type { | ||||
| 					typ_sym := c.table.get_type_symbol(typ) | ||||
| 					c.error('for in: cannot index $typ_sym.name', it.pos) | ||||
| 				} | ||||
| 				scope.override_var(ast.Var{ | ||||
| 					name: it.val_var | ||||
| 					typ: c.table.value_type(typ) | ||||
| 				}) | ||||
| 			} | ||||
| 			c.stmts(it.stmts) | ||||
| 		} | ||||
| 		// ast.GlobalDecl {}
 | ||||
| 		// ast.HashStmt {}
 | ||||
|  | @ -566,9 +594,7 @@ fn (c mut Checker) stmt(node ast.Stmt) { | |||
| 		} | ||||
| 		// ast.StructDecl {}
 | ||||
| 		ast.UnsafeStmt { | ||||
| 			for stmt in it.stmts { | ||||
| 				c.stmt(stmt) | ||||
| 			} | ||||
| 			c.stmts(it.stmts) | ||||
| 		} | ||||
| 		else {} | ||||
| 		// println('checker.stmt(): unhandled node')
 | ||||
|  | @ -761,6 +787,15 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { | |||
| 		if !name.contains('.') && !(c.file.mod.name in ['builtin', 'main']) { | ||||
| 			name = '${c.file.mod.name}.$ident.name' | ||||
| 		} | ||||
| 		// hack - const until consts are fixed properly
 | ||||
| 		if ident.name == 'v_modules_path' { | ||||
| 			ident.name = name | ||||
| 			ident.kind = .constant | ||||
| 			ident.info = ast.IdentVar{ | ||||
| 				typ: table.string_type | ||||
| 			} | ||||
| 			return table.string_type | ||||
| 		} | ||||
| 		// constant
 | ||||
| 		if constant := c.table.find_const(name) { | ||||
| 			ident.name = name | ||||
|  | @ -913,30 +948,10 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type { | |||
| 		else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx { | ||||
| 			c.error('non-string map index (type `$typ_sym.name`)', node.pos) | ||||
| 		} | ||||
| 		if typ_sym.kind == .array { | ||||
| 			// Check index type
 | ||||
| 			info := typ_sym.info as table.Array | ||||
| 			return info.elem_type | ||||
| 		value_type := c.table.value_type(typ) | ||||
| 		if value_type != table.void_type { | ||||
| 			return value_type | ||||
| 		} | ||||
| 		else if typ_sym.kind == .array_fixed { | ||||
| 			info := typ_sym.info as table.ArrayFixed | ||||
| 			return info.elem_type | ||||
| 		} | ||||
| 		else if typ_sym.kind == .map { | ||||
| 			info := typ_sym.info as table.Map | ||||
| 			return info.value_type | ||||
| 		} | ||||
| 		else if typ_sym.kind in [.byteptr, .string] { | ||||
| 			return table.byte_type | ||||
| 		} | ||||
| 		else if table.type_is_ptr(typ) { | ||||
| 			// byte* => byte
 | ||||
| 			// bytes[0] is a byte, not byte*
 | ||||
| 			return table.type_deref(typ) | ||||
| 		} | ||||
| 		// else {
 | ||||
| 		// return table.int_type
 | ||||
| 		// }
 | ||||
| 	} | ||||
| 	return typ | ||||
| } | ||||
|  |  | |||
|  | @ -271,9 +271,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { | |||
| 			// g.stmt(it.inc)
 | ||||
| 			g.expr(it.inc) | ||||
| 			g.writeln(') {') | ||||
| 			for stmt in it.stmts { | ||||
| 				g.stmt(stmt) | ||||
| 			} | ||||
| 			g.stmts(it.stmts) | ||||
| 			g.writeln('}') | ||||
| 		} | ||||
| 		ast.ForInStmt { | ||||
|  | @ -284,7 +282,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { | |||
| 				g.write('; $i < ') | ||||
| 				g.expr(it.high) | ||||
| 				g.writeln('; $i++) { ') | ||||
| 				// g.stmts(it.stmts) TODO
 | ||||
| 				g.stmts(it.stmts) | ||||
| 				g.writeln('}') | ||||
| 			} | ||||
| 		} | ||||
|  | @ -297,9 +295,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { | |||
| 				g.expr(it.cond) | ||||
| 			} | ||||
| 			g.writeln(') {') | ||||
| 			for stmt in it.stmts { | ||||
| 				g.stmt(stmt) | ||||
| 			} | ||||
| 			g.stmts(it.stmts) | ||||
| 			g.writeln('}') | ||||
| 		} | ||||
| 		ast.GlobalDecl { | ||||
|  |  | |||
|  | @ -1096,13 +1096,14 @@ fn (p mut Parser) for_statement() ast.Stmt { | |||
| 	} | ||||
| 	// `for i in vals`, `for i in start .. end`
 | ||||
| 	else if p.peek_tok.kind in [.key_in, .comma] { | ||||
| 		var_name := p.check_name() | ||||
| 		mut val_name := '' | ||||
| 		mut key_var_name := '' | ||||
| 		mut val_var_name := p.check_name() | ||||
| 		if p.tok.kind == .comma { | ||||
| 			p.check(.comma) | ||||
| 			val_name = p.check_name() | ||||
| 			key_var_name = val_var_name | ||||
| 			val_var_name = p.check_name() | ||||
| 			p.scope.register_var(ast.Var{ | ||||
| 				name: val_name | ||||
| 				name: key_var_name | ||||
| 				typ: table.int_type | ||||
| 			}) | ||||
| 		} | ||||
|  | @ -1118,13 +1119,17 @@ fn (p mut Parser) for_statement() ast.Stmt { | |||
| 			is_range = true | ||||
| 			p.check(.dotdot) | ||||
| 			high_expr = p.expr(0) | ||||
| 			p.scope.register_var(ast.Var{ | ||||
| 				name: val_var_name | ||||
| 				typ: table.int_type | ||||
| 			}) | ||||
| 		} | ||||
| 		else { | ||||
| 			// this type will be set in checker
 | ||||
| 			p.scope.register_var(ast.Var{ | ||||
| 				name: val_var_name | ||||
| 			}) | ||||
| 		} | ||||
| 		// TODO: update var type in checker
 | ||||
| 		p.scope.register_var(ast.Var{ | ||||
| 			name: var_name | ||||
| 			// expr: cond
 | ||||
| 			 | ||||
| 		}) | ||||
| 		stmts := p.parse_block() | ||||
| 		// println('nr stmts=$stmts.len')
 | ||||
| 		p.close_scope() | ||||
|  | @ -1132,8 +1137,8 @@ fn (p mut Parser) for_statement() ast.Stmt { | |||
| 			stmts: stmts | ||||
| 			pos: p.tok.position() | ||||
| 			cond: cond | ||||
| 			key_var: var_name | ||||
| 			val_var: val_name | ||||
| 			key_var: key_var_name | ||||
| 			val_var: val_var_name | ||||
| 			high: high_expr | ||||
| 			is_range: is_range | ||||
| 		} | ||||
|  |  | |||
|  | @ -29,19 +29,19 @@ pub: | |||
| 
 | ||||
| pub struct Arg { | ||||
| pub: | ||||
| 	name        string | ||||
| 	is_mut      bool | ||||
| 	typ         Type | ||||
| 	name   string | ||||
| 	is_mut bool | ||||
| 	typ    Type | ||||
| } | ||||
| 
 | ||||
| pub struct Var { | ||||
| pub: | ||||
| 	name        string | ||||
| 	is_mut      bool | ||||
| 	is_const    bool | ||||
| 	is_global   bool | ||||
| 	name      string | ||||
| 	is_mut    bool | ||||
| 	is_const  bool | ||||
| 	is_global bool | ||||
| mut: | ||||
| 	typ         Type | ||||
| 	typ       Type | ||||
| } | ||||
| 
 | ||||
| pub fn new_table() &Table { | ||||
|  | @ -411,6 +411,43 @@ pub fn (t mut Table) add_placeholder_type(name string) int { | |||
| 	return t.register_type_symbol(ph_type) | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
| pub fn (t &Table) value_type(typ Type) Type { | ||||
| 	typ_sym := t.get_type_symbol(typ) | ||||
| 	if typ_sym.kind == .array { | ||||
| 		// Check index type
 | ||||
| 		info := typ_sym.info as Array | ||||
| 		return info.elem_type | ||||
| 	} | ||||
| 	else if typ_sym.kind == .array_fixed { | ||||
| 		info := typ_sym.info as ArrayFixed | ||||
| 		return info.elem_type | ||||
| 	} | ||||
| 	else if typ_sym.kind == .map { | ||||
| 		info := typ_sym.info as Map | ||||
| 		return info.value_type | ||||
| 	} | ||||
| 	else if typ_sym.kind in [.byteptr, .string] { | ||||
| 		return byte_type | ||||
| 	} | ||||
| 	else if type_is_ptr(typ) { | ||||
| 		// byte* => byte
 | ||||
| 		// bytes[0] is a byte, not byte*
 | ||||
| 		return type_deref(typ) | ||||
| 	} | ||||
| 	else if type_is_variadic(typ) { | ||||
| 		// ...string => string
 | ||||
| 		return type_clear_extra(typ) | ||||
| 	} | ||||
| 	else { | ||||
| 		// TODO: remove when map_string is removed
 | ||||
| 		if typ_sym.name == 'map_string' { | ||||
| 			return string_type | ||||
| 		} | ||||
| 		return void_type | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (t &Table) check(got, expected Type) bool { | ||||
| 	got_type_sym := t.get_type_symbol(got) | ||||
| 	exp_type_sym := t.get_type_symbol(expected) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue