From 6f3c6db8d0e5c5bf244f9a101e72e5e498b5fb6d Mon Sep 17 00:00:00 2001
From: NeilBrown <neil@brown.name>
Date: Thu, 9 May 2019 21:13:16 +1000
Subject: [PATCH] oceani: add conditional expression

[value] if [condition] else [alternate value]

is a conditional expression which will only evaluate and return one of
the two values, depending on the condition.
This has lowest precedence of all expressions.

Signed-off-by: NeilBrown <neil@brown.name>
---
 csrc/oceani-tests.mdc |  2 +
 csrc/oceani.mdc       | 90 ++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/csrc/oceani-tests.mdc b/csrc/oceani-tests.mdc
index b2c2e1b..d5e60b7 100644
--- a/csrc/oceani-tests.mdc
+++ b/csrc/oceani-tests.mdc
@@ -165,6 +165,7 @@ Now we need to test if/else and some different loops
 		pi ::= 3.1415926535897
 		if 355/113 == pi or else +(pi - 355/113) < 0.001:
 			print "Close enough"
+		print "lower" if 355/113 < pi else "higher"
 
 ###### output: cond_loop
 	Success
@@ -179,6 +180,7 @@ Now we need to test if/else and some different loops
 	20 / 6  = 3.33333
 	I won't calculate 20 / 9
 	Close enough
+	higher
 
 ## Say Hello
 
diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc
index 123fffc..07caefa 100644
--- a/csrc/oceani.mdc
+++ b/csrc/oceani.mdc
@@ -1861,16 +1861,86 @@ link to find the primary instance.
 ###### free exec cases
 	case Xvar: free_var(cast(var, e)); break;
 
+### Expressions: Conditional
+
+Our first user of the `binode` will be conditional expressions, which
+is a bit odd as they actually have three components.  That will be
+handled by having 2 binodes for each expression.  The conditional
+expression is the lowest precedence operatior, so it gets to define
+what an "Expression" is.  The next level up is "BoolExpr", which
+comes next.
+
+Conditional expressions are of the form "value `if` condition `else`
+other_value".  There is no associativite with this operator: the
+values and conditions can only be other conditional expressions if
+they are enclosed in parentheses.  Allowing nesting without
+parentheses would be too confusing.
+
+###### Binode types
+	CondExpr,
+
+###### Grammar
+
+	$*exec
+	Expression -> BoolExpr if BoolExpr else BoolExpr ${ {
+			struct binode *b1 = new(binode);
+			struct binode *b2 = new(binode);
+			b1->op = CondExpr;
+			b1->left = $<3;
+			b1->right = b2;
+			b2->op = CondExpr;
+			b2->left = $<1;
+			b2->right = $<5;
+			$0 = b1;
+		} }$
+		| BoolExpr ${ $0 = $<1; }$
+
+###### print binode cases
+
+	case CondExpr:
+		b2 = cast(binode, b->right);
+		print_exec(b2->left, -1, 0);
+		printf(" if ");
+		print_exec(b->left, -1, 0);
+		printf(" else ");
+		print_exec(b2->right, -1, 0);
+		break;
+
+###### propagate binode cases
+
+	case CondExpr: {
+		/* cond must be Tbool, others must match */
+		struct binode *b2 = cast(binode, b->right);
+		struct type *t2;
+
+		propagate_types(b->left, c, ok, Tbool, 0);
+		t = propagate_types(b2->left, c, ok, type, Rnolabel);
+		t2 = propagate_types(b2->right, c, ok, type ?: t, Rnolabel);
+		return t ?: t2;
+	}
+
+###### interp binode cases
+
+	case CondExpr: {
+		struct binode *b2 = cast(binode, b->right);
+		left = interp_exec(b->left);
+		if (left.bool)
+			rv = interp_exec(b2->left);
+		else
+			rv = interp_exec(b2->right);
+		}
+		break;
+
 ### Expressions: Boolean
 
-Our first user of the `binode` will be expressions, and particularly
-Boolean expressions.  As I haven't implemented precedence in the
-parser generator yet, we need different names for each precedence
-level used by expressions.  The outer most or lowest level precedence
-are Boolean operators which form an `Expression` out of `BTerm`s and
-`BFact`s.  As well as `or` `and`, and `not` we have `and then` and `or
-else` which only evaluate the second operand if the result would make
-a difference.
+The next class of expressions to use the `binode` will be Boolean
+expressions.  As I haven't implemented precedence in the parser
+generator yet, we need different names for each precedence level used
+by expressions.  The outer most or lowest level precedence are
+conditional expressions are Boolean operators which form an `BoolExpr`
+out of `BTerm`s and `BFact`s.  As well as `or` `and`, and `not` we
+have `and then` and `or else` which only evaluate the second operand
+if the result would make a difference.
 
 ###### Binode types
 	And,
@@ -1882,14 +1952,14 @@ a difference.
 ###### Grammar
 
 	$*exec
-	Expression -> Expression or BTerm ${ {
+	BoolExpr -> BoolExpr or BTerm ${ {
 			struct binode *b = new(binode);
 			b->op = Or;
 			b->left = $<1;
 			b->right = $<3;
 			$0 = b;
 		} }$
-		| Expression or else BTerm ${ {
+		| BoolExpr or else BTerm ${ {
 			struct binode *b = new(binode);
 			b->op = OrElse;
 			b->left = $<1;
-- 
2.43.0