Slowly adding multiple return values

This commit is contained in:
Krzosa Karol
2022-06-16 11:48:47 +02:00
parent 2a3284f70e
commit c604b44458
8 changed files with 122 additions and 48 deletions

18
ast.cpp
View File

@@ -139,7 +139,7 @@ struct Ast_Builtin: Ast_Expr{
// //
struct Ast_Return: Ast{ struct Ast_Return: Ast{
Ast_Expr *expr; Array<Ast_Expr *> expr;
}; };
struct Ast_If_Node: Ast{ struct Ast_If_Node: Ast{
@@ -164,7 +164,7 @@ struct Ast_For: Ast{
struct Ast_Lambda : Ast_Expr { struct Ast_Lambda : Ast_Expr {
Array<Ast_Decl *> args; Array<Ast_Decl *> args;
Ast_Expr *ret; Array<Ast_Expr *> ret;
Ast_Scope *scope; Ast_Scope *scope;
}; };
@@ -331,14 +331,12 @@ ast_expr_index(Token *pos, Ast_Expr *expr, Ast_Expr *index){
} }
function Ast_Lambda * function Ast_Lambda *
ast_lambda(Token *pos, Array<Ast_Decl *> params, Ast_Expr *ret, Ast_Scope *scope){ ast_lambda(Token *pos, Array<Ast_Decl *> params, Array<Ast_Expr *> ret, Ast_Scope *scope){
AST_NEW(Lambda, LAMBDA_EXPR, pos, AST_EXPR); AST_NEW(Lambda, LAMBDA_EXPR, pos, AST_EXPR);
result->flags = AST_EXPR; result->flags = AST_EXPR;
result->args = params.tight_copy(pctx->perm); result->args = params.tight_copy(pctx->perm);
result->ret = ret.tight_copy(pctx->perm);
result->scope = scope; result->scope = scope;
result->ret = ret;
if(!ret) result->ret = ast_ident(result->pos, intern_void);
return result; return result;
} }
@@ -372,11 +370,11 @@ ast_break(Token *pos){
} }
function Ast_Return * function Ast_Return *
ast_return(Token *pos, Ast_Expr *expr){ ast_return(Token *pos, Array<Ast_Expr *> expr){
AST_NEW(Return, RETURN, pos, AST_STMT); AST_NEW(Return, RETURN, pos, AST_STMT);
if(expr){ if(expr.len){
assert(is_flag_set(expr->flags, AST_EXPR)); For(expr) assert(is_flag_set(it->flags, AST_EXPR));
result->expr = expr; result->expr = expr.tight_copy(pctx->perm);
} }
return result; return result;
} }

View File

@@ -213,7 +213,10 @@ gen_lambda(Intern_String name, Ast_Lambda *lambda, B32 generate_block = true){
if(name == pctx->intern("main"_s) || name == pctx->intern("WinMain"_s)){ if(name == pctx->intern("main"_s) || name == pctx->intern("WinMain"_s)){
is_foreign = true; is_foreign = true;
} }
gen_simple_decl(lambda->resolved_type->func.ret, name, lambda->parent_scope, !is_foreign); if(lambda->resolved_type->func.ret->kind == TYPE_TUPLE){
gen("TUPLE ");
}
else gen_simple_decl(lambda->resolved_type->func.ret, name, lambda->parent_scope, !is_foreign);
gen("("); gen("(");
For(lambda->args){ For(lambda->args){
gen_var(it, DONT_EMIT_VALUE, true); gen_var(it, DONT_EMIT_VALUE, true);
@@ -379,9 +382,9 @@ gen_ast(Ast *ast){
CASE(RETURN, Return){ CASE(RETURN, Return){
gen("return"); gen("return");
if(node->expr){ For(node->expr){
gen(" "); gen(" ");
gen_expr(node->expr); gen_expr(it); // @todo multiple_returns
} }
gen(";"); gen(";");
BREAK(); BREAK();
@@ -524,6 +527,15 @@ gen_ast(Ast *ast){
BREAK(); BREAK();
} }
CASE(VAR_UNPACK, Var_Unpack){
For(node->vars) {
gen_ast(it);
}
gen(" = ");
gen_expr(node->expr);
BREAK();
}
case AST_CONSTANT_ASSERT: case AST_CONSTANT_ASSERT:
case AST_MODULE_NAMESPACE: case AST_MODULE_NAMESPACE:
CASE(FILE_NAMESPACE, File_Namespace){unused(node); BREAK();} CASE(FILE_NAMESPACE, File_Namespace){unused(node); BREAK();}
@@ -707,6 +719,7 @@ typedef struct String{
#define assert_msg(x,...) assert(x) #define assert_msg(x,...) assert(x)
)=="); )==");
//*(volatile int *)0 = 0;
#endif #endif
For(pctx->ordered_decls){ For(pctx->ordered_decls){
if(it->kind == AST_STRUCT){ if(it->kind == AST_STRUCT){

View File

@@ -214,9 +214,15 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){
if(!scope_defined_outside) scope = begin_stmt_scope(scratch, token_block); if(!scope_defined_outside) scope = begin_stmt_scope(scratch, token_block);
do{ do{
Token *token = token_get(); Token *token = token_get();
if(token_match_keyword(keyword_return)){ if(token_match_keyword(keyword_return)){
Ast_Expr *expr = 0; Array<Ast_Expr *> expr = {scratch};
if(!token_is_scope()) expr = parse_expr(); if(!token_is_scope()) {
do{
Ast_Expr *subexpr = parse_expr();
expr.add(subexpr);
} while(token_match(TK_Comma));
}
scope->stmts.add(ast_return(token, expr)); scope->stmts.add(ast_return(token, expr));
} }
@@ -323,7 +329,7 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){
decls.add(decl); decls.add(decl);
}while(token_match(TK_Comma)); }while(token_match(TK_Comma));
token_expect(TK_Assign); token_expect(TK_ColonAssign);
Ast_Expr *expr = parse_expr(); Ast_Expr *expr = parse_expr();
Ast_Var_Unpack *vars = ast_var_unpack(token, decls, expr); Ast_Var_Unpack *vars = ast_var_unpack(token, decls, expr);
scope->stmts.add(vars); scope->stmts.add(vars);
@@ -384,7 +390,16 @@ parse_lambda(Token *token){
} }
} }
token_expect(TK_CloseParen); token_expect(TK_CloseParen);
Ast_Expr *ret = parse_optional_type();
Array<Ast_Expr *> ret = {scratch};
if(token_match(TK_Colon)){
do{
Ast_Expr *typespec = parse_expr();
ret.add(typespec);
}while(token_match(TK_Comma));
}
else ret.add(ast_ident(token, intern_void));
Ast_Scope *scope = token_is(OPEN_SCOPE) ? parse_stmt_scope() : 0; Ast_Scope *scope = token_is(OPEN_SCOPE) ? parse_stmt_scope() : 0;
Ast_Lambda *result = ast_lambda(token, params, ret, scope); Ast_Lambda *result = ast_lambda(token, params, ret, scope);
return result; return result;

View File

@@ -100,6 +100,20 @@ string_to_string16 :: (in: String): String16
result.str[result.len] = 0 result.str[result.len] = 0
return result return result
test_unicode :: ()
string := " 豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵 ..."
string_result := string_to_string16(string)
print(string_result)
result := utf8_to_utf32(&"A"[0], 1)
assert(result.out_str == 'A, "Invalid decode") // '
result = utf8_to_utf32(&"ć"[0], 2)
assert(result.out_str == 0x107, "Invalid decode")
result = utf8_to_utf32(&"ó"[0], 2)
assert(result.out_str == 0xF3, "Invalid decode")
Vec2I :: struct;; x: S64; y: S64 Vec2I :: struct;; x: S64; y: S64
Vec2 :: struct;; x: F32; y: F32 Vec2 :: struct;; x: F32; y: F32
Windows_Bitmap :: struct Windows_Bitmap :: struct
@@ -128,7 +142,6 @@ create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap
hdc := GetDC(0) hdc := GetDC(0)
result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0) result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0)
error := GetLastError()
result.hdc = CreateCompatibleDC(hdc) result.hdc = CreateCompatibleDC(hdc)
return result return result
@@ -140,21 +153,11 @@ window_procedure :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRE
return 0 return 0
else;; return DefWindowProcW(hwnd, msg, wparam, lparam) else;; return DefWindowProcW(hwnd, msg, wparam, lparam)
test_unicode :: () multiple_return_values :: (i: int): int, int
string := " 豈 更 車 賈 滑 串 句 龜 龜 契 金 喇 奈 懶 癩 羅 蘿 螺 裸 邏 樂 洛 烙 珞 落 酪 駱 亂 卵 欄 爛 蘭 鸞 嵐 濫 藍 襤 拉 臘 蠟 廊 朗 浪 狼 郎 來 冷 勞 擄 櫓 爐 盧 老 蘆 虜 路 露 魯 鷺 碌 祿 綠 菉 錄 鹿 論 壟 弄 籠 聾 牢 磊 賂 雷 壘 屢 樓 淚 漏 累 縷 陋 勒 肋 凜 凌 稜 綾 菱 陵 讀 拏 樂 諾 丹 寧 怒 率 異 北 磻 便 復 不 泌 數 索 參 塞 省 葉 說 殺 辰 沈 拾 若 掠 略 亮 兩 凉 梁 糧 良 諒 量 勵 ..." return i, i*2
string_result := string_to_string16(string)
print(string_result)
result := utf8_to_utf32(&"A"[0], 1)
assert(result.out_str == 'A, "Invalid decode") // '
result = utf8_to_utf32(&"ć"[0], 2)
assert(result.out_str == 0x107, "Invalid decode")
result = utf8_to_utf32(&"ó"[0], 2)
assert(result.out_str == 0xF3, "Invalid decode")
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
a, b := multiple_return_values(10)
window_name := string_to_string16("Have a wonderful day! 豈 更 車 賈 滑 串 句 龜 ") window_name := string_to_string16("Have a wonderful day! 豈 更 車 賈 滑 串 句 龜 ")
w := WNDCLASSW{ w := WNDCLASSW{
lpfnWndProc = window_procedure, lpfnWndProc = window_procedure,

View File

@@ -17,7 +17,7 @@ test_types(){
Ast_Type *pointer_type4 = type_pointer(pointer_type2); Ast_Type *pointer_type4 = type_pointer(pointer_type2);
assert(pointer_type3 != pointer_type1); assert(pointer_type3 != pointer_type1);
assert(pointer_type3 == pointer_type4); assert(pointer_type3 == pointer_type4);
#if 0
Array<Ast_Type*> types = {scratch}; Array<Ast_Type*> types = {scratch};
types.add(type_array(type_s64, 32)); types.add(type_array(type_s64, 32));
Ast_Type *func_type1 = type_lambda(0, types[0], types); Ast_Type *func_type1 = type_lambda(0, types[0], types);
@@ -34,4 +34,5 @@ test_types(){
Ast_Type *func_type4 = type_lambda(0, types[0], types2); Ast_Type *func_type4 = type_lambda(0, types[0], types2);
assert(func_type1 != func_type3); assert(func_type1 != func_type3);
assert(func_type3 == func_type4); assert(func_type3 == func_type4);
#endif
} }

View File

@@ -422,10 +422,20 @@ resolve_stmt(Ast *ast, Ast_Type *ret){
switch(ast->kind){ switch(ast->kind){
CASE(RETURN, Return){ // @todo: need to check if all paths return a value CASE(RETURN, Return){ // @todo: need to check if all paths return a value
Operand op = resolve_expr(node->expr, AST_CAN_BE_NULL); Scratch scratch;
if(!op.type && ret != type_void) compiler_error(node->pos, "Function expects a void return value but the returned value is %s", docname(op.type)); Array<Ast_Type *> types = {scratch};
op.value = convert_untyped_to_typed(node->pos, op.value, ret); For(node->expr){
if(op.type && op.type != ret) compiler_error(node->pos, "Return statement has different type then returned value, expecting: %s got instead %s", docname(ret), docname(op.type)); Operand op = resolve_expr(it, AST_CAN_BE_NULL);
types.add(op.type);
}
Ast_Type *type = type_try_tupling(types, node);
if(!type && ret != type_void)
compiler_error(node->pos, "Function expects a void return value but the returned value is %s", docname(type));
Value value = {}; value.type = type;
value = convert_untyped_to_typed(node->pos, value, ret);
if(value.type && value.type != ret)
compiler_error(node->pos, "Return statement has different type then returned value, expecting: %s got instead %s", docname(ret), docname(type));
BREAK(); BREAK();
} }
@@ -484,6 +494,24 @@ resolve_stmt(Ast *ast, Ast_Type *ret){
BREAK(); BREAK();
} }
CASE(VAR_UNPACK, Var_Unpack){
Operand expr_op = resolve_expr(node->expr, AST_CANT_BE_NULL);
if(!is_tuple(expr_op.type))
compiler_error(node->pos, "Expected expression to be of type [Tuple]");
if(expr_op.type->agg.members.len != node->vars.len)
compiler_error(node->pos, "Different count of return values and assigning values");
node->resolved_type = expr_op.type;
For(node->vars){
S64 index = node->vars.get_index(&it);
Ast_Resolved_Member *type = expr_op.type->agg.members.data + index;
it->type = type->type;
resolve_decl(it);
insert_into_scope(node->parent_scope, it);
}
BREAK();
}
default:{ default:{
if(is_flag_set(ast->flags, AST_EXPR)){ if(is_flag_set(ast->flags, AST_EXPR)){
assert(is_flag_set(ast->flags, AST_STMT)); assert(is_flag_set(ast->flags, AST_STMT));
@@ -497,8 +525,12 @@ resolve_stmt(Ast *ast, Ast_Type *ret){
function Ast_Type * function Ast_Type *
resolve_lambda_type(Ast_Lambda *lambda){ resolve_lambda_type(Ast_Lambda *lambda){
Scratch scratch; Scratch scratch;
Ast_Type *ret_type = resolve_typespec(lambda->ret, AST_CANT_BE_NULL);
Array<Ast_Type *> args = {scratch}; Array<Ast_Type *> args = {scratch};
Array<Ast_Type *> ret = {scratch};
For(lambda->ret) {
Ast_Type *type = resolve_typespec(it, AST_CANT_BE_NULL);
ret.add(type);
}
For(lambda->args){ For(lambda->args){
Ast_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL); Ast_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL);
@@ -508,7 +540,7 @@ resolve_lambda_type(Ast_Lambda *lambda){
args.add(type); args.add(type);
} }
return type_lambda(lambda, ret_type, args); return type_lambda(lambda, ret, args);
} }
function void function void
@@ -1070,7 +1102,8 @@ resolve_decl(Ast_Decl *ast){
} }
CASE(VAR, Decl){ CASE(VAR, Decl){
Ast_Type *type = resolve_typespec(node->typespec, AST_CAN_BE_NULL | RESOLVE_TYPESPEC_COMPLETE); Ast_Type *type = node->type;
if(!type) type = resolve_typespec(node->typespec, AST_CAN_BE_NULL | RESOLVE_TYPESPEC_COMPLETE);
Operand op = resolve_expr(node->expr, AST_CAN_BE_NULL, type); Operand op = resolve_expr(node->expr, AST_CAN_BE_NULL, type);
assert(op.type != 0 || type != 0); assert(op.type != 0 || type != 0);

View File

@@ -153,21 +153,32 @@ type_slice(Ast_Type *base, Ast *ast){
} }
function Ast_Type * function Ast_Type *
type_tuple(Array<Ast_Resolved_Member> types, Ast *ast){ type_try_tupling(Array<Ast_Type *> types, Ast *ast){
U64 hash = 1234; assert(types.len != 0);
For(types) hash = hash_mix(hash, hash_ptr(it.type)); if(types.len == 1) return types[0];
U64 hash = 13;
For(types) hash = hash_mix(hash, hash_ptr(it));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){ if(result){
assert(result->kind == TYPE_TUPLE); assert(result->kind == TYPE_TUPLE);
assert(result->agg.members.len == types.len); assert(result->agg.members.len == types.len);
assert(result->agg.members.len > 1);
return result; return result;
} }
// @todo alignment, offsets
// @todo alignment, offsets
result = type_new(pctx->perm, TYPE_TUPLE, 0, pointer_align); result = type_new(pctx->perm, TYPE_TUPLE, 0, pointer_align);
For(types) result->size += it.type->size; result->agg.members = array_make<Ast_Resolved_Member>(pctx->perm, types.len);
result->agg.members = types.tight_copy(pctx->perm); For(types){
Ast_Resolved_Member m = {};
m.type = it;
m.offset = 0; // @todo
result->size += it->size;
result->agg.members.add(m);
}
map_insert(&pctx->type_map, hash, result); map_insert(&pctx->type_map, hash, result);
assert(result->agg.members.len > 1);
return result; return result;
} }
@@ -192,14 +203,14 @@ type_array(Ast_Type *base, S64 size){
} }
function Ast_Type * function Ast_Type *
type_lambda(Ast *ast, Ast_Type *ret, Array<Ast_Type *> args){ type_lambda(Ast *ast, Array<Ast_Type *> return_vals, Array<Ast_Type *> args){
Ast_Type *ret = type_try_tupling(return_vals, ast);
U64 hash = hash_ptr(ret); U64 hash = hash_ptr(ret);
For(args) hash = hash_mix(hash, hash_ptr(it)); For(args) hash = hash_mix(hash, hash_ptr(it));
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
if(result){ if(result){
assert(result->kind == TYPE_LAMBDA); assert(result->kind == TYPE_LAMBDA);
assert(result->func.ret == ret);
assert(result->func.args.len == args.len); assert(result->func.args.len == args.len);
return result; return result;
} }