package nebula.lang;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import nebula.data.Entity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.objectweb.asm.Opcodes;
import com.google.common.base.Preconditions;
public class Compiler {
static abstract class AbstractRange extends Expression<Object> {
@Override
public Type getType() {
throw new UnsupportedOperationException("Index");
}
}
public static class Action implements Statement {
LinkedHashMap<String, Var> locals;
Statement st;
public Action(LinkedHashMap<String, Var> locals, Statement st) {
this.locals = locals;
this.st = st;
}
@Override
public void compile(CompilerBase compiler) {
st.compile(compiler);
}
@Override
public void scan(CompilerContext context) {
st.scan(context);
}
}
static class Arithmetic extends Expression<Object> {
final Expr<Object> e1;
final Expr<Object> e2;
final Operator op;
Arithmetic(final Operator op, final Expr<Object> e1, final Expr<Object> e2) {
this.e1 = e1;
this.e2 = e2;
this.op = op;
}
public void compile(CompilerBase compiler) {
compiler.arithmetic(op, e1, e2);
}
@Override
public Long eval() {
return (Long) e1.eval() + (Long) e2.eval();
}
@Override
public Type getType() {
return e1.getType();
}
@Override
public void scan(CompilerContext context) {
e1.scan(context);
e2.scan(context);
Type type1 = e1.getType();
Type type2 = e2.getType();
Preconditions.checkArgument(type1.getRawType() == type2.getRawType());
}
@Override
public String toString() {
return "(" + e1.toString() + " " + op.getSign() + " " + e2.toString() + ")";
}
}
static class Block implements Opcodes, Statement {
final List<Statement> statements;
Block(List<Statement> statements) {
this.statements = statements;
}
public void compile(CompilerBase compiler) {
compiler.block(statements);
}
@Override
public void scan(CompilerContext context) {
for (Statement st : statements) {
st.scan(context);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(1024);
sb.append("{");
for (Statement st : statements) {
sb.append(st);
}
sb.append("}");
return sb.toString();
}
}
// TODO Not realized CallStatment
static class CallStatment implements Opcodes, Statement {
final Expr<Object> value;
CallStatment(Expr<Object> value) {
this.value = value;
}
public void compile(CompilerBase compiler) {
compiler.call(value);
}
@Override
public void scan(CompilerContext context) {
value.scan(context);
}
@Override
public String toString() {
return value.toString() + ";";
}
}
// TODO Not realized CallStatment
static class IfStatment implements Opcodes, Statement {
final Expr<Object> expr;
final Statement stIf;
final Statement stElse;
IfStatment(Expr<Object> expr, final Statement stIf, final Statement stElse) {
this.expr = expr;
this.stIf = stIf;
this.stElse = stElse;
}
public void compile(CompilerBase compiler) {
if (stElse != null) {
compiler.stIf(expr, stIf, stElse);
} else {
compiler.stIf(expr, stIf);
}
}
@Override
public void scan(CompilerContext context) {
expr.scan(context);
stIf.scan(context);
if (stElse != null) stElse.scan(context);
}
@Override
public String toString() {
return "if(" + expr.toString() + ")" + stIf.toString() + (stElse != null ? stElse.toString() : "") + ";";
}
}
/**
* A logical "and" expression.
*/
static class Conditional extends LogicExpr {
final Expr<Boolean> e1;
final Expr<Boolean> e2;
final Operator op;
public Conditional(Operator op, Expr<Boolean> e1, Expr<Boolean> e2) {
this.op = op;
this.e1 = e1;
this.e2 = e2;
}
public void compile(CompilerBase compiler) {
compiler.conditional(op, e1, e2);
}
@Override
public void scan(CompilerContext context) {
e1.scan(context);
e2.scan(context);
}
@Override
public String toString() {
return "(" + e1.toString() + " " + op.getSign() + " " + e2.toString() + ")";
}
}
static class DatastoreGet extends Expression<Object> {
final String name;
final Expr<Object> repos;
Type type;
DatastoreGet(final Expr<Object> repos, final String name) {
this.repos = repos;
this.name = name;
}
@Override
public void compile(CompilerBase compiler) {
compiler.datastoreGet(repos, name);
}
@Override
public Type getType() {
return this.type;
}
@Override
public void scan(CompilerContext context) {
context.referRepos = true;
type = new ListType(context.resolveType(name));
}
}
static class DateCst extends Tempral<DateTime> {
DateCst(String text) {
super(DateTimeFormat.forPattern("yyyy-MM-dd"), text);
}
@Override
public void compile(CompilerBase compiler) {
compiler.constDate(super.value);
}
@Override
public Type getType() {
return BootstrapTypeLoader.DATE;
}
@Override
public void scan(CompilerContext context) {
}
}
static class DatetimeCst extends Tempral<DateTime> {
DatetimeCst(String text) {
super(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"), text);
}
@Override
public void compile(CompilerBase compiler) {
compiler.constDatetime(super.value);
}
@Override
public Type getType() {
return BootstrapTypeLoader.DATETIME;
}
@Override
public void scan(CompilerContext context) {
}
}
static class DecimalCst extends Expression<BigDecimal> {
final String text;
DecimalCst(String text) {
this.text = text;
}
public void compile(CompilerBase compiler) {
compiler.constDecimal(text);
}
@Override
public Type getType() {
return BootstrapTypeLoader.DECIMAL;
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return text;
}
}
static class Decrement extends UnaryArithmeticExpr {
Decrement(Expr<Object> e1) {
super(e1);
}
public void compile(CompilerBase compiler) {
compiler.decrement(e1);
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return "(--" + e1.toString() + ")";
}
}
// EntityActionComplier
// static class EntityExpressionAgent<T> implements EntityExpression {
// final Expr<T> expr;
// final Type type;
//
// EntityExpressionAgent(final Expr<T> expr, final Type type) {
// this.expr = expr;
// this.type = type;
// }
//
// @Override
// public T eval(Entity entity) {
// return null;
// }
//
// EntityExpression compile() {
// return exprreturn compiler.compile(expr, type);
// }
// }
abstract static class Expression<T> implements Opcodes, Expr<T> {
@Override
public T eval() {
throw new UnsupportedOperationException();
}
}
static class FieldOf extends Expression<Object> {
final Expr<Object> entity;
Type fieldType;
final String name;
FieldOf(Expr<Object> entity, String name) {
this.entity = entity;
this.name = name;
}
public void compile(CompilerBase compiler) {
compiler.getField(entity, name, fieldType);
}
@Override
public Type getType() {
return fieldType;
}
@Override
public void scan(CompilerContext context) {
if (context.isTopLevelGet) {
context.isTopLevelGet = false;
context.from = entity;
entity.scan(context);
Type type = entity.getType();
for (Field f : type.getFields()) {
if (f.name.equals(name)) {
this.fieldType = f.getType();
context.field = f;
break;
}
}
if(context.from instanceof VarRefer && "this".equals(((VarRefer)context.from).var.name)){
context.refFields.add(context.field);
}
context.isTopLevelGet = true;
} else {
entity.scan(context);
Type type = entity.getType();
for (Field f : type.getFields()) {
if (f.name.equals(name)) {
this.fieldType = f.getType();
context.field = f;
break;
}
}
}
}
@Override
public String toString() {
return entity.toString() + "." + name.toString();
}
}
static class Increment extends UnaryArithmeticExpr {
Increment(Expr<Object> e1) {
super(e1);
}
public void compile(CompilerBase compiler) {
compiler.increment(e1);
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return "(++" + e1.toString() + ")";
}
}
static class ListFilterByClause extends Expression<Object> {
final Expr<Object> clause;
final Expr<Object> list;
final List<Expr<Object>> params;
Type type;
ListFilterByClause(final Expr<Object> list, final Expr<Object> clause, final List<Expr<Object>> params) {
this.list = list;
this.clause = clause;
this.params = params;
}
@Override
public void compile(CompilerBase compiler) {
compiler.listFilterByClause(list, clause, params);
}
@Override
public Type getType() {
return list.getType();
}
@Override
public void scan(CompilerContext context) {
list.scan(context);
clause.scan(context);
for (Expr<Object> param : params) {
param.scan(context);
}
}
}
static class ListFilterByRanger extends Expression<Object> {
final Expr<Object> list;
final List<Expr<Object>> ranges;
ListFilterByRanger(final Expr<Object> list, final List<Expr<Object>> ranges) {
this.list = list;
this.ranges = ranges;
}
@Override
public void compile(CompilerBase compiler) {
compiler.listFilter(list, ranges);
}
@Override
public Type getType() {
return list.getType();
}
@Override
public void scan(CompilerContext context) {
list.scan(context);
for (Expr<Object> expr : ranges) {
expr.scan(context);
}
Preconditions.checkArgument(list.getType() instanceof ListType);
}
}
static class ListThis extends Expression<Object> {
final Expr<Object> list;
Type type;
ListThis(final Expr<Object> list) {
this.list = list;
}
@Override
public void compile(CompilerBase compiler) {
compiler.varRefer(new Var("this", type));
}
@Override
public Type getType() {
return this.type;
}
@Override
public void scan(CompilerContext context) {
Type listType = list.getType();
Preconditions.checkArgument(listType instanceof ListType);
type = ((ListType) list.getType()).getUnderlyType();
}
@Override
public String toString() {
return "this";
}
}
static class ListGetItemByIndexExpr extends Expression<Object> {
final RangeSingle index;
final Expr<Object> list;
Type type;
ListGetItemByIndexExpr(final Expr<Object> list, final RangeSingle index) {
this.list = list;
this.index = index;
}
@Override
public void compile(CompilerBase compiler) {
compiler.get(list, index.value);
}
@Override
public Type getType() {
return this.type;
}
@Override
public void scan(CompilerContext context) {
list.scan(context);
Type listType = list.getType();
Preconditions.checkArgument(listType instanceof ListType);
type = ((ListType) list.getType()).getUnderlyType();
Type indexType = index.value.getType();
Preconditions.checkArgument(indexType.getRawType() == RawTypes.Long);
}
}
abstract static class LogicExpr extends Expression<Boolean> {
@Override
public Type getType() {
return BootstrapTypeLoader.BOOLEAN;
}
}
static class LongCst extends Expression<Long> {
final Long value;
LongCst(String text) {
this.value = Long.parseLong(text);
}
public void compile(CompilerBase compiler) {
compiler.constLong(value);
}
@Override
public Type getType() {
return BootstrapTypeLoader.LONG;
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return String.valueOf(value);
}
}
// TODO Not realized MethodCall
static class MethodCall extends Expression<Object> implements Statement {
final Expr<Entity> e1;
final String name;
MethodCall(Expr<Entity> e1, String name) {
this.e1 = e1;
this.name = name;
}
public void compile(CompilerBase compiler) {
compiler.callMethod(e1, name);
}
@Override
public Type getType() {
// TODO Auto-generated method stub
return null;
}
@Override
public void scan(CompilerContext context) {
// Type type = e1.scan(context);
// for (Field f : type.getFields()) {
// if (f.name.equals(name)) {
// return f.getType();
// }
// }
// throw new RuntimeException("Cannot find field");
}
@Override
public String toString() {
return e1.toString() + "." + name.toString();
}
}
static class Negates extends UnaryArithmeticExpr {
Negates(Expr<Object> e1) {
super(e1);
}
public void compile(CompilerBase compiler) {
compiler.negates(e1);
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return "(-" + e1.toString() + ")";
}
}
/**
* A logical "not" expression.
*/
static class Not extends LogicExpr {
final Expr<Boolean> e1;
Not(Expr<Boolean> e1) {
this.e1 = e1;
}
public void compile(CompilerBase compiler) {
compiler.not(e1);
}
@Override
public void scan(CompilerContext context) {
Preconditions.checkArgument(e1.getType() == BootstrapTypeLoader.BOOLEAN);
}
@Override
public String toString() {
return "(!" + e1.toString() + ")";
}
}
static class ParamsRefer extends Expression<Object> {
final Expr<Object> in;
final int index;
final int params;
ParamsRefer(Expr<Object> in, int params, int index) {
this.in = in;
this.params = params;
this.index = index;
}
@Override
public void compile(CompilerBase compiler) {
compiler.paramsRefer(in, params, index);
}
@Override
public Type getType() {
return in.getType();
}
@Override
public void scan(CompilerContext context) {
in.scan(context);
}
@Override
public String toString() {
return "params[" + String.valueOf(index) + "]";
}
}
static class Positive extends UnaryArithmeticExpr {
Positive(Expr<Object> e1) {
super(e1);
}
public void compile(CompilerBase compiler) {
compiler.positive(e1);
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return "(+" + e1.toString() + ")";
}
}
static class PutField extends Expression<Object> implements Opcodes, Statement {
final Expr<Object> entity;
Type fieldType;
final String name;
final Expr<Object> value;
PutField(FieldOf field, Expr<Object> value) {
this.entity = field.entity;
this.name = field.name;
this.value = value;
}
public void compile(CompilerBase compiler) {
compiler.setField(entity, name, fieldType, value);
}
@Override
public Type getType() {
return fieldType;
}
@Override
public void scan(CompilerContext context) {
if (context.isTopLevelGet) {
context.isTopLevelGet = false;
entity.scan(context);
Type type = entity.getType();
for (Field f : type.getFields()) {
if (f.name.equals(name)) {
this.fieldType = f.getType();
context.field = f;
}
}
context.isTopLevelGet = true;
value.scan(context);
} else {
entity.scan(context);
Type type = entity.getType();
for (Field f : type.getFields()) {
if (f.name.equals(name)) {
this.fieldType = f.getType();
}
}
value.scan(context);
}
}
@Override
public String toString() {
return entity.toString() + "." + name.toString() + " = " + value.toString() + ";";
}
}
// TODO Not realized VarDefineField
static class PutVar implements Opcodes, Statement {
final Expr<Object> initExpr;
final Var var;
PutVar(Var var, Expr<Object> initExpr) {
this.var = var;
this.initExpr = initExpr;
}
public void compile(CompilerBase compiler) {
compiler.putVar(var, initExpr);
}
@Override
public void scan(CompilerContext context) {
initExpr.scan(context);
}
@Override
public String toString() {
return var.name + " = " + initExpr.toString() + ";";
}
}
static class Range extends AbstractRange {
final Expr<Object> from;
final Expr<Object> to;
Range(final Expr<Object> from, final Expr<Object> to) {
this.from = from;
this.to = to;
}
@Override
public void compile(CompilerBase compiler) {
compiler.makeRange_From_To(from, to);
}
@Override
public void scan(CompilerContext context) {
from.scan(context);
Preconditions.checkArgument(from.getType().getRawType() == RawTypes.Long);
to.scan(context);
Preconditions.checkArgument(to.getType().getRawType() == RawTypes.Long);
}
}
static class Range_0_To extends AbstractRange {
final Expr<Object> to;
Range_0_To(final Expr<Object> index) {
this.to = index;
}
@Override
public void compile(CompilerBase compiler) {
compiler.makeRange_0_To(to);
}
@Override
public void scan(CompilerContext context) {
to.scan(context);
}
}
static class Range_From_ extends AbstractRange {
final Expr<Object> from;
Range_From_(final Expr<Object> index) {
this.from = index;
}
@Override
public void compile(CompilerBase compiler) {
compiler.makeRange_From(from);
}
@Override
public void scan(CompilerContext context) {
from.scan(context);
Preconditions.checkArgument(from.getType().getRawType() == RawTypes.Long);
}
}
static class RangeSingle extends AbstractRange {
final Expr<Object> value;
RangeSingle(final Expr<Object> index) {
this.value = index;
}
@Override
public void compile(CompilerBase compiler) {
compiler.makeRangeIndex(value);
}
@Override
public void scan(CompilerContext context) {
this.value.scan(context);
}
}
/**
* An addition expression.
*/
static class Relational<V extends Comparable<V>> extends Expression<Boolean> implements Expr<Boolean> {
final Expr<V> e1;
final Expr<V> e2;
final Operator op;
Relational(final Operator op, Expr<V> e1, Expr<V> e2) {
this.op = op;
this.e1 = e1;
this.e2 = e2;
}
@Override
public void compile(CompilerBase compiler) {
compiler.relational(op, e1, e2);
}
@Override
public Type getType() {
return BootstrapTypeLoader.BOOLEAN;
}
@Override
public void scan(CompilerContext context) {
e1.scan(context);
e2.scan(context);
// Preconditions.checkArgument(e1.getType() ==
// BootstrapTypeLoader.BOOLEAN);
// Preconditions.checkArgument(e2.getType() ==
// BootstrapTypeLoader.BOOLEAN);
}
@Override
public String toString() {
return "(" + e1.toString() + " " + op.getSign() + " " + e2.toString() + ")";
}
}
static class StringCst extends Expression<String> {
final String value;
StringCst(String value) {
this.value = value;
}
public void compile(CompilerBase compiler) {
compiler.constString(value);
}
@Override
public Type getType() {
return BootstrapTypeLoader.STRING;
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return value;
}
}
abstract static class Tempral<T> extends Expression<T> {
final DateTimeFormatter formater;
final long value;
Tempral(DateTimeFormatter formater, String text) {
this.formater = formater;
this.value = formater.parseDateTime(text).getMillis();
}
Tempral(String text) {
this(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS"), text);
}
@Override
public String toString() {
return formater.print(value);
}
}
static class TimeCst extends Tempral<DateTime> {
TimeCst(String text) {
super(DateTimeFormat.forPattern("HH:mm:ss"), text);
}
@Override
public void compile(CompilerBase compiler) {
compiler.constTime(super.value);
}
@Override
public Type getType() {
return BootstrapTypeLoader.TIME;
}
@Override
public void scan(CompilerContext context) {
}
}
static class TimestampCst extends Tempral<DateTime> {
TimestampCst(String text) {
super(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS"), text);
}
@Override
public void compile(CompilerBase compiler) {
compiler.constTimestamp(super.value);
}
@Override
public Type getType() {
return BootstrapTypeLoader.TIMESTAMP;
}
@Override
public void scan(CompilerContext context) {
}
}
abstract static class UnaryArithmeticExpr extends Expression<Object> {
final Expr<Object> e1;
UnaryArithmeticExpr(final Expr<Object> e1) {
this.e1 = e1;
}
@Override
public Type getType() {
return e1.getType();
}
}
static class VarRefer extends Expression<Object> {
final Var var;
VarRefer(final Var var) {
this.var = var;
}
@Override
public void compile(CompilerBase compiler) {
compiler.varRefer(var);
}
@Override
public Type getType() {
return var.type;
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return var.name;
}
}
static class YesnoCst extends Expression<Integer> {
final int value;
YesnoCst(boolean v) {
if (v) this.value = 1;
else this.value = 0;
}
public void compile(CompilerBase compiler) {
compiler.constYesno(value);
}
@Override
public Type getType() {
// TODO Auto-generated method stub
return BootstrapTypeLoader.BOOLEAN;
}
@Override
public void scan(CompilerContext context) {
}
@Override
public String toString() {
return value == 1 ? "Yes" : "No";
}
}
// public final static int CONTEXT = 1;
//
public final static int PARAMS = 4;
//
// public final static int REPOS = 2;
//
// public final static int SYSTEM_THIS = 0;
//
// public final static int THIS = 3;
CompilerContext context;
EntityExpressionComplier exprCompiler = EntityExpressionComplier.DEFAULT;
Log log = LogFactory.getLog(Compiler.class);
EntityActionComplier stCompiler = EntityActionComplier.DEFAULT;
Compiler(CompilerContext context) {
this.context = context;
}
public Action action(LinkedHashMap<String, Var> locals, Statement st) {
return new Action(locals, st);
}
public <T> EntityExpression compile(Type type, String name, Expr<?> expr) {
expr.scan(context);
return exprCompiler.compile(type, name, expr);
}
public EntityAction compileToJavaBytecode(Type type, String name, Action action) {
action.scan(context);
return stCompiler.compile(context, type, name, action);
}
public Expr<Object> entities(Expr<Object> repos, String string) {
return new DatastoreGet(repos, string);
}
public Expr<Object> index(Expr<Object> from) {
return new RangeSingle(from);
}
public Expr<Object> list(Expr<Object> list, Expr<Object> clause, List<Expr<Object>> params) {
return new ListFilterByClause(list, clause, params);
}
public Expr<Object> list(Expr<Object> list, List<Expr<Object>> ranges) {
if (ranges.size() == 1 && ranges.get(0) instanceof RangeSingle) {
return new ListGetItemByIndexExpr(list, (RangeSingle) ranges.get(0));
} else {
return new ListFilterByRanger(list, ranges);
}
}
public Expr<Object> opArithmetic(Operator op, Expr<Object> e1, Expr<Object> e2) {
return new Arithmetic(op, e1, e2);
}
public Expr<Boolean> opConditional(Operator op, Expr<Boolean> e1, Expr<Boolean> e2) {
return new Conditional(op, e1, e2);
}
public Expr<DateTime> opDateCst(String value) {
return new DateCst(value);
}
public Expr<DateTime> opDatetimeCst(String value) {
return new DatetimeCst(value);
}
public Expr<BigDecimal> opDecimalCst(String value) {
return new DecimalCst(value);
}
public Expr<Object> opDecrement(Expr<Object> e1) {
return new Decrement(e1);
}
public Expr<Object> opFieldInList(Expr<Object> list, String name) {
return new FieldOf(new ListThis(list), name);
}
public Expr<Object> opFieldOf(Expr<Object> e1, String name) {
return new FieldOf(e1, name);
}
public Expr<Object> opIncrement(Expr<Object> e1) {
return new Increment(e1);
}
// Type resolveType(Type type, String name) {
// for (Field f : type.getFields()) {
// if (f.name.equals(name)) {
// return f.getType();
// }
// }
// throw new RuntimeException("Cannot find field");
// }
public Expr<Object> opLocal(Var var) {
return new VarRefer(var);
}
public Expr<Long> opLongCst(String value) {
return new LongCst(value);
}
public Expr<Object> opMethodCall(Expr<Entity> e1, String name) {
return new MethodCall(e1, name);
}
public Expr<Object> opNegates(Expr<Object> e1) {
return new Negates(e1);
}
public Expr<Boolean> opNot(Expr<Boolean> e1) {
return new Not(e1);
}
public Expr<Object> opParamsl(Expr<Object> e1, int i) {
return new ParamsRefer(e1, PARAMS, i);
}
public Expr<Object> opPositive(Expr<Object> e1) {
return new Positive(e1);
}
public <V extends Comparable<V>> Expr<Boolean> opRelational(Operator op, Expr<V> e1, Expr<V> e2) {
return new Relational<V>(op, e1, e2);
}
public Expr<String> opStringCst(String value) {
return new StringCst(value);
}
public Expr<DateTime> opTimeCst(String value) {
return new TimeCst(value);
}
public Expr<DateTime> opTimestampCst(String value) {
return new TimestampCst(value);
}
public Expr<Object> opUnit(Expr<Object> v, String string) {
// TODO Auto-generated method stub
return null;
}
public Expr<Integer> opYesnoCst(boolean b) {
return new YesnoCst(b);
}
public Expr<Object> range(Expr<Object> from, Expr<Object> to) {
if (from == null) {
return new Range_0_To(to);
} else if (to == null) {
return new Range_From_(from);
} else {
return new Range(from, to);
}
}
public Statement stBlock(List<Statement> statements) {
return new Block(statements);
}
public Statement stCall(Expr<Object> e1) {
return new CallStatment(e1);
}
public Statement stIf(Expr<Object> expr, final Statement stIf, final Statement stElse) {
return new IfStatment(expr, stIf, stElse);
}
public Statement stPut(Expr<Object> field, Expr<Object> value) {
return new PutField((FieldOf) field, value);
}
public Statement stPutVar(Var var, Expr<Object> initExpr) {
return new PutVar(var, initExpr);
}
}