Skip to content

Commit d5a1bf9

Browse files
committed
#99 Improve Context and $ContextPath handling in packages
1 parent 01d1a84 commit d5a1bf9

File tree

5 files changed

+119
-69
lines changed

5 files changed

+119
-69
lines changed

symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/ConstantDefinitions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ private static class $Context extends AbstractSymbolEvaluator {
6868

6969
@Override
7070
public IExpr evaluate(final ISymbol symbol) {
71-
return EvalEngine.get().getContextPath().currentContext();
71+
return EvalEngine.get().getContextPath().currentContextString();
7272
}
7373

7474
}

symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/builtin/PatternMatching.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ public static class End extends AbstractCoreFunctionEvaluator {
133133
@Override
134134
public IExpr evaluate(final IAST ast, EvalEngine engine) {
135135
Context context = engine.end();
136+
if (context==null) {
137+
return F.NIL;
138+
}
136139
return F.stringx(context.getContextName());
137140
}
138141

symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/eval/EvalEngine.java

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,6 @@ public static void set(final EvalEngine engine) {
195195

196196
transient Stack<ContextPath> fContextPathStack;
197197

198-
transient Context fContext;
199-
200198
transient ContextPath fContextPath;
201199

202200
protected int fRecursionLimit;
@@ -374,7 +372,6 @@ public EvalEngine copy() {
374372
engine.REMEMBER_AST_CACHE = REMEMBER_AST_CACHE;
375373
engine.fAnswer = fAnswer;
376374
engine.fAssumptions = fAssumptions;
377-
engine.fContext = fContext;
378375
engine.fContextPath = fContextPath.copy();
379376
engine.fErrorPrintStream = fErrorPrintStream;
380377
engine.fEvalLHSMode = fEvalLHSMode;
@@ -407,34 +404,41 @@ public EvalEngine copy() {
407404
}
408405

409406
public void begin(String contextName) {
407+
fContextPathStack.push(fContextPath);
408+
fContextPath = fContextPath.copy();
410409
Context packageContext = fContextPath.getContext(contextName);
411410
setContext(packageContext);
412411
}
413-
412+
414413
public void beginPackage(String contextName) {
415414
fContextPathStack.push(fContextPath);
416415
Context packageContext = fContextPath.getContext(contextName);
417416
setContextPath(new ContextPath(packageContext));
418-
setContext(packageContext);
419417
}
420418

421419
public Context end() {
422-
Context packageContext = fContext;
423-
setContext(fContextPath.last());
424-
return packageContext;
420+
if (fContextPathStack.size() > 0) {
421+
ContextPath p = fContextPath;
422+
Context c = fContextPath.currentContext();
423+
fContextPath = fContextPathStack.pop();
424+
fContextPath.synchronize(p);
425+
return c;
426+
}
427+
return null;
425428
}
426-
429+
427430
public void endPackage() {
428431
if (fContextPathStack.size() > 0) {
432+
ContextPath p = fContextPath;
433+
Context c = fContextPath.currentContext();
429434
fContextPath = fContextPathStack.pop();
430-
fContextPath.add(0, fContext);
431-
fContext = fContextPath.last();
435+
fContextPath.synchronize(p);
436+
fContextPath.add(0, c);
432437
}
433438
}
434439

435440
public void cancel() {
436441
fLocalVariableStackMap = null;
437-
fContext = Context.SYSTEM;
438442
fContextPath = null;
439443
fErrorPrintStream = null;
440444
fFileSystemEnabled = false;
@@ -1768,7 +1772,7 @@ public IAssumptions getAssumptions() {
17681772
}
17691773

17701774
public final Context getContext() {
1771-
return fContext;
1775+
return fContextPath.currentContext();
17721776
}
17731777

17741778
public ContextPath getContextPath() {
@@ -1882,8 +1886,7 @@ final public void init() {
18821886
fSeconds = 0;
18831887
fModifiedVariablesList = null;
18841888
fContextPathStack = new Stack<ContextPath>();
1885-
fContextPath = new ContextPath();
1886-
fContext = fContextPath.last();
1889+
fContextPath = ContextPath.initialContext();
18871890
fLocalVariableStackMap = null;
18881891
REMEMBER_AST_CACHE = null;
18891892
}
@@ -2107,7 +2110,7 @@ public void setContextPath(ContextPath contextPath) {
21072110
}
21082111

21092112
public void setContext(Context context) {
2110-
this.fContext = context;
2113+
this.fContextPath.setCurrentContext(context);
21112114
}
21122115

21132116
public void setErrorPrintStream(final PrintStream errorPrintStream) {

symja_android_library/matheclipse-core/src/main/java/org/matheclipse/core/expression/ContextPath.java

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.util.ArrayList;
44
import java.util.HashMap;
5-
import java.util.List;
65
import java.util.Locale;
76
import java.util.Map;
87

@@ -12,43 +11,33 @@
1211
import org.matheclipse.core.interfaces.IStringX;
1312
import org.matheclipse.core.interfaces.ISymbol;
1413

15-
public class ContextPath {
16-
public final Map<String, Context> fContextMap;
17-
List<Context> path = new ArrayList<Context>();
14+
public final class ContextPath {
15+
private HashMap<String, Context> fContextMap;
16+
private ArrayList<Context> path = new ArrayList<Context>();
17+
private Context fContext;
1818

19-
private ContextPath(List<Context> path) {
20-
fContextMap = new HashMap<String, Context>(17);
21-
this.path.add(Context.SYSTEM);
22-
this.fContextMap.put(Context.SYSTEM.getContextName(), Context.SYSTEM);
23-
// don't put RUBI on the context path
24-
fContextMap.put(Context.RUBI.getContextName(), Context.RUBI);
25-
// fContextMap.put(Context.DUMMY.getContextName(), Context.DUMMY);
26-
for (int i = 1; i < path.size(); i++) {
27-
// Start at index 1 because SYSTEM is already set!
28-
this.path.add(path.get(i).copy());
29-
}
19+
private ContextPath() {
20+
// for copy() method
3021
}
3122

32-
public ContextPath() {
33-
fContextMap = new HashMap<String, Context>(17);
34-
path.add(Context.SYSTEM);
35-
fContextMap.put(Context.SYSTEM.getContextName(), Context.SYSTEM);
23+
/**
24+
* Get the initial context(s) for an evaluation engine.
25+
*
26+
* @return
27+
*/
28+
public static ContextPath initialContext() {
29+
ContextPath cp = new ContextPath();
30+
cp.fContextMap = new HashMap<String, Context>(17);
31+
cp.path.add(Context.SYSTEM);
32+
cp.fContextMap.put(Context.SYSTEM.getContextName(), Context.SYSTEM);
3633
// don't put RUBI on the context path
37-
fContextMap.put(Context.RUBI.getContextName(), Context.RUBI);
34+
cp.fContextMap.put(Context.RUBI.getContextName(), Context.RUBI);
3835
// fContextMap.put(Context.DUMMY.getContextName(), Context.DUMMY);
3936
Context global = new Context(Context.GLOBAL_CONTEXT_NAME);
40-
path.add(global);
41-
fContextMap.put(Context.GLOBAL_CONTEXT_NAME, global);
42-
}
43-
44-
public ContextPath(String contextName) {
45-
fContextMap = new HashMap<String, Context>(17);
46-
path.add(getContext(contextName));
47-
path.add(Context.SYSTEM);
48-
fContextMap.put(Context.SYSTEM.getContextName(), Context.SYSTEM);
49-
// don't put RUBI on the context path
50-
fContextMap.put(Context.RUBI.getContextName(), Context.RUBI);
51-
// fContextMap.put(Context.DUMMY.getContextName(), Context.DUMMY);
37+
cp.path.add(global);
38+
cp.fContextMap.put(Context.GLOBAL_CONTEXT_NAME, global);
39+
cp.fContext = global;
40+
return cp;
5241
}
5342

5443
public ContextPath(Context context) {
@@ -59,23 +48,19 @@ public ContextPath(Context context) {
5948
// don't put RUBI on the context path
6049
fContextMap.put(Context.RUBI.getContextName(), Context.RUBI);
6150
// fContextMap.put(Context.DUMMY.getContextName(), Context.DUMMY);
62-
51+
fContext = context;
6352
}
6453

6554
public ContextPath copy() {
66-
return new ContextPath(path);
55+
ContextPath cp = new ContextPath();
56+
cp.fContextMap = (HashMap<String, Context>) fContextMap.clone();
57+
cp.path = (ArrayList<Context>) path.clone();
58+
cp.fContext = fContext;
59+
return cp;
6760
}
6861

6962
public Context getGlobalContext() {
70-
int size = path.size();
71-
int start = size - 1;
72-
for (int i = start; i >= 0; i--) {
73-
Context temp = path.get(i);
74-
if (temp.getContextName().equals(Context.GLOBAL_CONTEXT_NAME)) {
75-
return temp;
76-
}
77-
}
78-
return null;
63+
return fContextMap.get(Context.GLOBAL_CONTEXT_NAME);
7964
}
8065

8166
/**
@@ -94,9 +79,16 @@ public IAST pathAsStrings() {
9479
return result;
9580
}
9681

97-
public IStringX currentContext() {
98-
int size = path.size() - 1;
99-
return F.stringx(path.get(size).getContextName());
82+
public IStringX currentContextString() {
83+
return F.stringx(fContext.getContextName());
84+
}
85+
86+
public Context currentContext() {
87+
return fContext;
88+
}
89+
90+
public void setCurrentContext(Context context) {
91+
fContext = context;
10092
}
10193

10294
public boolean setGlobalContext(Context context) {
@@ -138,10 +130,6 @@ public Context get(int index) {
138130
return path.get(index);
139131
}
140132

141-
public Context last() {
142-
return path.get(path.size() - 1);
143-
}
144-
145133
public ISymbol symbol(String symbolName, Context newContext, boolean relaxedSyntax) {
146134
String name = symbolName;
147135
if (relaxedSyntax) {
@@ -160,12 +148,12 @@ public ISymbol symbol(String symbolName, Context newContext, boolean relaxedSynt
160148
return symbol;
161149
}
162150
}
163-
151+
164152
symbol = newContext.get(name);
165153
if (symbol != null) {
166154
return symbol;
167155
}
168-
156+
169157
symbol = new Symbol(name, newContext);
170158
newContext.put(name, symbol);
171159
// engine.putUserVariable(name, symbol);
@@ -233,6 +221,24 @@ public Context remove(int index) {
233221
return path.remove(index);
234222
}
235223

224+
/**
225+
* Synchronize the contexts back to this context map.
226+
*
227+
* @param path
228+
* @return
229+
*/
230+
public void synchronize(ContextPath path) {
231+
Context c = path.fContext;
232+
if (!fContextMap.containsKey(c.getContextName())) {
233+
fContextMap.put(c.getContextName(), c);
234+
}
235+
for (Map.Entry<String, Context> entry : path.fContextMap.entrySet()) {
236+
if (!fContextMap.containsKey(entry.getKey())) {
237+
fContextMap.put(entry.getKey(), entry.getValue());
238+
}
239+
}
240+
}
241+
236242
public Context set(int index, Context element) {
237243
return path.set(index, element);
238244
}

symja_android_library/matheclipse-core/src/test/java/org/matheclipse/core/system/LowercaseTestCase.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,44 @@ public void testBeginPackage() {
672672
"144");
673673
}
674674

675+
public void testBeginPackageNested() {
676+
check("BeginPackage(\"test`\")", //
677+
"");
678+
check("Context( )", //
679+
"test`");
680+
check("$ContextPath", //
681+
"{test`,System`}");
682+
check("testit::usage = \"testit(x) gives x^2\"", //
683+
"testit(x) gives x^2");
684+
check("testit(x_) := x^2 ", //
685+
"");
686+
check("Begin(\"test`Private`\")", //
687+
"");
688+
check("test2(x_) := x^3 ", //
689+
"");
690+
check("testit(12)", //
691+
"144");
692+
check("End( )", //
693+
"test`Private`");
694+
check("$ContextPath", //
695+
"{test`,System`}");
696+
check("Context( )", //
697+
"test`");
698+
check("EndPackage( )", //
699+
"");
700+
check("test`Private`test2(12)", //
701+
"1728");
702+
check("$ContextPath", //
703+
"{test`,System`,Global`}");
704+
check("Context( )", //
705+
"Global`");
706+
// print usage message in console
707+
check("?testit", //
708+
"");
709+
check("testit(12)", //
710+
"144");
711+
}
712+
675713
public void testBegin() {
676714
check("Begin(\"mytest`\")", //
677715
"");

0 commit comments

Comments
 (0)