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.ELinkedList;
25  import org.millscript.millscript.alert.Alerts;
26  import org.millscript.millscript.expr.CommaExpr;
27  import org.millscript.millscript.expr.ConstantExpr;
28  import org.millscript.millscript.expr.Expr;
29  import org.millscript.millscript.expr.NameExpr;
30  import org.millscript.millscript.expr.SkipExpr;
31  import org.millscript.millscript.expr.SpiceClassExpr;
32  import org.millscript.millscript.expr.SpiceClassSlotExpr;
33  import org.millscript.millscript.expr.VarExpr;
34  import org.millscript.millscript.functions.SlotFunction;
35  
36  /**
37   * This class implements <code>class</code> syntax.
38   *
39   * @see org.millscript.millscript.expr.SpiceClassExpr
40   * @see org.millscript.millscript.expr.VarExpr
41   */
42  public final class SpiceClassSyntax extends PrefixSyntax {
43  
44      /**
45       * The closing character sequence for this instance of class syntax.
46       */
47      private final String closingKeyword;
48  
49      /**
50       * The define syntax used for parsing method definitions.
51       */
52      private static final DefineSyntax DEFINE = new DefineSyntax();
53  
54      /**
55       * Creates a class syntax parser instance, with the specified closing
56       * character sequence.
57       *
58       * @param   x   the closing character seqeunce for this class syntax parser
59       * instance
60       */
61      SpiceClassSyntax( final String x ) {
62          closingKeyword = x;
63      }
64  
65      /**
66       * @see org.millscript.millscript.syntax.PrefixSyntaxInterface#prefix(java.lang.String, org.millscript.millscript.syntax.ParserImpl)
67       */
68      @Override
69      public Expr prefix( final String sym, final Parser parser ) {
70          // This holds all the definitions in the class,e.g. slots, methods and
71          // functions
72          Expr definitions = new SkipExpr();
73  
74          // This holds the parent classes we inherit from
75          Expr parentClasses = new SkipExpr();
76  
77          // This stack will hold all the slot initialisers for this class
78          final EList< SpiceClassSlotExpr > slotInitialisers = new ELinkedList< SpiceClassSlotExpr >();
79  
80          // Read the class name
81          final NameExpr className = parser.readName();
82  
83          // Have a look for any inheritance
84          if ( parser.tryRead( "extends" ) ) {
85              // Oooo, single inheritance for now, so read a single name
86              parentClasses = CommaExpr.make( parentClasses, parser.readName() );
87          } else {
88              parentClasses = null;
89          }
90  
91          // We use this parser for parsing the class body, so that we know we
92          // are inside a particular class definition when we parse methods
93          final SpiceClassParserDelegate classParser = new SpiceClassParserDelegate( parser, className );
94  
95          // Read the body of the class definition
96          while ( !parser.tryRead( closingKeyword ) ) {
97              if ( parser.tryRead( "slot" ) ) {
98                  // Read the slot name
99                  final NameExpr slotName = parser.readName();
100                 // The slot value, we default to whatever we like. For an easy
101                 // ride we choose absent.
102                 Expr slotValue = new ConstantExpr( null );
103                 // Check for the equals
104                 if ( parser.tryRead( "=" ) ) {
105                     // Read the slots initial value
106                     slotValue = parser.readExpr();
107                 }
108                 final SlotFunction sf = (SlotFunction) new SlotFunction().modName( slotName.getName() );
109                 // Store the new slot function
110                 definitions = CommaExpr.make(
111                     definitions,
112                     new VarExpr(
113                         false,
114                         slotName,
115                         new ConstantExpr( sf )
116                     )
117                 );
118                 // Store the new slot initialiser
119                 slotInitialisers.addLast(
120                     new SpiceClassSlotExpr( sf, slotValue )
121                 );
122             } else if ( parser.tryRead( "define" ) ) {
123                 // Ah ha, parse the define using the SpiceClassParserDelegate
124                 // so that methods will know their enclosing class
125                 definitions = CommaExpr.make(
126                     definitions,
127                     DEFINE.prefix( "define", classParser )
128                 );
129             } else {
130                 // Unexpected token in class body
131                 throw(
132                     Alerts.parse(
133                         "Unexpected token in class definition",
134                         "Only 'slot' is a valid token in a class body(at the moment)"
135                     ).culprit( "token", parser.getErrorString() ).mishap()
136                 );
137             }
138             // Read the semi-colon separating expressions.
139             // TODO - When is this optional?
140             parser.tryRead( ";" );
141         }
142 
143         // Make a new variable to hold the class
144         return CommaExpr.make(
145             new VarExpr(
146                 false,
147                 className,
148                 new SpiceClassExpr( className.getName(), parentClasses, slotInitialisers )
149             ),
150             definitions
151         );
152     }
153 
154 }