View Javadoc
1   package visitor;
2   
3   import calculator.Notation;
4   
5   import calculator.operations.Operation;
6   import calculator.atoms.*;
7   import calculator.functions.BinaryFunction;
8   import calculator.functions.UnaryFunction;
9   import calculator.Expression;
10  
11  /**
12   * Printer is a Visitor that converts arithmetic expressions into Strings, using
13   * a specified notation (prefix, infix or postfix).
14   * It is used in the Calculator class to print arithmetic expressions in a
15   * human-readable format.
16   *
17   * @see Visitor
18   * @see calculator.Calculator
19   */
20  public class Printer extends Visitor {
21  
22  	/*
23  	 * The StringBuilder that is used to build the string representation of an
24  	 * arithmetic expression
25  	 */
26  	private final StringBuilder sb = new StringBuilder();
27  	/*
28  	 * The notation to be used for printing expressions (prefix, infix or postfix)
29  	 */
30  	private final Notation notation;
31  
32  	/**
33  	 * Constructor of the Printer class, which takes a Notation as a parameter to
34  	 * specify the notation to be used for printing expressions.
35  	 * 
36  	 * @param notation The notation to be used for printing expressions (prefix,
37  	 *                 infix or postfix)
38  	 */
39  	public Printer(Notation notation) {
40  		this.notation = notation;
41  	}
42  
43  	/**
44  	 * Constructor of the Printer class, which initializes the notation to infix by
45  	 * default.
46  	 */
47  	public Printer() {
48  		this.notation = Notation.INFIX; // Default notation is infix
49  	}
50  
51  	/**
52  	 * The visit methods for Real.
53  	 * These methods build the string representation of the expression being
54  	 * visited, using the specified notation.
55  	 * 
56  	 * @param r The Real to be visited
57  	 */
58  	@Override
59  	public void visit(Real r) {
60  		sb.append(r.getValue().stripTrailingZeros());
61  	}
62  
63  	@Override
64  	public void visit(IntegerAtom i) {
65  		sb.append(i.getValue());
66  	}
67  
68  	@Override
69  	public void visit(Complex c) {
70  		double realPart = c.getValue().getReal();
71  		double imaginaryPart = c.getValue().getImaginary();
72  
73  		switch (notation) {
74  			case PREFIX -> {
75  				sb.append("+ ").append(realPart).append(" ").append(imaginaryPart).append("i");
76  			}
77  			case POSTFIX -> {
78  				sb.append(realPart).append(" ").append(imaginaryPart).append("i +");
79  			}
80  			case INFIX -> {
81  				sb.append(realPart).append(" + ").append(imaginaryPart).append("i");
82  			}
83  		}
84  	}
85  
86  	@Override
87  	public void visit(Rationnal q) {
88  		int num = q.getNumerator();
89  		int den = q.getDenominator();
90  
91  		if (den == 1) {
92  			sb.append(num);
93  			return;
94  		}
95  
96  		switch (notation) {
97  			case PREFIX -> {
98  				sb.append("/ ").append(num).append(" ").append(den);
99  			}
100 			case POSTFIX -> {
101 				sb.append(num).append(" ").append(den).append(" /");
102 			}
103 			case INFIX -> {
104 				sb.append(num).append("/").append(den);
105 			}
106 		}
107 	}
108 
109 	/**
110 	 * The visit method for Operation. Needs to handle the different notations
111 	 * (prefix, infix and postfix) and the different number of arguments that an
112 	 * operation can have.
113 	 * It uses helper methods visitArgs and visitArgsInfix to handle the different
114 	 * notations.
115 	 * 
116 	 * @param o The Operation to be visited
117 	 */
118 	@Override
119 	public void visit(Operation o) {
120 		switch (notation) {
121 			case PREFIX -> {
122 				sb.append(o.getSymbol()).append(" (");
123 				visitArgs(o, ", ");
124 				sb.append(")");
125 			}
126 			case INFIX -> {
127 				sb.append("( ");
128 				visitArgs(o, " " + o.getSymbol() + " ");
129 				sb.append(" )");
130 			}
131 			case POSTFIX -> {
132 				sb.append("(");
133 				visitArgs(o, ", ");
134 				sb.append(") ").append(o.getSymbol());
135 			}
136 		}
137 	}
138 
139 	@Override
140 	public void visit(UnaryFunction o) {
141 		switch (notation) {
142 			case PREFIX, INFIX -> {
143 				sb.append(o.getSymbol()).append("(");
144 				o.getArg().accept(this);
145 				sb.append(")");
146 			}
147 			case POSTFIX -> {
148 				sb.append("(");
149 				o.getArg().accept(this);
150 				sb.append(")").append(o.getSymbol());
151 			}
152 		}
153 	}
154 
155 	/**
156 	 * Helper method to visit the arguments of an operation and build their string
157 	 * representation.
158 	 * 
159 	 * @param o         The operation whose arguments are to be visited
160 	 * @param separator The string used to separate the arguments
161 	 */
162 	private void visitArgs(Operation o, String separator) {
163 		for (Expression arg : o.getArgs()) {
164 			arg.accept(this);
165 			sb.append(separator);
166 		}
167 		// Remove the last separator
168 		if (sb.length() > 0) {
169 			sb.setLength(sb.length() - separator.length());
170 		}
171 	}
172 
173 	/**
174 	 * Getter method to obtain the string representation of the expression that has
175 	 * been built by the visit methods.
176 	 * 
177 	 * @return The string representation of the expression that has been built by
178 	 *         the visit methods
179 	 */
180 	public String getResult() {
181 		return sb.toString();
182 	}
183 
184 	@Override
185 	public void visit(BinaryFunction f) {
186 		switch (notation) {
187 			case PREFIX, INFIX -> {
188 				sb.append(f.getSymbol()).append("(");
189 				f.getFirstArg().accept(this);
190 				sb.append(", ");
191 				f.getSecondArg().accept(this);
192 				sb.append(")");
193 			}
194 			case POSTFIX -> {
195 				sb.append("(");
196 				f.getFirstArg().accept(this);
197 				sb.append(", ");
198 				f.getSecondArg().accept(this);
199 				sb.append(")").append(f.getSymbol());
200 			}
201 		}
202 	}
203 
204 }