7796b4acb01f10aa2692a4eddd48e480e3f58b49
[phpeclipse.git] /
1 /*
2  * $RCSfile: JSParser.java,v $
3  *
4  * Copyright 2002
5  * CH-1700 Fribourg, Switzerland
6  * All rights reserved.
7  *
8  *========================================================================
9  * Modifications history
10  *========================================================================
11  * $Log: not supported by cvs2svn $
12  * Revision 1.1  2004/02/26 02:25:42  agfitzp
13  * renamed packages to match xml & css
14  *
15  * Revision 1.1  2004/02/05 03:10:08  agfitzp
16  * Initial Submission
17  *
18  * Revision 1.1.2.1  2003/12/12 21:37:24  agfitzp
19  * Experimental work for Classes view
20  *
21  * Revision 1.6  2003/12/10 20:19:16  agfitzp
22  * 3.0 port
23  *
24  * Revision 1.5  2003/06/21 03:48:51  agfitzp
25  * fixed global variables as functions bug
26  * fixed length calculation of instance variables
27  * Automatic outlining is now a preference
28  *
29  * Revision 1.4  2003/05/30 20:53:09  agfitzp
30  * 0.0.2 : Outlining is now done as the user types. Some other bug fixes.
31  *
32  * Revision 1.3  2003/05/28 20:47:58  agfitzp
33  * Outline the document, not the file.
34  *
35  * Revision 1.2  2003/05/28 15:20:00  agfitzp
36  * Trivial change to test CVS commit
37  *
38  * Revision 1.1  2003/05/28 15:17:12  agfitzp
39  * net.sourceforge.phpeclipse.js.core 0.0.1 code base
40  *
41  *========================================================================
42 */
43
44 package net.sourceforge.phpeclipse.js.core.parser;
45
46 import java.io.ByteArrayOutputStream;
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.util.HashMap;
50 import java.util.LinkedList;
51 import java.util.List;
52
53 import net.sourceforge.phpeclipse.js.core.model.*;
54
55 import org.eclipse.core.resources.IFile;
56 import org.eclipse.jface.text.BadLocationException;
57 import org.eclipse.jface.text.Document;
58 import org.eclipse.jface.text.IDocument;
59 import org.eclipse.jface.text.rules.IToken;
60
61 /**
62  * DOCUMENT ME!
63  * 
64  * @author Addi 
65  */
66 public class JSParser
67 {
68
69         public static final String FUNCTION = "function";
70
71         /**
72          * line separator
73          */
74         public static final String LINE_SEPARATOR = System.getProperty("line.separator");
75
76         /**
77          * Array of system types to ignore.
78          */
79         private static String[] systemClassNames= {"Array","String"};
80
81
82         protected HashMap systemClassMap = new HashMap();
83           
84         protected IFile sourceFile;
85         protected IDocument sourceDocument;
86         protected HashMap functions = new HashMap();
87         protected HashMap classes = new HashMap();
88         protected HashMap globalVariables = new HashMap();
89         protected List elementList = new LinkedList();
90         protected JSSyntaxScanner scanner = new JSSyntaxScanner();
91
92         /**
93          * Constructor for JSParser.
94          */
95         public JSParser()
96         {
97                 super();
98
99                 int i;
100
101                 for(i = 0;i < systemClassNames.length; i++)
102                 {
103                         String aName = systemClassNames[i];
104                         systemClassMap.put(aName, aName);                
105                 }
106         }
107
108         /**
109          * Returns a string containing the contents of the given file.  Returns an empty string if there
110          * were any errors reading the file.
111          * @param file
112          * 
113          * @return
114          */
115         protected static String getText(IFile file)
116         {
117                 try
118                 {
119                         InputStream in = file.getContents();
120                         return streamToString(in);
121                 } catch (Exception e)
122                 {
123                         e.printStackTrace();
124                 }
125                 return "";
126         }
127
128         protected static String streamToString(InputStream in) throws IOException
129         {
130                 ByteArrayOutputStream out = new ByteArrayOutputStream();
131                 byte[] buf = new byte[1024];
132                 int read = in.read(buf);
133
134                 while (read > 0)
135                 {
136                         out.write(buf, 0, read);
137                         read = in.read(buf);
138                 }
139
140                 return out.toString();
141         }
142
143         /**
144          * Skips ahead and finds next non-whitespace token.
145          *
146          */
147         public IToken nextNonWhitespaceToken()
148         {
149                 IToken aToken = scanner.nextToken();
150
151                 while (!aToken.isEOF() && aToken.isWhitespace())
152                 {
153                         aToken = scanner.nextToken();
154                 }
155
156                 return aToken;
157         }
158
159         /**
160          * Parses the input given by the argument.
161          * 
162          * @param file  the element containing the input text
163          * 
164          * @return an element collection representing the parsed input
165          */
166         public List parse(IFile file)
167         {
168                 this.sourceFile = file;
169                 return parse(new Document(getText(file)));
170         }
171
172         /**
173          * Parses the input given by the argument.
174          * 
175          * @param aSourceDocument  the element containing the input text
176          * 
177          * @return an element collection representing the parsed input
178          */
179         public List parse(IDocument aSourceDocument)
180         {
181                 sourceDocument = aSourceDocument;
182                 
183                 scanner.setRange(sourceDocument, 0, sourceDocument.getLength());
184                 IToken token = scanner.nextToken();
185                 while (!token.isEOF())
186                 {
187                         int offset = scanner.getTokenOffset();
188                         int length = scanner.getTokenLength();
189                         String expression = getExpression(offset, length);
190                 
191                         if (token.equals(JSSyntaxScanner.TOKEN_FUNCTION))
192                         {
193                                 addFunction(expression, offset, length);
194                         }
195                 
196                         if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
197                         {
198                                 //We need to check if the token is already a function or class
199                                 if (functions.containsKey(expression) || classes.containsKey(expression))
200                                 {
201                                         token = nextNonWhitespaceToken();
202                                         if (token.equals(JSSyntaxScanner.TOKEN_MEMBER))
203                                         {
204                                                 detectInstanceMethod(offset, expression);
205                                         } else
206                                         {
207                                                 detectClassMethod(token, offset, expression);
208                                         }
209                                 } else
210                                 {
211                                         if (expression.equals("var"))
212                                         {
213                                                 detectGlobalVariable();
214                                         }
215                                 }
216                         }
217                         token = scanner.nextToken();
218                 }
219                 return elementList;
220         }
221
222         private void addFunction(String expression, int offset, int length)
223         {
224                 String functionSignature = getNaked(expression);
225                 int braceOffset = functionSignature.indexOf("(");
226                 String functionName = functionSignature.substring(0, braceOffset).trim();
227                 String arguments =
228                         functionSignature.substring(functionSignature.indexOf("("), functionSignature.indexOf(")") + 1);
229
230                 if (functionName.indexOf(".") >= 0)
231                 {
232                         //If the function signature includes .prototype. then it's a member.
233                         if (functionName.indexOf(".prototype.") >= 0)
234                         {
235                                 String className = functionName.substring(0, functionName.indexOf("."));
236                                 String memberName = functionName.substring(functionName.lastIndexOf(".") + 1);
237                                 JSInstanceMethodElement aMethod =
238                                         this.addInstanceMethod(memberName, className, arguments, offset, offset, length);
239                                 detectInstanceMethodContext(className, aMethod);
240                         } else
241                         {
242                                 String className = functionName.substring(0, functionName.indexOf("."));
243                                 if (functions.containsKey(className) || classes.containsKey(className))
244                                 {
245                                         String memberName = functionName.substring(functionName.lastIndexOf(".") + 1);
246                                         JSFunctionElement aMethod =
247                                                 this.addClassMethod(memberName, className, arguments, offset, offset, length);
248                                 }
249                         }
250                 } else
251                 {
252                         if(! functions.containsKey(functionName))
253                         {
254                                 JSFunctionElement aFunction = new JSFunctionElement(this.sourceFile, functionName, arguments, offset, length);
255         
256                                 elementList.add(aFunction);
257                                 functions.put(functionName, aFunction);
258         
259                                 detectFunctionContext(aFunction);
260                         }
261                 }
262         }
263
264         /**
265          *
266          */     
267         private void checkForSpecialGlobalTypes(JSGlobalVariableElement aVariable)
268         {
269                 IToken token = nextNonWhitespaceToken();
270                 if (!token.isEOF())
271                 {
272                         if(!checkForDynamicClass(aVariable, token))
273                         {
274                                 checkForAnonymousFunction(aVariable, token);
275                         }
276                 }
277         }
278
279         /**
280          *
281          */     
282         private boolean checkForDynamicClass(JSGlobalVariableElement aVariable, IToken rhsToken)
283         {
284                 if (rhsToken.equals(JSSyntaxScanner.TOKEN_DEFAULT))
285                 {
286                         int offset = scanner.getTokenOffset();
287                         int length = scanner.getTokenLength();
288                         
289                         String expression = getExpression(offset, length);
290
291                         if (expression.equals("new"))
292                         {
293                                 IToken token = nextNonWhitespaceToken();
294                                 if (!token.isEOF())
295                                 {
296                                         if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
297                                         {
298                                                 offset = scanner.getTokenOffset();
299                                                 length = scanner.getTokenLength();
300                                                 expression = getExpression(offset, length);
301                                                                                                                                                 
302                                                 if(! isSystemClass(expression))
303                                                 {
304                                                         JSClassElement aClass = findOrCreateClass(aVariable.getName());
305                                                         if(aClass != null)
306                                                         {
307                                                                 //Tell the class it's dynamically declared: what we will parse as class methods & vars are really instance methods & vars
308                                                                 aClass.setPrototype(true);
309                                                                 
310                                                                 return true;
311                                                         }
312                                                 }
313                                         }
314                                 }
315                         }
316                 }
317                 return false;   
318         }
319
320         /**
321          *
322          */     
323         private boolean checkForAnonymousFunction(JSGlobalVariableElement aVariable, IToken rhsToken)
324         {
325                 if (rhsToken.equals(JSSyntaxScanner.TOKEN_FUNCTION))
326                 {
327                         String functionName = aVariable.getName();
328                         int offset = aVariable.getOffset();
329                         int length = aVariable.getLength();
330                         
331                         int functionOffset = scanner.getTokenOffset();
332                         int functionLength = scanner.getTokenLength();
333                         String functionSignature =
334                                 getExpression(functionOffset, functionLength);
335                         String arguments = getArgumentString(functionSignature);
336
337                         JSFunctionElement aFunction = new JSFunctionElement(this.sourceFile, functionName, arguments, offset, functionOffset - offset + functionLength);
338
339                         elementList.add(aFunction);
340                         functions.put(functionName, aFunction);
341
342                         elementList.remove(aVariable);
343                         globalVariables.remove(functionName);
344
345                         detectFunctionContext(aFunction);
346                         
347                         return true;
348                 }
349                 
350                 return false;
351         }               
352
353         /**
354          *
355          */     
356         private String getExpression(int offset, int length)
357         {
358                 String expression;
359                 try {
360                         expression = sourceDocument.get(offset, length);//sourceBuffer.substring(offset, offset + length);
361                 } catch(BadLocationException e)
362                 {
363                         expression = "";
364                 }
365                 return expression;
366         }
367
368         /**
369          *
370          */     
371         private void detectGlobalVariable()
372         {
373                 IToken token;
374                 int length;
375                 int offset;
376
377                 token = nextNonWhitespaceToken();
378                 if (!token.isEOF())
379                 {
380                         if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
381                         {
382                                 int varOffset = scanner.getTokenOffset();
383                                 length = scanner.getTokenLength();
384                                 String variableName = getExpression(varOffset, length);
385
386                                 token = nextNonWhitespaceToken();
387                                 if (!token.isEOF())
388                                 {
389                                         offset = scanner.getTokenOffset();
390                                         length = scanner.getTokenLength();
391                                         String expression = getExpression(offset, length);
392                                         if (expression.equals("="))
393                                         {
394                                                 JSGlobalVariableElement aVariable = addGlobalVariable(variableName, varOffset);
395                                                 checkForSpecialGlobalTypes(aVariable);
396                                         }
397                                 }
398                         }
399                 }
400         }
401
402         private void detectClassMethod(IToken token, int classOffset, String className)
403         {
404                 int offset = scanner.getTokenOffset();
405                 int length = scanner.getTokenLength();
406                 String expression = getExpression(offset, length);
407                 
408                 if (expression.equals("."))
409                 {
410
411                         token = nextNonWhitespaceToken();
412                         if (!token.isEOF())
413                         {
414                                 offset = scanner.getTokenOffset();
415                                 length = scanner.getTokenLength();
416                                 String memberName = getExpression(offset, length);
417                 
418                                 token = nextNonWhitespaceToken();
419                                 if (!token.isEOF())
420                                 {
421                                         offset = scanner.getTokenOffset();
422                                         length = scanner.getTokenLength();
423                                         expression = getExpression(offset, length);
424                                         if (expression.equals("="))
425                                         {
426         
427                                                 token = nextNonWhitespaceToken();
428                                                 int tokenOffset = scanner.getTokenOffset();
429                                                 int tokenLength = scanner.getTokenLength();
430         
431                                                 if (token.equals(JSSyntaxScanner.TOKEN_FUNCTION))
432                                                 {
433                                                         String functionSignature = getExpression(tokenOffset, tokenLength);
434                                                         String arguments = getArgumentString(functionSignature);
435         
436                                                         JSFunctionElement aMethod =
437                                                                 addClassMethod(memberName, className, arguments, classOffset, tokenOffset, tokenLength);
438                                                         
439         
440                                                 } else
441                                                 {
442                                                         addClassVariable(memberName, className, classOffset);
443                                                 }
444                                         }
445                                 }
446                         }
447                 }
448         }
449
450         private String getArgumentString(String functionSignature)
451         {
452                 return functionSignature.substring(
453                                 functionSignature.indexOf("("),
454                                 functionSignature.indexOf(")") + 1);
455         }
456
457         private void detectInstanceMethod(int classOffset, String className)
458         {
459                 String expression;
460                 IToken token;
461                 int length;
462                 int offset;
463
464                 token = nextNonWhitespaceToken();
465                 if (!token.isEOF())
466                 {
467                         offset = scanner.getTokenOffset();
468                         length = scanner.getTokenLength();
469                         expression = getExpression(offset, length);
470
471                         if (expression.equals("."))
472                         {
473
474                                 token = nextNonWhitespaceToken();
475                                 if (!token.isEOF())
476                                 {
477                                         offset = scanner.getTokenOffset();
478                                         length = scanner.getTokenLength();
479                                         String memberName = getExpression(offset, length);
480
481                                         token = nextNonWhitespaceToken();
482                                         if (!token.isEOF())
483                                         {
484                                                 offset = scanner.getTokenOffset();
485                                                 length = scanner.getTokenLength();
486                                                 expression = getExpression(offset, length);
487                                                 if (expression.equals("="))
488                                                 {
489                                                         token = nextNonWhitespaceToken();
490                                                         if (token.equals(JSSyntaxScanner.TOKEN_FUNCTION))
491                                                         {
492                                                                 int functionOffset = scanner.getTokenOffset();
493                                                                 int functionLength = scanner.getTokenLength();
494                                                                 String functionSignature =
495                                                                         getExpression(functionOffset, functionLength);
496                                                                 String arguments = getArgumentString(functionSignature);
497         
498                                                                 JSInstanceMethodElement aMethod =
499                                                                         addInstanceMethod(
500                                                                                 memberName,
501                                                                                 className,
502                                                                                 arguments,
503                                                                                 classOffset,
504                                                                                 functionOffset,
505                                                                                 functionLength);
506         
507                                                                 detectInstanceMethodContext(className, aMethod);
508         
509                                                         } else
510                                                         {
511                                                                 addInstanceVariable(memberName, className, classOffset, (".prototype.").length());
512                                                         }
513         
514                                                 }
515                                         }
516                                 }
517                         }
518                 }
519         }
520
521         private void parseInstanceMethodContext(String className, JSFunctionElement aMethod)
522         {
523                 IToken token;
524
525                 token = nextNonWhitespaceToken();
526                 while (!token.isEOF())
527                 {
528                         int offset = scanner.getTokenOffset();
529                         int length = scanner.getTokenLength();
530                         String expression = getExpression(offset, length);
531
532                         //                      if (token.equals(JSSyntaxScanner.TOKEN_END_CONTEXT))
533                         if (expression.equals("}"))
534                         {
535                                 return;
536                         } else if (expression.equals("{"))
537                         {
538                                 parseInstanceMethodContext(className, aMethod);
539                         } else if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
540                         {
541                                 if (expression.equals("this"))
542                                 {
543                                         handleThisReference(className, offset);
544                                 }
545                         }
546
547                         token = nextNonWhitespaceToken();
548                 }
549         }
550
551         private void detectInstanceMethodContext(String className, JSFunctionElement aMethod)
552         {
553                 IToken token;
554
555                 token = nextNonWhitespaceToken();
556                 while (!token.isEOF())
557                 {
558                         int offset = scanner.getTokenOffset();
559                         int length = scanner.getTokenLength();
560                         String expression = getExpression(offset, length);
561
562                         //                      if (token.equals(JSSyntaxScanner.TOKEN_BEGIN_CONTEXT))
563                         if (expression.equals("{"))
564                         {
565                                 parseInstanceMethodContext(className, aMethod);
566                                 return;
567                         }
568
569                         token = nextNonWhitespaceToken();
570                 }
571         }
572
573         private void parseClassMethodContext(JSFunctionElement aMethod)
574         {
575                 IToken token;
576
577                 token = nextNonWhitespaceToken();
578                 while (!token.isEOF())
579                 {
580                         int offset = scanner.getTokenOffset();
581                         int length = scanner.getTokenLength();
582                         String expression = getExpression(offset, length);
583
584                         if (expression.equals("}"))
585                         {
586                                 return;
587                         } else if (expression.equals("{"))
588                         {
589                                 parseClassMethodContext(aMethod);
590                         }
591
592                         token = nextNonWhitespaceToken();
593                 }
594         }
595
596         private void detectClassMethodContext(JSFunctionElement aMethod)
597         {
598                 IToken token = nextNonWhitespaceToken();
599                 while (!token.isEOF())
600                 {
601                         int offset = scanner.getTokenOffset();
602                         int length = scanner.getTokenLength();
603                         String expression = getExpression(offset, length);
604
605                         if (expression.equals("{"))
606                         {
607                                 parseClassMethodContext(aMethod);
608                                 return;
609                         }
610
611                         token = nextNonWhitespaceToken();
612                 }
613         }
614
615         private void handleThisReference(String className, int expressionStart)
616         {
617                 IToken token = nextNonWhitespaceToken();
618                 if (!token.isEOF())
619                 {
620                         int offset = scanner.getTokenOffset();
621                         int length = scanner.getTokenLength();
622         
623                         String expression = getExpression(offset, length);
624         
625                         if(expression.equals("."))
626                         {
627                                 token = nextNonWhitespaceToken();
628                                 if (!token.isEOF())
629                                 {
630                                         int memberStart = scanner.getTokenOffset();
631                                         length = scanner.getTokenLength();
632         
633                                         String memberName = getExpression(memberStart, length);
634         
635                                         token = nextNonWhitespaceToken();
636                                         if (!token.isEOF())
637                                         {
638                                                 offset = scanner.getTokenOffset();
639                                                 length = scanner.getTokenLength();
640                                                 expression = getExpression(offset, length);
641                 
642                                                 if (expression.equals("="))
643                                                 {
644                                                         addInstanceVariable(memberName, className, expressionStart, 1 + 4 - className.length());
645                                                 }
646                                         }
647                                 }
648                         }
649                 }
650         }
651
652         private void parseFunctionContext(JSFunctionElement aFunction)
653         {
654                 IToken token;
655
656                 token = nextNonWhitespaceToken();
657                 while (!token.isEOF())
658                 {
659                         int offset = scanner.getTokenOffset();
660                         int length = scanner.getTokenLength();
661                         String expression = getExpression(offset, length);
662
663                         if (expression.equals("}"))
664                         {
665                                 return;
666                         } else if (expression.equals("{"))
667                         {
668                                 parseFunctionContext(aFunction);
669                         } else if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
670                         {
671                                 if (expression.equals("this"))
672                                 {
673                                         handleThisReference(aFunction.getName(), offset);
674                                 }
675                         }
676
677                         token = nextNonWhitespaceToken();
678                 }
679         }
680
681         private void detectFunctionContext(JSFunctionElement aFunction)
682         {
683                 IToken token = nextNonWhitespaceToken();
684                 while (!token.isEOF())
685                 {
686                         int offset = scanner.getTokenOffset();
687                         int length = scanner.getTokenLength();
688                         String expression = getExpression(offset, length);
689
690                         if (expression.equals("{"))
691                         {
692                                 parseFunctionContext(aFunction);
693                                 return;
694                         }
695
696                         token = nextNonWhitespaceToken();
697                 }
698         }
699
700         private JSInstanceMethodElement addInstanceMethod(
701                 String memberName,
702                 String className,
703                 String arguments,
704                 int classOffset,
705                 int functionOffset,
706                 int functionLength)
707         {
708                 int signatureLength = functionOffset - classOffset + functionLength;
709                 JSInstanceMethodElement aMethod =
710                         new JSInstanceMethodElement(this.sourceFile, memberName, arguments, classOffset, signatureLength);
711
712                 findOrCreateClass(className).addChildElement(aMethod);
713
714                 return aMethod;
715         }
716
717         private JSFunctionElement addClassMethod(
718                 String memberName,
719                 String className,
720                 String arguments,
721                 int classOffset,
722                 int functionOffset,
723                 int functionLength)
724         {
725                 JSClassElement aClass = findOrCreateClass(className); 
726                 int signatureLength = functionOffset - classOffset + functionLength;
727                 JSFunctionElement aMethod;
728                 
729                 if(aClass.isPrototype()) {
730                         aMethod = new JSInstanceMethodElement(this.sourceFile, memberName, arguments, classOffset, signatureLength);
731
732                         aClass.addChildElement(aMethod);
733                         detectInstanceMethodContext(className, aMethod);
734                 } else {
735                         aMethod = new JSClassMethodElement(this.sourceFile, memberName, arguments, classOffset, signatureLength);
736
737                         aClass.addChildElement(aMethod);
738                         detectClassMethodContext(aMethod);
739                 }
740
741                 return aMethod;
742         }
743
744         /**
745          * @param memberName
746          * @param className
747          * @param classOffset
748          * @return
749          */
750         private JSElement addClassVariable(String memberName, String className, int classOffset)
751         {
752                 //One extra char for "."
753                 JSElement aVariable;
754                 JSClassElement aClass = findOrCreateClass(className);
755                 
756                 if(aClass.isPrototype())
757                 {
758                         aVariable =     new JSInstanceVariableElement(this.sourceFile, memberName, classOffset, className.length() + memberName.length() + 1);
759
760                 } else {
761                         aVariable =     new JSClassVariableElement(this.sourceFile, memberName, classOffset, className.length() + memberName.length() + 1);
762                 }
763                 aClass.addChildElement(aVariable);
764
765                 return aVariable;
766         }
767
768         private JSInstanceVariableElement addInstanceVariable(
769                 String memberName,
770                 String className,
771                 int classOffset,
772                 int paddingWidth)
773         {
774                 //11 extra chars for ".prototype."
775                 JSInstanceVariableElement aVariable =
776                         new JSInstanceVariableElement(
777                                 this.sourceFile, 
778                                 memberName,
779                                 classOffset,
780                                 className.length() + memberName.length() + paddingWidth);
781
782                 findOrCreateClass(className).addChildElement(aVariable);
783
784                 return aVariable;
785         }
786
787         private JSGlobalVariableElement addGlobalVariable(String variableName, int offset)
788         {
789                 JSGlobalVariableElement aVariable;
790                 if (!globalVariables.containsKey(variableName))
791                 {
792                         aVariable = new JSGlobalVariableElement(this.sourceFile, variableName, offset, variableName.length());
793
794                         elementList.add(aVariable);
795                         globalVariables.put(variableName, aVariable);
796                 } else
797                 {
798                         aVariable = (JSGlobalVariableElement) classes.get(variableName);
799                 }
800
801                 return aVariable;
802         }
803
804         private JSClassElement findOrCreateClass(String className)
805         {
806                 JSClassElement aClass = null;
807                 if (!classes.containsKey(className))
808                 {
809                         if(functions.containsKey(className))
810                         {
811                                 //if we're creating a class from an existing function we must
812                                 //migrate the existing function to become a constructor in the class.
813                                 JSFunctionElement constructor = (JSFunctionElement) functions.get(className);
814         
815                                 aClass = new JSClassElement(this.sourceFile, className, constructor.getStart(), constructor.getLength());
816                                 aClass.addChildElement(constructor);
817         
818                                 elementList.remove(constructor);
819                                 elementList.add(aClass);
820                                 classes.put(className, aClass);
821                         } else if(globalVariables.containsKey(className))
822                         {
823                                 //if we're creating a class from an existing global variable we must
824                                 //migrate the existing function to become a constructor in the class.
825                                 JSGlobalVariableElement aVariable = (JSGlobalVariableElement) globalVariables.get(className);
826
827                                 aClass = new JSClassElement(this.sourceFile, className, aVariable.getStart(), aVariable.getLength());
828
829                                 elementList.remove(aVariable);
830                                 elementList.add(aClass);
831                                 classes.put(className, aClass);                         
832                                 globalVariables.remove(className);
833                         } else {
834                                 //The final case is if we have no idea where this class came from, but shouldn't be ignored.
835                                 aClass = new JSClassElement(this.sourceFile, className, 0, 0);
836
837                                 elementList.add(aClass);
838                                 classes.put(className, aClass);                         
839                         }
840                 } else
841                 {
842                         aClass = (JSClassElement) classes.get(className);
843                 }
844
845                 return aClass;
846         }
847         
848         public boolean isSystemClass(String aClassName)
849         {
850                 return systemClassMap.containsKey(aClassName);
851         }
852
853         /**
854          * Method getNaked.
855          * @param funcName
856          */
857         private String getNaked(String funcName)
858         {
859                 if (funcName == null)
860                 {
861                         return null;
862                 }
863
864                 funcName = funcName.trim().substring(FUNCTION.length()).trim();
865                 funcName = replaceInString(funcName.trim(), LINE_SEPARATOR, "");
866
867                 StringBuffer strBuf = new StringBuffer("");
868                 int len = funcName.length();
869                 boolean wasSpace = false;
870                 for (int i = 0; i < len; i++)
871                 {
872                         char ch = funcName.charAt(i);
873                         if (ch == ' ')
874                         {
875                                 wasSpace = true;
876                         } else // not space
877                                 {
878                                 if (wasSpace)
879                                 {
880                                         strBuf.append(' ');
881                                 }
882                                 strBuf.append(ch);
883                                 wasSpace = false;
884                         }
885                 }
886                 return strBuf.toString();
887         }
888
889         /**
890          * replace in a string a string sequence with another string sequence
891          */
892         public static String replaceInString(String source, String whatBefore, String whatAfter)
893         {
894                 if (null == source || source.length() == 0)
895                 {
896                         return source;
897                 }
898                 int beforeLen = whatBefore.length();
899                 if (beforeLen == 0)
900                 {
901                         return source;
902                 }
903                 StringBuffer result = new StringBuffer("");
904                 int lastIndex = 0;
905                 int index = source.indexOf(whatBefore, lastIndex);
906                 while (index >= 0)
907                 {
908                         result.append(source.substring(lastIndex, index));
909                         result.append(whatAfter);
910                         lastIndex = index + beforeLen;
911
912                         // get next
913                         index = source.indexOf(whatBefore, lastIndex);
914                 }
915                 result.append(source.substring(lastIndex));
916                 return result.toString();
917         }
918
919         /**
920          * @return Returns the elementList.
921          */
922         public List getElementList() {
923                 return elementList;
924         }
925
926 }