View Javadoc

1   ////////////////////////////////////////////////////////////////////////////////
2   // MillScript: an Open Spice interpreter and batch website creation tool
3   // Copyright (C) 2004-2005 Kevin Rogers
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.syntax;
22  
23  import org.millscript.commons.util.EList;
24  import org.millscript.commons.util.list.EArrayList;
25  import org.millscript.millscript.alert.Alerts;
26  import org.millscript.millscript.expr.ApplyExpr;
27  import org.millscript.millscript.expr.CommaExpr;
28  import org.millscript.millscript.expr.Expr;
29  import org.millscript.millscript.expr.NameExpr;
30  import org.millscript.millscript.expr.SkipExpr;
31  
32  
33  /**
34   * This class represents a function header. The function header is the
35   * signature of a function, made up of the function name and it's argument
36   * list. e.g. <code>somefunc( arg1, arg2 )</code>.
37   */
38  public final class FunctionHeader {
39  
40      /**
41       * This is the function name, as a name expression.
42       */
43      private NameExpr name = null;
44  
45      /**
46       * This stack contains the function argument list. This stack should
47       * only contain {@link NameExpr}s.
48       */
49      private final EList< NameExpr > arglist = new EArrayList< NameExpr >( 8 );
50  
51      /**
52       * Returns a list holding the arguments for this function header.
53       *
54       * @return  a list holding the arguments for this function header.
55       */
56      public EList< NameExpr > getArglist() {
57          return arglist;
58      }
59  
60      /**
61       * Returns the function name expression for this header.
62       *
63       * @return  the NameExpr for the function name
64       */
65      public NameExpr getName() {
66          return name;
67      }
68  
69      /**
70       * Returns the symbol for this function. It is possible to declare
71       * annonymous functions, in which case their symbol will be "lambda".
72       *
73       * @return  a String containing the function name, or
74       *          <code>"lambda"</code> if it doesn't have one.
75       */
76      public String getSymbol() {
77          if ( name == null ) {
78              return "lambda";
79          } else {
80              return name.getName();
81          }
82      }
83  
84      /**
85       * Flattens the supplied function definition expression into its
86       * function name and arguments. This method takes a standard function
87       * definition expression, e.g. <code>somefunc( arg1, arg2 )</code>, and
88       * extracts the function and argument name expressions.
89       *
90       * @param   e   a function definition expression, i.e. the function and
91       *              it's arguments.
92       * @param   nameNeeded  a boolean indicating if this function must have
93       *                      a name or not.
94       */
95      void flatten( final Expr e, final boolean nameNeeded ) {
96          // Check what kind of expression we've been supplied
97          if ( e instanceof ApplyExpr ) {
98              // We were supplied an apply expression, which means we have a
99              // function name and some arguments. Hence, extract the function
100             // name from the apply expression.
101             Expr fun = ((ApplyExpr)e).getFun();
102             // Now extract the function argument expression from the apply
103             // expression.
104             Expr args = ((ApplyExpr)e).getArgs();
105             // Check that the function name expression is indeed a name
106             // expression
107             if ( fun instanceof NameExpr ) {
108                 // Set the function name expression
109                 name = (NameExpr)fun;
110                 // Process the argument expression
111                 pushArgs( args );
112             } else {
113                 // This is an invalid function definition
114                 throw(
115                     Alerts.parse(
116                         "Invalid procedure definition",
117                         "Proceedure names must be a name!"
118                     ).culprit( "procedure name", fun ).mishap()
119                 );
120             }
121         } else if ( nameNeeded ) {
122             // We weren't supplied an apply expression, but we need a
123             // function name, so this is an error.
124             throw(
125                 Alerts.parse(
126                     "Invalid procedure definition",
127                     "Procedures must have a name"
128                 ).mishap()
129             );
130         } else {
131             // We don't need a name, so the supplied expression is just a
132             // list of arguments. Hence process them.
133             pushArgs( e );
134         }
135     }
136 
137     /**
138      * Extracts all the argument names from the supplied expression for the
139      * arguments. Each argument will be pushed onto the argument stack,
140      * {@link #arglist}. An error will be raised if the specified expression
141      * contains expressions that are illegal in a function definition.
142      *
143      * @param   args    the expression containing the set of arguments for
144      *                  this function definition
145      */
146     private void pushArgs( final Expr args ) {
147         if ( args instanceof NameExpr ) {
148             // The supplied argument is a name expression, so just push it
149             // onto the argument stack
150             arglist.addLast( (NameExpr) args );
151         } else if ( args instanceof CommaExpr ) {
152             // The supplied argument is a comma expression, so push the left
153             // hand side, then the right hand side.
154             pushArgs( ((CommaExpr)args).getLeft() );
155             pushArgs( ((CommaExpr)args).getRight() );
156         } else if ( !( args instanceof SkipExpr ) ) {
157             // Invalid expression in argument list
158             throw(
159                 Alerts.parse(
160                     "Invalid procedure definition",
161                     "Procedure arguments must names(at the moment)"
162                 ).culprit( "arg", args ).mishap()
163             );
164         }
165     }
166 
167 }