1 51 package org.apache.fop.fo.expr; 52 53 import org.apache.fop.fo.Property; 54 import org.apache.fop.fo.ListProperty; 55 import org.apache.fop.fo.LengthProperty; 56 import org.apache.fop.fo.NumberProperty; 57 import org.apache.fop.fo.StringProperty; 58 import org.apache.fop.fo.ColorTypeProperty; 59 import org.apache.fop.datatypes.*; 60 61 import java.util.HashMap ; 62 63 68 public class PropertyParser extends PropertyTokenizer { 69 private PropertyInfo propInfo; 71 private static final String RELUNIT = "em"; 72 private static final Numeric negOne = new Numeric(new Double (-1.0)); 73 private static final HashMap functionTable = new HashMap (); 74 75 static { 76 functionTable.put("ceiling", new CeilingFunction()); 78 functionTable.put("floor", new FloorFunction()); 79 functionTable.put("round", new RoundFunction()); 80 functionTable.put("min", new MinFunction()); 81 functionTable.put("max", new MaxFunction()); 82 functionTable.put("abs", new AbsFunction()); 83 functionTable.put("rgb", new RGBColorFunction()); 84 functionTable.put("from-table-column", new FromTableColumnFunction()); 85 functionTable.put("inherited-property-value", 86 new InheritedPropFunction()); 87 functionTable.put("from-parent", new FromParentFunction()); 88 functionTable.put("from-nearest-specified-value", 89 new NearestSpecPropFunction()); 90 functionTable.put("proportional-column-width", 91 new PPColWidthFunction()); 92 functionTable.put("label-end", new LabelEndFunction()); 93 functionTable.put("body-start", new BodyStartFunction()); 94 functionTable.put("_fop-property-value", new FopPropValFunction()); 96 97 105 } 106 107 108 116 public static Property parse(String expr, PropertyInfo propInfo) 117 throws PropertyException { 118 return new PropertyParser(expr, propInfo).parseProperty(); 119 } 120 121 122 128 private PropertyParser(String propExpr, PropertyInfo pInfo) { 129 super(propExpr); 130 this.propInfo = pInfo; 131 } 132 133 140 private Property parseProperty() throws PropertyException { 141 next(); 142 if (currentToken == TOK_EOF) { 143 return new StringProperty(""); 145 } 146 ListProperty propList = null; 147 while (true) { 148 Property prop = parseAdditiveExpr(); 149 if (currentToken == TOK_EOF) { 150 if (propList != null) { 151 propList.addProperty(prop); 152 return propList; 153 } else 154 return prop; 155 } else { 156 if (propList == null) { 157 propList = new ListProperty(prop); 158 } else { 159 propList.addProperty(prop); 160 } 161 } 162 } 164 } 166 167 171 private Property parseAdditiveExpr() throws PropertyException { 172 Property prop = parseMultiplicativeExpr(); 174 loop: 175 for (; ; ) { 176 switch (currentToken) { 177 case TOK_PLUS: 178 next(); 179 prop = evalAddition(prop.getNumeric(), 180 parseMultiplicativeExpr().getNumeric()); 181 break; 182 case TOK_MINUS: 183 next(); 184 prop = 185 evalSubtraction(prop.getNumeric(), 186 parseMultiplicativeExpr().getNumeric()); 187 break; 188 default: 189 break loop; 190 } 191 } 192 return prop; 193 } 194 195 199 private Property parseMultiplicativeExpr() throws PropertyException { 200 Property prop = parseUnaryExpr(); 201 loop: 202 for (; ; ) { 203 switch (currentToken) { 204 case TOK_DIV: 205 next(); 206 prop = evalDivide(prop.getNumeric(), 207 parseUnaryExpr().getNumeric()); 208 break; 209 case TOK_MOD: 210 next(); 211 prop = evalModulo(prop.getNumber(), 212 parseUnaryExpr().getNumber()); 213 break; 214 case TOK_MULTIPLY: 215 next(); 216 prop = evalMultiply(prop.getNumeric(), 217 parseUnaryExpr().getNumeric()); 218 break; 219 default: 220 break loop; 221 } 222 } 223 return prop; 224 } 225 226 230 private Property parseUnaryExpr() throws PropertyException { 231 if (currentToken == TOK_MINUS) { 232 next(); 233 return evalNegate(parseUnaryExpr().getNumeric()); 234 } 235 return parsePrimaryExpr(); 236 } 237 238 239 243 private final void expectRpar() throws PropertyException { 244 if (currentToken != TOK_RPAR) 245 throw new PropertyException("expected )"); 246 next(); 247 } 248 249 257 private Property parsePrimaryExpr() throws PropertyException { 258 Property prop; 259 switch (currentToken) { 260 case TOK_LPAR: 261 next(); 262 prop = parseAdditiveExpr(); 263 expectRpar(); 264 return prop; 265 266 case TOK_LITERAL: 267 prop = new StringProperty(currentTokenValue); 268 break; 269 270 case TOK_NCNAME: 271 prop = new NCnameProperty(currentTokenValue); 273 break; 274 275 case TOK_FLOAT: 276 prop = new NumberProperty(new Double (currentTokenValue)); 277 break; 278 279 case TOK_INTEGER: 280 prop = new NumberProperty(new Integer (currentTokenValue)); 281 break; 282 283 case TOK_PERCENT: 284 288 double pcval = 289 new Double (currentTokenValue.substring(0, currentTokenValue.length() - 1)).doubleValue() 290 / 100.0; 291 PercentBase pcBase = this.propInfo.getPercentBase(); 293 if (pcBase != null) { 294 if (pcBase.getDimension() == 0) { 295 prop = new NumberProperty(pcval * pcBase.getBaseValue()); 296 } else if (pcBase.getDimension() == 1) { 297 prop = new LengthProperty(new PercentLength(pcval, 298 pcBase)); 299 } else { 300 throw new PropertyException("Illegal percent dimension value"); 301 } 302 } else { 303 prop = new NumberProperty(pcval); 305 } 306 break; 307 308 case TOK_NUMERIC: 309 int numLen = currentTokenValue.length() - currentUnitLength; 311 String unitPart = currentTokenValue.substring(numLen); 312 Double numPart = new Double (currentTokenValue.substring(0, 313 numLen)); 314 Length length = null; 315 if (unitPart.equals(RELUNIT)) { 316 length = new FixedLength(numPart.doubleValue(), 317 propInfo.currentFontSize()); 318 } else 319 length = new FixedLength(numPart.doubleValue(), unitPart); 320 if (length == null) { 321 throw new PropertyException("unrecognized unit name: " 322 + currentTokenValue); 323 } else 324 prop = new LengthProperty(length); 325 break; 326 327 case TOK_COLORSPEC: 328 prop = new ColorTypeProperty(new ColorType(currentTokenValue)); 329 break; 330 331 case TOK_FUNCTION_LPAR: { 332 Function function = 333 (Function)functionTable.get(currentTokenValue); 334 if (function == null) { 335 throw new PropertyException("no such function: " 336 + currentTokenValue); 337 } 338 next(); 339 propInfo.pushFunction(function); 341 prop = function.eval(parseArgs(function.nbArgs()), propInfo); 342 propInfo.popFunction(); 343 return prop; 344 } 345 default: 346 throw new PropertyException("syntax error"); 347 } 348 next(); 349 return prop; 350 } 351 352 362 Property[] parseArgs(int nbArgs) throws PropertyException { 363 Property[] args = new Property[nbArgs]; 364 Property prop; 365 int i = 0; 366 if (currentToken == TOK_RPAR) { 367 next(); 369 } else { 370 while (true) { 371 372 prop = parseAdditiveExpr(); 373 if (i < nbArgs) { 374 args[i++] = prop; 375 } 376 if (currentToken != TOK_COMMA) 378 break; 379 next(); 380 } 381 expectRpar(); 382 } 383 if (nbArgs != i) { 384 throw new PropertyException("Wrong number of args for function"); 385 } 386 return args; 387 } 388 389 390 399 private Property evalAddition(Numeric op1, 400 Numeric op2) throws PropertyException { 401 if (op1 == null || op2 == null) 402 throw new PropertyException("Non numeric operand in addition"); 403 return new NumericProperty(op1.add(op2)); 404 } 405 406 415 private Property evalSubtraction(Numeric op1, 416 Numeric op2) throws PropertyException { 417 if (op1 == null || op2 == null) 418 throw new PropertyException("Non numeric operand in subtraction"); 419 return new NumericProperty(op1.subtract(op2)); 420 } 421 422 430 private Property evalNegate(Numeric op) throws PropertyException { 431 if (op == null) 432 throw new PropertyException("Non numeric operand to unary minus"); 433 return new NumericProperty(op.multiply(negOne)); 434 } 435 436 445 private Property evalMultiply(Numeric op1, 446 Numeric op2) throws PropertyException { 447 if (op1 == null || op2 == null) 448 throw new PropertyException("Non numeric operand in multiplication"); 449 return new NumericProperty(op1.multiply(op2)); 450 } 451 452 453 462 private Property evalDivide(Numeric op1, 463 Numeric op2) throws PropertyException { 464 if (op1 == null || op2 == null) 465 throw new PropertyException("Non numeric operand in division"); 466 return new NumericProperty(op1.divide(op2)); 467 } 468 469 478 private Property evalModulo(Number op1, 479 Number op2) throws PropertyException { 480 if (op1 == null || op2 == null) 481 throw new PropertyException("Non number operand to modulo"); 482 return new NumberProperty(op1.doubleValue() % op2.doubleValue()); 483 } 484 485 } 486 | Popular Tags |