// 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 {
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 {
NODE(ArrayLiteral) \
NODE(RangeLiteral) \
NODE(Compound) \
+ NODE(IfExpression) \
\
NODE(DirectiveSolidify) \
NODE(DirectiveError) \
Ast_Kind_File_Contents,
Ast_Kind_Struct_Literal,
Ast_Kind_Array_Literal,
+ Ast_Kind_If_Expression,
Ast_Kind_If,
Ast_Kind_For,
bh_arr(AstTyped *) exprs;
};
+struct AstIfExpression {
+ AstTyped_base;
+
+ AstTyped* cond;
+ AstTyped* true_expr;
+ AstTyped* false_expr;
+};
struct AstDirectiveSolidify {
AstTyped_base;
"FILE CONTENTS",
"STRUCT LITERAL",
"ARRAY LITERAL",
+ "IF EXPRESSION",
"IF",
"FOR",
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;
}
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];
}
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);
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) {
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;
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;
}
((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;
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;
}
}
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);
SYMRES(package, (AstPackage *) *expr);
break;
+ case Ast_Kind_If_Expression:
+ SYMRES(if_expression, (AstIfExpression *) *expr);
+ break;
+
default: break;
}
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);
*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;
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;
--- /dev/null
+5678.0000
+True
+20
--- /dev/null
+#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