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.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
97 if ( e instanceof ApplyExpr ) {
98
99
100
101 Expr fun = ((ApplyExpr)e).getFun();
102
103
104 Expr args = ((ApplyExpr)e).getArgs();
105
106
107 if ( fun instanceof NameExpr ) {
108
109 name = (NameExpr)fun;
110
111 pushArgs( args );
112 } else {
113
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
123
124 throw(
125 Alerts.parse(
126 "Invalid procedure definition",
127 "Procedures must have a name"
128 ).mishap()
129 );
130 } else {
131
132
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
149
150 arglist.addLast( (NameExpr) args );
151 } else if ( args instanceof CommaExpr ) {
152
153
154 pushArgs( ((CommaExpr)args).getLeft() );
155 pushArgs( ((CommaExpr)args).getRight() );
156 } else if ( !( args instanceof SkipExpr ) ) {
157
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 }