/*
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.List;
import java.util.Map;
import java.util.TreeMap;
import com.ochafik.lang.jnaerator.parser.Function.Type;
/**
* @see <a href="http://msdn.microsoft.com/en-us/library/4x7sfztk(VS.80).aspx">MSDN Typedef Declarations</a>
* @author ochafik
*
*/
public abstract class Declarator extends ModifiableElement {
protected Expression defaultValue;
boolean parenthesized = false;
int bits = -1;
public int getBits() {
return bits;
}
public void setBits(int bits) {
this.bits = bits;
}
@Override
public Declarator clone() {
return (Declarator)super.clone();
}
public static interface MutableByDeclarator {
MutableByDeclarator clone();
}
public enum PointerStyle
{
Pointer { @Override public String toString() { return "*"; } },
Reference { @Override public String toString() { return "&"; } },
HatPointer { @Override public String toString() { return "^"; } };
static Map<String, PointerStyle> styles = new TreeMap<String, PointerStyle>();
static {
for (PointerStyle style : values())
styles.put(style.toString(), style);
}
public static PointerStyle parsePointerStyle(String s) {
return styles.get(s);
}
}
@Override
public Declarator addModifiers(Modifier... mds) {
return (Declarator)super.addModifiers(mds);
}
public abstract MutableByDeclarator mutateType(MutableByDeclarator t);
public final MutableByDeclarator mutateTypeKeepingParent(MutableByDeclarator type) {
if (type == null)
return null;
MutableByDeclarator mutated = mutateType(type);
if (mutated == null)
throw new RuntimeException("Mutation of " + type + " yielded NULL!");
((Element)mutated).setParentElement(((Element)type).getParentElement());
return mutated;
}
public static class DirectDeclarator extends Declarator {
public DirectDeclarator(String name, int bits, Expression defaultValue) {
setName(name);
setBits(bits);
setDefaultValue(defaultValue);
}
public DirectDeclarator(String name) {
setName(name);
}
public DirectDeclarator(String name, Expression defaultValue) {
setName(name);
setDefaultValue(defaultValue);
}
public DirectDeclarator() {}
String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public String resolveName() {
return getName();
}
public MutableByDeclarator mutateType(MutableByDeclarator type) {
if (type == null)
return null;
type = type.clone();
if (type instanceof Function) {
((Function)type).setName(new Identifier.SimpleIdentifier(getName()));
}
((Element)type).importDetails(this, false);
return type;
}
@Override
public void accept(Visitor visitor) {
visitor.visitDirectDeclarator(this);
}
@Override
public boolean replaceChild(Element child, Element by) {
return super.replaceChild(child, by);
}
@Override
public void propagateName(String name) {
setName(name);
}
}
public static abstract class TargettedDeclarator extends Declarator {
public TargettedDeclarator() {}
public TargettedDeclarator(Declarator target) {
setTarget(target);
}
Declarator target;
public Declarator getTarget() {
return target;
}
public void setTarget(Declarator target) {
this.target = changeValue(this, this.target, target);
}
@Override
public String resolveName() {
return getTarget() != null ? getTarget().resolveName() : null;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getTarget()) {
setTarget((Declarator)by);
return true;
}
return super.replaceChild(child, by);
}
@Override
public void propagateName(String name) {
if (getTarget() != null)
getTarget().propagateName(name);
else
setTarget(new DirectDeclarator(name));
}
}
public static class PointerDeclarator extends TargettedDeclarator {
Declarator.PointerStyle pointerStyle;
public PointerDeclarator() {}
public PointerDeclarator(Declarator target, Declarator.PointerStyle pointerStyle) {
super(target);
setPointerStyle(pointerStyle);
}
@Override
public void accept(Visitor visitor) {
visitor.visitPointerDeclarator(this);
}
@Override
public MutableByDeclarator mutateType(MutableByDeclarator type) {
if (type == null)
return null;
type = type.clone();
if (type instanceof Function) {
TypeRef fs = new TypeRef.FunctionSignature((Function)type).importDetails((Element)type, true);
type = (MutableByDeclarator) new TypeRef.Pointer(fs, getPointerStyle());
} else if (type instanceof TypeRef) {
type = (MutableByDeclarator) new TypeRef.Pointer((TypeRef)type, getPointerStyle()).importDetails((Element)type, true);
} else
throw new IllegalArgumentException(type.getClass().getName() + " cannot be mutated by pointer");
((Element)type).importDetails(this, false);
return getTarget() == null ? type : getTarget().mutateType(type);
}
public Declarator.PointerStyle getPointerStyle() {
return pointerStyle;
}
public void setPointerStyle(Declarator.PointerStyle pointerStyle) {
this.pointerStyle = pointerStyle;
}
}
public static class FunctionDeclarator extends TargettedDeclarator {
final List<Arg> args = new ArrayList<Arg>();
public FunctionDeclarator() {}
public FunctionDeclarator(Declarator target, List<Arg> args) {
setTarget(target);
setArgs(args);
}
@Override
public MutableByDeclarator mutateType(MutableByDeclarator type) {
/*if (type == null) {
System.out.println("mutating null type : " + this);
return null;
}*/
type = type == null ? null : type.clone();
if (type == null || type instanceof TypeRef) {
Function f = new Function();
f.importDetails(this, false);
f.setValueType((TypeRef)type);
f.setType(Type.CFunction);
f.setArgs(getArgs());
return getTarget().mutateType(f);
} else if (type instanceof Function) {
Function ff = (Function)type;
Function f = new Function();
f.importDetails(this, false);
f.setValueType(new TypeRef.FunctionSignature(ff));
f.setType(Type.CFunction);
f.setArgs(getArgs());
return getTarget().mutateType(f);
} else {
throw new IllegalArgumentException("Function declarator can only mutate type references ! (mutating \"" + type + "\" by \"" + this + "\")");
}
}
public List<Arg> getArgs() {
return unmodifiableList(args);
}
public void setArgs(List<Arg> args) {
changeValue(this, this.args, args);
}
@Override
public void accept(Visitor visitor) {
visitor.visitFunctionDeclarator(this);
}
@Override
public boolean replaceChild(Element child, Element by) {
if (replaceChild(args, Arg.class, this, child, by))
return true;
return super.replaceChild(child, by);
}
@Override
public Element getNextChild(Element child) {
Element e = getNextSibling(args, child);
if (e != null)
return e;
return super.getNextChild(child);
}
@Override
public Element getPreviousChild(Element child) {
Element e = getPreviousSibling(args, child);
if (e != null)
return e;
return super.getNextChild(child);
}
}
public static class ArrayDeclarator extends TargettedDeclarator {
protected final List<Expression> dimensions = new ArrayList<Expression>();
public ArrayDeclarator() {}
public ArrayDeclarator(Declarator target, List<Expression> dimensions) {
super(target);
setDimensions(dimensions);
}
public ArrayDeclarator(Declarator target, Expression... dimensions) {
this(target, Arrays.asList(dimensions));
}
@Override
public void accept(Visitor visitor) {
visitor.visitArrayDeclarator(this);
}
public void setDimensions(List<Expression> dimensions) {
changeValue(this, this.dimensions, dimensions);
}
public List<Expression> getDimensions() {
return unmodifiableList(dimensions);
}
public void addDimension(Expression ex) {
if (ex == null)
return;
dimensions.add(ex);
ex.setParentElement(this);
}
public MutableByDeclarator mutateType(MutableByDeclarator type) {
if (type == null)
return null;
type = type.clone();
if (type instanceof TypeRef)
type = new TypeRef.ArrayRef((TypeRef)type, deepClone(getDimensions()));
else if (type instanceof Function)
{
Function f = (Function)type;
f.setValueType(new TypeRef.ArrayRef(f.getValueType(), deepClone(getDimensions())));
type = f;
}
((Element)type).importDetails(this, false);
return target.mutateType(type);
}
@Override
public Element getNextChild(Element child) {
Element e = getNextSibling(dimensions, child);
if (e != null)
return null;
return super.getNextChild(child);
}
@Override
public Element getPreviousChild(Element child) {
Element e = getPreviousSibling(dimensions, child);
if (e != null)
return null;
return super.getPreviousChild(child);
}
@Override
public boolean replaceChild(Element child, Element by) {
if (super.replaceChild(child, by))
return true;
if (replaceChild(dimensions, Expression.class, this, child, by))
return true;
return super.replaceChild(child, by);
}
}
public void setDefaultValue(Expression defaultValue) {
this.defaultValue = changeValue(this, this.defaultValue, defaultValue);
}
public Expression getDefaultValue() {
return defaultValue;
}
@Override
public boolean replaceChild(Element child, Element by) {
if (child == getDefaultValue()) {
setDefaultValue((Expression) by);
return true;
}
return super.replaceChild(child, by);
}
public boolean isParenthesized() {
return parenthesized;
}
public void setParenthesized(boolean parenthesized) {
this.parenthesized = parenthesized;
}
public abstract String resolveName();
public abstract void propagateName(String name);
}