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.expr;
22
23 import org.millscript.commons.util.IList;
24 import org.millscript.commons.util.ListIterator;
25 import org.millscript.millscript.action.Action;
26 import org.millscript.millscript.vm.CompilerState;
27
28 /**
29 * This class represents the base class of all expressions in MillScript. As
30 * such any new type of expression must extend this class, or one of it's more
31 * specific subclasses. An expression is the result of parsing syntax, and is
32 * the middle stage of compiling to actions.
33 *
34 * @see org.millscript.millscript.action.Action
35 * @see org.millscript.millscript.syntax.Syntax
36 */
37 public abstract class Expr< A extends Action > {
38
39 /**
40 * Adds two arities together to obtain the combined arity. As with
41 * {@link #arity}, positive numbers represent exact arity while negative
42 * numbers represent unknown arity.
43 *
44 * @param a the arity of the first expression
45 * @param b the arity of the second expression
46 * @return the combined arity of the two expressions, positive for exact
47 * arity and negative for unknown arity
48 */
49 static int addArity( final int a, final int b ) {
50 return ( a < 0 || b < 0 ) ? -1 : a + b;
51 }
52
53 /**
54 * Checks if the specified expression is a constant integer and returns it.
55 *
56 * @param x the expression to check
57 * @return <code>null</code> or an Integer if the expression represents a
58 * constant integer
59 */
60 public static final Integer isIntegerExpr( final Expr x ) {
61 if ( x instanceof ConstantExpr ) {
62 ConstantExpr c = (ConstantExpr)x;
63 Object obj = c.getValue();
64 if ( obj instanceof Integer ) {
65 return (Integer)obj;
66 } else {
67 return null;
68 }
69 } else {
70 return null;
71 }
72 }
73
74 /**
75 * Joins two arities together. This is used to obtain the arity of the whole
76 * expression, where one of two expressions will be executed. In this case
77 * the arity can only be exact, hence positive, if both expressions have the
78 * same arity.
79 *
80 * @param a the arity of the first expression
81 * @param b the arity of the second expression
82 * @return the joined arity of the two expressions, positive for exact
83 * arity and negative for unknown arity
84 */
85 static int joinArity( final int a, final int b ) {
86 return a == b ? a : -1;
87 }
88
89 /**
90 * Resolves all the expressions in the specified list, by calling the
91 * {@link #resolve(CompilerState)} method on each one in turn.
92 *
93 * @param state the compiler state we are resolving in
94 * @param list the list of expressions to resolve
95 */
96 public static void resolveList( final CompilerState state, final IList< ? extends Expr > list ) {
97 ListIterator< ? extends Expr > it = list.iterator( true );
98 while ( it.hasNext() ) {
99 it.nextValue().resolve( state );
100 }
101 }
102
103 /**
104 * The line number of this expression in the origin.
105 */
106 private int lineNumber = -1;
107
108 /**
109 * A message indicating the origin of this expression.
110 */
111 private String origin = null;
112
113 /**
114 * Returns the arity of this expression. Positive numbers represent exact
115 * arity, while negative numbers represent unknown arity.
116 *
117 * @return <code>0</code> if the expression returns zero results,
118 * <code>1</code> if the expression returns one result or
119 * <code>-1</code> if the expression returns an unknown number of
120 * results.
121 */
122 public int arity() {
123 if ( this instanceof ZeroResults ) {
124 return 0;
125 }
126 if ( this instanceof OneResult ) {
127 return 1;
128 }
129 return -1;
130 }
131
132 /**
133 * Compiles this expression into an action, setting the context of the
134 * action. The resulting action will have it's origin and line numbers set
135 * to assist with debugging.
136 *
137 * @return the {@link Action} for this expression, with it's context set.
138 */
139 public A compile() {
140
141 A a = compileIt();
142
143 a.setContext( origin, lineNumber );
144
145 return a;
146 }
147
148 /**
149 * Compiles this expression into an action.
150 *
151 * @return the {@link Action} for this expression
152 */
153 public abstract A compileIt();
154
155 /**
156 * Displays the specified line with the specified indent level.
157 *
158 * @param n the indent level at which to start displaying
159 * @param line the message to display
160 */
161 void indent( final int n, final String line ) {
162 for ( int i = 0; i < n; i++ ) {
163 System.out.print( " " );
164 }
165 System.out.println( line );
166 }
167
168 /**
169 * Resolves any {@link NameExpr} in the tree so that they refer to the
170 * correct ident. e.g. This method is responsible for ensuring that
171 * references to a function argument in the body of a function actually
172 * refer to the correct value.
173 *
174 * @param state the compiler state we are resolving in
175 */
176 public abstract void resolve( final CompilerState state );
177
178 /**
179 * Sets the line number of this expression in the origin.
180 *
181 * @param n the line number at which this expression appears in the
182 * given origin
183 */
184 public void setLineNumber( final int n ) {
185 lineNumber = n;
186 }
187
188 /**
189 * Sets the origin of this expression.
190 *
191 * @param x a String describing this expressions origin
192 */
193 public void setOrigin( final String x ) {
194 origin = x;
195 }
196
197 /**
198 * Displays details about this expression, starting with no indent.
199 */
200 public void show() { show( 0 ); }
201
202 /**
203 * Displays details about this expression, with the specified indent level.
204 * This expressions class name, origin and, at a new indent level, component
205 * expressions.
206 *
207 * @param n the indent level at which to start displaying
208 */
209 public void show( final int n ) {
210 showClass( n );
211 indent( n, "origin = " + origin );
212 indent( n, "lineno = " + lineNumber );
213 this.showComponents( n + 1 );
214 }
215
216 /**
217 * Displays the name of the instance of this class, with the specified
218 * indent level.
219 *
220 * @param n the indent level for displaying the class name
221 */
222 void showClass( final int n ) {
223 indent( n, this.getClass().getName() );
224 }
225
226 void showComponents( int n ) {
227 }
228
229 }