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/11/04 17:32] (current) – Further simplified instanceof code 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) { | ||
| + | if (junct instanceof Expr.Variadic vjunct | ||
| + | && vjunct.operator.type == op.type) { | ||
| + | flattened.addAll(vjunct.parameters); | ||
| + | } else { | ||
| + | flattened.add(junct); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | return new Expr.Variadic(op, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | 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: | ||