cgen: fix &string cast; vfmt fixes
							parent
							
								
									4aedef367c
								
							
						
					
					
						commit
						6bbd1943dd
					
				| 
						 | 
					@ -43,12 +43,12 @@ NB: A V string should be/is immutable from the point of view of
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct string {
 | 
					pub struct string {
 | 
				
			||||||
	// mut:
 | 
					 | 
				
			||||||
	// hash_cache int
 | 
					 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
	str byteptr // points to a C style 0 terminated string of bytes.
 | 
						str byteptr // points to a C style 0 terminated string of bytes.
 | 
				
			||||||
	len int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str).
 | 
						len int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str).
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
						// mut:
 | 
				
			||||||
 | 
						// hash_cache int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct ustring {
 | 
					pub struct ustring {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
| 
						 | 
					@ -166,8 +166,8 @@ pub fn (s string) replace(rep, with string) string {
 | 
				
			||||||
	mut cur_idx := idxs[idx_pos]
 | 
						mut cur_idx := idxs[idx_pos]
 | 
				
			||||||
	mut b_i := 0
 | 
						mut b_i := 0
 | 
				
			||||||
	for i := 0; i < s.len; i++ {
 | 
						for i := 0; i < s.len; i++ {
 | 
				
			||||||
		// Reached the location of rep, replace it with "with"
 | 
					 | 
				
			||||||
		if i == cur_idx {
 | 
							if i == cur_idx {
 | 
				
			||||||
 | 
								// Reached the location of rep, replace it with "with"
 | 
				
			||||||
			for j in 0..with.len {
 | 
								for j in 0..with.len {
 | 
				
			||||||
				b[b_i] = with[j]
 | 
									b[b_i] = with[j]
 | 
				
			||||||
				b_i++
 | 
									b_i++
 | 
				
			||||||
| 
						 | 
					@ -180,8 +180,8 @@ pub fn (s string) replace(rep, with string) string {
 | 
				
			||||||
				cur_idx = idxs[idx_pos]
 | 
									cur_idx = idxs[idx_pos]
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Rep doesnt start here, just copy
 | 
					 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
 | 
								// Rep doesnt start here, just copy
 | 
				
			||||||
			b[b_i] = s[i]
 | 
								b[b_i] = s[i]
 | 
				
			||||||
			b_i++
 | 
								b_i++
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -263,8 +263,8 @@ pub fn (s string) replace_each(vals []string) string {
 | 
				
			||||||
	mut cur_idx := idxs[idx_pos]
 | 
						mut cur_idx := idxs[idx_pos]
 | 
				
			||||||
	mut b_i := 0
 | 
						mut b_i := 0
 | 
				
			||||||
	for i := 0; i < s.len; i++ {
 | 
						for i := 0; i < s.len; i++ {
 | 
				
			||||||
		// Reached the location of rep, replace it with "with"
 | 
					 | 
				
			||||||
		if i == cur_idx.idx {
 | 
							if i == cur_idx.idx {
 | 
				
			||||||
 | 
								// Reached the location of rep, replace it with "with"
 | 
				
			||||||
			rep := vals[cur_idx.val_idx]
 | 
								rep := vals[cur_idx.val_idx]
 | 
				
			||||||
			with := vals[cur_idx.val_idx + 1]
 | 
								with := vals[cur_idx.val_idx + 1]
 | 
				
			||||||
			for j in 0..with.len {
 | 
								for j in 0..with.len {
 | 
				
			||||||
| 
						 | 
					@ -279,8 +279,8 @@ pub fn (s string) replace_each(vals []string) string {
 | 
				
			||||||
				cur_idx = idxs[idx_pos]
 | 
									cur_idx = idxs[idx_pos]
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// Rep doesnt start here, just copy
 | 
					 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
 | 
								// Rep doesnt start here, just copy
 | 
				
			||||||
			b[b_i] = s.str[i]
 | 
								b[b_i] = s.str[i]
 | 
				
			||||||
			b_i++
 | 
								b_i++
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -265,6 +265,7 @@ pub struct GlobalDecl {
 | 
				
			||||||
pub:
 | 
					pub:
 | 
				
			||||||
	name string
 | 
						name string
 | 
				
			||||||
	expr Expr
 | 
						expr Expr
 | 
				
			||||||
 | 
						has_expr bool
 | 
				
			||||||
mut:
 | 
					mut:
 | 
				
			||||||
	typ  table.Type
 | 
						typ  table.Type
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -139,7 +139,8 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if table.type_is_ptr(field.typ) {
 | 
									if table.type_is_ptr(field.typ) {
 | 
				
			||||||
					c.warn('reference field `${typ_sym.name}.${field.name}` must be initialized', struct_init.pos)
 | 
										c.warn('reference field `${typ_sym.name}.${field.name}` must be initialized', 
 | 
				
			||||||
 | 
											struct_init.pos)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -212,7 +213,7 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
 | 
				
			||||||
	if !c.table.check(right_type, left_type) {
 | 
						if !c.table.check(right_type, left_type) {
 | 
				
			||||||
		left_type_sym := c.table.get_type_symbol(left_type)
 | 
							left_type_sym := c.table.get_type_symbol(left_type)
 | 
				
			||||||
		right_type_sym := c.table.get_type_symbol(right_type)
 | 
							right_type_sym := c.table.get_type_symbol(right_type)
 | 
				
			||||||
		c.error('cannot assign $right_type_sym.name to $left_type_sym.name', assign_expr.pos)
 | 
							c.error('cannot assign `$right_type_sym.name` to `$left_type_sym.name`', assign_expr.pos)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,8 +225,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
 | 
				
			||||||
		left_type_sym := c.table.get_type_symbol(left_type)
 | 
							left_type_sym := c.table.get_type_symbol(left_type)
 | 
				
			||||||
		method_name := call_expr.name
 | 
							method_name := call_expr.name
 | 
				
			||||||
		// TODO: remove this for actual methods, use only for compiler magic
 | 
							// TODO: remove this for actual methods, use only for compiler magic
 | 
				
			||||||
		if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', 'map', 
 | 
							if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', 
 | 
				
			||||||
			'slice'] {
 | 
								'map', 'slice'] {
 | 
				
			||||||
			if method_name in ['filter', 'map'] {
 | 
								if method_name in ['filter', 'map'] {
 | 
				
			||||||
				array_info := left_type_sym.info as table.Array
 | 
									array_info := left_type_sym.info as table.Array
 | 
				
			||||||
				mut scope := c.file.scope.innermost(call_expr.pos.pos)
 | 
									mut scope := c.file.scope.innermost(call_expr.pos.pos)
 | 
				
			||||||
| 
						 | 
					@ -252,7 +253,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if method := c.table.type_find_method(left_type_sym, method_name) {
 | 
							if method := c.table.type_find_method(left_type_sym, method_name) {
 | 
				
			||||||
			no_args := method.args.len - 1
 | 
								no_args := method.args.len - 1
 | 
				
			||||||
			min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
 | 
								min_required_args := method.args.len - if method.is_variadic && method.args.len > 
 | 
				
			||||||
 | 
									1 { 2 } else { 1 }
 | 
				
			||||||
			if call_expr.args.len < min_required_args {
 | 
								if call_expr.args.len < min_required_args {
 | 
				
			||||||
				c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)', 
 | 
									c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)', 
 | 
				
			||||||
					call_expr.pos)
 | 
										call_expr.pos)
 | 
				
			||||||
| 
						 | 
					@ -479,7 +481,8 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if return_stmt.exprs.len > 0 && c.fn_return_type == table.void_type {
 | 
						if return_stmt.exprs.len > 0 && c.fn_return_type == table.void_type {
 | 
				
			||||||
		c.error('too many arguments to return, current function does not return anything', return_stmt.pos)
 | 
							c.error('too many arguments to return, current function does not return anything', 
 | 
				
			||||||
 | 
								return_stmt.pos)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	expected_type := c.fn_return_type
 | 
						expected_type := c.fn_return_type
 | 
				
			||||||
| 
						 | 
					@ -542,7 +545,8 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
 | 
				
			||||||
				if !c.table.check(val_type, var_type) {
 | 
									if !c.table.check(val_type, var_type) {
 | 
				
			||||||
					val_type_sym := c.table.get_type_symbol(val_type)
 | 
										val_type_sym := c.table.get_type_symbol(val_type)
 | 
				
			||||||
					var_type_sym := c.table.get_type_symbol(var_type)
 | 
										var_type_sym := c.table.get_type_symbol(var_type)
 | 
				
			||||||
					c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
 | 
										c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', 
 | 
				
			||||||
 | 
											assign_stmt.pos)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ident_var_info.typ = val_type
 | 
								ident_var_info.typ = val_type
 | 
				
			||||||
| 
						 | 
					@ -568,7 +572,8 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
 | 
				
			||||||
				if !c.table.check(val_type, var_type) {
 | 
									if !c.table.check(val_type, var_type) {
 | 
				
			||||||
					val_type_sym := c.table.get_type_symbol(val_type)
 | 
										val_type_sym := c.table.get_type_symbol(val_type)
 | 
				
			||||||
					var_type_sym := c.table.get_type_symbol(var_type)
 | 
										var_type_sym := c.table.get_type_symbol(var_type)
 | 
				
			||||||
					c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
 | 
										c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', 
 | 
				
			||||||
 | 
											assign_stmt.pos)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ident_var_info.typ = val_type
 | 
								ident_var_info.typ = val_type
 | 
				
			||||||
| 
						 | 
					@ -1181,7 +1186,8 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type {
 | 
				
			||||||
		// index_type_sym.kind != .enum_) {
 | 
							// index_type_sym.kind != .enum_) {
 | 
				
			||||||
		if typ_sym.kind in [.array, .array_fixed] && !(table.is_number(index_type) || index_type_sym.kind == 
 | 
							if typ_sym.kind in [.array, .array_fixed] && !(table.is_number(index_type) || index_type_sym.kind == 
 | 
				
			||||||
			.enum_) {
 | 
								.enum_) {
 | 
				
			||||||
			c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)', node.pos)
 | 
								c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)', 
 | 
				
			||||||
 | 
									node.pos)
 | 
				
			||||||
		} else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx {
 | 
							} else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx {
 | 
				
			||||||
			c.error('non-string map index (map type `$typ_sym.name`)', node.pos)
 | 
								c.error('non-string map index (map type `$typ_sym.name`)', node.pos)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -1252,12 +1258,14 @@ pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type {
 | 
				
			||||||
		if !c.table.check(key_type, key0_type) {
 | 
							if !c.table.check(key_type, key0_type) {
 | 
				
			||||||
			key0_type_sym := c.table.get_type_symbol(key0_type)
 | 
								key0_type_sym := c.table.get_type_symbol(key0_type)
 | 
				
			||||||
			key_type_sym := c.table.get_type_symbol(key_type)
 | 
								key_type_sym := c.table.get_type_symbol(key_type)
 | 
				
			||||||
			c.error('map init: cannot use `$key_type_sym.name` as `$key0_type_sym` for map key', node.pos)
 | 
								c.error('map init: cannot use `$key_type_sym.name` as `$key0_type_sym` for map key', 
 | 
				
			||||||
 | 
									node.pos)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !c.table.check(val_type, val0_type) {
 | 
							if !c.table.check(val_type, val0_type) {
 | 
				
			||||||
			val0_type_sym := c.table.get_type_symbol(val0_type)
 | 
								val0_type_sym := c.table.get_type_symbol(val0_type)
 | 
				
			||||||
			val_type_sym := c.table.get_type_symbol(val_type)
 | 
								val_type_sym := c.table.get_type_symbol(val_type)
 | 
				
			||||||
			c.error('map init: cannot use `$val_type_sym.name` as `$val0_type_sym` for map value', node.pos)
 | 
								c.error('map init: cannot use `$val_type_sym.name` as `$val0_type_sym` for map value', 
 | 
				
			||||||
 | 
									node.pos)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	map_type := table.new_type(c.table.find_or_register_map(key0_type, val0_type))
 | 
						map_type := table.new_type(c.table.find_or_register_map(key0_type, val0_type))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t']
 | 
						tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t']
 | 
				
			||||||
	max_len = 100
 | 
						max_len = 90
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Fmt {
 | 
					struct Fmt {
 | 
				
			||||||
| 
						 | 
					@ -137,6 +137,11 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			f.is_assign = false
 | 
								f.is_assign = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ast.AssertStmt {
 | 
				
			||||||
 | 
								f.write('assert ')
 | 
				
			||||||
 | 
								f.expr(it.expr)
 | 
				
			||||||
 | 
								f.writeln('')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ast.Attr {
 | 
							ast.Attr {
 | 
				
			||||||
			f.writeln('[$it.name]')
 | 
								f.writeln('[$it.name]')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -159,6 +164,16 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
 | 
				
			||||||
		ast.Comment {
 | 
							ast.Comment {
 | 
				
			||||||
			f.comment(it)
 | 
								f.comment(it)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ast.CompIf {
 | 
				
			||||||
 | 
								inversion := if it.is_not { '!' } else { '' }
 | 
				
			||||||
 | 
								f.writeln('\$if ${inversion}${it.val} {')
 | 
				
			||||||
 | 
								f.stmts(it.stmts)
 | 
				
			||||||
 | 
								if it.has_else {
 | 
				
			||||||
 | 
									f.writeln('} \$else {')
 | 
				
			||||||
 | 
									f.stmts(it.else_stmts)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								f.writeln('}')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ast.ConstDecl {
 | 
							ast.ConstDecl {
 | 
				
			||||||
			if it.is_pub {
 | 
								if it.is_pub {
 | 
				
			||||||
				f.write('pub ')
 | 
									f.write('pub ')
 | 
				
			||||||
| 
						 | 
					@ -252,6 +267,14 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
 | 
				
			||||||
			f.stmts(it.stmts)
 | 
								f.stmts(it.stmts)
 | 
				
			||||||
			f.writeln('}')
 | 
								f.writeln('}')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ast.GlobalDecl {
 | 
				
			||||||
 | 
								f.write('__global $it.name ')
 | 
				
			||||||
 | 
								f.write(f.table.type_to_str(it.typ))
 | 
				
			||||||
 | 
								if it.has_expr {
 | 
				
			||||||
 | 
									f.write(' = ')
 | 
				
			||||||
 | 
									f.expr(it.expr)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ast.GotoLabel {
 | 
							ast.GotoLabel {
 | 
				
			||||||
			f.writeln('$it.name:')
 | 
								f.writeln('$it.name:')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -285,29 +308,13 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
 | 
				
			||||||
		ast.StructDecl {
 | 
							ast.StructDecl {
 | 
				
			||||||
			f.struct_decl(it)
 | 
								f.struct_decl(it)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.UnsafeStmt {
 | 
					 | 
				
			||||||
			f.writeln('unsafe {')
 | 
					 | 
				
			||||||
			f.stmts(it.stmts)
 | 
					 | 
				
			||||||
			f.writeln('}')
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ast.Import {}
 | 
					 | 
				
			||||||
		ast.TypeDecl {
 | 
							ast.TypeDecl {
 | 
				
			||||||
			// already handled in f.imports
 | 
								// already handled in f.imports
 | 
				
			||||||
			f.type_decl(it)
 | 
								f.type_decl(it)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ast.AssertStmt {
 | 
							ast.UnsafeStmt {
 | 
				
			||||||
			f.write('assert ')
 | 
								f.writeln('unsafe {')
 | 
				
			||||||
			f.expr(it.expr)
 | 
					 | 
				
			||||||
			f.writeln('')
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ast.CompIf {
 | 
					 | 
				
			||||||
			inversion := if it.is_not { '!' } else { '' }
 | 
					 | 
				
			||||||
			f.writeln('\$if ${inversion}${it.val} {')
 | 
					 | 
				
			||||||
			f.stmts(it.stmts)
 | 
								f.stmts(it.stmts)
 | 
				
			||||||
			if it.has_else {
 | 
					 | 
				
			||||||
				f.writeln('} \$else {')
 | 
					 | 
				
			||||||
				f.stmts(it.else_stmts)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			f.writeln('}')
 | 
								f.writeln('}')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
| 
						 | 
					@ -575,6 +582,15 @@ fn (f mut Fmt) expr(node ast.Expr) {
 | 
				
			||||||
			f.write('.')
 | 
								f.write('.')
 | 
				
			||||||
			f.write(it.field)
 | 
								f.write(it.field)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							ast.SizeOf {
 | 
				
			||||||
 | 
								f.writeln('sizeof(')
 | 
				
			||||||
 | 
								if it.type_name != '' {
 | 
				
			||||||
 | 
									f.writeln(it.type_name)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									f.writeln(f.table.type_to_str(it.typ))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								f.writeln(')')
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		ast.StringLiteral {
 | 
							ast.StringLiteral {
 | 
				
			||||||
			if it.val.contains("'") {
 | 
								if it.val.contains("'") {
 | 
				
			||||||
				f.write('"$it.val"')
 | 
									f.write('"$it.val"')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,10 +15,10 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free',
 | 
						c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free', 'panic', 'auto', 
 | 
				
			||||||
		'panic', 'auto', 'char', 'default', 'do', 'double', 'extern', 'float', 'inline',
 | 
							'char', 'default', 'do', 'double', 'extern', 'float', 'inline', 'int', 'long', 'register', 
 | 
				
			||||||
		'int', 'long', 'register', 'restrict', 'short', 'signed', 'sizeof', 'static', 'switch',
 | 
							'restrict', 'short', 'signed', 'sizeof', 'static', 'switch', 'typedef', 'union', 'unsigned', 
 | 
				
			||||||
		'typedef', 'union', 'unsigned', 'void', 'volatile', 'while']
 | 
							'void', 'volatile', 'while']
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Gen {
 | 
					struct Gen {
 | 
				
			||||||
| 
						 | 
					@ -58,8 +58,8 @@ mut:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t',
 | 
						tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t', 
 | 
				
			||||||
		'\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t']
 | 
							'\t\t\t\t\t\t\t\t']
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string {
 | 
					pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string {
 | 
				
			||||||
| 
						 | 
					@ -117,8 +117,8 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// 
 | 
						// 
 | 
				
			||||||
	g.finish()
 | 
						g.finish()
 | 
				
			||||||
	return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() +
 | 
						return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() + g.definitions.str() + 
 | 
				
			||||||
		g.definitions.str() + g.gowrappers.str() + g.stringliterals.str() + g.out.str()
 | 
							g.gowrappers.str() + g.stringliterals.str() + g.out.str()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (g Gen) hashes() string {
 | 
					pub fn (g Gen) hashes() string {
 | 
				
			||||||
| 
						 | 
					@ -1006,7 +1006,8 @@ fn (g mut Gen) expr(node ast.Expr) {
 | 
				
			||||||
				g.out.go_back(1)
 | 
									g.out.go_back(1)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			sym := g.table.get_type_symbol(it.typ)
 | 
								sym := g.table.get_type_symbol(it.typ)
 | 
				
			||||||
			if sym.kind == .string {
 | 
								if sym.kind == .string && !table.type_is_ptr(it.typ) {
 | 
				
			||||||
 | 
									// `string(x)` needs `tos()`, but not `&string(x)
 | 
				
			||||||
				// `tos(str, len)`, `tos2(str)`
 | 
									// `tos(str, len)`, `tos2(str)`
 | 
				
			||||||
				if it.has_arg {
 | 
									if it.has_arg {
 | 
				
			||||||
					g.write('tos(')
 | 
										g.write('tos(')
 | 
				
			||||||
| 
						 | 
					@ -1135,8 +1136,7 @@ fn (g mut Gen) expr(node ast.Expr) {
 | 
				
			||||||
				g.write('tos3("$escaped_val")')
 | 
									g.write('tos3("$escaped_val")')
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			escaped_val := it.val.replace_each(['"', '\\"', '\r\n', '\\n', '\n',
 | 
								escaped_val := it.val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n'])
 | 
				
			||||||
				'\\n'])
 | 
					 | 
				
			||||||
			if g.is_c_call || it.is_c {
 | 
								if g.is_c_call || it.is_c {
 | 
				
			||||||
				// In C calls we have to generate C strings
 | 
									// In C calls we have to generate C strings
 | 
				
			||||||
				// `C.printf("hi")` => `printf("hi");`
 | 
									// `C.printf("hi")` => `printf("hi");`
 | 
				
			||||||
| 
						 | 
					@ -1361,8 +1361,7 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) {
 | 
				
			||||||
			g.expr(node.left)
 | 
								g.expr(node.left)
 | 
				
			||||||
			g.write(')')
 | 
								g.write(')')
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if node.op == .left_shift && g.table.get_type_symbol(node.left_type).kind ==
 | 
						} else if node.op == .left_shift && g.table.get_type_symbol(node.left_type).kind == .array {
 | 
				
			||||||
		.array {
 | 
					 | 
				
			||||||
		// arr << val
 | 
							// arr << val
 | 
				
			||||||
		tmp := g.new_tmp_var()
 | 
							tmp := g.new_tmp_var()
 | 
				
			||||||
		sym := g.table.get_type_symbol(node.left_type)
 | 
							sym := g.table.get_type_symbol(node.left_type)
 | 
				
			||||||
| 
						 | 
					@ -1547,8 +1546,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
 | 
				
			||||||
	// one line ?:
 | 
						// one line ?:
 | 
				
			||||||
	// TODO clean this up once `is` is supported
 | 
						// TODO clean this up once `is` is supported
 | 
				
			||||||
	// TODO: make sure only one stmt in each branch
 | 
						// TODO: make sure only one stmt in each branch
 | 
				
			||||||
	if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind !=
 | 
						if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind != .void {
 | 
				
			||||||
		.void {
 | 
					 | 
				
			||||||
		g.inside_ternary = true
 | 
							g.inside_ternary = true
 | 
				
			||||||
		g.write('(')
 | 
							g.write('(')
 | 
				
			||||||
		for i, branch in node.branches {
 | 
							for i, branch in node.branches {
 | 
				
			||||||
| 
						 | 
					@ -1996,8 +1994,7 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[inline]
 | 
					[inline]
 | 
				
			||||||
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
 | 
					fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
 | 
				
			||||||
	arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in
 | 
						arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs
 | 
				
			||||||
		table.pointer_type_idxs
 | 
					 | 
				
			||||||
	expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs
 | 
						expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs
 | 
				
			||||||
	if arg.is_mut && !arg_is_ptr {
 | 
						if arg.is_mut && !arg_is_ptr {
 | 
				
			||||||
		g.write('&/*mut*/')
 | 
							g.write('&/*mut*/')
 | 
				
			||||||
| 
						 | 
					@ -2201,8 +2198,8 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
 | 
				
			||||||
	// sort graph
 | 
						// sort graph
 | 
				
			||||||
	dep_graph_sorted := dep_graph.resolve()
 | 
						dep_graph_sorted := dep_graph.resolve()
 | 
				
			||||||
	if !dep_graph_sorted.acyclic {
 | 
						if !dep_graph_sorted.acyclic {
 | 
				
			||||||
		verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' +
 | 
							verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' + dep_graph_sorted.display_cycles() + 
 | 
				
			||||||
			dep_graph_sorted.display_cycles() + '\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' +
 | 
								'\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' + 
 | 
				
			||||||
			'\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro')
 | 
								'\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// sort types
 | 
						// sort types
 | 
				
			||||||
| 
						 | 
					@ -2339,8 +2336,8 @@ fn (g mut Gen) method_call(node ast.CallExpr) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// TODO performance, detect `array` method differently
 | 
						// TODO performance, detect `array` method differently
 | 
				
			||||||
	if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free',
 | 
						if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many', 
 | 
				
			||||||
		'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
 | 
							'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
 | 
				
			||||||
		// && rec_sym.name == 'array' {
 | 
							// && rec_sym.name == 'array' {
 | 
				
			||||||
		// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
 | 
							// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
 | 
				
			||||||
		// `array_byte_clone` => `array_clone`
 | 
							// `array_byte_clone` => `array_clone`
 | 
				
			||||||
| 
						 | 
					@ -2743,8 +2740,7 @@ pub fn (g mut Gen) write_tests_main() {
 | 
				
			||||||
	g.definitions.writeln('int g_test_fails = 0;')
 | 
						g.definitions.writeln('int g_test_fails = 0;')
 | 
				
			||||||
	$if windows {
 | 
						$if windows {
 | 
				
			||||||
		g.writeln('int wmain() {')
 | 
							g.writeln('int wmain() {')
 | 
				
			||||||
	}
 | 
						} $else {
 | 
				
			||||||
	$else {
 | 
					 | 
				
			||||||
		g.writeln('int main() {')
 | 
							g.writeln('int main() {')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	g.writeln('\t_vinit();')
 | 
						g.writeln('\t_vinit();')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -627,7 +627,8 @@ pub fn (p mut Parser) name_expr() ast.Expr {
 | 
				
			||||||
		name_w_mod := p.prepend_mod(name)
 | 
							name_w_mod := p.prepend_mod(name)
 | 
				
			||||||
		// type cast. TODO: finish
 | 
							// type cast. TODO: finish
 | 
				
			||||||
		// if name in table.builtin_type_names {
 | 
							// if name in table.builtin_type_names {
 | 
				
			||||||
		if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', 'C.sigaction']) {
 | 
							if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', 
 | 
				
			||||||
 | 
								'C.sigaction']) {
 | 
				
			||||||
			// TODO handle C.stat()
 | 
								// TODO handle C.stat()
 | 
				
			||||||
			mut to_typ := p.parse_type()
 | 
								mut to_typ := p.parse_type()
 | 
				
			||||||
			if p.is_amp {
 | 
								if p.is_amp {
 | 
				
			||||||
| 
						 | 
					@ -660,9 +661,9 @@ pub fn (p mut Parser) name_expr() ast.Expr {
 | 
				
			||||||
			x := p.call_expr(is_c, mod)			// TODO `node,typ :=` should work
 | 
								x := p.call_expr(is_c, mod)			// TODO `node,typ :=` should work
 | 
				
			||||||
			node = x
 | 
								node = x
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && p.tok.lit in 
 | 
						} else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && 
 | 
				
			||||||
		table.builtin_type_names)) && (p.tok.lit.len in [1, 2] || !p.tok.lit[p.tok.lit.len - 1].is_capital()) && 
 | 
							p.tok.lit in table.builtin_type_names)) && (p.tok.lit.len in [1, 2] || !p.tok.lit[p.tok.lit.len - 
 | 
				
			||||||
		!p.inside_match_case {
 | 
							1].is_capital()) && !p.inside_match_case {
 | 
				
			||||||
		// || p.table.known_type(p.tok.lit)) {
 | 
							// || p.table.known_type(p.tok.lit)) {
 | 
				
			||||||
		return p.struct_init(false)		// short_syntax: false
 | 
							return p.struct_init(false)		// short_syntax: false
 | 
				
			||||||
	} else if p.peek_tok.kind == .dot && (p.tok.lit[0].is_capital() && !known_var) {
 | 
						} else if p.peek_tok.kind == .dot && (p.tok.lit[0].is_capital() && !known_var) {
 | 
				
			||||||
| 
						 | 
					@ -1714,17 +1715,19 @@ fn (p mut Parser) hash() ast.HashStmt {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn (p mut Parser) global_decl() ast.GlobalDecl {
 | 
					fn (p mut Parser) global_decl() ast.GlobalDecl {
 | 
				
			||||||
	if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' && 
 | 
						if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 
 | 
				
			||||||
		p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
 | 
							'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
 | 
				
			||||||
		p.error('use `v --enable-globals ...` to enable globals')
 | 
							p.error('use `v --enable-globals ...` to enable globals')
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.next()
 | 
						p.next()
 | 
				
			||||||
	name := p.check_name()
 | 
						name := p.check_name()
 | 
				
			||||||
	// println(name)
 | 
						// println(name)
 | 
				
			||||||
	typ := p.parse_type()
 | 
						typ := p.parse_type()
 | 
				
			||||||
	if p.tok.kind == .assign {
 | 
						mut expr := ast.Expr{}
 | 
				
			||||||
 | 
						has_expr := p.tok.kind == .assign
 | 
				
			||||||
 | 
						if has_expr {
 | 
				
			||||||
		p.next()
 | 
							p.next()
 | 
				
			||||||
		p.expr(0)
 | 
							expr = p.expr(0)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// p.genln(p.table.cgen_name_type_pair(name, typ))
 | 
						// p.genln(p.table.cgen_name_type_pair(name, typ))
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -1744,6 +1747,8 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
 | 
				
			||||||
	glob := ast.GlobalDecl{
 | 
						glob := ast.GlobalDecl{
 | 
				
			||||||
		name: name
 | 
							name: name
 | 
				
			||||||
		typ: typ
 | 
							typ: typ
 | 
				
			||||||
 | 
							has_expr: has_expr
 | 
				
			||||||
 | 
							expr: expr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p.global_scope.register(name, glob)
 | 
						p.global_scope.register(name, glob)
 | 
				
			||||||
	return glob
 | 
						return glob
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -389,34 +389,36 @@ pub fn (t &Table) value_type(typ Type) Type {
 | 
				
			||||||
		// ...string => string
 | 
							// ...string => string
 | 
				
			||||||
		return type_set(typ, .unset)
 | 
							return type_set(typ, .unset)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if typ_sym.kind == .array {
 | 
						if typ_sym.kind == .array {
 | 
				
			||||||
		// Check index type
 | 
							// Check index type
 | 
				
			||||||
		info := typ_sym.info as Array
 | 
							info := typ_sym.info as Array
 | 
				
			||||||
		return info.elem_type
 | 
							return info.elem_type
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if typ_sym.kind == .array_fixed {
 | 
						if typ_sym.kind == .array_fixed {
 | 
				
			||||||
		info := typ_sym.info as ArrayFixed
 | 
							info := typ_sym.info as ArrayFixed
 | 
				
			||||||
		return info.elem_type
 | 
							return info.elem_type
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if typ_sym.kind == .map {
 | 
						if typ_sym.kind == .map {
 | 
				
			||||||
		info := typ_sym.info as Map
 | 
							info := typ_sym.info as Map
 | 
				
			||||||
		return info.value_type
 | 
							return info.value_type
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if typ_sym.kind in [.byteptr, .string] {
 | 
						if typ_sym.kind == .string && table.type_is_ptr(typ) {
 | 
				
			||||||
 | 
							// (&string)[i] => string
 | 
				
			||||||
 | 
							return string_type
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if typ_sym.kind in [.byteptr, .string] {
 | 
				
			||||||
		return byte_type
 | 
							return byte_type
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else if type_is_ptr(typ) {
 | 
						if type_is_ptr(typ) {
 | 
				
			||||||
		// byte* => byte
 | 
							// byte* => byte
 | 
				
			||||||
		// bytes[0] is a byte, not byte*
 | 
							// bytes[0] is a byte, not byte*
 | 
				
			||||||
		return type_deref(typ)
 | 
							return type_deref(typ)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
					 | 
				
			||||||
	// TODO: remove when map_string is removed
 | 
						// TODO: remove when map_string is removed
 | 
				
			||||||
	if typ_sym.name == 'map_string' {
 | 
						if typ_sym.name == 'map_string' {
 | 
				
			||||||
		return string_type
 | 
							return string_type
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return void_type
 | 
						return void_type
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn (t &Table) check(got, expected Type) bool {
 | 
					pub fn (t &Table) check(got, expected Type) bool {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,10 @@
 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import time as t
 | 
					 | 
				
			||||||
import crypto.sha256 as s2
 | 
					 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						os
 | 
				
			||||||
 | 
						time as t
 | 
				
			||||||
 | 
						crypto.sha256
 | 
				
			||||||
	math
 | 
						math
 | 
				
			||||||
	log as l
 | 
						log as l
 | 
				
			||||||
	crypto.sha512 as s5
 | 
						crypto.sha512
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TestAliasInStruct {
 | 
					struct TestAliasInStruct {
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,9 @@ struct TestAliasInStruct {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn test_import() {
 | 
					fn test_import() {
 | 
				
			||||||
	assert os.O_RDONLY == os.O_RDONLY && t.month_days[0] == t.month_days[0] && s2.size == s2.size && math.pi == math.pi && l.INFO == l.INFO && s5.size == s5.size
 | 
						info := l.Level.info
 | 
				
			||||||
 | 
						assert os.O_RDONLY == os.O_RDONLY && t.month_days[0] == t.month_days[0] && sha256.size == 
 | 
				
			||||||
 | 
							sha256.size && math.pi == math.pi && info == .info && sha512.size == sha512.size
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn test_alias_in_struct_field() {
 | 
					fn test_alias_in_struct_field() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue