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.action;
23  
24  import org.millscript.commons.alert.Alert;
25  import org.millscript.commons.alert.AlertOrigin;
26  import org.millscript.commons.alert.EscapeException;
27  import org.millscript.millscript.alert.Alerts;
28  import org.millscript.millscript.alert.Phases;
29  import org.millscript.millscript.vm.Machine;
30  
31  /**
32   * This class represents the base class of all actions in MillScript. As such
33   * all actions must extend this class, or one of it's sub-classes. An action
34   * is the result of compiling an expression and is the final stage of
35   * compilation.
36   *
37   * @see org.millscript.millscript.expr.Expr
38   * @see org.millscript.millscript.syntax.Syntax
39   */
40  public abstract class Action implements AlertOrigin {
41  
42      /**
43       * This originating line number in the origin, where this action was
44       * compiled from.
45       */
46      private int lineNumber = -1;
47  
48      /**
49       * The origin of the expression this action was compiled from.
50       */
51      private String origin = null;
52  
53      /**
54       * This method wraps <code>action</code>, to perform general purpose
55       * exception handling. Generally this method would be called to perform
56       * an action, rather than <code>action</code> directly.
57       *
58       * @param mc    the machine to perform this action on
59       */
60      public final void act( final Machine mc ) {
61          try {
62              action( mc );
63          } catch ( EscapeException ex ) {
64              // We're trying to escape to the top level, so just re-throw it
65              throw ex;
66          } catch ( Alert ex ) {
67              // Get the originating alert, try to decorate it then remishap it
68              throw(
69                  ex.decorate( mc ).origin( this ).setPhase( Phases.EVAL ).remishap()
70              );
71          } catch ( Exception ex ) {
72              // Ah, a generic exception. Turn it into an alert and fill in as
73              // much information as possible.
74              final Alert alert = Alerts.eval(
75                  "An exception has aborted execution",
76                  null
77              );
78  
79              alert.culprit( "exception", ex );
80  
81              String reason = ex.getMessage();
82              if ( reason != null ) {
83                  alert.culprit( "reason", reason );
84              }
85  
86              // We need to add any available information from the machine and origin
87              throw(
88                  alert.decorate( mc ).origin( this ).setParentThrowable( ex ).mishap()
89              );
90          }
91      }
92  
93      /**
94       * Returns the last object pushed onto the stack, after performing this
95       * action. This is the equivalent of performing the <code>act</code> method
96       * and poping a result off the machine's stack.
97       *
98       * @param mc    the machine to perform this action on
99       * @return  the object poped off the machines stack after performing this
100      * action
101      */
102     public final Object act1( final Machine mc ) {
103         act( mc );
104         return mc.popObject();
105     }
106 
107     /**
108      * Performs this action, on the specified machine. This method must be
109      * implemented in sub-classes to perform the required actions.
110      *
111      * @param mc    the machine to perform this action on
112      */
113     public abstract void action( final Machine mc );
114 
115     /**
116      * @see org.millscript.commons.alert.AlertOrigin#getLineNumber()
117      */
118     public int getLineNumber() {
119         return lineNumber;
120     }
121 
122     /**
123      * @see org.millscript.commons.alert.AlertOrigin#getOrigin()
124      */
125     public String getOrigin() {
126         return origin;
127     }
128 
129     /**
130      * Returns the boolean value of the last object pushed onto the stack,
131      * after performing this action. This is roughly equivalent to the
132      * <code>act1</code> method, but it requires that the last value on the
133      * stack is a <code>Boolean</code>.
134      *
135      * @param mc    the machine to perform this action on
136      * @return  the boolean value of the last object on the stack
137      */
138     public final boolean predAct( final Machine mc ) {
139         act( mc );
140         Object x = mc.popObject();
141         if ( x instanceof Boolean ) {
142             return ((Boolean)x).booleanValue();
143         } else {
144             throw(
145                 Alerts.eval( "Predicate returned non-boolean", null ).culprit( "object", x ).mishap()
146             );
147         }
148     }
149 
150     /**
151      * @see org.millscript.commons.alert.AlertOrigin#setContext(java.lang.String, int)
152      */
153     public final void setContext( final String fname, final int ln ) {
154         this.origin = fname;
155         this.lineNumber = ln;
156     }
157 
158     /**
159      * @see org.millscript.commons.alert.AlertOrigin#setLineNumber(int)
160      */
161     public void setLineNumber( final int n ) {
162         this.lineNumber = n;
163     }
164 
165     /**
166      * @see org.millscript.commons.alert.AlertOrigin#setOrigin(java.lang.String)
167      */
168     public void setOrigin( final String o ) {
169         this.origin = o;
170     }
171 
172 }