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.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         // Compile the expression
141         A a = compileIt();
142         // Set the context
143         a.setContext( origin, lineNumber );
144         // Return the compiled expression
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 }