mucgly 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +8 -0
  3. data/LICENSE +1 -1
  4. data/README.rdoc +160 -130
  5. data/bin/mucgly +4 -217
  6. data/doc/Mucgly.html +24 -82
  7. data/doc/_index.html +5 -153
  8. data/doc/class_list.html +7 -2
  9. data/doc/css/style.css +2 -1
  10. data/doc/file.CHANGELOG.html +16 -8
  11. data/doc/file.README.html +210 -187
  12. data/doc/file_list.html +6 -1
  13. data/doc/frames.html +5 -7
  14. data/doc/index.html +210 -187
  15. data/doc/js/app.js +7 -2
  16. data/doc/js/full_list.js +9 -6
  17. data/doc/method_list.html +7 -686
  18. data/doc/top-level-namespace.html +5 -5
  19. data/ext/mucgly/extconf.rb +11 -0
  20. data/ext/mucgly/mucgly.c +2095 -0
  21. data/lib/version.rb +6 -0
  22. data/test/golden/test_basic.txt +18 -0
  23. data/test/golden/test_specials_cli.txt +11 -0
  24. data/test/golden/test_specials_cmd.txt +36 -0
  25. data/test/result/test_basic.txt +18 -0
  26. data/test/result/test_specials_cli.txt +11 -0
  27. data/test/result/test_specials_cmd.txt +36 -0
  28. data/test/result/test_specials_cmd2.txt +1 -0
  29. data/test/test_basic.rx.txt +10 -6
  30. data/test/test_mucgly.rb +4 -6
  31. data/test/test_specials_cli.rx.txt +4 -4
  32. data/test/test_specials_cmd.rx.txt +5 -5
  33. metadata +45 -63
  34. data/Rakefile +0 -29
  35. data/doc/EasyFile/InOut.html +0 -2097
  36. data/doc/EasyFile/Read.html +0 -1334
  37. data/doc/EasyFile/ReadStack.html +0 -461
  38. data/doc/EasyFile/Stacked.html +0 -411
  39. data/doc/EasyFile/String.html +0 -570
  40. data/doc/EasyFile/Write.html +0 -1084
  41. data/doc/EasyFile/WriteStack.html +0 -305
  42. data/doc/EasyFile.html +0 -155
  43. data/doc/Mucgly/Env.html +0 -1675
  44. data/doc/Mucgly/MucglyFile/ParseState.html +0 -1662
  45. data/doc/Mucgly/MucglyFile/Token.html +0 -529
  46. data/doc/Mucgly/MucglyFile.html +0 -545
  47. data/doc/Mucgly/Separators.html +0 -521
  48. data/lib/easyfile.rb +0 -720
  49. data/lib/mucgly.rb +0 -627
  50. data/test/test_multi.rx.txt +0 -4
data/lib/mucgly.rb DELETED
@@ -1,627 +0,0 @@
1
- module Mucgly
2
-
3
-
4
- def Mucgly::error( str )
5
- if Opt['warn_only'].given
6
- puts "*** Mucgly Error: #{str}"
7
- else
8
- raise RuntimeError, "*** Mucgly Error: #{str}"
9
- end
10
- end
11
-
12
- def Mucgly::debug( str )
13
- puts "\nMucglyDebug: #{str}" if Opt['debug'].given
14
- end
15
-
16
-
17
- # Execution environment for MucglyFile.
18
- class Env
19
-
20
- @@fileStartHook = nil
21
- @@fileEndHook = nil
22
-
23
- attr_accessor :_separators
24
- attr_accessor :_inIO
25
- attr_accessor :_outIO
26
-
27
- def initialize
28
- @_outIO = STDOUT
29
- end
30
-
31
- def Env.fileStartHook=( val )
32
- @@fileStartHook = val
33
- end
34
-
35
- def Env.fileEndHook=( val )
36
- @@fileEndHook = val
37
- end
38
-
39
- def Env.fileStartHook
40
- @@fileStartHook
41
- end
42
-
43
- def Env.fileEndHook
44
- @@fileEndHook
45
- end
46
-
47
- def fileStartHook
48
- @@fileStartHook
49
- end
50
-
51
- def fileEndHook
52
- @@fileEndHook
53
- end
54
-
55
- def write( str )
56
- @_outIO.write str
57
- end
58
-
59
- def puts( str )
60
- @_outIO.puts str
61
- end
62
-
63
- def source( file )
64
- instance_eval( File.read( file ), file )
65
- end
66
-
67
-
68
- # ------------------------------------------------------------
69
- # Interface methods:
70
-
71
-
72
- def _processFilePair( filePair )
73
- _openInput( filePair[ 0 ] )
74
- _openOutput( filePair[ 1 ] )
75
- Mucgly::MucglyFile.new( self )
76
- end
77
-
78
- def _processFilePairs( filePairs )
79
- filePairs.each do |pair|
80
- _processFilePair( pair )
81
- end
82
- end
83
-
84
- def _openInput( filename )
85
- @_inIO = EasyFile::ReadStack.new( filename )
86
- end
87
-
88
- def _openOutput( filename )
89
- @_outIO = EasyFile::WriteStack.new( filename )
90
- end
91
-
92
- def _openString( filename )
93
- @_outIO = EasyFile::String.open( filename )
94
- end
95
-
96
- def _pushInput( name )
97
- @_inIO.push( name )
98
- end
99
-
100
- def _pushOutput( name )
101
- @_outIO.push( name )
102
- end
103
-
104
- def _closeInput
105
- @_inIO.close
106
- end
107
-
108
- def _closeOutput
109
- @_outIO.close
110
- end
111
-
112
- def _ofilename
113
- @_outIO.filename
114
- end
115
-
116
- def _olinenumber
117
- @_outIO.line
118
- end
119
-
120
- def _ifilename
121
- @_inIO.filename
122
- end
123
-
124
- def _ilinenumber
125
- @_inIO.line
126
- end
127
-
128
- def _eval( cmd )
129
- instance_eval cmd
130
- end
131
-
132
- end
133
-
134
-
135
- # MucglyFile includes processing and status for a file that is treated
136
- # as Mucgly file. Separators are copied from the upper level
137
- # context i.e. lower level settings does NOT affect higher level
138
- # settings. Status of parsing is kept within the class.
139
- class MucglyFile
140
-
141
- attr_accessor :env, :parseState
142
-
143
- def initialize( env )
144
-
145
- @env = env
146
-
147
- # Process fileStartHook callback:
148
- @env._eval( @env.fileStartHook ) if @env.fileStartHook
149
-
150
- # Copy upper level separators.
151
- @env._separators = @env._separators.copy
152
-
153
- # Process the Mucgly file.
154
- parse
155
- end
156
-
157
-
158
- # Input is a stream of characters or control values.
159
- #
160
- # Supported types: char, hookEnd, hookBeg, escape, eof, and
161
- # empty
162
- class Token
163
-
164
- attr_accessor :type, :value
165
-
166
- def initialize( type, value = nil )
167
- @type = type
168
- @value = value
169
- end
170
-
171
- def isPunct
172
- !isChar
173
- end
174
-
175
- def isChar
176
- @type == :char
177
- end
178
-
179
- def to_s
180
- "#{@type.to_s}:#{value}"
181
- end
182
-
183
- end
184
-
185
-
186
- # Parse state regarding buffered tokens.
187
- class ParseState
188
-
189
- def initialize( host )
190
- @host = host
191
- @stack = [[]]
192
- @level = 0
193
- @active = false
194
- end
195
-
196
- # Add token.
197
- def shift( token )
198
- if @stack[-1][-1] && @stack[-1][-1].type == token.type
199
- @stack[-1][-1].value += token.value
200
- else
201
- @stack[-1].push token
202
- end
203
- end
204
-
205
- # Push new parse context.
206
- def push
207
- unless inside?
208
- flush
209
- end
210
- inc
211
- @stack.push []
212
- end
213
-
214
- # Pop top parse context.
215
- def pop
216
- if @active
217
- # Execute.
218
- eval( @stack[-1] )
219
- @stack.pop
220
- else
221
- # Output literal.
222
- output( @stack[-1] )
223
- @stack.pop
224
- end
225
-
226
- dec
227
- end
228
-
229
- # Output shifted tokens.
230
- def flush
231
- output( @stack[-1] )
232
- @stack[-1] = []
233
- end
234
-
235
- # Output list of tokens.
236
- def output( list )
237
- list.each do |t|
238
- @host.env.write t.value
239
- end
240
- end
241
-
242
- # Inside macro def.
243
- def inside?
244
- @level > 0
245
- end
246
-
247
- # Inc macro level.
248
- def inc
249
- @active = true
250
- @level += 1
251
- end
252
-
253
- # Dec macro level.
254
- def dec
255
- @level -= 1
256
- @active = false
257
- end
258
-
259
- # Evaluate shifted tokens.
260
- def eval( list )
261
- idx = 0
262
-
263
- # Skip hookbeg.
264
- idx += 1
265
-
266
- # Check if macro is internal command.
267
- if list[idx].value[0] == "."
268
-
269
- # Variable reference.
270
-
271
- varname = list[idx].value[1..-1]
272
-
273
- # Skip hookend.
274
- idx += 2
275
-
276
- raise RuntimeError, "Garbage after hookend." if list[ idx ]
277
-
278
- @host.env._eval( "write @#{varname}" )
279
-
280
- elsif list[idx].value[0] == ":"
281
-
282
- # Command.
283
-
284
- cmd, rest = list[idx].value[1..-1].scan( /([a-z]+) (.*)/ )[0]
285
-
286
- # Skip hookend.
287
- idx += 2
288
-
289
- raise RuntimeError, "Garbage after hookend." if list[ idx ]
290
-
291
- case cmd
292
-
293
- when 'include'
294
- @host.env._pushInput( rest )
295
- @host.env._inIO.automode = false
296
- @host.parse
297
-
298
- when 'output'
299
- @host.env._pushOutput( rest )
300
-
301
- when 'close'
302
- @host.env._closeOutput
303
-
304
- when 'comment'
305
- # ' mode coloring fix comment.
306
- true
307
-
308
- when 'source'
309
- @host.env.source( rest )
310
-
311
- when 'hook'
312
- if rest.split.length == 2
313
- @host.env._separators.hookBegChars = rest.split[0]
314
- @host.env._separators.hookEndChars = rest.split[1]
315
- else
316
- @host.env._separators.hookBegChars = rest
317
- @host.env._separators.hookEndChars = rest
318
- end
319
-
320
- when 'hookbeg'
321
- @host.env._separators.hookBegChars = rest
322
-
323
- when 'hookend'
324
- @host.env._separators.hookEndChars = rest
325
-
326
- when 'escape'
327
- @host.env._separators.escapeChar = rest
328
-
329
- when 'exit'
330
- exit
331
-
332
- else
333
- Mucgly::error "unkown internal command: \"#{cmd}\""
334
-
335
- end
336
-
337
- elsif list[idx].value[0] == "#"
338
-
339
- # Remove macro cancel char from macro and output
340
- # the macro again.
341
-
342
- @host.env.write( list[idx-1].value )
343
- @host.env.write( list[idx].value[1..-1] )
344
- @host.env.write( list[idx+1].value )
345
-
346
- # Skip hookend.
347
- idx += 2
348
-
349
- raise RuntimeError, "Garbage after hookend." if list[ idx ]
350
-
351
- else
352
-
353
- # Ruby code to evaluate.
354
-
355
- code = list[idx].value
356
-
357
- # Skip hookend.
358
- idx += 2
359
-
360
- raise RuntimeError, "Garbage after hookend." if list[ idx ]
361
-
362
- @host.env._eval code
363
-
364
- end
365
-
366
- end
367
-
368
-
369
- # Return char either from character buffer (String) or file stream.
370
- def getChars( cnt = 1 )
371
- c = @host.env._inIO.read( cnt )
372
- Mucgly::debug( "Read char: \"#{c}\"" )
373
- c
374
- end
375
-
376
- # Put character back.
377
- def putBack( c )
378
- @host.env._inIO.putback( c )
379
- Mucgly::debug( "Putback char: \"#{c}\"" )
380
- end
381
-
382
- # Find a given string from input (true/false).
383
- def findInInput( this )
384
-
385
- str = getChars( this.length )
386
-
387
- if str == this
388
- # Found requested string from input.
389
- true
390
- else
391
- # Mismatch to requested string, put back to input.
392
- putBack( str )
393
- false
394
- end
395
- end
396
-
397
-
398
- # Create a token based on the current characters. The
399
- # token returned is effected by parsing context and
400
- # separator settings.
401
- def getTokenRaw
402
-
403
- escapeChar = @host.env._separators.escapeChar
404
- hookEndChars = @host.env._separators.hookEndChars
405
- hookBegChars = @host.env._separators.hookBegChars
406
-
407
-
408
- c = getChars
409
-
410
- if c == nil
411
-
412
- Token.new( :eof )
413
-
414
- else
415
-
416
- # Handle escape characters before hooks.
417
- if c == escapeChar
418
-
419
- c = getChars
420
-
421
- if c == "\n"
422
- # Escaped newline.
423
- return Token.new( :empty, "" )
424
-
425
- elsif c == escapeChar
426
- # Escaped escape.
427
- return Token.new( :char, escapeChar )
428
-
429
- elsif inside?
430
-
431
- # Escape inside first level macro.
432
-
433
- if ( c == " " || c == "\n" ) and
434
- ( escapeChar ==
435
- hookEndChars )
436
-
437
- # Hookend when same as escape is
438
- # "hookend+space".
439
- return Token.new( :hookEnd, escapeChar + c )
440
-
441
- elsif c == hookEndChars[0]
442
-
443
- # Escaped hookend.
444
- return Token.new( :char, c )
445
-
446
- else
447
-
448
- # Ineffective escape.
449
- return Token.new( :char,
450
- escapeChar + c )
451
- end
452
-
453
- else
454
-
455
- # Escape outside macro.
456
-
457
- if escapeChar == hookEndChars
458
-
459
- putBack( c )
460
- return Token.new( :hookBeg,
461
- hookBegChars )
462
-
463
- elsif c == hookEndChars[0]
464
-
465
- return Token.new( :char, c )
466
-
467
- elsif ( c == " " || c == "\n" )
468
-
469
- # Remove escaped space and newlines.
470
- return Token.new( :empty )
471
-
472
- elsif c == hookBegChars[0]
473
-
474
- return Token.new( :char, c )
475
-
476
- else
477
-
478
- # Ineffective escape.
479
- return Token.new( :char,
480
- escapeChar + c )
481
-
482
- end
483
-
484
- end
485
-
486
- else
487
-
488
- # No escape, putback and search for hooks.
489
- putBack c
490
-
491
- end
492
-
493
-
494
- # Look for hooks or return a character.
495
- if inside?
496
-
497
- # Inside macro.
498
-
499
- if findInInput( hookEndChars )
500
- return Token.new( :hookEnd, hookEndChars )
501
- end
502
-
503
- else
504
-
505
- # Outside macro.
506
-
507
- if findInInput( hookBegChars )
508
- return Token.new( :hookBeg, hookBegChars )
509
- end
510
-
511
- end
512
-
513
-
514
- # No escapes, no hooks, so return a char.
515
- c = getChars
516
-
517
- if c == nil
518
- return Token.new( :eof )
519
- else
520
- return Token.new( :char, c )
521
- end
522
-
523
- end
524
- end
525
-
526
-
527
- def getToken
528
- t = getTokenRaw
529
- Mucgly::debug( "Got token: #{t.type}:\"#{t.value}\"" )
530
- t
531
- end
532
-
533
- end
534
-
535
-
536
- # Process a Mucgly file.
537
- def parse
538
-
539
- parseState = ParseState.new( self )
540
-
541
- while true
542
-
543
- t = parseState.getToken
544
-
545
- if t.type == :eof
546
-
547
- parseState.flush
548
-
549
- # Process fileEndHook callback:
550
- @env._eval( @env.fileEndHook ) if @env.fileEndHook
551
-
552
- # End of stream.
553
- # @fp.close
554
-
555
- @env._inIO.close
556
-
557
- return
558
-
559
- elsif t.type == :hookBeg
560
-
561
- parseState.push
562
- parseState.shift( t )
563
-
564
- elsif t.type == :hookEnd
565
-
566
- parseState.shift( t )
567
- parseState.pop
568
-
569
- else
570
-
571
- parseState.shift( t )
572
-
573
- end
574
-
575
-
576
- end
577
-
578
- end
579
-
580
- end
581
-
582
-
583
-
584
- # Separators are collection of special characters used by Mucgly.
585
- #
586
- # These are:
587
- # [escape] Escape char is used to convert special chars into their
588
- # literal form or to remove the following char. Special
589
- # characters are: escape char, hookbeg, hookend. Escape
590
- # can remove the following newline, and space in special
591
- # circumtances.
592
- # [hookbeg] Hookbeg char (or string) starts macros. If user wants
593
- # a literal hookbeg, then <escape> should be put before
594
- # it.
595
- # [hookend] Hookend char (or string) terminates macros. Hookend
596
- # can also be escaped. If hookend end is same character
597
- # as escape, then hookend followed by a space is
598
- # considered as hookend.
599
- class Separators
600
-
601
- # Set of control characters for hook and escape indentification.
602
- attr_reader :escapeChar
603
- attr_accessor :hookBegChars, :hookEndChars
604
-
605
- def initialize
606
- @escapeChar = "\\"
607
- @hookBegChars = "-<"
608
- @hookEndChars = ">-"
609
- end
610
-
611
- def escapeChar=( value )
612
- if value.length != 1
613
- Mucgly::error( "Escape must be 1 char long, got \"#{value}\"" )
614
- end
615
- @escapeChar = value
616
- end
617
-
618
- def copy
619
- c = Separators.new
620
- c.escapeChar = @escapeChar
621
- c.hookBegChars = @hookBegChars
622
- c.hookEndChars = @hookEndChars
623
- return c
624
- end
625
- end
626
-
627
- end
@@ -1,4 +0,0 @@
1
- -<@counter = 0>-\
2
- -<write "Counter value is #{@counter} at round 1">-
3
- -<#@counter += 1>-\
4
- -<#write "Counter value is #{@counter} at round 2">-