Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
creating:jlists [2025/04/28 18:39] – Simplified jlist parsing logic ahelwer | creating:jlists [2025/05/21 18:21] (current) – Disjunction does not short-circuit ahelwer | ||
---|---|---|---|
Line 249: | Line 249: | ||
This puts you in rarified air. | This puts you in rarified air. | ||
Only a handful of people in the world possess this knowledge, and now you are among them. | Only a handful of people in the world possess this knowledge, and now you are among them. | ||
+ | |||
+ | ====== Evaluation ====== | ||
+ | |||
+ | Now that we can parse jlists, let's interpret them. | ||
+ | Similar to the logical operators covered in the book, conjunction lists short-circuit. | ||
+ | That means conjuncts are evaluated in order and, if a single conjunct is false, evaluation immediately stops and returns false. | ||
+ | In an odd contrast, disjunction lists do //not// short-circuit; | ||
+ | |||
+ | Add conjunction list evaluation logic to '' | ||
+ | <code java [highlight_lines_extra=" | ||
+ | return set; | ||
+ | case AND: | ||
+ | for (Expr conjunct : expr.parameters) { | ||
+ | Object result = evaluate(conjunct); | ||
+ | checkBooleanOperand(expr.operator, | ||
+ | if (!(boolean)result) return false; | ||
+ | } | ||
+ | return true; | ||
+ | default: | ||
+ | // Unreachable. | ||
+ | return null | ||
+ | </ | ||
+ | |||
+ | Then add the disjunction list logic right below that: | ||
+ | <code java [highlight_lines_extra=" | ||
+ | return true; | ||
+ | case OR: | ||
+ | boolean result = false; | ||
+ | for (Expr disjunct : expr.parameters) { | ||
+ | Object junctResult = evaluate(disjunct); | ||
+ | checkBooleanOperand(expr.operator, | ||
+ | result |= (Boolean)junctResult; | ||
+ | } | ||
+ | return result; | ||
+ | default: | ||
+ | // Unreachable. | ||
+ | return null; | ||
+ | </ | ||
+ | |||
+ | Remember we also parsed the ''/ | ||
+ | This is a bit annoying! | ||
+ | They should function in the exact same way as their respective jlists, but now we have to copy a duplicate of our evaluation logic to '' | ||
+ | So, we'll perform a trick which also has its parallel in chapter 9 of the book: [[https:// | ||
+ | We will flatten infix ''/ | ||
+ | |||
+ | In the '' | ||
+ | <code java [highlight_lines_extra=" | ||
+ | Expr expr = operatorExpression(prec + 1); | ||
+ | while ((op = matchOp(Fix.INFIX, | ||
+ | Token operator = previous(); | ||
+ | Expr right = operatorExpression(op.highPrec + 1); | ||
+ | expr = flattenInfix(expr, | ||
+ | if (!op.assoc) return expr; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Define '' | ||
+ | <code java> | ||
+ | private Expr flattenInfix(Expr left, Token op, Expr right) { | ||
+ | if (op.type == AND) { | ||
+ | | ||
+ | } else if (op.type == OR) { | ||
+ | | ||
+ | } else { | ||
+ | return new Expr.Binary(left, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | The helper returns a regular binary expression except when the operator is '' | ||
+ | <code java [highlight_lines_extra=" | ||
+ | private Expr flattenInfix(Expr left, Token op, Expr right) { | ||
+ | if (op.type == AND) { | ||
+ | List< | ||
+ | conjuncts.add(left); | ||
+ | conjuncts.add(right); | ||
+ | return new Expr.Variadic(op, | ||
+ | } else if (op.type == OR) { | ||
+ | List< | ||
+ | disjuncts.add(left); | ||
+ | disjuncts.add(right); | ||
+ | return new Expr.Variadic(op, | ||
+ | } else { | ||
+ | return new Expr.Binary(left, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ====== Further Desugaring ====== | ||
+ | |||
+ | This is all right, but it could be even better! | ||
+ | An expression like '' | ||
+ | <code haskell> | ||
+ | /\ /\ /\ 1 | ||
+ | /\ 2 | ||
+ | /\ 3 | ||
+ | /\ 4 | ||
+ | </ | ||
+ | Which is quite a lot of nesting! | ||
+ | It would be nice if it were instead translated to a single flat jlist with four conjuncts. | ||
+ | This rewrite is safe because conjunction & disjunction are associative. | ||
+ | So, define a new '' | ||
+ | Here's what it looks like: | ||
+ | <code java> | ||
+ | private Expr flattenJLists(Token op, List< | ||
+ | List< | ||
+ | for (Expr junct : juncts) { | ||
+ | Expr.Variadic vjunct; | ||
+ | if ((vjunct = asVariadicOp(op, | ||
+ | flattened.addAll(vjunct.parameters); | ||
+ | } else { | ||
+ | flattened.add(junct); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return new Expr.Variadic(op, | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | This uses Java's conditional-assign syntax along with the '' | ||
+ | <code java> | ||
+ | private Expr.Variadic asVariadicOp(Token op, Expr expr) { | ||
+ | if (expr instanceof Expr.Variadic) { | ||
+ | Expr.Variadic vExpr = (Expr.Variadic)expr; | ||
+ | if (vExpr.operator.type == op.type) return vExpr; | ||
+ | } | ||
+ | |||
+ | return null; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Replace the calls to '' | ||
+ | <code java [highlight_lines_extra=" | ||
+ | private Expr flattenInfix(Expr left, Token op, Expr right) { | ||
+ | if (op.type == AND) { | ||
+ | List< | ||
+ | conjuncts.add(left); | ||
+ | conjuncts.add(right); | ||
+ | return flattenJLists(op, | ||
+ | } else if (op.type == OR) { | ||
+ | List< | ||
+ | disjuncts.add(left); | ||
+ | disjuncts.add(right); | ||
+ | return flattenJLists(op, | ||
+ | } else { | ||
+ | return new Expr.Binary(left, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Do the same in the jlist parsing loop in '' | ||
+ | <code java [highlight_lines_extra=" | ||
+ | if (match(AND, OR)) { | ||
+ | Token op = previous(); | ||
+ | jlists.push(op.column); | ||
+ | List< | ||
+ | do { | ||
+ | juncts.add(expression()); | ||
+ | } while (matchBullet(op.type, | ||
+ | jlists.pop(); | ||
+ | return flattenJLists(op, | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Infix ''/ | ||
+ | So concludes this lynchpin tutorial on conjunction & disjunction lists. | ||
+ | Good job making it to the end! | ||
If your code got out of sync during this tutorial, you can find its expected state [[https:// | If your code got out of sync during this tutorial, you can find its expected state [[https:// | ||
Continue on the [[creating: | Continue on the [[creating: |