/*******************************************************************************
* LastCalc - The last calculator you'll ever need
* Copyright (C) 2011, 2012 Uprizer Labs LLC
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Affero General Public License for more
* details.
******************************************************************************/
package com.lastcalc.parsers;
import java.io.Serializable;
import java.util.*;
import com.google.common.collect.Sets;
import com.lastcalc.TokenList;
import com.lastcalc.parsers.amounts.*;
import com.lastcalc.parsers.bool.*;
import com.lastcalc.parsers.collections.*;
import com.lastcalc.parsers.currency.Currencies;
import com.lastcalc.parsers.math.*;
import com.lastcalc.parsers.meta.ImportParser;
import com.lastcalc.parsers.strings.StringAppender;
import com.lastcalc.parsers.web.*;
public abstract class Parser implements Serializable {
private static final long serialVersionUID = -6533682381337736230L;
public static Set<String> reservedTokens = Sets.newHashSet("(", ")", "[", "]", ",", "{", "}", "=", "is");
public ParseResult parse(final TokenList tokens, final int templatePos, final ParserContext context) {
if (context == null)
throw new IllegalArgumentException("context is null");
return parse(tokens, templatePos);
}
public ParseResult parse(final TokenList tokens, final int templatePos) {
return parse(tokens, templatePos, null);
}
public abstract TokenList getTemplate();
@Override
public abstract int hashCode();
@Override
public abstract boolean equals(Object obj);
protected final ArrayList<Object> createResponseWithCollection(final List<Object> input, final int templatePos,
final Collection<Object> values) {
final int tSize = getTemplate().size();
final ArrayList<Object> response = new ArrayList<Object>(input.size() + values.size() - tSize);
for (final Object x : input.subList(0, templatePos)) {
response.add(x);
}
for (final Object x : values) {
response.add(x);
}
for (final Object x : input.subList(templatePos + tSize, input.size())) {
response.add(x);
}
return response;
}
protected final ArrayList<Object> createResponse(final List<Object> input, final int templatePos,
final Object... values) {
final int tSize = getTemplate().size();
final ArrayList<Object> response = new ArrayList<Object>(input.size() + values.length - tSize);
for (final Object x : input.subList(0, templatePos)) {
response.add(x);
}
Collections.addAll(response, values);
for (final Object x : input.subList(templatePos + tSize, input.size())) {
response.add(x);
}
return response;
}
public final int matchTemplate(final TokenList input) {
return matchTemplate(input, 0);
}
public final int matchTemplate(final TokenList input, final int startPos) {
final int templateSize = getTemplate().size();
templateScan: for (int sPos = startPos; sPos < 1 + input.size() - templateSize; sPos++) {
for (int x = 0; x < templateSize; x++) {
final Object templ = getTemplate().get(x);
final Object src = input.get(sPos + x);
if (!match(templ, src)) {
continue templateScan;
}
}
return sPos;
}
return -1;
}
private boolean match(final Object templ, final Object src) {
if (templ instanceof Class) {
final Class<?> templC = (Class<?>) templ;
return !reservedTokens.contains(src) && templC.isAssignableFrom(src.getClass());
} else if (templ instanceof Iterable<?>) {
for (final Object t : ((Iterable<?>) templ)) {
if (match(t, src))
return true;
}
}
return templ.equals(src);
}
public static void getAll(final Collection<Parser> parsers) {
parsers.addAll(UnitParser.getParsers());
parsers.addAll(Currencies.getParsers());
parsers.add(new TrailingEqualsStripper());
parsers.add(new AmountParser());
parsers.add(new UDPApplier());
parsers.add(new AmountConverterParser());
parsers.add(new GetFromListOrMap());
parsers.add(new ApplyTo());
parsers.add(new Filter());
parsers.add(new FoldLeft());
parsers.add(new BoolParser());
parsers.add(new NotParser());
parsers.add(new BoolFunctionsParser());
parsers.add(new EqualityParser());
parsers.add(new FoldLeft());
parsers.add(new ToLowerCase());
parsers.add(new MathBiOp());
parsers.add(new MathOp());
parsers.add(new BitwiseOp());
parsers.add(new RadixConverter());
parsers.add(new HttpRetriever());
parsers.add(new Select());
parsers.add(new GetFromElement());
parsers.add(new Interpret());
parsers.add(new StringAppender());
parsers.add(new ImportParser());
parsers.add(new FactorialParser());
parsers.add(new PrimesUnderParser());
parsers.add(new IsPrimeParser());
parsers.add(new GCDLCMParser());
}
public static final class ParseResult {
public final double scoreBias;
public final TokenList output;
private ParseResult(final TokenList output, final double scoreBias) {
this.output = output;
this.scoreBias = scoreBias;
}
public static ParseResult fail() {
return new ParseResult(null, 0);
}
public static ParseResult success(final TokenList tokens) {
return new ParseResult(tokens, 0);
}
public static ParseResult success(final TokenList tokens, final double scoreBias) {
return new ParseResult(tokens, scoreBias);
}
public boolean isSuccess() {
return output != null;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("ParseResult [scoreBias=");
builder.append(scoreBias);
builder.append(", output=");
builder.append(output);
builder.append("]");
return builder.toString();
}
}
}