1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.millscript.millscript.action;
22
23 import org.millscript.commons.util.EMap;
24 import org.millscript.commons.util.defaults.ConstantMapDefault;
25 import org.millscript.commons.util.map.EHashMap;
26 import org.millscript.millscript.functions.Function;
27 import org.millscript.millscript.vm.Machine;
28
29 /**
30 * This class implements the action used when defining a memo function. This
31 * action returns a new memo function which can then be bound to the relevant
32 * variable.
33 * <p>
34 * The memo action is a simple wrapper around a normal function that takes a
35 * single argument and returns a single result.
36 * </p>
37 *
38 * @see org.millscript.millscript.expr.MemoExpr
39 * @see org.millscript.millscript.syntax.DefineSyntax
40 */
41 public final class MemoAction extends Action {
42
43 /**
44 * This class implements the memo function.
45 */
46 private static final class MemoFunction extends Function {
47
48 /**
49 * This is used as the default value for the map holding the memo'd values.
50 */
51 private static final class MemoMarker {};
52
53 /**
54 * This is the instance of the MemoMarker class used as the default
55 * value.
56 */
57 private static final MemoMarker MEMO_DEFAULT = new MemoMarker();
58
59 /**
60 * The function to memoise.
61 */
62 private final Function fn;
63
64 /**
65 * The table to store the argument to result mapping. i.e. the memo.
66 */
67 private final EMap< Object, Object > table;
68
69 /**
70 * Construct a new memo function to remember the results of applying
71 * the specified function.
72 *
73 * @param f the function to make a memo for
74 */
75 private MemoFunction( final Function f ) {
76 this.fn = f;
77 this.table = new EHashMap< Object, Object >();
78 this.table.setDefault(
79 new ConstantMapDefault< Object, Object >( MEMO_DEFAULT )
80 );
81 }
82
83 /**
84 * @see org.millscript.millscript.functions.Function#apply(org.millscript.millscript.vm.Machine, int)
85 */
86 @Override
87 public void apply( final Machine mc, final int nargs ) {
88 if ( nargs == 1 ) {
89
90 Object x = mc.popObject();
91
92
93 Object c = table.get( x );
94 if ( c != MEMO_DEFAULT ) {
95
96 mc.pushObject( c );
97 } else {
98
99
100
101 mc.pushObject( x );
102
103 fn.apply( mc, 1 );
104
105
106
107
108 Object y = mc.popObject();
109
110
111 table.insert( x, y );
112
113 mc.pushObject( y );
114 }
115 } else {
116 checkNargs( mc, 1, nargs );
117 }
118 }
119
120 }
121
122 /**
123 * The action that returns the function this memo action is based on.
124 */
125 private final Action cont;
126
127 /**
128 * Constructs a new memo action to wrap the specified function action.
129 *
130 * @param c the function action, which generates the function to memoise.
131 */
132 public MemoAction( final Action c ) {
133 this.cont = c;
134 }
135
136 /**
137 * @see org.millscript.millscript.action.Action#action(org.millscript.millscript.vm.Machine)
138 */
139 @Override
140 public void action( final Machine mc ) {
141
142
143 mc.pushObject(
144 new MemoFunction( (Function)cont.act1( mc ) )
145 );
146 }
147
148 }