Skip to content

Commit 0abd372

Browse files
committed
(fix) can't overload logic operator.
1 parent 84a7173 commit 0abd372

File tree

8 files changed

+141
-79
lines changed

8 files changed

+141
-79
lines changed

src/main/java/com/googlecode/aviator/AviatorEvaluatorInstance.java

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,11 @@ public final class AviatorEvaluatorInstance {
206206
/** internal libs in main resources */
207207
private static final String[] libs = new String[] {"aviator.av"};
208208

209-
/** cached compiled internal lib functions */
210-
private static volatile Map<String, AviatorFunction> internalLibFunctions;
209+
/** cached compiled internal ASM lib functions */
210+
private static volatile Map<String, AviatorFunction> internalASMLibFunctions;
211211

212+
/** cached compiled internal interpred lib functions */
213+
private static volatile Map<String, AviatorFunction> internalInterpretedLibFunctions;
212214

213215
/**
214216
* Adds a function loader
@@ -1022,32 +1024,46 @@ private void loadSystemFunctions() {
10221024
}
10231025

10241026
private void loadInternalLibs() {
1025-
if (internalLibFunctions == null) {
1026-
Map<String, AviatorFunction> funcs = new HashMap<>();
1027-
for (String lib : libs) {
1028-
try (final InputStream in = this.getClass().getResourceAsStream("/" + lib);
1029-
final BufferedInputStream bis = new BufferedInputStream(in);
1030-
final Reader reader = new InputStreamReader(bis)) {
1031-
Expression exp = this.compile(lib, Utils.readFully(reader), false);
1032-
Map<String, Object> exports = executeModule(exp, lib);
1033-
for (Map.Entry<String, Object> entry : exports.entrySet()) {
1034-
if (entry.getValue() instanceof AviatorFunction) {
1035-
final AviatorFunction fn = (AviatorFunction) entry.getValue();
1036-
addFunction(entry.getKey(), fn);
1037-
funcs.put(entry.getKey(), fn);
1038-
}
1039-
}
1040-
} catch (IOException e) {
1041-
throw new IllegalStateException("Fail to load internal lib: " + lib, e);
1027+
if (getEvalMode() == EvalMode.ASM) {
1028+
if (internalASMLibFunctions == null) {
1029+
internalASMLibFunctions = loadInternalFunctions(); // cache it
1030+
} else {
1031+
for (Map.Entry<String, AviatorFunction> entry : internalASMLibFunctions.entrySet()) {
1032+
addFunction(entry.getKey(), entry.getValue());
10421033
}
10431034
}
1044-
1045-
internalLibFunctions = funcs; // cache it
10461035
} else {
1047-
for (Map.Entry<String, AviatorFunction> entry : internalLibFunctions.entrySet()) {
1048-
addFunction(entry.getKey(), entry.getValue());
1036+
if (internalInterpretedLibFunctions == null) {
1037+
internalInterpretedLibFunctions = loadInternalFunctions(); // cache it
1038+
} else {
1039+
for (Map.Entry<String, AviatorFunction> entry : internalInterpretedLibFunctions
1040+
.entrySet()) {
1041+
addFunction(entry.getKey(), entry.getValue());
1042+
}
1043+
}
1044+
}
1045+
}
1046+
1047+
private Map<String, AviatorFunction> loadInternalFunctions() {
1048+
Map<String, AviatorFunction> funcs = new HashMap<>();
1049+
for (String lib : libs) {
1050+
try (final InputStream in = this.getClass().getResourceAsStream("/" + lib);
1051+
final BufferedInputStream bis = new BufferedInputStream(in);
1052+
final Reader reader = new InputStreamReader(bis)) {
1053+
Expression exp = this.compile(lib, Utils.readFully(reader), false);
1054+
Map<String, Object> exports = executeModule(exp, lib);
1055+
for (Map.Entry<String, Object> entry : exports.entrySet()) {
1056+
if (entry.getValue() instanceof AviatorFunction) {
1057+
final AviatorFunction fn = (AviatorFunction) entry.getValue();
1058+
addFunction(entry.getKey(), fn);
1059+
funcs.put(entry.getKey(), fn);
1060+
}
1061+
}
1062+
} catch (IOException e) {
1063+
throw new IllegalStateException("Fail to load internal lib: " + lib, e);
10491064
}
10501065
}
1066+
return funcs;
10511067
}
10521068

10531069
/**

src/main/java/com/googlecode/aviator/code/BaseEvalCodeGenerator.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.googlecode.aviator.parser.VariableMeta;
1414
import com.googlecode.aviator.runtime.FunctionArgument;
1515
import com.googlecode.aviator.runtime.LambdaFunctionBootstrap;
16+
import com.googlecode.aviator.utils.Env;
1617

1718
public abstract class BaseEvalCodeGenerator implements EvalCodeGenerator {
1819

@@ -37,6 +38,10 @@ public abstract class BaseEvalCodeGenerator implements EvalCodeGenerator {
3738
*/
3839
protected Map<Integer/* internal function id */, List<FunctionArgument>> funcsArgs;
3940
private int funcInvocationId = 0;
41+
/**
42+
* Compile environment only has the *instance*.
43+
*/
44+
protected final Env compileEnv;
4045

4146
protected Map<Integer/* internal function id */, List<FunctionArgument>> getFuncsArgs() {
4247
if (this.funcsArgs == null) {
@@ -55,10 +60,22 @@ public void setParser(final Parser parser) {
5560
this.symbolTable = this.parser.getSymbolTable();
5661
}
5762

63+
@Override
64+
public void setLambdaBootstraps(final Map<String, LambdaFunctionBootstrap> lambdaBootstraps) {
65+
this.lambdaBootstraps = lambdaBootstraps;
66+
}
67+
68+
@Override
69+
public AviatorClassLoader getClassLoader() {
70+
return this.classLoader;
71+
}
72+
5873
public BaseEvalCodeGenerator(final AviatorEvaluatorInstance instance, final String sourceFile,
5974
final AviatorClassLoader classLoader) {
6075
super();
6176
this.instance = instance;
77+
this.compileEnv = new Env();
78+
this.compileEnv.setInstance(this.instance);
6279
this.sourceFile = sourceFile;
6380
this.classLoader = classLoader;
6481
}

src/main/java/com/googlecode/aviator/code/asm/ASMCodeGenerator.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
import com.googlecode.aviator.runtime.LambdaFunctionBootstrap;
8181
import com.googlecode.aviator.runtime.op.OperationRuntime;
8282
import com.googlecode.aviator.utils.Constants;
83-
import com.googlecode.aviator.utils.Env;
8483
import com.googlecode.aviator.utils.TypeUtils;
8584

8685

@@ -100,10 +99,6 @@ public class ASMCodeGenerator extends BaseEvalCodeGenerator {
10099
private static final String OBJECT_OWNER = "com/googlecode/aviator/runtime/type/AviatorObject";
101100
public static final String FUNC_ARGS_INNER_VAR = "__fas__";
102101
private static final String FIELD_PREFIX = "f";
103-
/**
104-
* Compile environment only has the *instance*.
105-
*/
106-
private final Env compileEnv;
107102
// Class Writer to generate class
108103
// private final ClassWriter clazzWriter;
109104
// Trace visitor
@@ -151,8 +146,6 @@ private void setMaxStacks(final int newMaxStacks) {
151146
public ASMCodeGenerator(final AviatorEvaluatorInstance instance, final String sourceFile,
152147
final AviatorClassLoader classLoader, final OutputStream traceOut) {
153148
super(instance, sourceFile, classLoader);
154-
this.compileEnv = new Env();
155-
this.compileEnv.setInstance(this.instance);
156149
// Generate inner class name
157150
this.className = "Script_" + System.currentTimeMillis() + "_" + CLASS_COUNTER.getAndIncrement();
158151
// Auto compute frames
@@ -166,14 +159,6 @@ public ASMCodeGenerator(final AviatorEvaluatorInstance instance, final String so
166159
visitClass();
167160
}
168161

169-
170-
171-
@Override
172-
public AviatorClassLoader getClassLoader() {
173-
return this.classLoader;
174-
}
175-
176-
177162
LambdaGenerator getLambdaGenerator() {
178163
return this.lambdaGenerator;
179164
}
@@ -968,13 +953,6 @@ private boolean loadConstant(final Token<?> lookhead, final boolean inConstructo
968953
return false;
969954
}
970955

971-
972-
@Override
973-
public void setLambdaBootstraps(final Map<String, LambdaFunctionBootstrap> lambdaBootstraps) {
974-
this.lambdaBootstraps = lambdaBootstraps;
975-
}
976-
977-
978956
@Override
979957
public void initVariables(final Map<String, VariableMeta/* counter */> vars) {
980958
this.variables = vars;

src/main/java/com/googlecode/aviator/code/interpreter/InterpretCodeGenerator.java

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@
3232
import com.googlecode.aviator.code.interpreter.ir.SourceInfo;
3333
import com.googlecode.aviator.code.interpreter.ir.VisitLabelIR;
3434
import com.googlecode.aviator.exception.CompileExpressionErrorException;
35+
import com.googlecode.aviator.lexer.token.OperatorType;
3536
import com.googlecode.aviator.lexer.token.Token;
3637
import com.googlecode.aviator.lexer.token.Token.TokenType;
3738
import com.googlecode.aviator.parser.AviatorClassLoader;
3839
import com.googlecode.aviator.parser.VariableMeta;
3940
import com.googlecode.aviator.runtime.FunctionArgument;
4041
import com.googlecode.aviator.runtime.FunctionParam;
4142
import com.googlecode.aviator.runtime.LambdaFunctionBootstrap;
43+
import com.googlecode.aviator.runtime.op.OperationRuntime;
4244
import com.googlecode.aviator.utils.Constants;
4345
import com.googlecode.aviator.utils.IdentityHashSet;
4446

@@ -120,16 +122,6 @@ public void initMethods(final Map<String, Integer> methods) {
120122

121123
}
122124

123-
@Override
124-
public void setLambdaBootstraps(final Map<String, LambdaFunctionBootstrap> lambdaBootstraps) {
125-
this.lambdaBootstraps = lambdaBootstraps;
126-
}
127-
128-
@Override
129-
public AviatorClassLoader getClassLoader() {
130-
return this.classLoader;
131-
}
132-
133125
@Override
134126
public void genNewLambdaCode(final LambdaFunctionBootstrap bootstrap) {
135127
emit(new NewLambdaIR(bootstrap.getName()));
@@ -213,12 +205,14 @@ public void onDiv(final Token<?> lookhead) {
213205

214206
@Override
215207
public void onAndLeft(final Token<?> lookhead) {
216-
emit(new AssertTypeIR(AssertTypes.Bool));
217-
Label label = makeLabel();
218-
pushLabel0(label);
219-
this.instruments
220-
.add(new BranchUnlessIR(label, new SourceInfo(this.sourceFile, lookhead.getLineNo())));
221-
emit(PopIR.INSTANCE);
208+
if (!OperationRuntime.containsOpFunction(this.compileEnv, OperatorType.AND)) {
209+
emit(new AssertTypeIR(AssertTypes.Bool));
210+
Label label = makeLabel();
211+
pushLabel0(label);
212+
this.instruments
213+
.add(new BranchUnlessIR(label, new SourceInfo(this.sourceFile, lookhead.getLineNo())));
214+
emit(PopIR.INSTANCE);
215+
}
222216
}
223217

224218
private void emit(final IR ir) {
@@ -227,9 +221,13 @@ private void emit(final IR ir) {
227221

228222
@Override
229223
public void onAndRight(final Token<?> lookhead) {
230-
emit(new AssertTypeIR(AssertTypes.Bool));
231-
Label label = popLabel0();
232-
visitLabel(label);
224+
if (!OperationRuntime.containsOpFunction(this.compileEnv, OperatorType.AND)) {
225+
emit(new AssertTypeIR(AssertTypes.Bool));
226+
Label label = popLabel0();
227+
visitLabel(label);
228+
} else {
229+
emit(OperatorIR.AND);
230+
}
233231
}
234232

235233
@Override
@@ -267,19 +265,25 @@ public void onTernaryEnd(final Token<?> lookhead) {
267265

268266
@Override
269267
public void onJoinLeft(final Token<?> lookhead) {
270-
emit(new AssertTypeIR(AssertTypes.Bool));
271-
Label label = makeLabel();
272-
pushLabel0(label);
273-
this.instruments
274-
.add(new BranchIfIR(label, new SourceInfo(this.sourceFile, lookhead.getLineNo())));
275-
emit(PopIR.INSTANCE);
268+
if (!OperationRuntime.containsOpFunction(this.compileEnv, OperatorType.AND)) {
269+
emit(new AssertTypeIR(AssertTypes.Bool));
270+
Label label = makeLabel();
271+
pushLabel0(label);
272+
this.instruments
273+
.add(new BranchIfIR(label, new SourceInfo(this.sourceFile, lookhead.getLineNo())));
274+
emit(PopIR.INSTANCE);
275+
}
276276
}
277277

278278
@Override
279279
public void onJoinRight(final Token<?> lookhead) {
280-
emit(new AssertTypeIR(AssertTypes.Bool));
281-
Label label = popLabel0();
282-
visitLabel(label);
280+
if (!OperationRuntime.containsOpFunction(this.compileEnv, OperatorType.AND)) {
281+
emit(new AssertTypeIR(AssertTypes.Bool));
282+
Label label = popLabel0();
283+
visitLabel(label);
284+
} else {
285+
emit(OperatorIR.OR);
286+
}
283287
}
284288

285289
@Override

src/main/java/com/googlecode/aviator/code/interpreter/ir/OperatorIR.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ public class OperatorIR implements IR {
3737

3838
public static final OperatorIR MATCH = OperatorIR.valueOf(OperatorType.MATCH);
3939

40+
public static final OperatorIR AND = OperatorIR.valueOf(OperatorType.AND);
41+
42+
public static final OperatorIR OR = OperatorIR.valueOf(OperatorType.OR);
43+
4044
public static final OperatorIR NOT = OperatorIR.valueOf(OperatorType.NOT);
4145

4246
public static final OperatorIR NEG = OperatorIR.valueOf(OperatorType.NEG);

src/main/java/com/googlecode/aviator/runtime/op/OperationRuntime.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private static AviatorObject eval0(final Map<String, Object> env, final AviatorO
5656
if (func == null) {
5757
return opType.eval(args, env);
5858
} else {
59-
switch (args.length) {
59+
switch (opType.getArity()) {
6060
case 1:
6161
return func.call(env, args[0]);
6262
case 2:
@@ -146,8 +146,12 @@ private static AviatorObject eval0(final AviatorObject left, final AviatorObject
146146

147147
public static final boolean hasRuntimeContext(final Map<String, Object> env,
148148
final OperatorType opType) {
149-
return RuntimeUtils.getInstance(env).getOpsMap().containsKey(opType)
150-
|| RuntimeUtils.isTracedEval(env);
149+
return containsOpFunction(env, opType) || RuntimeUtils.isTracedEval(env);
150+
}
151+
152+
public static boolean containsOpFunction(final Map<String, Object> env,
153+
final OperatorType opType) {
154+
return RuntimeUtils.getInstance(env).getOpsMap().containsKey(opType);
151155
}
152156

153157
private static final String WHITE_SPACE = " ";

src/test/java/com/googlecode/aviator/example/SimpleExample.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
import com.googlecode.aviator.AviatorEvaluator;
44
import com.googlecode.aviator.EvalMode;
5-
import com.googlecode.aviator.Options;
65

76

87
public class SimpleExample {
98
public static void main(final String[] args) throws Exception {
10-
AviatorEvaluator.setOption(Options.EVAL_MODE, EvalMode.INTERPRETER);
11-
AviatorEvaluator.setOption(Options.TRACE_EVAL, true);
9+
// AviatorEvaluator.setOption(Options.EVAL_MODE, EvalMode.INTERPRETER);
10+
// AviatorEvaluator.setOption(Options.TRACE_EVAL, true);
11+
12+
AviatorEvaluator.newInstance(EvalMode.INTERPRETER);
1213
Object result = AviatorEvaluator.execute("a=1; '#{a+100}'");
1314
System.out.println(result);
1415
System.out.println(1 == 1 && 2 != 2 ? 1 : 2 == 3 ? 4 : 5);

src/test/java/com/googlecode/aviator/test/function/FunctionTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.googlecode.aviator.exception.CompareNotSupportedException;
4343
import com.googlecode.aviator.exception.ExpressionRuntimeException;
4444
import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
45+
import com.googlecode.aviator.lexer.token.OperatorType;
4546
import com.googlecode.aviator.runtime.FunctionArgument;
4647
import com.googlecode.aviator.runtime.RuntimeUtils;
4748
import com.googlecode.aviator.runtime.function.AbstractFunction;
@@ -1455,6 +1456,43 @@ public void testSystemMinMaxFunction() {
14551456
}
14561457
}
14571458

1459+
@Test
1460+
public void testOverloadLogicOperator() {
1461+
// AviatorEvaluator.setOption(Options.TRACE_EVAL, true);
1462+
AviatorEvaluator.addOpFunction(OperatorType.AND, new AbstractFunction() {
1463+
1464+
@Override
1465+
public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
1466+
final AviatorObject arg2) {
1467+
return arg1.add(arg2, env);
1468+
}
1469+
1470+
@Override
1471+
public String getName() {
1472+
return "&&";
1473+
}
1474+
});
1475+
AviatorEvaluator.addOpFunction(OperatorType.OR, new AbstractFunction() {
1476+
1477+
@Override
1478+
public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
1479+
final AviatorObject arg2) {
1480+
return arg1.sub(arg2, env);
1481+
}
1482+
1483+
@Override
1484+
public String getName() {
1485+
return "||";
1486+
}
1487+
});
1488+
assertEquals(3, AviatorEvaluator.execute("1 && 2"));
1489+
assertEquals(6, AviatorEvaluator.execute("1 && 2 && 3"));
1490+
assertEquals(0, AviatorEvaluator.execute("1 && 2 || 3"));
1491+
assertEquals(-4, AviatorEvaluator.execute("1 || 2 || 3"));
1492+
AviatorEvaluator.removeOpFunction(OperatorType.AND);
1493+
AviatorEvaluator.removeOpFunction(OperatorType.OR);
1494+
}
1495+
14581496
@Test
14591497
public void testTypeFunctions() {
14601498
assertEquals("long", AviatorEvaluator.execute("type(1)"));

0 commit comments

Comments
 (0)