[ERA-CVS] src/org/jdaemon/util/expression DelegatingExpressionWriter.java, NONE, 1.1 Expression.jav
Brought to you by:
jessex
|
From: <je...@23...> - 2008-10-06 10:23:16
|
Update of /cvsroot/era/src/org/jdaemon/util/expression In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv12559/util/expression Added Files: DelegatingExpressionWriter.java Expression.java ExpressionWriter.java Expressions.java OutputError.java SimpleExpressionWriter.java ValueExpression.java Log Message: Various changes for ERA v2 - 'This time it's Generic...' --- NEW FILE: DelegatingExpressionWriter.java --- /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.jdaemon.util.expression; import org.jdaemon.util.expression.Expression.Type; /** * * @author jonathan */ class DelegatingExpressionWriter implements ExpressionWriter { protected ExpressionWriter parent; public <T> void writeValue(T value) throws OutputError { parent.writeValue(value); } public void writeParameter(String name) throws OutputError { parent.writeParameter(name); } public void beginExpression(Type type) throws OutputError { parent.beginExpression(type); } public void endExpression(Type type) throws OutputError { parent.endExpression(type); } public DelegatingExpressionWriter(ExpressionWriter parent) { this.parent = parent; } } --- NEW FILE: Expression.java --- /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.jdaemon.util.expression; /** * * @author jonathan */ public interface Expression { public enum Type { ADD, SUB, MUL, DIV, EQ, LT, GT, LTE, GTE, AND, OR, NOT, PARAM, VALUE, FUNC } public void write(ExpressionWriter out) throws OutputError; } --- NEW FILE: ExpressionWriter.java --- /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.jdaemon.util.expression; /** ExpressionWriter provices a mechanism for processing expressions. * * The convention is that an expression object will write its sub-expressions * and values before writing its own type. * * For example, an expression 1 + 2 should be written this: * * writer.writeValue(1); * writer.writeValue(2); * writer.endExpression(Expression.Type.ADD); * * @author jonathan */ public interface ExpressionWriter { /** Push a value. * * @param value to push. */ public <T> void writeValue(T value) throws OutputError; /** Push a parameter. * * @param value to push. */ public void writeParameter(String name) throws OutputError; /** Push a value. * * @param value to push. */ public void beginExpression(Expression.Type type) throws OutputError; /** Push a value. * * @param value to push. */ public void endExpression(Expression.Type type) throws OutputError; } --- NEW FILE: Expressions.java --- /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.jdaemon.util.expression; /** * * @author jonathan */ public class Expressions { private static class ParameterBinder extends DelegatingExpressionWriter { private int index; private Expression bound; public ParameterBinder(ExpressionWriter writer, Expression bound, int index) { super(writer); this.index = index; this.bound = bound; } /** Output bound expression or pass on unbound parameter up delegation chain. * * @param name * @throws org.jdaemon.util.expression.OutputError */ public void writeParameter(String name) throws OutputError { index--; if (index == 0) bound.write(parent); else parent.writeParameter(name); } } public static ExpressionWriter bindParameter(ExpressionWriter writer, Expression value) { return new ParameterBinder(writer, value, 1); } public static ExpressionWriter bindParameter(ExpressionWriter writer, Expression value, int index) { return new ParameterBinder(writer, value, index); } public static <T> ExpressionWriter bindParameter(ExpressionWriter writer, T value) { return bindParameter(writer, new ValueExpression<T>(value)); } public static <T> ExpressionWriter bindParameter(ExpressionWriter writer, T value, int index) { return bindParameter(writer, new ValueExpression<T>(value), index); } } --- NEW FILE: OutputError.java --- /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.jdaemon.util.expression; /** * * @author jonathan */ public class OutputError extends Exception { /** * Creates a new instance of <code>OutputError</code> without detail message. */ public OutputError() { } /** * Constructs an instance of <code>OutputError</code> with the specified detail message. * @param msg the detail message. */ public OutputError(String msg) { super(msg); } } --- NEW FILE: SimpleExpressionWriter.java --- /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.jdaemon.util.expression; import java.io.IOException; import java.util.Stack; import java.io.Writer; import java.util.LinkedList; import java.util.Iterator; import java.util.Map; import java.util.HashMap; import java.util.Collections; import java.util.Set; import java.util.HashSet; /** ExpressionWriter that outputs 'natural' expression to a writer. * * * * * @author jonathan */ public class SimpleExpressionWriter implements ExpressionWriter { /** Private base class for all types of expression. * * YES, it has a public data member. */ private static abstract class Node { /** Type of node. */ public final Expression.Type type; /** Construct a node of given type. * * Note type of node cannot be changed after creation. * * @param type Type of node. */ public Node(Expression.Type type) { this.type = type; } } /** Subclass of Node representing a complex expression. * */ private static class ExpressionNode extends Node { public final LinkedList<Node> children = new LinkedList<Node>(); public ExpressionNode(Expression.Type type) { super(type); } } private static class ValueNode<T> extends Node { public final T value; public ValueNode(Expression.Type type, T value) { super(type); this.value = value; } } private static Map<Expression.Type, String> initDefaultOperators() { HashMap<Expression.Type,String> operators = new HashMap<Expression.Type, String>(); operators.put(Expression.Type.ADD, "+"); operators.put(Expression.Type.AND, " && "); operators.put(Expression.Type.DIV, "/"); operators.put(Expression.Type.EQ, "="); operators.put(Expression.Type.GT, ">"); operators.put(Expression.Type.GTE, ">="); operators.put(Expression.Type.LT, "<"); operators.put(Expression.Type.LTE, "<="); operators.put(Expression.Type.MUL, "*"); operators.put(Expression.Type.NOT, "!"); operators.put(Expression.Type.OR, " || "); operators.put(Expression.Type.SUB, "-"); return Collections.unmodifiableMap(operators); } private static Set<Expression.Type> initInfixOperators() { HashSet<Expression.Type> operators = new HashSet<Expression.Type>(); operators.add(Expression.Type.ADD); operators.add(Expression.Type.AND); operators.add(Expression.Type.DIV); operators.add(Expression.Type.EQ); operators.add(Expression.Type.GT); operators.add(Expression.Type.GTE); operators.add(Expression.Type.LT); operators.add(Expression.Type.LTE); operators.add(Expression.Type.MUL); operators.add(Expression.Type.OR); operators.add(Expression.Type.SUB); return Collections.unmodifiableSet(operators); } private static Set<Expression.Type> initPrefixOperators() { HashSet<Expression.Type> operators = new HashSet<Expression.Type>(); operators.add(Expression.Type.NOT); return Collections.unmodifiableSet(operators); } public static final Map<Expression.Type, String> DEFAULT_STRING_MAP = initDefaultOperators(); public static final Set<Expression.Type> DEFAULT_INFIX_SET = initInfixOperators(); public static final Set<Expression.Type> DEFAULT_PREFIX_SET = initPrefixOperators(); private Writer out; private Stack<ExpressionNode> stack = new Stack<ExpressionNode>(); private ExpressionNode top = null; private Map<Expression.Type, String> operators; private Set<Expression.Type> prefix_operators; private Set<Expression.Type> infix_operators; /** Output a child expression, bracketed as necessary. * * We must insert brackets in order to preserve the evaluation order specified by the original expression. * We supress the bracketing of the child expression in three cases: * * 1) the child expression is a value * 2) the child expression is an operation with a priority greater than the parent expression (BODMASS) * 3) the child expression and parent expression have the same operator, and the operation is associative * * @param parent * @param child * @throws java.io.IOException */ private void outputChildExpression(ExpressionNode parent, Node child) throws IOException, OutputError { if (parent.type == child.type && isAssociative(parent.type) || getPriority(parent.type) < getPriority(child.type)) { outputExpression(child); } else { out.write("("); outputExpression(child); out.write(")"); } } private void outputPrefixExpression(ExpressionNode expression) throws IOException, OutputError { out.write(operators.get(expression.type)); outputChildExpression(expression, expression.children.getFirst()); } private void outputInfixExpression(ExpressionNode expression) throws IOException, OutputError { if(expression.children.size() != 2) throw new OutputError("Infix expression must have two parameters"); outputChildExpression(expression, expression.children.getFirst()); out.write(operators.get(expression.type)); outputChildExpression(expression, expression.children.getLast()); } private void outputPostfixExpression(ExpressionNode expression) throws IOException, OutputError { out.write(operators.get(expression.type)); out.write("("); Iterator<Node> params = expression.children.iterator(); if (params.hasNext()) { outputExpression(params.next()); while(params.hasNext()) { out.write(","); outputExpression(params.next()); } } out.write(")"); } private void outputExpression(Node expression) throws IOException, OutputError { switch (expression.type) { case PARAM: case VALUE: outputValueExpression((ValueNode<?>)expression); break; case FUNC: outputFunctionExpression((ExpressionNode)expression); break; default: if (infix_operators.contains(expression.type)) outputInfixExpression((ExpressionNode)expression); else if (prefix_operators.contains(expression.type)) outputPrefixExpression((ExpressionNode)expression); else outputPostfixExpression((ExpressionNode)expression); } } private void outputValueExpression(ValueNode<?> expression) throws IOException { out.write(expression.value.toString()); } private void outputFunctionExpression(ExpressionNode expression) throws IOException, OutputError { Iterator<Node> params = expression.children.iterator(); // First parameter is obligatory as it's the function name if (params.hasNext()) { Node name = params.next(); if(name.type != Expression.Type.VALUE) throw new OutputError("function name must be a simple value."); outputValueExpression((ValueNode<?>)name); out.write("("); // Subsequent parameters are optional; we have to piss about to put the commas in the right places if (params.hasNext()) { outputExpression(params.next()); while(params.hasNext()) { out.write(","); outputExpression(params.next()); } } out.write(")"); } else { throw new OutputError("First parameter of a function expression must be function name"); } } private static int getPriority(Expression.Type operator) { switch(operator) { case VALUE: case PARAM: return 100; case NOT: return 95; case DIV: return 90; case MUL: return 80; case ADD: return 70; case SUB: return 60; case LT: case GT: case LTE: case GTE: case EQ: return 40; case AND: return 20; case OR: return 10; default: return 0; } } private static boolean isAssociative(Expression.Type operator) { switch(operator) { case ADD: case MUL: return true; default: return false; } } public <T> void writeValue(T value) { top.children.add(new ValueNode<T>(Expression.Type.VALUE, value)); } public void writeParameter(String name) { top.children.add(new ValueNode<String>(Expression.Type.PARAM, name)); } public void beginExpression(Expression.Type type) { if (top != null) stack.push(top); top = new ExpressionNode(type); } public void endExpression(Expression.Type type) throws OutputError { if (top.type != type) throw new OutputError("Mismatched type in beginExpression and endExpression"); if (stack.empty()) { try { outputExpression(top); out.flush(); top = null; } catch (java.io.IOException e) { throw new OutputError(e.getMessage()); } } else { ExpressionNode parent = stack.pop(); parent.children.add(top); top = parent; } } /** Initialise a SimpleExpressionWriter. * * @param out Where to write the resulting expression * @param operators A map of strings to output for values of Expression.Type */ public SimpleExpressionWriter( Writer out, Map<Expression.Type, String> string_map, Set<Expression.Type> infix_operators, Set<Expression.Type> prefix_operators) { this.out = out; this.operators = string_map; this.infix_operators = infix_operators; this.prefix_operators = prefix_operators; } /** Initialise a SimpleExpressionWriter. * * Equivalent to SimpleExpressionWriter(out, DEFAULT_STRING_MAP, DEFAULT_INFIX_SET, DEFAULT_PREFIX_SET); * * @param out Where to write the resulting expression */ public SimpleExpressionWriter(Writer out) { this.out = out; this.operators = DEFAULT_STRING_MAP; this.infix_operators = DEFAULT_INFIX_SET; this.prefix_operators = DEFAULT_PREFIX_SET; } } --- NEW FILE: ValueExpression.java --- /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.jdaemon.util.expression; /** A simple expression containing a single value. * * @author jonathan */ public class ValueExpression<T> implements Expression { private T value; public void write(ExpressionWriter writer) throws OutputError { writer.writeValue(value); } public ValueExpression(T value) { this.value = value; } } |