builtin: prepare for error interfaces (#9043)
							parent
							
								
									c474106511
								
							
						
					
					
						commit
						be409b52e9
					
				|  | @ -3,74 +3,66 @@ | |||
| // that can be found in the LICENSE file.
 | ||||
| module builtin | ||||
| 
 | ||||
| struct OptionBase { | ||||
| 	ok      bool | ||||
| 	is_none bool | ||||
| 	error   string | ||||
| 	ecode   int | ||||
| 	// Data is trailing after ecode
 | ||||
| 	// and is not included in here but in the
 | ||||
| 	// derived Option_xxx types
 | ||||
| // IError holds information about an error instance
 | ||||
| pub interface IError { | ||||
| 	msg  string | ||||
| 	code int | ||||
| } | ||||
| 
 | ||||
| // `fn foo() ?Foo { return foo }` => `fn foo() ?Foo { return opt_ok(foo); }`
 | ||||
| fn opt_ok2(data voidptr, mut option OptionBase, size int) { | ||||
| // Error is the default implementation of IError, that is returned by e.g. `error()`
 | ||||
| pub struct Error { | ||||
| pub: | ||||
| 	msg  string | ||||
| 	code int | ||||
| } | ||||
| 
 | ||||
| pub struct Option3 { | ||||
| 	state byte | ||||
| 	err   IError | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
| fn (e IError) str() string { | ||||
| 	return e.msg | ||||
| } | ||||
| 
 | ||||
| fn opt_ok3(data voidptr, mut option Option3, size int) { | ||||
| 	unsafe { | ||||
| 		*option = OptionBase{ | ||||
| 			ok: true | ||||
| 		} | ||||
| 		// use ecode to get the end of OptionBase and then memcpy into it
 | ||||
| 		C.memcpy(byteptr(&option.ecode) + sizeof(int), data, size) | ||||
| 		*option = Option3{} | ||||
| 		// use err to get the end of Option3 and then memcpy into it
 | ||||
| 		C.memcpy(byteptr(&option.err) + sizeof(IError), data, size) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Option is the old option type used for bootstrapping
 | ||||
| struct Option { | ||||
| 	ok      bool | ||||
| 	is_none bool | ||||
| 	error   string | ||||
| 	ecode   int | ||||
| } | ||||
| 
 | ||||
| // str returns the string representation of the Option.
 | ||||
| pub fn (o Option) str() string { | ||||
| 	if o.ok && !o.is_none { | ||||
| pub fn (o Option3) str() string { | ||||
| 	if o.state == 0 { | ||||
| 		return 'Option{ ok }' | ||||
| 	} | ||||
| 	if o.is_none { | ||||
| 	if o.state == 1 { | ||||
| 		return 'Option{ none }' | ||||
| 	} | ||||
| 	return 'Option{ error: "$o.error" }' | ||||
| 	return 'Option{ err: "$o.err" }' | ||||
| } | ||||
| 
 | ||||
| // opt_none is used internally when returning `none`.
 | ||||
| fn opt_none() Option { | ||||
| 	return Option{ | ||||
| 		ok: false | ||||
| 		is_none: true | ||||
| [inline] | ||||
| pub fn error3(message string) IError { | ||||
| 	return &Error{ | ||||
| 		msg: message | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // error returns an optional containing the error given in `message`.
 | ||||
| // `if ouch { return error('an error occurred') }`
 | ||||
| pub fn error(message string) Option { | ||||
| 	return Option{ | ||||
| 		ok: false | ||||
| 		is_none: false | ||||
| 		error: message | ||||
| pub fn error_with_code3(message string, code int) IError { | ||||
| 	return &Error { | ||||
| 		msg: message | ||||
| 		code: code | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // error_with_code returns an optional containing both error `message` and error `code`.
 | ||||
| // `if ouch { return error_with_code('an error occurred',1) }`
 | ||||
| pub fn error_with_code(message string, code int) Option { | ||||
| 	return Option{ | ||||
| 		ok: false | ||||
| 		is_none: false | ||||
| 		error: message | ||||
| 		ecode: code | ||||
| 	} | ||||
| } | ||||
| ////////////////////////////////////////
 | ||||
| 
 | ||||
| // these are just here temporarily to avoid breaking the compiler; they will be removed soon
 | ||||
| pub fn error(a string) Option2 { return {} } | ||||
| pub fn error_with_code(a string, b int) Option2 { return {} } | ||||
| 
 | ||||
| // Option2 is the base of V's new internal optional return system.
 | ||||
| struct Option2 { | ||||
|  | @ -81,13 +73,6 @@ struct Option2 { | |||
| 	// derived Option2_xxx types
 | ||||
| } | ||||
| 
 | ||||
| // Error holds information about an error instance
 | ||||
| pub struct Error { | ||||
| pub: | ||||
| 	msg  string | ||||
| 	code int | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
| fn (e Error) str() string { | ||||
| 	// TODO: this should probably have a better str method,
 | ||||
|  | @ -104,15 +89,14 @@ fn opt_ok(data voidptr, mut option Option2, size int) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // /*
 | ||||
| pub fn (o Option2) str() string { | ||||
| 	if o.state == 0 { | ||||
| 		return 'Option2{ ok }' | ||||
| 		return 'Option{ ok }' | ||||
| 	} | ||||
| 	if o.state == 1 { | ||||
| 		return 'Option2{ none }' | ||||
| 		return 'Option{ none }' | ||||
| 	} | ||||
| 	return 'Option2{ err: "$o.err" }' | ||||
| 	return 'Option{ err: "$o.err" }' | ||||
| } | ||||
| 
 | ||||
| // error returns an optional containing the error given in `message`.
 | ||||
|  | @ -137,4 +121,3 @@ pub fn error_with_code2(message string, code int) Option2 { | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| // */
 | ||||
|  |  | |||
|  | @ -2387,7 +2387,7 @@ pub fn (mut c Checker) return_stmt(mut return_stmt ast.Return) { | |||
| 	return_stmt.types = got_types | ||||
| 	// allow `none` & `error (Option)` return types for function that returns optional
 | ||||
| 	if exp_is_optional | ||||
| 		&& got_types[0].idx() in [table.none_type_idx, table.error_type_idx, c.table.type_idxs['Option'], c.table.type_idxs['Option2']] { | ||||
| 		&& got_types[0].idx() in [table.none_type_idx, table.error_type_idx, c.table.type_idxs['Option'], c.table.type_idxs['Option2'], c.table.type_idxs['Option3']] { | ||||
| 		return | ||||
| 	} | ||||
| 	if expected_types.len > 0 && expected_types.len != got_types.len { | ||||
|  |  | |||
|  | @ -552,9 +552,6 @@ fn (mut g Gen) base_type(t table.Type) string { | |||
| 	if nr_muls > 0 { | ||||
| 		styp += strings.repeat(`*`, nr_muls) | ||||
| 	} | ||||
| 	// if styp == 'Option' {
 | ||||
| 	// 	return 'Option2'
 | ||||
| 	// }
 | ||||
| 	return styp | ||||
| } | ||||
| 
 | ||||
|  | @ -591,7 +588,6 @@ fn (g &Gen) optional_type_text(styp string, base string) string { | |||
| } | ||||
| 
 | ||||
| fn (mut g Gen) register_optional(t table.Type) string { | ||||
| 	// g.typedefs2.writeln('typedef Option $x;')
 | ||||
| 	styp, base := g.optional_type_name(t) | ||||
| 	if styp !in g.optionals { | ||||
| 		g.typedefs2.writeln('typedef struct $styp $styp;') | ||||
|  | @ -736,6 +732,9 @@ fn (g &Gen) type_sidx(t table.Type) string { | |||
| //
 | ||||
| pub fn (mut g Gen) write_typedef_types() { | ||||
| 	for typ in g.table.types { | ||||
| 		if typ.name in c.builtins { | ||||
| 			continue | ||||
| 		} | ||||
| 		match typ.kind { | ||||
| 			.alias { | ||||
| 				parent := unsafe { &g.table.types[typ.parent_idx] } | ||||
|  | @ -755,16 +754,7 @@ pub fn (mut g Gen) write_typedef_types() { | |||
| 				g.type_definitions.writeln('typedef array $typ.cname;') | ||||
| 			} | ||||
| 			.interface_ { | ||||
| 				info := typ.info as table.Interface | ||||
| 				g.type_definitions.writeln('typedef struct {') | ||||
| 				g.type_definitions.writeln('\tvoid* _object;') | ||||
| 				g.type_definitions.writeln('\tint _interface_idx;') | ||||
| 				for field in info.fields { | ||||
| 					styp := g.typ(field.typ) | ||||
| 					cname := c_name(field.name) | ||||
| 					g.type_definitions.writeln('\t$styp* $cname;') | ||||
| 				} | ||||
| 				g.type_definitions.writeln('} ${c_name(typ.name)};') | ||||
| 				g.write_interface_typesymbol_declaration(typ) | ||||
| 			} | ||||
| 			.chan { | ||||
| 				if typ.name != 'chan' { | ||||
|  | @ -799,6 +789,19 @@ static inline void __${typ.cname}_pushval($typ.cname ch, $el_stype val) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (mut g Gen) write_interface_typesymbol_declaration(sym table.TypeSymbol) { | ||||
| 	info := sym.info as table.Interface | ||||
| 	g.type_definitions.writeln('typedef struct {') | ||||
| 	g.type_definitions.writeln('\tvoid* _object;') | ||||
| 	g.type_definitions.writeln('\tint _interface_idx;') | ||||
| 	for field in info.fields { | ||||
| 		styp := g.typ(field.typ) | ||||
| 		cname := c_name(field.name) | ||||
| 		g.type_definitions.writeln('\t$styp* $cname;') | ||||
| 	} | ||||
| 	g.type_definitions.writeln('} ${c_name(sym.name)};\n') | ||||
| } | ||||
| 
 | ||||
| pub fn (mut g Gen) write_fn_typesymbol_declaration(sym table.TypeSymbol) { | ||||
| 	info := sym.info as table.FnType | ||||
| 	func := info.func | ||||
|  | @ -908,7 +911,7 @@ fn (mut g Gen) stmts_with_tmp_var(stmts []ast.Stmt, tmp_var string) { | |||
| 				g.skip_stmt_pos = true | ||||
| 				if stmt is ast.ExprStmt { | ||||
| 					sym := g.table.get_type_symbol(stmt.typ) | ||||
| 					if sym.name in ['Option', 'Option2'] || stmt.expr is ast.None { | ||||
| 					if sym.name in ['Option2', 'Option3'] || stmt.expr is ast.None { | ||||
| 						tmp := g.new_tmp_var() | ||||
| 						g.write('Option2 $tmp = ') | ||||
| 						g.expr(stmt.expr) | ||||
|  | @ -4336,7 +4339,7 @@ fn (mut g Gen) return_statement(node ast.Return) { | |||
| 	if fn_return_is_optional { | ||||
| 		optional_none := node.exprs[0] is ast.None | ||||
| 		ftyp := g.typ(node.types[0]) | ||||
| 		mut is_regular_option := ftyp in ['Option', 'Option2'] | ||||
| 		mut is_regular_option := ftyp in ['Option2', 'Option3'] | ||||
| 		if optional_none || is_regular_option { | ||||
| 			tmp := g.new_tmp_var() | ||||
| 			g.write('Option2 $tmp = ') | ||||
|  | @ -4453,7 +4456,7 @@ fn (mut g Gen) return_statement(node ast.Return) { | |||
| 				node.types[0].has_flag(.optional) | ||||
| 			} | ||||
| 		} | ||||
| 		if fn_return_is_optional && !expr_type_is_opt && return_sym.name !in ['Option', 'Option2'] { | ||||
| 		if fn_return_is_optional && !expr_type_is_opt && return_sym.name !in ['Option2', 'Option3'] { | ||||
| 			styp := g.base_type(g.fn_decl.return_type) | ||||
| 			opt_type := g.typ(g.fn_decl.return_type) | ||||
| 			// Create a tmp for this option
 | ||||
|  | @ -4608,9 +4611,6 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, val string, typ ta | |||
| 	// Initialize more complex consts in `void _vinit/2{}`
 | ||||
| 	// (C doesn't allow init expressions that can't be resolved at compile time).
 | ||||
| 	mut styp := g.typ(typ) | ||||
| 	if styp == 'Option' { | ||||
| 		styp = 'Option2' | ||||
| 	} | ||||
| 	cname := '_const_$name' | ||||
| 	g.definitions.writeln('$styp $cname; // inited later') | ||||
| 	if cname == '_const_os__args' { | ||||
|  | @ -4996,7 +4996,7 @@ fn (mut g Gen) write_init_function() { | |||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	builtins = ['string', 'array', 'KeyValue', 'DenseArray', 'map', 'Option', 'Error', 'Option2'] | ||||
| 	builtins = ['string', 'array', 'DenseArray', 'map', 'Error', 'IError', 'Option2', 'Option3'] | ||||
| ) | ||||
| 
 | ||||
| fn (mut g Gen) write_builtin_types() { | ||||
|  | @ -5004,7 +5004,12 @@ fn (mut g Gen) write_builtin_types() { | |||
| 	// builtin types need to be on top
 | ||||
| 	// everything except builtin will get sorted
 | ||||
| 	for builtin_name in c.builtins { | ||||
| 		builtin_types << g.table.types[g.table.type_idxs[builtin_name]] | ||||
| 		sym := g.table.types[g.table.type_idxs[builtin_name]] | ||||
| 		if sym.kind == .interface_ { | ||||
| 			g.write_interface_typesymbol_declaration(sym) | ||||
| 		} else { | ||||
| 			builtin_types << sym | ||||
| 		} | ||||
| 	} | ||||
| 	g.write_types(builtin_types) | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue