KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubySymbol


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
15  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
16  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
17  * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
18  * Copyright (C) 2004 Joey Gibson <joey@joeygibson.com>
19  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
20  * Copyright (C) 2006 Derek Berner <derek.berner@state.nm.us>
21  * Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either of the GNU General Public License Version 2 or later (the "GPL"),
25  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the CPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the CPL, the GPL or the LGPL.
34  ***** END LICENSE BLOCK *****/

35 package org.jruby;
36
37 import java.util.HashMap JavaDoc;
38 import java.util.Iterator JavaDoc;
39 import java.util.Map JavaDoc;
40 import org.jruby.runtime.ClassIndex;
41 import org.jruby.runtime.builtin.IRubyObject;
42 import org.jruby.runtime.marshal.UnmarshalStream;
43
44 /**
45  *
46  * @author jpetersen
47  */

48 public class RubySymbol extends RubyObject {
49     private final String JavaDoc symbol;
50     private final int id;
51     
52     private RubySymbol(Ruby runtime, String JavaDoc symbol) {
53         super(runtime, runtime.getClass("Symbol"));
54         this.symbol = symbol;
55
56         runtime.symbolLastId++;
57         this.id = runtime.symbolLastId;
58     }
59     
60     public int getNativeTypeIndex() {
61         return ClassIndex.SYMBOL;
62     }
63
64     /** rb_to_id
65      *
66      * @return a String representation of the symbol
67      */

68     public String JavaDoc asSymbol() {
69         return symbol;
70     }
71
72     public boolean isImmediate() {
73         return true;
74     }
75     
76     public static String JavaDoc getSymbol(Ruby runtime, long id) {
77         RubySymbol result = runtime.getSymbolTable().lookup(id);
78         if (result != null) {
79             return result.symbol;
80         }
81         return null;
82     }
83
84     /* Symbol class methods.
85      *
86      */

87
88     public static RubySymbol newSymbol(Ruby runtime, String JavaDoc name) {
89         RubySymbol result;
90         synchronized (RubySymbol.class) {
91             // Locked to prevent the creation of multiple instances of
92
// the same symbol. Most code depends on them being unique.
93

94             result = runtime.getSymbolTable().lookup(name);
95             if (result == null) {
96                 result = new RubySymbol(runtime, name);
97                 runtime.getSymbolTable().store(result);
98             }
99         }
100         return result;
101     }
102
103     public IRubyObject equal(IRubyObject other) {
104         // Symbol table ensures only one instance for every name,
105
// so object identity is enough to compare symbols.
106
return RubyBoolean.newBoolean(getRuntime(), this == other);
107     }
108
109     public RubyFixnum to_i() {
110         return getRuntime().newFixnum(id);
111     }
112
113     public IRubyObject inspect() {
114         return getRuntime().newString(":" +
115             (isSymbolName(symbol) ? symbol : getRuntime().newString(symbol).dump().toString()));
116     }
117
118     public IRubyObject to_s() {
119         return getRuntime().newString(symbol);
120     }
121
122     public RubyFixnum hash() {
123         return getRuntime().newFixnum(hashCode());
124     }
125     
126     public int hashCode() {
127         return id;
128     }
129     
130     public boolean equals(Object JavaDoc other) {
131         return other == this;
132     }
133     
134     public IRubyObject to_sym() {
135         return this;
136     }
137
138     public IRubyObject freeze() {
139         return this;
140     }
141
142     public IRubyObject taint() {
143         return this;
144     }
145     
146     private static boolean isIdentStart(char c) {
147         return ((c >= 'a' && c <= 'z')|| (c >= 'A' && c <= 'Z')
148                 || c == '_');
149     }
150     private static boolean isIdentChar(char c) {
151         return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
152                 || c == '_');
153     }
154     
155     private static boolean isIdentifier(String JavaDoc s) {
156         if (s == null || s.length() <= 0) {
157             return false;
158         }
159         
160         if (!isIdentStart(s.charAt(0))) {
161             return false;
162         }
163         for (int i = 1; i < s.length(); i++) {
164             if (!isIdentChar(s.charAt(i))) {
165                 return false;
166             }
167         }
168         
169         return true;
170     }
171     
172     /**
173      * is_special_global_name from parse.c.
174      * @param s
175      * @return
176      */

177     private static boolean isSpecialGlobalName(String JavaDoc s) {
178         if (s == null || s.length() <= 0) {
179             return false;
180         }
181
182         int length = s.length();
183            
184         switch (s.charAt(0)) {
185         case '~': case '*': case '$': case '?': case '!': case '@': case '/': case '\\':
186         case ';': case ',': case '.': case '=': case ':': case '<': case '>': case '\"':
187         case '&': case '`': case '\'': case '+': case '0':
188             return length == 1;
189         case '-':
190             return (length == 1 || (length == 2 && isIdentChar(s.charAt(1))));
191             
192         default:
193             // we already confirmed above that length > 0
194
for (int i = 0; i < length; i++) {
195                 if (!Character.isDigit(s.charAt(i))) {
196                     return false;
197                 }
198             }
199         }
200         return true;
201     }
202     
203     private static boolean isSymbolName(String JavaDoc s) {
204         if (s == null || s.length() < 1) {
205             return false;
206         }
207
208         int length = s.length();
209
210         char c = s.charAt(0);
211         switch (c) {
212         case '$':
213             return length > 1 && isSpecialGlobalName(s.substring(1));
214         case '@':
215             int offset = 1;
216             if (length >= 2 && s.charAt(1) == '@') {
217                 offset++;
218             }
219
220             return isIdentifier(s.substring(offset));
221         case '<':
222             return (length == 1 || (length == 2 && (s.equals("<<") || s.equals("<="))) ||
223                     (length == 3 && s.equals("<=>")));
224         case '>':
225             return (length == 1) || (length == 2 && (s.equals(">>") || s.equals(">=")));
226         case '=':
227             return ((length == 2 && (s.equals("==") || s.equals("=~"))) ||
228                     (length == 3 && s.equals("===")));
229         case '*':
230             return (length == 1 || (length == 2 && s.equals("**")));
231         case '+':
232             return (length == 1 || (length == 2 && s.equals("+@")));
233         case '-':
234             return (length == 1 || (length == 2 && s.equals("-@")));
235         case '|': case '^': case '&': case '/': case '%': case '~': case '`':
236             return length == 1;
237         case '[':
238             return s.equals("[]") || s.equals("[]=");
239         }
240         
241         if (!isIdentStart(c)) {
242             return false;
243         }
244
245         boolean localID = (c >= 'a' && c <= 'z');
246         int last = 1;
247         
248         for (; last < length; last++) {
249             char d = s.charAt(last);
250             
251             if (!isIdentChar(d)) {
252                 break;
253             }
254         }
255                     
256         if (last == length) {
257             return true;
258         } else if (localID && last == length - 1) {
259             char d = s.charAt(last);
260             
261             return d == '!' || d == '?' || d == '=';
262         }
263         
264         return false;
265     }
266     
267  
268
269     public static RubySymbol unmarshalFrom(UnmarshalStream input) throws java.io.IOException JavaDoc {
270         RubySymbol result = RubySymbol.newSymbol(input.getRuntime(), RubyString.byteListToString(input.unmarshalString()));
271         input.registerLinkTarget(result);
272         return result;
273     }
274
275     public static class SymbolTable {
276        
277         private Map JavaDoc table = new HashMap JavaDoc();
278         
279         public IRubyObject[] all_symbols() {
280             int length = table.size();
281             IRubyObject[] array = new IRubyObject[length];
282             System.arraycopy(table.values().toArray(), 0, array, 0, length);
283             return array;
284         }
285         
286         public RubySymbol lookup(long symbolId) {
287             Iterator JavaDoc iter = table.values().iterator();
288             while (iter.hasNext()) {
289                 RubySymbol symbol = (RubySymbol) iter.next();
290                 if (symbol != null) {
291                     if (symbol.id == symbolId) {
292                         return symbol;
293                     }
294                 }
295             }
296             return null;
297         }
298         
299         public RubySymbol lookup(String JavaDoc name) {
300             return (RubySymbol) table.get(name);
301         }
302         
303         public void store(RubySymbol symbol) {
304             table.put(symbol.asSymbol(), symbol);
305         }
306         
307     }
308     
309 }
310
Popular Tags