// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.
package wyc.lang;
import static wyc.lang.WhileyFile.internalFailure;
import java.util.HashSet;
import wybs.lang.SyntaxError;
import wyc.lang.WhileyFile.Context;
import wycc.util.Pair;
import wyil.lang.Type;
public class Exprs {
/**
* Determine the set of variable names (and their types) used in a given expression.
*
* @param expr
* @param context
* @return
*/
public static HashSet<Pair<Type,String>> uses(Expr expr, Context context) {
HashSet<Pair<Type,String>> r = new HashSet<Pair<Type,String>>();
uses(expr,context,r);
return r;
}
private static void uses(Expr expr, Context context, HashSet<Pair<Type,String>> uses) {
try {
if (expr instanceof Expr.Constant) {
// do nout
} else if (expr instanceof Expr.LocalVariable) {
Expr.LocalVariable lv = (Expr.LocalVariable) expr;
uses.add(new Pair<Type,String>(lv.type,lv.var));
} else if (expr instanceof Expr.ConstantAccess) {
// do nout
} else if (expr instanceof Expr.ArrayInitialiser) {
Expr.ArrayInitialiser e = (Expr.ArrayInitialiser) expr;
for(Expr p : e.arguments) {
uses(p, context, uses);
}
} else if (expr instanceof Expr.BinOp) {
Expr.BinOp e = (Expr.BinOp) expr;
uses(e.lhs, context, uses);
uses(e.rhs, context, uses);
} else if (expr instanceof Expr.Dereference) {
Expr.Dereference e = (Expr.Dereference) expr;
uses(e.src, context, uses);
} else if (expr instanceof Expr.Cast) {
Expr.Cast e = (Expr.Cast) expr;
uses(e.expr, context, uses);
} else if (expr instanceof Expr.IndexOf) {
Expr.IndexOf e = (Expr.IndexOf) expr;
uses(e.src, context, uses);
uses(e.index, context, uses);
} else if (expr instanceof Expr.UnOp) {
Expr.UnOp e = (Expr.UnOp) expr;
uses(e.mhs, context, uses);
} else if (expr instanceof Expr.FunctionCall) {
Expr.FunctionCall e = (Expr.FunctionCall) expr;
for(Expr p : e.arguments) {
uses(p, context, uses);
}
} else if (expr instanceof Expr.MethodCall) {
Expr.MethodCall e = (Expr.MethodCall) expr;
for(Expr p : e.arguments) {
uses(p, context, uses);
}
} else if (expr instanceof Expr.IndirectFunctionCall) {
Expr.IndirectFunctionCall e = (Expr.IndirectFunctionCall) expr;
uses(e.src, context, uses);
for(Expr p : e.arguments) {
uses(p, context, uses);
}
} else if (expr instanceof Expr.IndirectMethodCall) {
Expr.IndirectMethodCall e = (Expr.IndirectMethodCall) expr;
uses(e.src, context, uses);
for(Expr p : e.arguments) {
uses(p, context, uses);
}
} else if (expr instanceof Expr.Quantifier) {
Expr.Quantifier e = (Expr.Quantifier) expr;
for(Pair<String,Expr> p : e.sources) {
uses(p.second(), context, uses);
}
uses(e.condition, context, uses);
} else if (expr instanceof Expr.FieldAccess) {
Expr.FieldAccess e = (Expr.FieldAccess) expr;
uses(e.src, context, uses);
} else if (expr instanceof Expr.Record) {
Expr.Record e = (Expr.Record) expr;
for(Expr p : e.fields.values()) {
uses(p, context, uses);
}
} else if (expr instanceof Expr.FunctionOrMethod) {
// do nout
} else if (expr instanceof Expr.New) {
Expr.New e = (Expr.New) expr;
uses(e.expr, context, uses);
} else {
// should be dead-code
internalFailure("unknown expression: "
+ expr.getClass().getName(), context, expr);
}
} catch (SyntaxError se) {
throw se;
} catch (Exception ex) {
internalFailure(ex.getMessage(), context, expr, ex);
}
}
/**
* Determine whether this expression is "pure" or not. A pure expression has
* no non-local side effects. More specifically, it does not contain: a
* direct (or indirect) invocation of a method; or, the construction of an
* object via new; or, finally, a dereference operation.
*
* @return
*/
public static boolean isPure(Expr expr, Context context) {
try {
if (expr instanceof Expr.Constant) {
return true;
} else if (expr instanceof Expr.LocalVariable) {
return true;
} else if (expr instanceof Expr.ConstantAccess) {
return true;
} else if (expr instanceof Expr.ArrayInitialiser) {
Expr.ArrayInitialiser e = (Expr.ArrayInitialiser) expr;
for(Expr p : e.arguments) {
if(!isPure(p, context)) {
return false;
}
}
return true;
} else if (expr instanceof Expr.BinOp) {
Expr.BinOp e = (Expr.BinOp) expr;
return isPure(e.lhs, context) && isPure(e.rhs, context);
} else if (expr instanceof Expr.Dereference) {
return false;
} else if (expr instanceof Expr.Cast) {
Expr.Cast e = (Expr.Cast) expr;
return isPure(e.expr, context);
} else if (expr instanceof Expr.IndexOf) {
Expr.IndexOf e = (Expr.IndexOf) expr;
return isPure(e.src, context) && isPure(e.index, context);
} else if (expr instanceof Expr.UnOp) {
Expr.UnOp e = (Expr.UnOp) expr;
return isPure(e.mhs, context);
} else if (expr instanceof Expr.FunctionCall) {
Expr.FunctionCall e = (Expr.FunctionCall) expr;
for(Expr p : e.arguments) {
if(!isPure(p, context)) {
return false;
}
}
return true;
} else if (expr instanceof Expr.MethodCall) {
return false;
} else if (expr instanceof Expr.IndirectFunctionCall) {
Expr.IndirectFunctionCall e = (Expr.IndirectFunctionCall) expr;
if (!isPure(e.src, context)) {
return false;
}
for(Expr p : e.arguments) {
if(!isPure(p, context)) {
return false;
}
}
return isPure(e.src, context);
} else if (expr instanceof Expr.IndirectMethodCall) {
return false;
} else if (expr instanceof Expr.Quantifier) {
Expr.Quantifier e = (Expr.Quantifier) expr;
for(Pair<String,Expr> p : e.sources) {
if(!isPure(p.second(), context)) {
return false;
}
}
return (e.condition == null || isPure(e.condition, context));
} else if (expr instanceof Expr.FieldAccess) {
Expr.FieldAccess e = (Expr.FieldAccess) expr;
return isPure(e.src, context);
} else if (expr instanceof Expr.Record) {
Expr.Record e = (Expr.Record) expr;
for(Expr p : e.fields.values()) {
if(!isPure(p, context)) {
return false;
}
}
return true;
} else if (expr instanceof Expr.FunctionOrMethod) {
Expr.FunctionOrMethod e = (Expr.FunctionOrMethod) expr;
// FIXME: need to expand this to be a functionOrMethod #667
return e.type instanceof Type.Function;
} else if (expr instanceof Expr.New) {
return false;
} else {
// should be dead-code
internalFailure("unknown expression: "
+ expr.getClass().getName(), context, expr);
return false; // deadcode
}
} catch (SyntaxError se) {
throw se;
} catch (Exception ex) {
internalFailure(ex.getMessage(), context, expr, ex);
return false; // deadcode
}
}
}