From: Brendan Hansen Date: Tue, 6 Jul 2021 22:10:58 +0000 (-0500) Subject: added if-expressions X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=324aecf0e1734f75cbab35abd1aebbbe6f0ecf79;p=onyx.git added if-expressions --- diff --git a/bin/onyx b/bin/onyx index 4248b85a..c27bdd35 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/math.onyx b/core/math.onyx index 11e6610e..7030b086 100644 --- a/core/math.onyx +++ b/core/math.onyx @@ -232,14 +232,12 @@ log :: (a: $T, base: $R) -> T { // as values. max :: #match { wasm.max_f32, wasm.max_f64, max_poly } max_poly :: (a: $T, b: T) -> T { - if a >= b do return a; - else do return b; + return a if a >= b else b; } min :: #match { wasm.min_f32, wasm.min_f64, min_poly } min_poly :: (a: $T, b: T) -> T { - if a <= b do return a; - else do return b; + return a if a <= b else b; } clamp :: (v: $T, lo: T, hi: T) -> T { @@ -255,8 +253,7 @@ sqrt_poly :: (x: $T) -> T { abs :: #match { wasm.abs_f32, wasm.abs_f64, abs_poly } abs_poly :: (x: $T) -> T { - if x >= 0 do return x; - else do return -x; + return x if x >= 0 else -x; } sign :: (x: $T) -> T { diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 0b0d0067..2dd0327c 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -28,6 +28,7 @@ NODE(ArrayLiteral) \ NODE(RangeLiteral) \ NODE(Compound) \ + NODE(IfExpression) \ \ NODE(DirectiveSolidify) \ NODE(DirectiveError) \ @@ -165,6 +166,7 @@ typedef enum AstKind { Ast_Kind_File_Contents, Ast_Kind_Struct_Literal, Ast_Kind_Array_Literal, + Ast_Kind_If_Expression, Ast_Kind_If, Ast_Kind_For, @@ -594,6 +596,13 @@ struct AstCompound { bh_arr(AstTyped *) exprs; }; +struct AstIfExpression { + AstTyped_base; + + AstTyped* cond; + AstTyped* true_expr; + AstTyped* false_expr; +}; struct AstDirectiveSolidify { AstTyped_base; diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c index 0571e989..09168c19 100644 --- a/src/onyxastnodes.c +++ b/src/onyxastnodes.c @@ -67,6 +67,7 @@ static const char* ast_node_names[] = { "FILE CONTENTS", "STRUCT LITERAL", "ARRAY LITERAL", + "IF EXPRESSION", "IF", "FOR", @@ -515,6 +516,20 @@ b32 type_check_or_auto_cast(AstTyped** pnode, Type* type) { return 1; } + else if (node->kind == Ast_Kind_If_Expression) { + AstIfExpression* if_expr = (AstIfExpression *) node; + + b32 true_success = type_check_or_auto_cast(&if_expr->true_expr, type); + b32 false_success = type_check_or_auto_cast(&if_expr->false_expr, type); + + if (true_success && false_success) { + if_expr->type = type; + return 1; + + } else { + return 0; + } + } return 0; } @@ -532,6 +547,15 @@ Type* resolve_expression_type(AstTyped* node) { node->type = resolve_expression_type(((AstArgument *) node)->value); } + if (node->kind == Ast_Kind_If_Expression) { + AstIfExpression* if_expr = (AstIfExpression *) node; + + Type* ltype = resolve_expression_type(if_expr->true_expr); + type_check_or_auto_cast(&if_expr->false_expr, ltype); + + if_expr->type = ltype; + } + if (node_is_type((AstNode *) node)) { return &basic_types[Basic_Kind_Type_Index]; } diff --git a/src/onyxchecker.c b/src/onyxchecker.c index b7c13d2f..4c2fbe45 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -35,6 +35,7 @@ CheckStatus check_struct_literal(AstStructLiteral* sl); CheckStatus check_array_literal(AstArrayLiteral* al); CheckStatus check_range_literal(AstRangeLiteral** range); CheckStatus check_compound(AstCompound* compound); +CheckStatus check_if_expression(AstIfExpression* if_expr); CheckStatus check_expression(AstTyped** expr); CheckStatus check_address_of(AstAddressOf* aof); CheckStatus check_dereference(AstDereference* deref); @@ -1276,6 +1277,28 @@ CheckStatus check_compound(AstCompound* compound) { return Check_Success; } +CheckStatus check_if_expression(AstIfExpression* if_expr) { + CHECK(expression, &if_expr->cond); + CHECK(expression, &if_expr->true_expr); + CHECK(expression, &if_expr->false_expr); + + if (!type_check_or_auto_cast(&if_expr->cond, &basic_types[Basic_Kind_Bool])) { + onyx_report_error(if_expr->token->pos, "If-expression expected boolean for condition, got '%s'.", + type_get_name(if_expr->cond->type)); + return Check_Error; + } + + resolve_expression_type((AstTyped *) if_expr); + + if (!types_are_compatible(if_expr->true_expr->type, if_expr->false_expr->type)) { + onyx_report_error(if_expr->token->pos, "Mismatched types for if-expression, left side is '%s', and right side is '%s'.", + type_get_name(if_expr->true_expr->type), type_get_name(if_expr->false_expr->type)); + return Check_Error; + } + + return Check_Success; +} + CheckStatus check_address_of(AstAddressOf* aof) { CHECK(expression, &aof->expr); if (aof->expr->type == NULL) { @@ -1625,6 +1648,10 @@ CheckStatus check_expression(AstTyped** pexpr) { expr->type_node = builtin_callsite_type; break; + case Ast_Kind_If_Expression: + CHECK(if_expression, (AstIfExpression *) expr); + break; + case Ast_Kind_StrLit: break; case Ast_Kind_File_Contents: break; case Ast_Kind_Overloaded_Function: break; diff --git a/src/onyxclone.c b/src/onyxclone.c index 6fbda843..2d4145d4 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -92,6 +92,7 @@ static inline i32 ast_kind_to_size(AstNode* node) { case Ast_Kind_Named_Value: return sizeof(AstNamedValue); case Ast_Kind_Call_Site: return sizeof(AstCallSite); case Ast_Kind_Static_If: return sizeof(AstIfWhile); + case Ast_Kind_If_Expression: return sizeof(AstIfExpression); case Ast_Kind_Count: return 0; } @@ -425,6 +426,13 @@ AstNode* ast_clone(bh_allocator a, void* n) { ((AstNamedValue *) nn)->value = (AstTyped *) ast_clone(a, ((AstNamedValue *) node)->value); break; } + + case Ast_Kind_If_Expression: { + ((AstIfExpression *) nn)->cond = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->cond); + ((AstIfExpression *) nn)->true_expr = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->true_expr); + ((AstIfExpression *) nn)->false_expr = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->false_expr); + break; + } } return nn; diff --git a/src/onyxparser.c b/src/onyxparser.c index e80c64b4..4dfee9d5 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -682,6 +682,21 @@ static AstTyped* parse_factor(OnyxParser* parser) { break; } + case Token_Type_Keyword_If: { + AstIfExpression* if_expression = make_node(AstIfExpression, Ast_Kind_If_Expression); + if_expression->token = expect_token(parser, Token_Type_Keyword_If); + + if_expression->true_expr = retval; + if_expression->cond = parse_expression(parser, 0); + expect_token(parser, Token_Type_Keyword_Else); + if_expression->false_expr = parse_expression(parser, 0); + + retval = (AstTyped *) if_expression; + + // nocheckin This should maybe be goto factor_parsed; ?? + break; + } + default: goto factor_parsed; } } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 0c416376..410444d5 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -297,6 +297,13 @@ static SymresStatus symres_compound(AstCompound* compound) { return Symres_Success; } +static SymresStatus symres_if_expression(AstIfExpression* if_expr) { + SYMRES(expression, &if_expr->cond); + SYMRES(expression, &if_expr->true_expr); + SYMRES(expression, &if_expr->false_expr); + return Symres_Success; +} + static SymresStatus symres_pipe(AstBinaryOp** pipe) { AstCall* call_node = (AstCall *) (*pipe)->right; SYMRES(expression, (AstTyped **) &call_node); @@ -462,6 +469,10 @@ static SymresStatus symres_expression(AstTyped** expr) { SYMRES(package, (AstPackage *) *expr); break; + case Ast_Kind_If_Expression: + SYMRES(if_expression, (AstIfExpression *) *expr); + break; + default: break; } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index c0777af9..7393bd32 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -254,6 +254,7 @@ EMIT_FUNC(compound_store, Type* type, u64 offset, b32 location_fi EMIT_FUNC(array_store, Type* type, u32 offset); EMIT_FUNC(array_literal, AstArrayLiteral* al); EMIT_FUNC(range_literal, AstRangeLiteral* range); +EMIT_FUNC(if_expression, AstIfExpression* if_expr); EMIT_FUNC(expression, AstTyped* expr); EMIT_FUNC(cast, AstUnaryOp* cast); EMIT_FUNC(return, AstReturn* ret); @@ -2238,6 +2239,45 @@ EMIT_FUNC(range_literal, AstRangeLiteral* range) { *pcode = code; } +EMIT_FUNC(if_expression, AstIfExpression* if_expr) { + bh_arr(WasmInstruction) code = *pcode; + + u64 offset = 0; + u64 result_local = local_allocate(mod->local_alloc, (AstTyped *) if_expr); + b32 result_is_local = (b32) ((result_local & LOCAL_IS_WASM) != 0); + bh_imap_put(&mod->local_map, (u64) if_expr, result_local); + + emit_expression(mod, &code, if_expr->cond); + + emit_enter_structured_block(mod, &code, SBT_Basic_If); + if (!result_is_local) emit_local_location(mod, &code, (AstLocal *) if_expr, &offset); + + emit_expression(mod, &code, if_expr->true_expr); + + if (!result_is_local) emit_store_instruction(mod, &code, if_expr->type, offset); + else WIL(WI_LOCAL_SET, result_local); + + WI(WI_ELSE); + if (!result_is_local) emit_local_location(mod, &code, (AstLocal *) if_expr, &offset); + + emit_expression(mod, &code, if_expr->false_expr); + + if (!result_is_local) emit_store_instruction(mod, &code, if_expr->type, offset); + else WIL(WI_LOCAL_SET, result_local); + + emit_leave_structured_block(mod, &code); + + if (!result_is_local) { + emit_local_location(mod, &code, (AstLocal *) if_expr, &offset); + emit_load_instruction(mod, &code, if_expr->type, offset); + + } else { + WIL(WI_LOCAL_GET, result_local); + } + + *pcode = code; +} + EMIT_FUNC(location_return_offset, AstTyped* expr, u64* offset_return) { bh_arr(WasmInstruction) code = *pcode; @@ -2590,6 +2630,12 @@ EMIT_FUNC(expression, AstTyped* expr) { break; } + case Ast_Kind_If_Expression: { + AstIfExpression* if_expr = (AstIfExpression *) expr; + emit_if_expression(mod, &code, if_expr); + break; + } + default: bh_printf("Unhandled case: %d\n", expr->kind); DEBUG_HERE; diff --git a/tests/if_expressions b/tests/if_expressions new file mode 100644 index 00000000..462d7752 --- /dev/null +++ b/tests/if_expressions @@ -0,0 +1,3 @@ +5678.0000 +True +20 diff --git a/tests/if_expressions.onyx b/tests/if_expressions.onyx new file mode 100644 index 00000000..3388df86 --- /dev/null +++ b/tests/if_expressions.onyx @@ -0,0 +1,25 @@ +#load "core/std" + +use package core + +some_function :: () -> f32 { + println("In some function!"); + return 1234; +} + +new_max :: (a: $T, b: T) -> T { + // Much much better! + return a if a > b else b; +} + +main :: (args: [] cstr) { + + condition := 12 > 34; + + x := some_function() if condition else 5678.0f; + println(x); + + println("True" if x > 5000 else "False" if false else "REALLY FALSE"); + + println(new_max(10, 20)); +} \ No newline at end of file