/* 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); }