cgialib 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,660 @@
1
+ # File: JavaLanguageScanner.rb
2
+ # Author: Jack Herrington
3
+ # Purpose: The JavaLanguageScanner object specialized to read Java token streams (from Java files)
4
+ # Date: 12/21/02
5
+
6
+ #require "Tokenizer"
7
+ #require "Language"
8
+ #require "JavaDoc"
9
+
10
+ module LanguageParser
11
+ # class : JavaVariable
12
+ #
13
+ # A specialized ClassVariable that includes the JavaDoc for the class
14
+
15
+ class JavaVariable < ClassVariable
16
+
17
+ # initialize()
18
+ #
19
+ # Constructor
20
+
21
+ def initialize()
22
+
23
+ super()
24
+
25
+ @javadoc = nil
26
+ @javadocClass = JavaDoc
27
+
28
+ end
29
+
30
+ attr_reader :javadoc # The JavaDoc object
31
+
32
+ attr_accessor :javadocClass # The class to use to creat the JavaDoc object
33
+
34
+ # comment=( text )
35
+ #
36
+ # text - The comment text
37
+ #
38
+ # Override of the comment set method to not only set the comment but also
39
+ # to parse it into the JavaDoc
40
+
41
+ def comment=( text )
42
+
43
+ super( text )
44
+
45
+ @javadoc = @javadocClass.new() unless ( @javadoc )
46
+ @javadoc.parse( text )
47
+
48
+ end
49
+
50
+ end
51
+
52
+ # class : JavaClass
53
+ #
54
+ # A specialization for LanguageClass to handle the JavaDoc markup on a Java
55
+ # class declaration
56
+
57
+ class JavaClass < LanguageClass
58
+
59
+ # initialize()
60
+ #
61
+ # Constructor
62
+
63
+ def initialize()
64
+
65
+ super()
66
+
67
+ @javadoc = nil
68
+ @javadocClass = JavaDoc
69
+
70
+ end
71
+
72
+ attr_reader :javadoc # The JavaDoc attached to the class
73
+
74
+ attr_accessor :javadocClass # The class to use to build the JavaDoc object
75
+
76
+ # comments=( text )
77
+ #
78
+ # text - The comment text
79
+ #
80
+ # Overrides the comment text setter to build the JavaDoc as well as setting
81
+ # the comment
82
+
83
+ def comments=( text )
84
+
85
+ super( text )
86
+
87
+ @javadoc = @javadocClass.new() unless ( @javadoc )
88
+ @javadoc.parse( text )
89
+
90
+ end
91
+
92
+ end
93
+
94
+ # class : JavaPrototype
95
+ #
96
+ # A derived class of Prototype to account for the JavaDoc attached to the
97
+ # prototype
98
+
99
+ class JavaPrototype < Prototype
100
+
101
+ # initialize()
102
+ #
103
+ # Constructor for the class
104
+
105
+ def initialize()
106
+
107
+ super()
108
+
109
+ @javadoc = nil
110
+ @javadocClass = JavaDoc
111
+
112
+ end
113
+
114
+ attr_reader :javadoc # The JavaDoc attached to the method
115
+
116
+ attr_accessor :javadocClass # The class to build the JavaDoc object
117
+
118
+ # add_comment( text )
119
+ #
120
+ # text - The comment text
121
+ #
122
+ # Overrides the add_comment method to account for the JavaDoc as well as
123
+ # adding the comment.
124
+
125
+ def add_comment( text )
126
+
127
+ super( text )
128
+
129
+ @javadoc = @javadocClass.new() unless ( @javadoc )
130
+ @javadoc.parse( text.to_s )
131
+
132
+ end
133
+
134
+ end
135
+
136
+ # class : JavaLanguageScanner
137
+ #
138
+ # This is the JavaLanguageScanner specialized to read prototypes for Java
139
+ # functions.
140
+
141
+ class JavaLanguageScanner < LanguageScanner
142
+
143
+ # initialize()
144
+ #
145
+ # Constructs the C language scanner class
146
+
147
+ def initialize()
148
+
149
+ super()
150
+
151
+ @classes = []
152
+
153
+ @prototypeClass = JavaPrototype
154
+ @variableClass = JavaVariable
155
+ @classClass = JavaClass
156
+ @javadocClass = JavaDoc
157
+
158
+ end
159
+
160
+ attr_accessor :prototypeClass # The prototype class to build
161
+
162
+ attr_reader :classes # An accessor for the array of classes found
163
+
164
+ attr_accessor :javadocClass # The class to use when build JavaDoc objects
165
+
166
+ attr_accessor :variableClass # The class to use when building variables
167
+
168
+ attr_accessor :classClass # The class to use when building classes
169
+
170
+ # to_s()
171
+ #
172
+ # Pretty printer
173
+
174
+ def to_s()
175
+
176
+ text = ""
177
+
178
+ text += "Classes:\n"
179
+
180
+ @classes.each { |jclass|
181
+
182
+ text += jclass.to_s
183
+
184
+ }
185
+
186
+ text
187
+
188
+ end
189
+
190
+ # parse( tokens )
191
+ #
192
+ # tokens - An array of tokens built by a Tokenizer
193
+ #
194
+ # This method reads the stream of tokens built by a Tokenizer
195
+ # and fills the @prototypes array with the prototypes
196
+ # that are found.
197
+
198
+ def parse( tokens )
199
+
200
+ tokens.each_index { |index|
201
+
202
+ if ( tokens[ index ].to_s == "class" || tokens[ index ].to_s == "interface" )
203
+
204
+ parse_class( tokens, index )
205
+
206
+ break;
207
+
208
+ end
209
+
210
+ }
211
+
212
+ end
213
+
214
+ protected
215
+
216
+ # parse_class( tokens, start, base_class = nil )
217
+ #
218
+ # tokens - The full array of tokens in the file
219
+ # start - The start of our class definition
220
+ # base_class - The name of the base class (nil if none)
221
+ #
222
+ # Parses the class and adds it to the class list.
223
+
224
+ def parse_class( tokens, start, base_class = nil )
225
+
226
+ # Build the class and add it
227
+
228
+ class_data = build_class()
229
+ class_data.javadocClass = @javadocClass
230
+ @classes.push( class_data )
231
+
232
+ # Backtrack to get the class comment
233
+
234
+ index = start
235
+ while( index >= 0 )
236
+
237
+ break if ( tokens[ index ].to_s == "public" )
238
+ break if ( tokens[ index ].to_s == "private" )
239
+ break if ( tokens[ index ].to_s == "class" )
240
+
241
+ index -= 1
242
+
243
+ end
244
+
245
+ # Add the comments to the class
246
+
247
+ comment = tokens.get_comments( index )
248
+ class_data.comments = comment
249
+ class_data.comments.strip!
250
+
251
+ # Make sure the name is set to nil, we use nil as a marker in the state
252
+ # machine
253
+
254
+ class_data.name = nil
255
+
256
+ # This is the code fragment leading up to the interior
257
+ # of the function
258
+
259
+ codefrag = TokenStream.new
260
+
261
+ # 'level' is the level of bracket nesting.
262
+
263
+ level = 0
264
+
265
+ # This will be true if we are looking at precompiler tokens
266
+
267
+ hold_until_return = false
268
+
269
+ # Look through each token
270
+
271
+ index = start
272
+
273
+ while( index < tokens.length )
274
+
275
+ tok = tokens[ index ]
276
+
277
+ # Handles parsing the class name
278
+
279
+ if ( class_data.name == nil && tok.is_a?( CodeToken ) && tok.to_s != "class" )
280
+
281
+ class_name = tok.to_s
282
+
283
+ class_name = "#{base_class}.#{class_name}" if ( base_class )
284
+
285
+ class_data.name = class_name
286
+ class_data.type = tokens[ start ].to_s
287
+
288
+ end
289
+
290
+ # Handles parsing the parents of the class
291
+
292
+ if ( level == 0 && tok.is_a?( CodeToken ) && class_data.name != nil )
293
+
294
+ if ( tok.to_s != "{" && tok.to_s != class_data.name &&
295
+ tok.to_s != "implements" && tok.to_s != "extends" )
296
+
297
+ class_data.add_parent( tok.to_s )
298
+
299
+ end
300
+
301
+ end
302
+
303
+ # For imports we wait until a return
304
+
305
+ if ( hold_until_return )
306
+
307
+ hold_until_return = false if ( tok.to_s =~ /^\n/ )
308
+ next
309
+
310
+ end
311
+
312
+ if tok.to_s == "class" || tok.to_s == "interface"
313
+
314
+ # Waiting for the class name
315
+
316
+ index = parse_class( tokens, index, class_data.name ) if ( index != start )
317
+
318
+ codefrag = TokenStream.new()
319
+
320
+ elsif tok.to_s == "{"
321
+
322
+ # If we are at level zero then we are
323
+ # opening a function for code, so we
324
+ # should interpret what we have
325
+ # up until now.
326
+
327
+ if level == 1
328
+
329
+ parse_prototype( class_data, codefrag )
330
+
331
+ codefrag = TokenStream.new()
332
+
333
+ end
334
+
335
+ # Now increment the level
336
+
337
+ level += 1
338
+
339
+ elsif tok.to_s == "}"
340
+
341
+ # Decrement the level
342
+
343
+ level -= 1
344
+
345
+ break if ( level == 0 )
346
+
347
+ elsif tok.to_s == ";"
348
+
349
+ # If we see a ";" and we are at level
350
+ # zero then we have a constant
351
+ # declaration
352
+
353
+ if level == 1
354
+
355
+ parse_variable( class_data, codefrag )
356
+
357
+ codefrag = TokenStream.new()
358
+
359
+ end
360
+
361
+
362
+ else
363
+
364
+ # Otherwise push the fragment
365
+
366
+ codefrag.push( tok ) if level == 1
367
+
368
+ end
369
+
370
+ index += 1
371
+
372
+ end
373
+
374
+ index
375
+
376
+ end
377
+
378
+ # parse_declaration( codefrag )
379
+ #
380
+ # codefrag - The code token array
381
+ #
382
+ # This turns the set of tokens that represent a declaration
383
+ # ("int *a[]") into a name ("a"), a type "int *", and an
384
+ # array boolean (true).
385
+
386
+ def parse_declaration( codefrag )
387
+
388
+ # Get just the code
389
+
390
+ code = codefrag.code_only
391
+
392
+ # If we are an assignment declaration then parse that
393
+
394
+ if ( code.find( "=" ) )
395
+
396
+ value = code.pop
397
+ code.pop
398
+
399
+ end
400
+
401
+ # See if we are private, public or protected
402
+
403
+ visibility = ""
404
+ visibility = "private" if code.find_and_remove( "private" )
405
+ visibility = "public" if code.find_and_remove( "public" )
406
+ visibility = "protected" if code.find_and_remove( "protected" )
407
+
408
+ # Get the static and final values
409
+
410
+ static = code.find_and_remove( "static" )
411
+ final = code.find_and_remove( "final" )
412
+
413
+ # By default this will not be an array
414
+
415
+ array = false
416
+
417
+ # Here we are backtracking from the end to find the name
418
+ # within the declaration
419
+
420
+ while( code.length > 0 )
421
+
422
+ frag = code.last
423
+
424
+ array = true if ( frag.to_s == "[" )
425
+
426
+ break unless ( frag.to_s == "[" || frag.to_s == "]" )
427
+
428
+ code.delete_at( code.length - 1 )
429
+
430
+ end
431
+
432
+ # We assume that the name is the last non-whitespace,
433
+ # non-array token
434
+
435
+ name = code.last.to_s
436
+
437
+ code.delete_at( code.length - 1 )
438
+
439
+ # Then we build the type from the remainder
440
+
441
+ type = code.map { |tok| tok.to_s }.join( " " )
442
+
443
+ # Then we return a structure that contains the declaration
444
+ # data
445
+
446
+ return {
447
+ 'name' => name,
448
+ 'type' => type,
449
+ 'array' => array,
450
+ 'value' => value,
451
+ 'visibility' => visibility,
452
+ 'static' => static,
453
+ 'final' => final
454
+ }
455
+
456
+ end
457
+
458
+ # parse_prototype( class_data, codefrag )
459
+ #
460
+ # class_data - The class object
461
+ # codefrag - The tokens leading up to a function definition
462
+ #
463
+ # This turns the series of tokens leading up to the function
464
+ # definition and turns it into a prototype object which it
465
+ # adds to the prototype list.
466
+
467
+ def parse_prototype( class_data, codefrag )
468
+
469
+ # This will be true when we have found the first
470
+ # code token
471
+
472
+ found_code = false
473
+
474
+ # True when our iterator is within the arguments tokens
475
+
476
+ in_arguments = false
477
+
478
+ # Start contains the tokens before the arguments
479
+
480
+ start = TokenStream.new()
481
+
482
+ # args contains the sets of arguments tokens
483
+
484
+ args = TokenStream.new()
485
+
486
+ # cur_arg contains the tokens of the argument
487
+ # currently being parsed
488
+
489
+ cur_arg = TokenStream.new()
490
+
491
+ # Contains any comments found within the tokens
492
+
493
+ comments = TokenStream.new()
494
+
495
+ # Iterate through the codefrag tokens
496
+
497
+ codefrag.each { |tok|
498
+
499
+ # Set found_code to true when we find a CodeToken
500
+
501
+ found_code = true if ( tok.is_a?( CodeToken ) )
502
+
503
+ # Add the comment if the token is a comment
504
+
505
+ if tok.is_a?( CommentToken )
506
+
507
+ comments.push( tok.to_s() )
508
+ next
509
+
510
+ end
511
+
512
+ # Go to the next token if we have not found code
513
+
514
+ next unless ( found_code )
515
+
516
+ if tok.to_s == "("
517
+
518
+ # Look for the start of the arguments
519
+
520
+ in_arguments = true
521
+ cur_arg = TokenStream.new()
522
+
523
+ elsif tok.to_s == ")"
524
+
525
+ # Look for the end of the arguments, when
526
+ # we find it we dump out of the iterator
527
+
528
+ args.push( cur_arg ) if cur_arg.length > 0
529
+ cur_arg = TokenStream.new()
530
+ break
531
+
532
+ elsif in_arguments == false
533
+
534
+ # If we are not in the arguments then
535
+ # push these code tokens into the start
536
+ # fragment list
537
+
538
+ start.push( tok )
539
+
540
+ else
541
+
542
+ # We are in the arguments, so look for
543
+ # the comments that seperate the arguments
544
+
545
+ if tok.to_s == ","
546
+
547
+ args.push( cur_arg ) if cur_arg.length > 0
548
+ cur_arg = TokenStream.new()
549
+
550
+ else
551
+
552
+ cur_arg.push( tok )
553
+
554
+ end
555
+
556
+ end
557
+
558
+ }
559
+
560
+ # Have the base class build the new prototype
561
+
562
+ proto = build_prototype()
563
+ proto.javadocClass = @javadocClass
564
+
565
+ # Parse the starting declaration and set the prototype
566
+
567
+ start_decl = parse_declaration( start )
568
+
569
+ proto.class_name = class_data.name
570
+ proto.method_name = start_decl['name']
571
+ proto.method_type = start_decl['type']
572
+ proto.static = start_decl['static']
573
+ proto.visibility = start_decl['visibility']
574
+
575
+ # Parse the arguments and add them to the prototype
576
+
577
+ args.each { |arg|
578
+
579
+ arg_decl = parse_declaration( arg )
580
+
581
+ proto.add_argument( arg_decl[ 'name' ], arg_decl['type'] )
582
+
583
+ }
584
+
585
+ # Add the comments
586
+
587
+ comments.each { |comment| proto.add_comment( comment.to_s ) }
588
+
589
+ # Add this prototype to the array of found prototypes
590
+
591
+ class_data.add_method( proto )
592
+
593
+ end
594
+
595
+ # parse_variable( class_data, codefrag )
596
+ #
597
+ # class_data - The class to which we add the variable declaration
598
+ # codefrag - The code fragmen that describes the variable
599
+ #
600
+ # Parses a variable declaration and adds it to the class
601
+
602
+ def parse_variable( class_data, codefrag )
603
+
604
+ # Get the comments
605
+
606
+ comment = codefrag.comments_only.to_s
607
+
608
+ # Get the declaration
609
+
610
+ varData = parse_declaration( codefrag )
611
+
612
+ # Build the variable object and populate it
613
+
614
+ varObj = build_variable()
615
+ varObj.javadocClass = @javadocClass
616
+ varObj.name = varData[ 'name' ]
617
+ varObj.type = varData[ 'type' ]
618
+ varObj.value = varData[ 'value' ]
619
+ varObj.visibility = varData[ 'visibility' ]
620
+ varObj.static = varData[ 'static' ]
621
+ varObj.comment = comment
622
+
623
+ # Add it to our class
624
+
625
+ class_data.add_variable( varObj )
626
+
627
+ end
628
+
629
+ # build_variable()
630
+ #
631
+ # Builds a new variable object
632
+
633
+ def build_variable()
634
+
635
+ @variableClass.new()
636
+
637
+ end
638
+
639
+ # build_class()
640
+ #
641
+ # Builds a new class object
642
+
643
+ def build_class()
644
+
645
+ @classClass.new()
646
+
647
+ end
648
+
649
+ # build_prototype()
650
+ #
651
+ # Builds and returns a prototype object
652
+
653
+ def build_prototype()
654
+
655
+ @prototypeClass.new()
656
+
657
+ end
658
+
659
+ end
660
+ end