Add _true, _false, ==, and _if..._then..._else to your MSD script implementation.
Some details on the forms:
Val subclass.+ or * gets a boolean value, then it should complain at run time. Note that they complain about values, not expressions. The left and right subexpressions in a + expression can be anything, and it's only when you interp them that you know whether the results are integers.== operation can work on any kinds of values, and it's even allowed to compare a boolean to a number — but only booleans are equal to booleans and only numbers are equal to numbers. That is, unlike * and +, == never complains about its arguments, and it always produces a boolean value.if..._then..._else form requires its first subexpression to produce a boolean value. (Again, it can only complain after interp produces a non-boolean value, no matter what the expression is). Also, only the “then” or “else” branch should be interpreted, not both.print method should always put parentheses around a == or _if..._then..._else form, and never around _true or _false. Make print include no space around ==, while pretty_print includes a space on both sides of ==. Both printing modes include a single space after _if, _then, and _else. For parentheses, the pretty_print method on expressions should be consistent with the usual goals: minimal parentheses as needed to make the expression unambigious, parentheses added to the smallest expressions when necessary, and all consistent with the parser. For line breaks, pretty_print should start _then and _else on new lines and aligned under the _if, while print simply emits a space before _then and _else.As an example, the MSDscript program
_let same = 1 == 2
_in _if 1 == 2
_then _false + 5
_else 88
should interp to the value 88, and it should not complain about false being added to 5.
The example
_if 4 + 1
_then 2
_else 3
does not have a value; interpreting it should raise an exception, because 5 is not a boolean.
This is a big change to your MSDscript code base, involving a lot of method and function definitions and well as tests. Fortunately, with the possible exception of pretty printing (see further below), the changes should be straightforward; they follow recipes and patterns that we've used already.
You should break down this big change into manageable steps, and here are some suggested steps:
Val class to represent boolean values. You can implement and test the new class without changing anything else about your MSDcript implementation, except that you can't complete a to_expr method to convert a value back to an expression (because you haven't added boolean expressions, yet). For to_expr, just return NULL and save it for testing later — but make sure you have good test coverage for the new code otherwise.Expr classes for booleans, equality expressions, and conditionals. Add one class at a time, and get back to good test coverage before writing more. Save pretty printing for last, perhaps just using print as the operation temporarily.Here are some observations and advice on pretty-print with the expanded language:
== form has lower precedence than +, which has lower precedence than *. So, to handle parenthesization for those forms, the “accumulated” mode might which level of precedence needs parentheses._let and _if end up having the same parenthesization rules. Instead of trying to combine the keyword-form printing mode with an operation-precedence level, you'll probably find it easier to make ”keyword forms need parentheses" a separate accumulator. When it's split this way, note that unparethesized operators tend to pass the keyword-form mode down to subexpressions on the right-hand side, while parenthesized operators can always clear that mode. (On the left-hand side of a operator, the mode can be always set to parenthesize keyword forms.)