diff --git a/ast.cpp b/ast.cpp index 8882256..89d65f5 100644 --- a/ast.cpp +++ b/ast.cpp @@ -139,7 +139,7 @@ struct Ast_Builtin: Ast_Expr{ // struct Ast_Return: Ast{ - Ast_Expr *expr; + Array expr; }; struct Ast_If_Node: Ast{ @@ -164,7 +164,7 @@ struct Ast_For: Ast{ struct Ast_Lambda : Ast_Expr { Array args; - Ast_Expr *ret; + Array ret; Ast_Scope *scope; }; @@ -331,14 +331,12 @@ ast_expr_index(Token *pos, Ast_Expr *expr, Ast_Expr *index){ } function Ast_Lambda * -ast_lambda(Token *pos, Array params, Ast_Expr *ret, Ast_Scope *scope){ +ast_lambda(Token *pos, Array params, Array ret, Ast_Scope *scope){ AST_NEW(Lambda, LAMBDA_EXPR, pos, AST_EXPR); result->flags = AST_EXPR; result->args = params.tight_copy(pctx->perm); + result->ret = ret.tight_copy(pctx->perm); result->scope = scope; - result->ret = ret; - if(!ret) result->ret = ast_ident(result->pos, intern_void); - return result; } @@ -372,11 +370,11 @@ ast_break(Token *pos){ } function Ast_Return * -ast_return(Token *pos, Ast_Expr *expr){ +ast_return(Token *pos, Array expr){ AST_NEW(Return, RETURN, pos, AST_STMT); - if(expr){ - assert(is_flag_set(expr->flags, AST_EXPR)); - result->expr = expr; + if(expr.len){ + For(expr) assert(is_flag_set(it->flags, AST_EXPR)); + result->expr = expr.tight_copy(pctx->perm); } return result; } diff --git a/ccodegen.cpp b/ccodegen.cpp index a8f7433..7345cac 100644 --- a/ccodegen.cpp +++ b/ccodegen.cpp @@ -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)){ 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("("); For(lambda->args){ gen_var(it, DONT_EMIT_VALUE, true); @@ -379,9 +382,9 @@ gen_ast(Ast *ast){ CASE(RETURN, Return){ gen("return"); - if(node->expr){ + For(node->expr){ gen(" "); - gen_expr(node->expr); + gen_expr(it); // @todo multiple_returns } gen(";"); BREAK(); @@ -524,6 +527,15 @@ gen_ast(Ast *ast){ BREAK(); } + CASE(VAR_UNPACK, Var_Unpack){ + For(node->vars) { + gen_ast(it); + } + gen(" = "); + gen_expr(node->expr); + BREAK(); + } + case AST_CONSTANT_ASSERT: case AST_MODULE_NAMESPACE: CASE(FILE_NAMESPACE, File_Namespace){unused(node); BREAK();} @@ -707,6 +719,7 @@ typedef struct String{ #define assert_msg(x,...) assert(x) )=="); + //*(volatile int *)0 = 0; #endif For(pctx->ordered_decls){ if(it->kind == AST_STRUCT){ diff --git a/parsing.cpp b/parsing.cpp index 866ff53..a221fd8 100644 --- a/parsing.cpp +++ b/parsing.cpp @@ -214,9 +214,15 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){ if(!scope_defined_outside) scope = begin_stmt_scope(scratch, token_block); do{ Token *token = token_get(); + if(token_match_keyword(keyword_return)){ - Ast_Expr *expr = 0; - if(!token_is_scope()) expr = parse_expr(); + Array expr = {scratch}; + 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)); } @@ -323,7 +329,7 @@ parse_stmt_scope(Ast_Scope *scope_defined_outside = 0){ decls.add(decl); }while(token_match(TK_Comma)); - token_expect(TK_Assign); + token_expect(TK_ColonAssign); Ast_Expr *expr = parse_expr(); Ast_Var_Unpack *vars = ast_var_unpack(token, decls, expr); scope->stmts.add(vars); @@ -384,7 +390,16 @@ parse_lambda(Token *token){ } } token_expect(TK_CloseParen); - Ast_Expr *ret = parse_optional_type(); + + Array 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_Lambda *result = ast_lambda(token, params, ret, scope); return result; diff --git a/programs/main.kl b/programs/main.kl index 00fb507..7059fda 100644 --- a/programs/main.kl +++ b/programs/main.kl @@ -100,6 +100,20 @@ string_to_string16 :: (in: String): String16 result.str[result.len] = 0 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 Vec2 :: struct;; x: F32; y: F32 Windows_Bitmap :: struct @@ -128,7 +142,6 @@ create_bitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap hdc := GetDC(0) result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0) - error := GetLastError() result.hdc = CreateCompatibleDC(hdc) return result @@ -140,21 +153,11 @@ window_procedure :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRE return 0 else;; return DefWindowProcW(hwnd, msg, wparam, lparam) -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") +multiple_return_values :: (i: int): int, int + return i, i*2 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! 豈 更 車 賈 滑 串 句 龜 ") w := WNDCLASSW{ lpfnWndProc = window_procedure, diff --git a/tests.cpp b/tests.cpp index 8a4dc7e..9b86ce4 100644 --- a/tests.cpp +++ b/tests.cpp @@ -17,7 +17,7 @@ test_types(){ Ast_Type *pointer_type4 = type_pointer(pointer_type2); assert(pointer_type3 != pointer_type1); assert(pointer_type3 == pointer_type4); - +#if 0 Array types = {scratch}; types.add(type_array(type_s64, 32)); 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); assert(func_type1 != func_type3); assert(func_type3 == func_type4); +#endif } \ No newline at end of file diff --git a/typechecking.cpp b/typechecking.cpp index b99760c..c8a9b03 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -422,10 +422,20 @@ resolve_stmt(Ast *ast, Ast_Type *ret){ switch(ast->kind){ CASE(RETURN, Return){ // @todo: need to check if all paths return a value - Operand op = resolve_expr(node->expr, AST_CAN_BE_NULL); - 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)); - op.value = convert_untyped_to_typed(node->pos, op.value, ret); - 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)); + Scratch scratch; + Array types = {scratch}; + For(node->expr){ + 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(); } @@ -484,6 +494,24 @@ resolve_stmt(Ast *ast, Ast_Type *ret){ 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:{ if(is_flag_set(ast->flags, AST_EXPR)){ assert(is_flag_set(ast->flags, AST_STMT)); @@ -497,8 +525,12 @@ resolve_stmt(Ast *ast, Ast_Type *ret){ function Ast_Type * resolve_lambda_type(Ast_Lambda *lambda){ Scratch scratch; - Ast_Type *ret_type = resolve_typespec(lambda->ret, AST_CANT_BE_NULL); Array args = {scratch}; + Array ret = {scratch}; + For(lambda->ret) { + Ast_Type *type = resolve_typespec(it, AST_CANT_BE_NULL); + ret.add(type); + } For(lambda->args){ Ast_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL); @@ -508,7 +540,7 @@ resolve_lambda_type(Ast_Lambda *lambda){ args.add(type); } - return type_lambda(lambda, ret_type, args); + return type_lambda(lambda, ret, args); } function void @@ -1070,7 +1102,8 @@ resolve_decl(Ast_Decl *ast){ } 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); assert(op.type != 0 || type != 0); diff --git a/typechecking.h b/typechecking.h index 4b3c57a..5a38dbe 100644 --- a/typechecking.h +++ b/typechecking.h @@ -153,21 +153,32 @@ type_slice(Ast_Type *base, Ast *ast){ } function Ast_Type * -type_tuple(Array types, Ast *ast){ - U64 hash = 1234; - For(types) hash = hash_mix(hash, hash_ptr(it.type)); +type_try_tupling(Array types, Ast *ast){ + assert(types.len != 0); + 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); if(result){ assert(result->kind == TYPE_TUPLE); assert(result->agg.members.len == types.len); + assert(result->agg.members.len > 1); return result; } - // @todo alignment, offsets + // @todo alignment, offsets result = type_new(pctx->perm, TYPE_TUPLE, 0, pointer_align); - For(types) result->size += it.type->size; - result->agg.members = types.tight_copy(pctx->perm); + result->agg.members = array_make(pctx->perm, types.len); + 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); + assert(result->agg.members.len > 1); return result; } @@ -192,14 +203,14 @@ type_array(Ast_Type *base, S64 size){ } function Ast_Type * -type_lambda(Ast *ast, Ast_Type *ret, Array args){ +type_lambda(Ast *ast, Array return_vals, Array args){ + Ast_Type *ret = type_try_tupling(return_vals, ast); U64 hash = hash_ptr(ret); For(args) hash = hash_mix(hash, hash_ptr(it)); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); if(result){ assert(result->kind == TYPE_LAMBDA); - assert(result->func.ret == ret); assert(result->func.args.len == args.len); return result; } diff --git a/types.h b/types.h index 2bc50d6..1138976 100644 --- a/types.h +++ b/types.h @@ -96,7 +96,7 @@ struct Ast_Type{ Array members; }agg; struct{ - Ast_Type *ret; + Ast_Type * ret; Array args; }func; };