/*
Copyright (c) 2009-2011 Olivier Chafik, All Rights Reserved
This file is part of JNAerator (http://jnaerator.googlecode.com/).
JNAerator is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JNAerator 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ochafik.lang.jnaerator.parser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.ochafik.lang.jnaerator.parser.Identifier.SimpleIdentifier;
import com.nativelibs4java.jalico.Pair;
import java.math.BigInteger;
import java.util.Collections;
public abstract class Expression extends Element {
private static final long MAX_UINT_VALUE = 2L * Integer.MAX_VALUE;
public static class ExpressionsBlock extends ExpressionSequence {
@Override
public void accept(Visitor visitor) {
visitor.visitExpressionsBlock(this);
}
}
public static class ExpressionSequence extends Expression {
final List<Expression> expressions = new ArrayList<Expression>();
public ExpressionSequence() {
}
public ExpressionSequence(Expression... expressions) {
this(Arrays.asList(expressions));
}
public ExpressionSequence(List<Expression> expressions) {
setExpressions(expressions);
}
public void addExpression(Expression e) {
if (e != null) {
expressions.add(e);
e.setParentElement(this);
}
}
public List<Expression> getExpressions() {
return expressions;
}
public void setExpressions(List<Expression> sequence) {
changeValue(this, this.expressions, sequence);
}
@Override
public void accept(Visitor visitor) {
visitor.visitExpressionSequence(this);
}
@Override
public Element getNextChild(Element child) {
return getNextSibling(getExpressions(), child);
}
@Override
public Element getPreviousChild(Element child) {
return getPreviousSibling(getExpressions(), child);
}
@Override
public boolean replaceChild(Element child, Element by) {
return replaceChild(getExpressions(), Expression.class, this, child, by) ||
super.replaceChild(child, by);
}
}
public static class OpaqueExpression extends Expression {
String opaqueString;
public void setOpaqueString(String opaqueString) {
this.opaqueString = opaqueString;
}
public String getOpaqueString() {
return opaqueString;
}
public OpaqueExpression() {
}
public OpaqueExpression(String opaqueString) {
setOpaqueString(opaqueString);
}
@Override
public void accept(Visitor visitor) {
visitor.visitOpaqueExpression(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
}
boolean parenthesis;
public Expression setParenthesis(boolean parenthesis) {
this.parenthesis = parenthesis;
return this;
}
public Expression setParenthesisIfNeeded() {
setParenthesis(!(
this instanceof VariableRef ||
this instanceof FunctionCall ||
this instanceof MemberRef ||
this instanceof ArrayAccess
));
return this;
}
public boolean getParenthesis() {
return parenthesis;
}
public boolean isParenthesis() {
return parenthesis;
}
@Override
public Expression clone() {
return (Expression)super.clone();
}
public enum MemberRefStyle {
Dot, SquareBrackets, Arrow, Colons
}
public static MemberRefStyle parseMemberRefStyle(String s) {
if (s.equals("->"))
return MemberRefStyle.Arrow;
if (s.equals("."))
return MemberRefStyle.Dot;
if (s.equals("::"))
return MemberRefStyle.Colons;
return null;
}
public static class TypeRefExpression extends Expression {
TypeRef type;
public TypeRefExpression(TypeRef type) {
setType(type);
}
public TypeRefExpression() {}
public TypeRef getType() {
return type;
}
public void setType(TypeRef type) {
this.type = changeValue(this, this.type, type);
}
@Override
public void accept(Visitor visitor) {
visitor.visitTypeRefExpression(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getType()) {
setType((TypeRef) by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class EmptyArraySize extends Expression {
@Override
public void accept(Visitor visitor) {
visitor.visitEmptyArraySize(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
}
public static class MemberRef extends Expression {
MemberRefStyle memberRefStyle;
Expression target;
Identifier name;
public MemberRef(SimpleIdentifier name) {
setName(name);
}
public MemberRef(Expression target, MemberRefStyle memberRefStyle, Identifier name) {
setTarget(target);
setName(name);
setMemberRefStyle(memberRefStyle);
}
public MemberRef() {
}
public void setName(Identifier name) {
this.name = changeValue(this, this.name, name);
}
public Identifier getName() {
return name;
}
public void setTarget(Expression target) {
this.target = changeValue(this, this.target, target);
}
public Expression getTarget() {
return target;
}
public void setMemberRefStyle(MemberRefStyle memberRefStyle) {
this.memberRefStyle = memberRefStyle;
}
public MemberRefStyle getMemberRefStyle() {
return memberRefStyle;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getTarget())
setTarget((Expression)by);
if (child == getName())
setName((Identifier)by);
return super.replaceChild(child, by);
}
@Override
public void accept(Visitor visitor) {
visitor.visitMemberRef(this);
}
@Override
public Element getNextChild(Element child) {
// TODO Auto-generated method stub
return null;
}
@Override
public Element getPreviousChild(Element child) {
// TODO Auto-generated method stub
return null;
}
}
public static class NewArray extends Expression {
TypeRef type;
boolean isAnnotationValue;
List<Expression> dimensions = new ArrayList<Expression>();
List<Expression> initialValues = new ArrayList<Expression>();
public NewArray() {}
public NewArray(TypeRef type, List<Expression> dimensions, List<Expression> initialValues) {
setType(type);
setDimensions(dimensions);
setInitialValues(initialValues);
}
public static NewArray newAnnotationArrayValue(List<Expression> initialValues) {
NewArray a = new NewArray(null, Collections.EMPTY_LIST, initialValues);
a.setAnnotationValue(true);
return a;
}
public boolean isAnnotationValue() {
return isAnnotationValue;
}
public void setAnnotationValue(boolean value) {
isAnnotationValue = value;
}
public List<Expression> getDimensions() {
return unmodifiableList(dimensions);
}
public void addDimension(Expression dimension) {
if (dimension == null)
return;
dimension.setParentElement(this);
dimensions.add(dimension);
}
public void setDimensions(List<Expression> dimensions) {
changeValue(this, this.dimensions, dimensions);
}
public List<Expression> getInitialValues() {
return unmodifiableList(initialValues);
}
public void setInitialValues(List<Expression> initialValues) {
changeValue(this, this.initialValues, initialValues);
}
public TypeRef getType() {
return type;
}
public void setType(TypeRef type) {
this.type = changeValue(this, this.type, type);
}
@Override
public void accept(Visitor visitor) {
visitor.visitNewArray(this);
}
@Override
public Element getNextChild(Element child) {
Element e = getNextSibling(dimensions, child);
if (e == null)
e = getNextSibling(initialValues, child);
return e;
}
@Override
public Element getPreviousChild(Element child) {
Element e = getPreviousSibling(dimensions, child);
if (e == null)
e = getPreviousSibling(initialValues, child);
return e;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getType()) {
setType((TypeRef)by);
return true;
}
return
replaceChild(initialValues, Expression.class, this, child, by) ||
replaceChild(dimensions, Expression.class, this, child, by) ||
super.replaceChild(child, by);
}
}
public static class New extends Expression {
TypeRef type;
FunctionCall construction;
public New(TypeRef type) {
setType(type);
}
public New(TypeRef type, FunctionCall construction) {
setType(type);
setConstruction(construction);
}
public New(TypeRef type, Expression... arguments) {
setType(type);
setConstruction(new FunctionCall(null, arguments));
}
public New(TypeRef type, List<Expression> arguments) {
this(type, arguments.toArray(new Expression[arguments.size()]));
}
public New() {}
public void setType(TypeRef type) {
this.type = changeValue(this, this.type, type);
}
public TypeRef getType() {
return type;
}
public void setConstruction(FunctionCall construction) {
this.construction = changeValue(this, this.construction, construction);
}
public FunctionCall getConstruction() {
return construction;
}
@Override
public void accept(Visitor visitor) {
visitor.visitNew(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getType()) {
setType((TypeRef) by);
return true;
}
if (child == getConstruction()) {
setConstruction((FunctionCall) by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class FunctionCall extends MemberRef {
Expression function;
//String functionName;
List<Pair<String, Expression>> arguments = new ArrayList<Pair<String, Expression>>();
public List<Pair<String, Expression>> getArguments() {
return unmodifiableList(arguments);
}
public void setArguments(List<Pair<String, Expression>> arguments) {
for (Pair<String, Expression> p : this.arguments)
p.getSecond().setParentElement(null);
this.arguments.clear();
for (Pair<String, Expression> p : arguments)
addArgument(p.getFirst(), p.getSecond());
}
public FunctionCall(Expression function) {
setFunction(function);
}
public FunctionCall(Expression function, Expression... unnamedArgs) {
setFunction(function);
for (Expression x : unnamedArgs)
if (x != null)
addArgument(x);
}
public FunctionCall(Expression target, Expression function, MemberRefStyle memberRefStyle, Expression... unnamedArgs) {
setTarget(target);
setFunction(function);
setMemberRefStyle(memberRefStyle);
for (Expression x : unnamedArgs)
addArgument(x);
}
public FunctionCall() {
}
public void addArgument(Expression ex) {
addArgument(null, ex);
}
public void addArguments(List<Expression> ex) {
for (Expression x : ex)
addArgument(null, x);
}
public void addArgument(String argumentSelector, Expression ex) {
if (ex == null)
return;
ex.setParentElement(this);
arguments.add(new Pair<String, Expression>(argumentSelector, ex));
}
public Expression getFunction() {
return function;
}
public void setFunction(Expression function) {
this.function = changeValue(this, this.function, function);
}
@Override
public void accept(Visitor visitor) {
visitor.visitFunctionCall(this);
}
protected int indexOf(Element x, List<Pair<String, Expression>> list) {
int i = 0;
for (Pair<String, Expression> p : list) {
if (p.getValue() == x)
return i;
i++;
}
return -1;
}
@Override
public Element getNextChild(Element child) {
int i = indexOf(child, arguments);
if (i >= 0) {
return i < arguments.size() - 1 ? arguments.get(i + 1).getValue() : null;
}
return null;
}
@Override
public Element getPreviousChild(Element child) {
int i = indexOf(child, arguments);
if (i >= 0) {
return i > 0 ? arguments.get(i - 1).getValue() : null;
}
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getTarget()) {
setTarget((Expression) by);
return true;
}
if (child == getFunction()) {
setFunction((Expression) by);
return true;
}
//return replaceChild(arguments, Expression.class, this, child, by);
int i = indexOf(child, arguments);
if (i >= 0) {
Expression old;
if (by == null)
old = arguments.remove(i).getValue();
else
old = arguments.get(i).setValue((Expression)by);
if (old != by) {
if (old != null)
old.setParentElement(null);
if (by != null)
by.setParentElement(this);
}
return true;
}
return super.replaceChild(child, by);
}
}
public static class ArrayAccess extends Expression {
Expression target, index;
public ArrayAccess() {}
public ArrayAccess(Expression target, Expression index) {
setTarget(target);
setIndex(index);
}
public Expression getTarget() {
return target;
}
public void setTarget(Expression target) {
this.target = changeValue(this, this.target, target);
}
public void setIndex(Expression index) {
this.index = changeValue(this, this.index, index);
}
public Expression getIndex() {
return index;
}
@Override
public void accept(Visitor visitor) {
visitor.visitArrayAccess(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getTarget()) {
setTarget((Expression)by);
return true;
}
if (child == getIndex()) {
setIndex((Expression)by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class VariableRef extends Expression {
Identifier name;
public VariableRef(Identifier name) {
setName(name);
}
public VariableRef() {
}
public Identifier getName() {
return name;
}
public void setName(Identifier name) {
this.name = changeValue(this, this.name, name);
}
@Override
public void accept(Visitor visitor) {
visitor.visitVariableRef(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getName()) {
setName((Identifier) by);
return true;
}
return super.replaceChild(child, by);
}
}
public enum BinaryOperator implements Operator {
Assign("="),
Arrow("->"),
ArrowStar("->*"),
SquareBrackets("[]"),
Comma(","),
Plus("+"), Minus("-"), Divide("/"), Multiply("*"), Modulo("%"), LeftShift("<<"), RightShift(">>"), SignedRightShift(">>>"), XOR("^"),
LessEqual("<=", true), GreaterEqual(">=", true), Less("<", true), Greater(">", true), IsEqual("==", true), IsDifferent("!=", true),
BitOr("|"), Or("||", true), BitAnd("&"), And("&&", true);
final String s;
public final boolean givesBool;
BinaryOperator(String s) {
this(s, false);
}
BinaryOperator(String s, boolean givesBool) {
this.s = s;
this.givesBool = givesBool;
}
@Override
public String toString() {
return s;
}
};
public interface Operator {
}
public enum AssignmentOperator implements Operator {
Equal("=", null),
MultiplyEqual("*=", BinaryOperator.Multiply),
DivideEqual("/=", BinaryOperator.Divide),
ModuloEqual("%=", BinaryOperator.Modulo),
PlusEqual("+=", BinaryOperator.Plus),
MinusEqual("-=", BinaryOperator.Minus),
LeftShiftEqual("<<=", BinaryOperator.LeftShift),
RightShiftEqual(">>=", BinaryOperator.RightShift),
SignedRightShiftEqual(">>>=", BinaryOperator.SignedRightShift),
BitAndEqual("&=", BinaryOperator.BitAnd),
XOREqual("^=", BinaryOperator.XOR),
//ComplementEqual("~=", BinaryOperator.C),
BitOrEqual("|=", BinaryOperator.BitOr);
String s;
AssignmentOperator(String s, BinaryOperator correspondingBinaryOp) {
this.s = s;
this.correspondingBinaryOp = correspondingBinaryOp;
}
@Override
public String toString() {
return s;
}
BinaryOperator correspondingBinaryOp;
public BinaryOperator getCorrespondingBinaryOp() {
return correspondingBinaryOp;
}
}
public enum UnaryOperator implements Operator {
Not("!"),
Minus("-"),
Parenthesis("()"),
Complement("~"),
Reference("&"),
Dereference("*"),
PreIncr("++"),
PreDecr("--"),
PostIncr("++"),
PostDecr("--");
String s;
UnaryOperator(String s) {
this.s = s;
}
@Override
public String toString() {
return s;
}
};
static final Map<String, AssignmentOperator> assignOps = new LinkedHashMap<String, AssignmentOperator>();
static final Map<String, BinaryOperator> binOps = new LinkedHashMap<String, BinaryOperator>();
static final Map<String, UnaryOperator> unOps = new LinkedHashMap<String, UnaryOperator>();
static final Map<AssignmentOperator, String> assignOpsRev = new LinkedHashMap<AssignmentOperator, String>();
static final Map<BinaryOperator, String> binOpsRev = new LinkedHashMap<BinaryOperator, String>();
static final Map<UnaryOperator, String> unOpsRev = new LinkedHashMap<UnaryOperator, String>();
//public static final Expression EMPTY_EXPRESSION = new Constant(null, null, "");
static {
for (AssignmentOperator op : AssignmentOperator.values())
map(assignOps, assignOpsRev, op.toString(), op);
for (UnaryOperator op : UnaryOperator.values())
map(unOps, unOpsRev, op.toString(), op);
for (BinaryOperator op : BinaryOperator.values())
map(binOps, binOpsRev, op.toString(), op);
}
static <K, V> void map(Map<K, V> m, Map<V, K> r, K k, V v) {
m.put(k, v);
r.put(v, k);
}
public static BinaryOperator getBinaryOperator(String s) {
return binOps.get(s);
}
public static AssignmentOperator getAssignmentOperator(String s) {
AssignmentOperator op = assignOps.get(s);
if (op == null)
throw new RuntimeException("Failed to parse op " + s);
return op;
}
public static UnaryOperator getUnaryOperator(String s) {
UnaryOperator op = unOps.get(s);
if (op == null)
throw new RuntimeException("Failed to parse op " + s);
return op;
}
public static java.lang.Enum<?> getAnyOperator(String s) {
java.lang.Enum<?> e = binOps.get(s);//Expression.getBinaryOperator(s);
if (e != null)
return e;
e = unOps.get(s);//Expression.getUnaryOperator(s);
if (e != null)
return e;
return Expression.getAssignmentOperator(s);
}
public static class NullExpression extends Expression {
@Override
public void accept(Visitor visitor) {
visitor.visitNullExpression(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
}
public static class ConditionalExpression extends Expression {
Expression test, thenValue, elseValue;
public ConditionalExpression() {}
public ConditionalExpression(Expression test, Expression thenValue, Expression elseValue) {
setTest(test);
setThenValue(thenValue);
setElseValue(elseValue);
}
public Expression getTest() {
return test;
}
public void setTest(Expression test) {
this.test = changeValue(this, this.test, test);
}
public Expression getThenValue() {
return thenValue;
}
public void setThenValue(Expression thenValue) {
this.thenValue = changeValue(this, this.thenValue, thenValue);
}
public Expression getElseValue() {
return elseValue;
}
public void setElseValue(Expression elseValue) {
this.elseValue = changeValue(this, this.elseValue, elseValue);
}
@Override
public void accept(Visitor visitor) {
visitor.visitConditionalExpression(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getTest()) {
setTest((Expression)by);
return true;
}
if (child == getThenValue()) {
setThenValue((Expression)by);
return true;
}
if (child == getElseValue()) {
setElseValue((Expression)by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class Cast extends Expression {
TypeRef type;
Expression target;
public Cast(TypeRef type, Expression target) {
setTarget(target);
setType(type);
}
public Cast() {
}
public void setTarget(Expression target) {
this.target = changeValue(this, this.target, target);
}
public void setType(TypeRef type) {
this.type = changeValue(this, this.type, type);
}
public Expression getTarget() {
return target;
}
public TypeRef getType() {
return type;
}
@Override
public void accept(Visitor visitor) {
visitor.visitCast(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getTarget()) {
setTarget((Expression)by);
return true;
}
if (child == getType()) {
setType((TypeRef)by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class AssignmentOp extends Expression {
Expression target, value;
AssignmentOperator operator;
public AssignmentOp() {
}
public AssignmentOp(Expression target, AssignmentOperator operator, Expression value) {
if (operator == null)
throw new NullPointerException();
setValue(value);
setTarget(target);
setOperator(operator);
}
public AssignmentOperator getOperator() {
return operator;
}
public void setOperator(AssignmentOperator operator) {
this.operator = operator;
}
public Expression getValue() {
return value;
}
public Expression getTarget() {
return target;
}
public void setValue(Expression value) {
this.value = changeValue(this, this.value, value);
}
public void setTarget(Expression target) {
this.target = changeValue(this, this.target, target);
}
@Override
public void accept(Visitor visitor) {
visitor.visitAssignmentOp(this);
}
@Override
public Element getNextChild(Element child) {
if (child == getTarget())
return getValue();
return null;
}
@Override
public Element getPreviousChild(Element child) {
if (child == getValue())
return getTarget();
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getTarget()) {
setTarget((Expression) by);
return true;
}
if (child == getValue()) {
setValue((Expression) by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class BinaryOp extends Expression {
BinaryOperator operator;
Expression firstOperand, secondOperand;
public BinaryOp(Expression firstOperand, BinaryOperator operator, Expression secondOperand) {
if (operator == null)
throw new NullPointerException();
setOperator(operator);
setFirstOperand(firstOperand);
setSecondOperand(secondOperand);
}
public BinaryOp() {
}
public void setOperator(BinaryOperator operator) {
this.operator = operator;
}
public Expression getSecondOperand() {
return secondOperand;
}
public Expression getFirstOperand() {
return firstOperand;
}
public void setSecondOperand(Expression secondOperand) {
this.secondOperand = changeValue(this, this.secondOperand, secondOperand);
}
public void setFirstOperand(Expression firstOperand) {
this.firstOperand = changeValue(this, this.firstOperand, firstOperand);
}
public BinaryOperator getOperator() {
return operator;
}
@Override
public void accept(Visitor visitor) {
visitor.visitBinaryOp(this);
}
@Override
public Element getNextChild(Element child) {
if (child == getFirstOperand())
return getSecondOperand();
return null;
}
@Override
public Element getPreviousChild(Element child) {
if (child == getSecondOperand())
return getFirstOperand();
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getFirstOperand()) {
setFirstOperand((Expression) by);
return true;
}
if (child == getSecondOperand()) {
setSecondOperand((Expression) by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class UnaryOp extends Expression {
UnaryOperator operator;
Expression operand;
public UnaryOp(Expression operand, UnaryOperator operator) {
setOperand(operand);
setOperator(operator);
}
public UnaryOp() {
}
public Expression getOperand() {
return operand;
}
public void setOperator(UnaryOperator operator) {
this.operator = operator;
}
public void setOperand(Expression operand) {
this.operand = changeValue(this, this.operand, operand);
}
public UnaryOperator getOperator() {
return operator;
}
@Override
public void accept(Visitor visitor) {
visitor.visitUnaryOp(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getOperand()) {
setOperand((Expression) by);
return true;
}
return super.replaceChild(child, by);
}
}
public static class Constant extends Expression {
public enum Type {
Int, String, Char, IntegerString, Float, Short, Byte, Long, UInt, Double, LongString, ULong, Bool, Null
}
public enum IntForm {
Hex, Octal, String, Decimal
}
Type type;
IntForm intForm;
Object value;
String originalTextualRepresentation;
public Constant(Type type, IntForm intForm, Object value, String originalTextualRepresentation) {
if (value == null)
throw new NullPointerException();
setType(type);
setIntForm(intForm);
setValue(value);
setOriginalTextualRepresentation(originalTextualRepresentation);
checkType();
}
public Constant(Type type, Object value, String originalTextualRepresentation) {
setType(type);
setValue(value);
setOriginalTextualRepresentation(originalTextualRepresentation);
checkType();
}
public void setOriginalTextualRepresentation(String originalTextualRepresentation) {
this.originalTextualRepresentation = originalTextualRepresentation;
}
public String getOriginalTextualRepresentation() {
return originalTextualRepresentation;
}
void checkType() {
if (type == null)
return;
Object value = getValue();
switch (type) {
case Int:
case UInt:
case IntegerString:
value = (Integer)value;
break;
case ULong:
case Long:
case LongString:
value = (Long)value;
break;
case Char:
value = (Character)value;
break;
case Double:
value = (Double)value;
break;
case Float:
value = (Float)value;
break;
case String:
value = (String)value;
break;
case Bool:
value = (Boolean)value;
}
}
public static Constant newNull() {
return new Constant(Constant.Type.Null, null, null);
}
public void setIntForm(IntForm intForm) {
this.intForm = intForm;
}
public IntForm getIntForm() {
return intForm;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public Constant() {
}
/*
public Constant fromString(String s) {
String v = s.toUpperCase();
Type type = null;
if (v.startsWith("\""))
type = Type.String;
else if (v.startsWith("'"))
type = v.length()Type.String;
else if (v.contains(".")) {
if (v.endsWith("L"))
c = Float.TYPE;
else
c = Double.TYPE;
} else if (v.endsWith("L"))
c = Long.TYPE;
else if (v.endsWith("F"))
c = Float.TYPE;
else if (v.endsWith("D"))
c = Double.TYPE;
else {
//TODO try to parse as long and if it fails as integer, use Long.TYPE
c = Integer.TYPE;
}
}*/
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
static String intStr(int intVal) {
return String.valueOf((char)(0xff & (intVal >> 24))) +
((char)(0xff & (intVal >> 16)))+
((char)(0xff & (intVal >> 8)))+
((char)(0xff & (intVal)))
;
}
public void accept(Visitor visitor) {
visitor.visitConstant(this);
}
@Override
public Element getNextChild(Element child) {
return null;
}
@Override
public Element getPreviousChild(Element child) {
return null;
}
public Integer asInteger() {
switch (getType()) {
case Int:
case IntegerString:
return (Integer)value;
}
throw new ClassCastException("Constant " + getValue() + " is not an integer, but a " + getType());
}
public static Constant parseCharOrStringInteger(final String orig) {
String string = orig;
int len = string.length();
if (len <= 2 || string.charAt(0) != '\'' || string.charAt(len - 1) != '\'')
throw new IllegalArgumentException("Expecting char or integer string, got " + string);
string = string.substring(1, len - 1);
len -= 2;
if (len == 4) {
boolean isIntegerString = true;
for (int i = len; i-- != 0;) {
if (string.charAt(i) == '\\') {
isIntegerString = false;
break;
}
}
if (isIntegerString) {
long result = 0;
for (int i = 0; i < len; i++) {
result = result << 8 | (int)string.charAt(i);
}
if (len == 4)
return new Constant(Type.IntegerString, IntForm.String, (int)result, orig);
else
return new Constant(Type.LongString, IntForm.String, result, orig);
}
}
String parsed = parseNakedString(string);
if (parsed.length() != 1) {
throw new IllegalArgumentException("Expected char, go string of length " + parsed.length() + ": '" + parsed + "'");
}
return new Constant(Type.Char, parsed.charAt(0), orig);
}
public static Constant parseChar(final String orig) {
String string = orig;
int len = string.length();
if (len <= 2 || string.charAt(0) != '\'' || string.charAt(len - 1) != '\'')
throw new IllegalArgumentException("Expecting char, got " + string);
string = string.substring(1, len - 1);
return new Constant(Type.Char, parseNakedString(string).charAt(0), orig);
}
private static String parseNakedString(String string) {
//return StringUtils.javaUnEscape(string)
int len = string.length();
StringBuffer b = new StringBuffer(len);
for (int i = 0; i < len;) {
char c = string.charAt(i++);
if (c == '\\') {
c = string.charAt(i++);
switch (c) {
case 't':
b.append('\t');
break;
case 'n':
b.append('\n');
break;
case 'r':
b.append('\r');
break;
case 'f':
b.append('\f');
break;
case 'b':
b.append('\b');
break;
case '\\':
b.append('\\');
break;
case '"':
b.append('"');
break;
case '\'':
b.append('\'');
break;
case 'u':
if (i < (len - 3)) {
b.append((char)Integer.parseInt(string.substring(i, i + 4), 16));
i += 4;
}
break;
case '0':
b.append('\0');
break;
default:
if (Character.isDigit(c)) {
int start = i - 1;
int end = i;
while (end < len && Character.isDigit(string.charAt(end))) {
end++;
}
b.append((char)Integer.parseInt(string.substring(start, end), 8));
i = end;
}
}
} else {
b.append(c);
}
}
return b.toString();
}
public static Constant parseStringInteger(final String orig) {
String string = orig;
int len = string.length();
if (len <= 2 || string.charAt(0) != '\'' || string.charAt(len - 1) != '\'' || ((len -= 2) != 4 && len != 8))
throw new IllegalArgumentException("Expecting 'xxxx' or 'xxxxxxxx', got " + string);
string = string.substring(1, len - 1);
long result = 0;
for (int i = len; i-- != 0;) {
result = result << 8 | (int)string.charAt(i);
}
if (len == 4)
return new Constant(Type.Int, IntForm.String, (int)result, orig);
else
return new Constant(Type.Long, IntForm.String, result, orig);
}
public static Constant parseString(final String orig) {
String string = orig;
int len = string.length();
if (len < 2 || string.charAt(0) != '"' || string.charAt(len - 1) != '"')
throw new IllegalArgumentException("Expecting string, got " + string);
string = string.substring(1, len - 1);
return new Constant(Type.String, parseNakedString(string), orig);
}
public static Constant string(final String s) {
return new Constant(Type.String, s, s);
}
public static Constant parseDecimal(String string) {
return parseInteger(string, 10, IntForm.Decimal, false);
}
public static Constant parseInteger(final String string, int radix, IntForm form, boolean negate) {
return parseInteger(string, radix, form, negate, string);
}
public static Constant parseInteger(String string, int radix, IntForm form, boolean negate, final String orig) {
string = string.trim().toLowerCase();
if (string.startsWith("+"))
string = string.substring(1);
Type tpe = Type.Int;
boolean unsigned = false;
char c;
while (string.length() > 0 &&
((c = string.charAt(string.length() - 1)) == 'u' || c == 'i' || c == 'l' || c == 's')) {
if (string.endsWith("ll") || string.endsWith("li")) {
tpe = Type.Long;
string = string.substring(0, string.length() - 2);
} else if (string.endsWith("l") /*) {
tpe = Type.Long;
string = string.substring(0, string.length() - 1);
} else if (*/ || string.endsWith("i")) {
string = string.substring(0, string.length() - 1);
} else if (string.endsWith("s")) {
tpe = Type.Short;
string = string.substring(0, string.length() - 1);
} else if (string.endsWith("u")) {
unsigned = true;
string = string.substring(0, string.length() - 1);
}
}
Object value;
if (string.equals("ffffffffffffffff")) {
tpe = Type.Long;
value = 0xffffffffffffffffL;
} else {
long longValue;
if (tpe == Type.Long && unsigned || string.length() == 16) {
longValue = new BigInteger(string, radix).longValue();
} else {
longValue = Long.parseLong(string, radix);
}
switch (tpe) {
case Bool:
assert !negate;
value = (boolean)(longValue != 0);
break;
case Byte:
if (longValue > Byte.MAX_VALUE || longValue < 2 * Byte.MIN_VALUE) {
tpe = Type.Short;
value = (short)(negate ? -longValue : longValue);
} else {
byte v = (byte)(longValue & 0xff);
value = negate ? -v : v;
}
break;
case Char:
assert !negate;
value = (char)(longValue & 0xffff);
break;
case Short:
if (longValue > 2 * Short.MAX_VALUE || longValue < 2 * Short.MIN_VALUE) {
tpe = Type.Int;
value = (int)(negate ? -longValue : longValue);
} else {
short v = (short)(longValue & 0xffff);
value = negate ? -v : v;
}
break;
case Int:
if (longValue > 2L * Integer.MAX_VALUE || longValue < 2L * Integer.MIN_VALUE) {
tpe = Type.Long;
value = negate ? -longValue : longValue;
} else {
if (longValue > Integer.MAX_VALUE || longValue < Integer.MIN_VALUE)
tpe = Type.UInt;
int v = (int)(longValue & 0xffffffff);
value = negate ? -v : v;
}
break;
case Long:
value = negate ? -longValue : longValue;
break;
default:
throw new UnsupportedOperationException("Can't parse decimal of type " + tpe);
}
}
if (unsigned || form == IntForm.Hex) {
switch (tpe) {
case Int:
tpe = Type.UInt;
break;
case Long:
tpe = Type.ULong;
break;
// TODO: handle UShort, UByte
}
}
return new Constant(tpe, form, value, orig);
}
public static Constant parseHex(final String orig, boolean negate) {
String string = orig;
string = string.trim().toLowerCase();
if (!string.startsWith("0x"))
throw new IllegalArgumentException("Expected hex literal, got " + string);
try {
return parseInteger(string.substring(2), 16, IntForm.Hex, negate, orig);
} catch (NumberFormatException ex) {
throw new NumberFormatException("Parsing hex : \"" + string +"\"");
}
}
public static Constant parseOctal(String string, boolean negate) {
string = string.trim().toLowerCase();
if (!string.startsWith("0"))
throw new IllegalArgumentException("Expected octal literal, got " + string);
return parseInteger(string.substring(1), 8, IntForm.Octal, negate);
}
public static Constant parseFloat(final String orig) {
String string = orig;
string = string.trim().toLowerCase();
if (string.length() > 0) {
int lm1 = string.length() - 1;
char c = string.charAt(lm1);
if (Character.isLetter(c)) {
String beg = string.substring(0, lm1);
if (c == 'f')
return new Constant(Type.Float, Float.parseFloat(beg), orig);
}
}
return new Constant(Type.Double, Double.parseDouble(string), orig);
}
static final String[] trailingTypeInfos = new String[] { "ll", "li", "l", "s", "u" };
static String trimTrailingTypeInfo(String s) {
if (s == null)
return null;
while (s.length() > 0) {
switch (Character.toLowerCase(s.charAt(s.length() - 1))) {
case 'u':
case 'l':
case 'i':
case 's':
s = s.substring(0, s.length() - 1);
break;
default:
return s;
}
}
return s;
}
public Constant asJava() {
Type type = getType();
String txt = originalTextualRepresentation;
switch (type) {
case Byte:
case Int:
case Long:
case LongString:
case Short:
txt = trimTrailingTypeInfo(txt);
break;
case UInt:
if (intForm != IntForm.Hex && (getValue() instanceof Long) && ((Long)getValue()) > Integer.MAX_VALUE) {
txt = null;
break;
}
case ULong:
if (intForm == IntForm.Hex) {
txt = trimTrailingTypeInfo(txt);
break;
}
case IntegerString:
txt = null;
break;
}
switch (type) {
case Long:
case ULong:
if (txt != null)
txt += "L";
case LongString:
type = Type.Long;
break;
case UInt:
case IntegerString:
type = Type.Int;
break;
}
return new Constant(type, getValue(), txt);
}
}
}