View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2001-2004 Open World Ltd
4   //
5   // This file is part of MillScript.
6   //
7   // MillScript is free software; you can redistribute it and/or modify it under
8   // the terms of the GNU General Public License as published by the Free
9   // Software Foundation; either version 2 of the License, or (at your option)
10  // any later version.
11  //
12  // MillScript is distributed in the hope that it will be useful, but WITHOUT
13  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  // more details.
16  //
17  // You should have received a copy of the GNU General Public License along with
18  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
19  // Place, Suite 330, Boston, MA  02111-1307  USA
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                  // Get the memo's argument
90                  Object x = mc.popObject();
91                  // Have a look for a mapping from this argument to a
92                  // previously calculated value
93                  Object c = table.get( x );
94                  if ( c != MEMO_DEFAULT ) {
95                      // We found a previous value, so simply return it
96                      mc.pushObject( c );
97                  } else {
98                      // We haven't calculated a value for this argument
99                      // yet, so push back the argument so we can apply
100                     // the function
101                     mc.pushObject( x );
102                     // Apply the function to the single argument
103                     fn.apply( mc, 1 );
104                     // Get the result of the function
105                     // TODO - Shouldn't this check the number of values
106                     // on the stack, to ensure a single result was
107                     // returned?
108                     Object y = mc.popObject();
109                     // Store this result against the argument for
110                     // future reference
111                     table.insert( x, y );
112                     // Return the result of the function
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         // Perform the function action to get the basic function we want to
142         // memoise, then make a new memo function with it
143         mc.pushObject(
144             new MemoFunction( (Function)cont.act1( mc ) )
145         );
146     }
147 
148 }