View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2001-2004 Open World Ltd
4   // Copyright (C) 2005 Kevin Rogers
5   //
6   // This file is part of MillScript.
7   //
8   // MillScript is free software; you can redistribute it and/or modify it under
9   // the terms of the GNU General Public License as published by the Free
10  // Software Foundation; either version 2 of the License, or (at your option)
11  // any later version.
12  //
13  // MillScript is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  // more details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // MillScript; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA  02111-1307  USA
21  ////////////////////////////////////////////////////////////////////////////////
22  package org.millscript.millscript.functions;
23  
24  import org.millscript.commons.util.list.ELinkedList;
25  import org.millscript.millscript.action.Action;
26  import org.millscript.millscript.expr.LocalIdent;
27  import org.millscript.millscript.vm.Machine;
28  import org.millscript.millscript.vm.Ref;
29  
30  /**
31   * This class implements a function defined within a piece of MillScript code.
32   * As such it may take a variable number of arguments, depending on its
33   * definition.
34   */
35  public final class LambdaFunction extends Function {
36  
37      /**
38       * The idents for the local arguments. This is required when we add support
39       * for debugging.
40       */
41      private final LocalIdent[] args;
42  
43      /**
44       * The local ident for the optional last argument that soaks up all the
45       * extra parameters.
46       */
47      private final LocalIdent rest;
48  
49      /**
50       * The action for the body of the function.
51       */
52      private final Action body;
53  
54      /**
55       * The number of arguments this function has.
56       */
57      private final int numArgs;
58  
59      /**
60       * The Ref's for each arguments value.
61       */
62      private final Ref[] refs;
63  
64      /**
65       * The Ref for the optional last argument that soaks up all the extra
66       * parameters.
67       */
68      private final Ref restRef;
69  
70      /**
71       * Constructs a new <code>LambdaFunction</code> to execute the specified
72       * body with the specified number of arguments.
73       *
74       * @param a the local idents for the functions arguments
75       * @param r the optional ident for the argument that can soak up any
76       * additional parameters to the function
77       * @param b the body of the function
78       */
79      public LambdaFunction( final LocalIdent[] a, final LocalIdent r, final Action b ) {
80          this.args = a;
81          this.rest = r;
82          this.body = b;
83          this.numArgs = args.length;
84          this.refs = new Ref[ numArgs ];
85          for ( int i = 0; i < numArgs; i++ ) {
86              refs[ i ] = args[ i ].getRef();
87          }
88          if ( rest != null ) {
89              this.restRef = this.rest.getRef();
90          } else {
91              this.restRef = null;
92          }
93      }
94  
95      /**
96       * @see org.millscript.millscript.functions.Function#apply(org.millscript.millscript.vm.Machine, int)
97       */
98      @Override
99      public void apply( final Machine mc, final int nargs ) {
100         if ( nargs != numArgs ) {
101             if ( rest == null || numArgs > nargs ) {
102                 throw(
103                     FunctionAlert.eval(
104                         "Wrong number of arguments",
105                         rest == null ?
106                         "Exactly " + numArgs + " needed" :
107                         numArgs + " or more arguments needed"
108                     ).culpritArgs( this, mc, nargs ).mishap()
109                 );
110             }
111         }
112         mc.startSaving();
113         if ( restRef != null ) {
114             int nrest = nargs - numArgs;
115             ELinkedList< Object > restList = new ELinkedList< Object >();
116             for ( int i = 0; i < nrest; i++ ) {
117                 restList.addFirst( mc.popObject() );
118             }
119             restRef.value = restList;
120         }
121         for ( int i = numArgs - 1; i >= 0; i-- ) {
122             Ref r = refs[ i ];
123             mc.saveRef( r );
124             r.value = mc.popObject();
125         }
126         body.act( mc );
127         mc.restoreSaved();
128     }
129 
130     /**
131      * @see java.lang.Object#toString()
132      */
133     @Override
134     public String toString() {
135         String arity = "(" + numArgs + ( restRef == null ? "" : "+" ) + ")";
136         if ( arity.equals( "(0+)" ) ) {
137             arity = "";
138         }
139         String name = getName();
140         return (
141             name == null ?
142             "<function" + arity + ">" :
143             "<function " + name + arity + ">"
144         );
145     }
146 
147 }