WALA/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/TranslatorToCAst.java

221 lines
6.2 KiB
Java

/*******************************************************************************
* Copyright (c) 2013 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package com.ibm.wala.cast.ir.translator;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
import com.ibm.wala.cast.tree.impl.CAstNodeTypeMapRecorder;
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
import com.ibm.wala.cast.tree.rewrite.CAstCloner;
import com.ibm.wala.cast.tree.rewrite.CAstRewriter;
import com.ibm.wala.cast.tree.rewrite.CAstRewriter.CopyKey;
import com.ibm.wala.cast.tree.rewrite.CAstRewriter.RewriteContext;
import com.ibm.wala.cast.tree.rewrite.CAstRewriterFactory;
import com.ibm.wala.util.WalaException;
import com.ibm.wala.util.warnings.Warning;
public interface TranslatorToCAst {
public <C extends RewriteContext<K>, K extends CopyKey<K>> void addRewriter(CAstRewriterFactory<C, K> factory, boolean prepend);
public class Error extends WalaException {
public final Set<Warning> warning;
public Error(Set<Warning> message) {
super(message.iterator().next().getMsg());
warning = message;
}
}
public CAstEntity translateToCAst() throws Error, IOException;
public interface WalkContext<C extends WalkContext<C, T>, T> {
/**
* get a mapping from CAstNodes to the scoped entities (e.g. functions or
* local classes) introduced by those nodes. Also maps <code>null</code> to
* those entities not corresponding to any node (e.g nested classes)
*/
Map<CAstNode, Collection<CAstEntity>> getScopedEntities();
/**
* associate a child entity with a given CAstNode, e.g. for a function declaration
*/
void addScopedEntity(CAstNode newNode, CAstEntity visit);
/**
* for recording control-flow relationships among the CAst nodes
*/
CAstControlFlowRecorder cfg();
/**
* for recording source positions
*/
CAstSourcePositionRecorder pos();
/**
* for recording types of nodes
*/
CAstNodeTypeMapRecorder getNodeTypeMap();
/**
* for a 'continue' style goto, return the control flow target
*/
T getContinueFor(String label);
/**
* for a 'break' style goto, return the control flow target
*/
T getBreakFor(String label);
}
public class RootContext <C extends WalkContext<C, T>, T> implements WalkContext<C, T> {
@Override
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
assert false;
return Collections.emptyMap();
}
@Override
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
assert false;
}
@Override
public CAstControlFlowRecorder cfg() {
assert false;
return null;
}
@Override
public CAstSourcePositionRecorder pos() {
assert false;
return null;
}
@Override
public CAstNodeTypeMapRecorder getNodeTypeMap() {
assert false;
return null;
}
@Override
public T getContinueFor(String label) {
assert false;
return null;
}
@Override
public T getBreakFor(String label) {
assert false;
return null;
}
}
public class DelegatingContext<C extends WalkContext<C, T>, T> implements WalkContext<C, T> {
protected final C parent;
protected DelegatingContext(C parent) {
this.parent = parent;
}
@Override
public CAstControlFlowRecorder cfg() {
return parent.cfg();
}
@Override
public CAstSourcePositionRecorder pos() {
return parent.pos();
}
@Override
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return parent.getNodeTypeMap();
}
@Override
public T getContinueFor(String label) {
return parent.getContinueFor(label);
}
@Override
public T getBreakFor(String label) {
return parent.getBreakFor(label);
}
@Override
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
parent.addScopedEntity(newNode, visit);
}
@Override
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return parent.getScopedEntities();
}
}
public static class DoLoopTranslator {
private final boolean replicateForDoLoops;
private final CAst Ast;
public DoLoopTranslator(boolean replicateForDoLoops, CAst ast) {
this.replicateForDoLoops = replicateForDoLoops;
Ast = ast;
}
public CAstNode translateDoLoop(CAstNode loopTest, CAstNode loopBody, CAstNode continueNode, CAstNode breakNode, WalkContext<?,?> wc) {
if (replicateForDoLoops) {
loopBody = Ast.makeNode(CAstNode.BLOCK_STMT, loopBody, continueNode);
CAstRewriter.Rewrite x = (new CAstCloner(Ast, false)).copy(loopBody, wc.cfg(), wc.pos(), wc.getNodeTypeMap(), null);
CAstNode otherBody = x.newRoot();
wc.cfg().addAll(x.newCfg());
wc.pos().addAll(x.newPos());
wc.getNodeTypeMap().addAll(x.newTypes());
return Ast.makeNode(CAstNode.BLOCK_STMT,
loopBody,
Ast.makeNode(CAstNode.LOOP, loopTest, otherBody),
breakNode);
} else {
CAstNode header = Ast.makeNode(CAstNode.LABEL_STMT, Ast.makeConstant("_do_label"), Ast.makeNode(CAstNode.EMPTY));
CAstNode loopGoto = Ast.makeNode(CAstNode.IFGOTO, loopTest);
wc.cfg().map(header, header);
wc.cfg().map(loopGoto, loopGoto);
wc.cfg().add(loopGoto, header, Boolean.TRUE);
return Ast.makeNode(CAstNode.BLOCK_STMT,
header,
Ast.makeNode(CAstNode.BLOCK_STMT, loopBody, continueNode),
loopGoto,
breakNode);
}
}
}
}