bets 0.0.13 → 0.0.14

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.
data/lib/bets.rb CHANGED
@@ -1,165 +1,1073 @@
1
1
  # encoding: utf-8
2
2
 
3
- require "rubygems"
4
3
  require "bets/version"
5
- require 'watir-webdriver'
4
+ require 'gtk2'
5
+ require 'stringio'
6
+ require 'rules.rb'
6
7
 
7
- require 'betlinks'
8
- module Bets
9
- class Parse
8
+ module RulesDebuger
9
+ class BetsGUI
10
10
  def initialize
11
+ @dbg_buffers = {}
12
+ @edt_buffers = {}
13
+ @state = []
14
+
15
+ stdout_stream_recreate
16
+
17
+ @options = {}
18
+ @options[:curr_filename] = ''
19
+ @options[:curr_extension] = ''
20
+
21
+ # Загрузка сценария RAD
22
+ Gtk.init
23
+ builder = Gtk::Builder.new
24
+ builder.add_from_file(File.join(File.dirname(__FILE__), 'bets.glade'))
25
+ builder.connect_signals {|handler| method(handler) }
26
+ @imi_new = builder.get_object('imi_new')
27
+ @imi_open = builder.get_object('imi_open')
28
+ @imi_save = builder.get_object('imi_save')
29
+ @imi_save_as = builder.get_object('imi_save_as')
30
+ @mi_close = builder.get_object('mi_close')
31
+ @imi_quit = builder.get_object('imi_quit')
32
+
33
+ @mi_console = builder.get_object('mi_console')
34
+ @mi_files = builder.get_object('mi_files')
35
+
36
+ @mi_build = builder.get_object('mi_build')
37
+ @mi_debug = builder.get_object('mi_debug')
38
+ @mi_reset = builder.get_object('mi_reset')
39
+ @mi_play = builder.get_object('mi_play')
40
+ @mi_pause = builder.get_object('mi_pause')
41
+ @mi_slow = builder.get_object('mi_slow')
42
+ @mi_overstep = builder.get_object('mi_overstep')
43
+ @mi_step = builder.get_object('mi_step')
44
+ # toolbar
45
+ @tb_new = builder.get_object('tb_new')
46
+ @tb_open = builder.get_object('tb_open')
47
+ @tb_save = builder.get_object('tb_save')
48
+ @bt_close = builder.get_object('bt_close')
49
+
50
+ @tb_build = builder.get_object('tb_build')
51
+ @tbt_debug = builder.get_object('tbt_debug')
52
+ @tb_reset = builder.get_object('tb_reset')
53
+ @tbt_play = builder.get_object('tbt_play')
54
+ @tbt_pause = builder.get_object('tbt_pause')
55
+ @sb_delay = builder.get_object('sb_delay')
56
+ @adj_delay = builder.get_object('adj_delay')
57
+ @tbt_slow = builder.get_object('tbt_slow')
58
+ @tb_step = builder.get_object('tb_step')
59
+ @tb_overstep = builder.get_object('tb_overstep')
60
+ # Область состояния переменных
61
+ @trv_variables = builder.get_object('trv_variables')
62
+ renderer = Gtk::CellRendererText.new
63
+ column = Gtk::TreeViewColumn.new("Переменная", renderer, :text => 0)
64
+ @trv_variables.append_column(column)
65
+ column = Gtk::TreeViewColumn.new("Значение", renderer, :text => 1)
66
+ @trv_variables.append_column(column)
67
+ @ls_variables = Gtk::ListStore.new(String, String)
68
+ @trv_variables.model = @ls_variables
69
+ # Область файлов
70
+ @scw_files = builder.get_object('scw_files')
71
+ @trv_files = builder.get_object('trv_files')
72
+
73
+ @trv_files.modify_base(Gtk::STATE_NORMAL,Gdk::Color.parse('#EEEEEE'))
74
+ # @trv_files.modify_text(Gtk::STATE_NORMAL,Gdk::Color.parse('#FFFFFF'))
75
+
76
+
77
+ renderer = Gtk::CellRendererText.new
78
+ column = Gtk::TreeViewColumn.new("Файл", renderer, :text => 0)
79
+ @trv_files.append_column(column)
80
+ column = Gtk::TreeViewColumn.new("filename", renderer, :text => 1)
81
+ column.visible = false
82
+ @trv_files.append_column(column)
83
+ @ts_files = Gtk::TreeStore.new(String, String)
84
+ @trv_files.model = @ts_files
85
+
86
+ @hp_files = builder.get_object('hp_files')
87
+
88
+ # Область программы
89
+ @txv_program = builder.get_object('txv_program')
90
+ @tb_program = builder.get_object('tb_program')
91
+ # @txv_program.modify_base(Gtk::STATE_NORMAL,Gdk::Color.parse('#000000'))
92
+ # @txv_program.modify_text(Gtk::STATE_NORMAL,Gdk::Color.parse('#FFFFFF'))
93
+ @txv_program.modify_font(Pango::FontDescription.new('Monospace 12'))
94
+ @lb_filename = builder.get_object('lb_filename')
95
+
96
+ @hp_vars = builder.get_object('hp_vars')
97
+ # Область состояния стека
98
+ @txv_stack = builder.get_object('txv_stack')
99
+ @tb_stack = builder.get_object('tb_stack')
100
+ @txv_limit = builder.get_object('txv_limit')
101
+ @tb_limit = builder.get_object('tb_limit')
102
+ # Вывод консоли
103
+ @vb_stack = builder.get_object('vb_stack')
104
+ @txv_console = builder.get_object('txv_console')
105
+ @tb_console = builder.get_object('tb_console')
106
+ @vp_console = builder.get_object('vp_console')
107
+ @vb_footer = builder.get_object('vb_footer')
108
+ # Строка состояния
109
+ @pb_progress = builder.get_object('pb_progress')
110
+
111
+ # Окно
112
+ @wnd_main = builder.get_object('wnd_main')
113
+
114
+ cmd(:start)
115
+
116
+ begin
117
+ @options = File.open(File.join(File.dirname(__FILE__), "options.dat"), "rb") {|f| Marshal.load(f)}
118
+ rescue Exception => e
119
+ puts e
120
+ end
121
+
122
+ files = @options[:files]
123
+ if files != nil and files.length > 0
124
+ files.each do |f|
125
+ edt_openfile(f, true)
126
+ end
127
+
128
+ edt_openfile(@options[:curr_filename])
129
+ refresh_files
130
+ cmd(:editor)
131
+ end
132
+
133
+ @wnd_main.move(@options[:pos_x], @options[:pos_y]) if !@options[:pos_x].nil? and !@options[:pos_y].nil?
134
+ @wnd_main.set_default_size(@options[:width], @options[:heigh]) if !@options[:width].nil? and !@options[:heigh].nil?
135
+ @wnd_main.maximize if @options[:maximized]
136
+ @wnd_main.show
137
+
138
+ # @wnd_catalog = builder.get_object('wnd_catalog')
139
+ # @wnd_catalog.show
140
+
141
+ # Сброс
142
+ # Gtk::main_iteration_do(blocking = false) while Gtk::events_pending?
143
+ # on_tb_reset_clicked(@tb_reset)
144
+ # Основной цикл
145
+
146
+ @hp_files.position = @options[:hp_files] unless @options[:hp_files].nil?
147
+ @hp_vars.position = @hp_vars.max_position - @options[:hp_vars] unless @options[:hp_vars].nil?
148
+ @vp_console.position = @options[:vp_console] unless @options[:vp_console].nil?
149
+ Gtk.main
150
+ end
151
+
152
+ def on_wnd_main_delete_event(widget, event)
153
+ @options[:files] = []
154
+ auto = false
155
+ result = nil # Это корректирует глюк ruby интерпретатора
156
+ @edt_buffers.each do |k,v|
157
+ @options[:files] << k
158
+ if v.modified?
159
+ result = dialog_saveall_yes_no_cancel("Файл #{k} не сохранен! Сохранить?") unless auto
160
+ case result
161
+ when Gtk::Dialog::RESPONSE_CANCEL
162
+ return true
163
+ when Gtk::Dialog::RESPONSE_YES
164
+ File.open(k, 'wb') { |f| f.write(v.text) }
165
+ when Gtk::Dialog::RESPONSE_APPLY
166
+ File.open(k, 'wb') { |f| f.write(v.text) }
167
+ auto = true
168
+ end
169
+ end
170
+ end
171
+
172
+ @options[:hp_files] = @hp_files.position
173
+ @options[:hp_vars] = @hp_vars.max_position - @hp_vars.position
174
+ @options[:vp_console] = @vp_console.position
175
+
176
+ begin
177
+ File.open(File.join(File.dirname(__FILE__), "options.dat"), "wb") {|f| Marshal.dump(@options, f)}
178
+ rescue Exception => e
179
+ puts e
180
+ end
181
+ return false
182
+ end
183
+
184
+
185
+ def gtk_main_quit
186
+ Gtk.main_quit()
187
+ end
188
+
189
+ def on_wnd_main_configure_event(widget, event)
190
+ mask = Gdk::EventWindowState::MAXIMIZED
191
+ @options[:maximized] = @wnd_main.window.state & mask == mask
192
+ unless @options[:maximized]
193
+ @options[:width], @options[:heigh] = event.width, event.height
194
+ @options[:pos_x], @options[:pos_y] = event.x, event.y
195
+ end
196
+ false
197
+ end
198
+
199
+ def on_toolbutton_clicked(widget)
200
+ case widget.builder_name
201
+ when "tb_new"
202
+ @imi_new.activate
203
+ when "tb_open"
204
+ @imi_open.activate
205
+ when "tb_save"
206
+ @imi_save.activate
207
+ when "tb_save_as"
208
+ @imi_save_as.activate
209
+ when "bt_close"
210
+ @mi_close.activate
211
+
212
+ when "tb_build"
213
+ @mi_build.activate
214
+ when "tbt_debug"
215
+ @mi_debug.activate if widget.active? != @mi_debug.active?
216
+ when "tb_reset"
217
+ @mi_reset.activate
218
+ when "tbt_play"
219
+ @mi_play.active = true if widget.active? != @mi_play.active?
220
+ when "tbt_pause"
221
+ @mi_pause.active = true if widget.active? != @mi_pause.active?
222
+ when "tbt_slow"
223
+ @mi_slow.active = true if widget.active? != @mi_slow.active?
224
+ when "tb_step"
225
+ @mi_step.activate
226
+ when "tb_overstep"
227
+ @mi_overstep.activate
228
+ end
11
229
  end
12
- public
13
- def parse
14
- end
15
- end
16
230
 
17
- class Processor
18
- private
19
- include Betlinks
20
- def initialize
21
- @names = {}
22
- @browsers = {}
23
- @lexems = {
24
- 'ПРОГРАММА' => [:name, :text, :end],
25
- }
26
- @lang_map = {
27
- '[^\_]БРАУЗЕР' => 'ff_open',
28
- 'ЗАКРЫТЬ_БРАУЗЕР' => 'ff_close',
29
- 'НАЖАТЬ' => 'ff_click ',
30
- 'ОТКРЫТЬ' => 'ff_goto ',
31
- 'ЗНАЧЕНИЕ' => 'ff_get',
32
- 'ЗАПОЛНИТЬ' => 'ff_set ',
33
- 'ПОВТОРЯТЬ' => 'loop do',
34
- 'ПРЕРВАТЬ' => 'break',
35
- '\ И\ ' => ' && ',
36
- '\ ИЛИ\ ' => ' || ',
37
- '\ НЕТ\ ' => ' not ',
38
- 'ЕСЛИ\ ' => 'if ',
39
- ' ТО ' => ' then ',
40
- '\ ИНАЧЕ\ ' => ' else ',
41
- 'КОНЕЦ' => 'end;',
42
- 'ЗАДЕРЖКА' => 'pause ',
43
- 'СЛ\_ЧИСЛО\(' => 'Random.new.rand(',
44
- 'Игра' => '$game',
45
- '%_прибыли' => '$percent',
46
- 'Дата_игры' => '$date',
47
- 'Время_игры' => '$time',
48
- 'Б1[^_]' => '$b1_name',
49
- 'Б1\_ставка' => '$b1_type',
50
- 'Б1\_коэф' => '$b1_coef',
51
- 'Б1\_вид\_спорта' => '$b1_kind',
52
- 'Б1\_ссылка' => '$b1_link',
53
- 'Б2[^_]' => '$b2_name',
54
- 'Б2\_ставка' => '$b2_type',
55
- 'Б2\_коэф' => '$b2_coef',
56
- 'Б2\_вид\_спорта' => '$b2_kind',
57
- 'Б2\_ссылка' => '$b2_link',
58
- 'ПЕЧАТЬ ' => 'puts ',
59
- 'ВЫХОД' => 'exit',
60
- 'ИСТИНА' => 'true',
61
- 'ЛОЖЬ' => 'false'
62
- }
63
- trap("SIGINT") { exit! }
64
- instance_eval "betlinks_init"
65
- end
66
-
67
-
68
- def translator
69
- # Чтение исходного кода
70
- text = File.open(ARGV[0], "r:UTF-8").read
71
- # Удаление комментариев
72
- text.gsub!(/\-\-.*\n/,'')
73
- # Разделение на слова
74
- input = text.split
75
-
76
- p = 0
77
- while p < input.length do
78
- context = @lexems[input[p]]
79
- return if context.nil?
80
- i = 0
81
- name = ''
82
- while i < context.length
83
- case context[i]
84
- when :name
85
- name = input[p+=1]
86
- @names[name] = ''
87
- i+=1
88
- when :text
89
- if input[p+=1] =~ /КОНЕЦ_.*?/
90
- @lang_map.each { |k,v| @names[name].gsub!(Regexp.new(k),v) }
91
- i += 1
92
- else
93
- @names[name] += ' ' + input[p]
94
- end
95
- when :end
96
- p+=1
97
- i+=1
98
- else
99
- puts "error i=#{i} p=#{p}"
100
- return
231
+ def on_menu_activate(widget)
232
+ case widget.builder_name
233
+ when "imi_new"
234
+ cmd(:new)
235
+ when "imi_open"
236
+ cmd(:load)
237
+ when "imi_save"
238
+ cmd(:save)
239
+ when "imi_save_as"
240
+ cmd(:save_as)
241
+ when "mi_close"
242
+ cmd(:close)
243
+ when "imi_quit"
244
+ cmd(:quit)
245
+
246
+ when "mi_console"
247
+ @vb_footer.visible = widget.active?
248
+ when "mi_files"
249
+ @scw_files.visible = widget.active?
250
+ when "mi_build"
251
+ cmd(:build)
252
+ when "mi_debug"
253
+ cmd(widget.active? ? :debug : :editor)
254
+ when "mi_reset"
255
+ cmd(:reset)
256
+ when "mi_play"
257
+ cmd(:play) if widget.active?
258
+ when "mi_pause"
259
+ cmd(:pause) if widget.active?
260
+ when "mi_slow"
261
+ cmd(:slow) if widget.active?
262
+ when "mi_step"
263
+ cmd(:step)
264
+ when "mi_overstep"
265
+ cmd(:overstep)
266
+ end
267
+ end
268
+
269
+ def cmd(command)
270
+ case command
271
+ when :start
272
+ @mode = :start
273
+ stdout_restore
274
+ @imi_new.sensitive =
275
+ @tb_new.sensitive =
276
+ @imi_open.sensitive =
277
+ @tb_open.sensitive = true
278
+
279
+ @mi_play.active =
280
+ @tbt_play.active =
281
+ @mi_pause.active =
282
+ @tbt_pause.active =
283
+ @mi_slow.active =
284
+ @tbt_slow.active =
285
+
286
+ @imi_save.sensitive =
287
+ @tb_save.sensitive =
288
+ @imi_save_as.sensitive =
289
+ @mi_close.sensitive =
290
+ @bt_close.sensitive =
291
+ @mi_build.sensitive =
292
+ @tb_build.sensitive =
293
+ @mi_debug.sensitive =
294
+ @tbt_debug.sensitive =
295
+ @mi_reset.sensitive =
296
+ @tb_reset.sensitive =
297
+ @mi_play.sensitive =
298
+ @tbt_play.sensitive =
299
+ @mi_pause.sensitive =
300
+ @tbt_pause.sensitive =
301
+ @mi_slow.sensitive =
302
+ @tbt_slow.sensitive =
303
+ @mi_step.sensitive =
304
+ @tb_step.sensitive =
305
+ @mi_overstep.sensitive =
306
+ @tb_overstep.sensitive =
307
+ @sb_delay.sensitive =
308
+ @txv_program.sensitive =
309
+ @txv_console.sensitive =
310
+ @vb_stack.visible =
311
+ @scw_files.visible = false
312
+
313
+ @lb_filename.text = ''
314
+ @txv_program.buffer = @tb_program
315
+ progress_reset
316
+ when :editor
317
+ @vm.halt unless @vm.nil?
318
+ edt_pop_state
319
+ @mode = :edit
320
+ stdout_restore
321
+ # вкл
322
+ @imi_new.sensitive =
323
+ @tb_new.sensitive =
324
+ @imi_open.sensitive =
325
+ @tb_open.sensitive =
326
+ @imi_save_as.sensitive =
327
+ @mi_close.sensitive =
328
+ @bt_close.sensitive =
329
+ @mi_build.sensitive =
330
+ @tb_build.sensitive =
331
+ @mi_debug.sensitive =
332
+ @tbt_debug.sensitive =
333
+ @txv_program.sensitive =
334
+ @txv_console.sensitive =
335
+ @scw_files.visible = true
336
+ # выкл
337
+ @tbt_debug.active =
338
+ @mi_play.active =
339
+ @tbt_play.active =
340
+ @mi_pause.active =
341
+ @tbt_pause.active =
342
+ @mi_slow.active =
343
+ @tbt_slow.active =
344
+
345
+ @mi_reset.sensitive =
346
+ @tb_reset.sensitive =
347
+ @mi_play.sensitive =
348
+ @tbt_play.sensitive =
349
+ @mi_pause.sensitive =
350
+ @tbt_pause.sensitive =
351
+ @sb_delay.sensitive =
352
+ @mi_slow.sensitive =
353
+ @tbt_slow.sensitive =
354
+ @mi_step.sensitive =
355
+ @tb_step.sensitive =
356
+ @mi_overstep.sensitive =
357
+ @tb_overstep.sensitive =
358
+ @trv_variables.visible =
359
+ @vb_stack.visible = false
360
+
361
+ edt_openfile(@options[:curr_filename])
362
+
363
+ @tb_save.sensitive = @txv_program.buffer.modified?
364
+ # Прервать текущую отладку
365
+ @debuger_mode = :default
366
+ @pause_flag = true
367
+ progress_reset
368
+ when :new
369
+ dialog = Gtk::FileChooserDialog.new("Save File", @wnd_main,
370
+ Gtk::FileChooser::ACTION_SAVE,
371
+ nil,
372
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
373
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
374
+ result = (dialog.run == Gtk::Dialog::RESPONSE_ACCEPT)
375
+ filename = dialog.filename
376
+ dialog.destroy
377
+ return unless result
378
+ return if File.exist?(filename) and
379
+ !dialog_ok_cancel("Файл с таким именем уже существует! Перезаписать?")
380
+
381
+ edt_openfile(filename)
382
+ File.open(filename, 'wb') { |f| f.write(@txv_program.buffer.text) }
383
+
384
+ cmd(:editor)
385
+ cmd(:not_modified)
386
+ refresh_files
387
+ when :load
388
+ # Прочее
389
+ dialog = Gtk::FileChooserDialog.new("Open File", @wnd_main,
390
+ Gtk::FileChooser::ACTION_OPEN,
391
+ nil,
392
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
393
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
394
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
395
+ edt_openfile(dialog.filename)
396
+ refresh_files
397
+ cmd(:editor)
398
+ cmd(:not_modified)
399
+ end
400
+ dialog.destroy
401
+ when :save
402
+ filename = @options[:curr_filename]
403
+ unless File.exist?(filename)
404
+ dialog = Gtk::FileChooserDialog.new("Save File", @wnd_main,
405
+ Gtk::FileChooser::ACTION_SAVE,
406
+ nil,
407
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
408
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
409
+ result = (dialog.run == Gtk::Dialog::RESPONSE_ACCEPT)
410
+ filename = dialog.filename
411
+ dialog.destroy
412
+ return unless result
413
+ buffer = @edt_buffers[@options[:curr_filename]]
414
+ @edt_buffers.delete @options[:curr_filename]
415
+ @edt_buffers[filename] = buffer
416
+ edt_set_curr_filename(filename)
417
+ end
418
+ File.open(filename, 'wb') { |f| f.write(@txv_program.buffer.text) } unless filename.empty?
419
+ cmd(:not_modified)
420
+ refresh_files
421
+ when :save_as
422
+ dialog = Gtk::FileChooserDialog.new("Save File", @wnd_main,
423
+ Gtk::FileChooser::ACTION_SAVE,
424
+ nil,
425
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
426
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
427
+ result = (dialog.run == Gtk::Dialog::RESPONSE_ACCEPT)
428
+ filename = dialog.filename
429
+ dialog.destroy
430
+ return unless result
431
+ buffer = @edt_buffers[@options[:curr_filename]]
432
+ @edt_buffers.delete @options[:curr_filename]
433
+ @edt_buffers[filename] = buffer
434
+ edt_set_curr_filename(filename)
435
+ File.open(filename, 'wb') { |f| f.write(@txv_program.buffer.text) } unless filename.empty?
436
+ cmd(:not_modified)
437
+ refresh_files
438
+ when :close
439
+ if @edt_buffers[@options[:curr_filename]].modified?
440
+ result = dialog_yes_no_cancel("Файл #{@options[:curr_filename]} не сохранен! Cохранить?")
441
+ case result
442
+ when Gtk::RESPONSE_YES
443
+ File.open(@options[:curr_filename], 'wb') { |f| f.write(@txv_program.buffer.text) }
444
+ when Gtk::RESPONSE_CANCEL
445
+ return
446
+ end
447
+ end
448
+
449
+ a = []
450
+ a = @edt_buffers.map { |f,b| f }
451
+ p = 0
452
+ a.each_index do |i|
453
+ p = i if a[i] == @options[:curr_filename]
454
+ end
455
+ if a[p+1].nil?
456
+ if a.length == 1
457
+ cmd(:start)
458
+ else
459
+ edt_openfile(a[p-1])
101
460
  end
461
+ else
462
+ edt_openfile(a[p+1])
463
+ end
464
+ @edt_buffers.delete(a[p])
465
+ refresh_files
466
+ when :build
467
+ return unless edt_save_changes
468
+ stdout_stream_recreate
469
+ stdout_redirect
470
+ errors = build(@options[:curr_filename])
471
+ error_select(errors)
472
+ error_puts(errors)
473
+ when :debug
474
+ @vm.halt unless @vm.nil?
475
+ unless edt_save_changes
476
+ cmd(:editor)
477
+ return
102
478
  end
479
+ edt_push_state
480
+ @mode = :debug
481
+ stdout_stream_recreate
482
+ stdout_redirect
483
+
484
+ # вкл
485
+ @tbt_debug.active =
486
+ @tbt_pause.active =
487
+ @mi_pause.active =
488
+
489
+ @mi_reset.sensitive =
490
+ @tb_reset.sensitive =
491
+ @mi_play.sensitive =
492
+ @tbt_play.sensitive =
493
+ @sb_delay.sensitive =
494
+ @mi_step.sensitive =
495
+ @tb_step.sensitive =
496
+ @mi_slow.sensitive =
497
+ @tbt_slow.sensitive =
498
+ @mi_overstep.sensitive =
499
+ @tb_overstep.sensitive =
500
+ @trv_variables.visible =
501
+ @vb_stack.visible = true
502
+
503
+ # выкл
504
+ @tbt_play.active =
505
+ @mi_play.active =
506
+ @tbt_slow.active =
507
+ @mi_slow.active =
508
+
509
+ @imi_new.sensitive =
510
+ @tb_new.sensitive =
511
+ @imi_open.sensitive =
512
+ @tb_open.sensitive =
513
+ @imi_save.sensitive =
514
+ @tb_save.sensitive =
515
+ @imi_save_as.sensitive =
516
+ @mi_close.sensitive =
517
+ @bt_close.sensitive =
518
+ @mi_build.sensitive =
519
+ @tb_build.sensitive =
520
+ @mi_pause.sensitive =
521
+ @tbt_pause.sensitive =
522
+ @txv_program.sensitive =
523
+ @scw_files.visible = false
524
+ debuger_reset
525
+ progress_reset
526
+ when :reset
527
+ cmd(:debug)
528
+ when :play
529
+ # вкл
530
+ @mi_play.active =
531
+ @tbt_play.active =
532
+
533
+ @mi_pause.sensitive =
534
+ @tbt_pause.sensitive =
535
+ @mi_slow.sensitive =
536
+ @tbt_slow.sensitive = true
537
+ # выкл
538
+ @mi_pause.active =
539
+ @tbt_pause.active =
540
+ @mi_slow.active =
541
+ @tbt_slow.active =
542
+
543
+ @mi_play.sensitive =
544
+ @tbt_play.sensitive =
545
+ @mi_step.sensitive =
546
+ @tb_step.sensitive =
547
+ @mi_overstep.sensitive =
548
+ @tb_overstep.sensitive =
549
+ @mi_slow.active =
550
+ @tbt_slow.active = false
551
+ # Прочее
552
+ @delay = 0
553
+ @pause_flag = false
554
+ @debuger_mode = :start
555
+ when :slow
556
+ # вкл
557
+ @mi_slow.active =
558
+ @tbt_slow.active =
559
+
560
+ @mi_pause.sensitive =
561
+ @tbt_pause.sensitive =
562
+ @mi_play.sensitive =
563
+ @tbt_play.sensitive = true
564
+ # выкл
565
+ @mi_pause.active =
566
+ @tbt_pause.active =
567
+ @mi_play.active =
568
+ @tbt_play.active =
569
+
570
+ @mi_play.sensitive =
571
+ @tbt_play.sensitive =
572
+ @mi_slow.sensitive =
573
+ @tbt_slow.sensitive =
574
+ @mi_step.sensitive =
575
+ @tb_step.sensitive =
576
+ @mi_overstep.sensitive =
577
+ @tb_overstep.sensitive = false
578
+ # Прочее
579
+ @debuger_mode = :default
580
+ @delay = @adj_delay.value
581
+ @pause_flag = false
582
+ when :pause
583
+ # вкл
584
+ @tbt_pause.active =
585
+ @mi_pause.active =
586
+
587
+ @mi_play.sensitive =
588
+ @tbt_play.sensitive =
589
+ @mi_slow.sensitive =
590
+ @tbt_slow.sensitive =
591
+ @mi_step.sensitive =
592
+ @tb_step.sensitive =
593
+ @mi_overstep.sensitive =
594
+ @tb_overstep.sensitive = true
595
+ # выкл
596
+ @mi_play.active =
597
+ @tbt_play.active =
598
+ @mi_slow.active =
599
+ @tbt_slow.active =
600
+
601
+ @mi_pause.sensitive =
602
+ @tbt_pause.sensitive = false
603
+ # Прочее
604
+ @debuger_mode = :default
605
+ @pause_flag = true
606
+ when :step
607
+ @delay = 0
608
+ @debuger_mode = :step
609
+ @pause_flag = false
610
+ when :overstep
611
+ @delay = 0
612
+ @debuger_mode = :overstep
613
+ @pause_flag = false
614
+ when :stop
615
+ # вкл
616
+ @mi_pause.active =
617
+ @tbt_pause.active = true
618
+ # выкл
619
+ @mi_play.active =
620
+ @tbt_play.active =
621
+ @mi_slow.active =
622
+ @tbt_slow.active =
623
+
624
+ @mi_pause.sensitive =
625
+ @tbt_pause.sensitive =
626
+ @mi_slow.sensitive =
627
+ @tbt_slow.sensitive =
628
+ @mi_play.sensitive =
629
+ @tbt_play.sensitive =
630
+ @mi_step.sensitive =
631
+ @tb_step.sensitive =
632
+ @mi_overstep.sensitive =
633
+ @tb_overstep.sensitive = false
634
+ # Прочее
635
+ message_out("[Выполнение программы окончено]")
636
+ refresh_vars_state
637
+ when :modified
638
+ refresh_modified(true)
639
+ progress_reset
640
+ when :not_modified
641
+ @edt_buffers[@options[:curr_filename]].modified = false
642
+ refresh_modified
643
+ when :quit
644
+ gtk_main_quit
645
+ end
646
+ end
647
+
648
+ def build(filename)
649
+ begin
650
+ filename = File.expand_path(filename)
651
+ text = File.open(filename, "r:UTF-8").read
652
+ rescue Exception => e
653
+ puts e
654
+ end
655
+ progress_reset
656
+ lexical = Rules::Lexical.new
657
+ lexical.set_progress_callback(self, :progress_callback)
658
+ lexical.analyze(text, filename)
659
+ syntax = Rules::Syntax.new
660
+ syntax.set_progress_callback(self, :progress_callback)
661
+ syntax.analyze(lexical.result)
662
+ if lexical.errors.length + syntax.errors.length > 0
663
+ progress_reset
664
+ return lexical.errors + syntax.errors
665
+ end
666
+ translator = Rules::Translator.new
667
+ translator.set_progress_callback(self, :progress_callback)
668
+ translator.translate(lexical.result, File.dirname(filename))
669
+ if translator.errors.length > 0
670
+ return translator.errors
671
+ progress_reset
672
+ end
673
+ @ids_map = translator.ids
674
+ @data_seg = translator.data_seg
675
+ @code_seg = translator.code_seg
676
+ @debug = translator.debug
677
+ @includes = translator.includes
678
+ return []
679
+ end
680
+
681
+ def debuger_reset
682
+ # Прервать текущую отладку
683
+ @debuger_mode = :default
684
+ @call_stack = []
685
+ @old_lex = nil
686
+ @old_lex_iter = nil
687
+ @dbg_buffers = {}
688
+ @delay = 0
689
+ @ip = nil
690
+ @pause_flag = true
691
+
692
+ errors = build(@options[:curr_filename])
693
+ if errors.length > 0
694
+ error_puts errors
695
+ error_select errors
696
+ cmd(:editor)
697
+ return
698
+ end
699
+
700
+ @vm = Rules::VM.new(@data_seg, @code_seg, @debug)
701
+ @vm.set_debug_callback(self, :debug_callback)
702
+
703
+ $export = []
704
+ errors = []
705
+ begin
706
+ @includes.each do |f|
707
+ load Gem::find_files("#{f}_rules.rb").last
708
+ @vm.extend(self.class.const_get("#{f.capitalize}Rules"))
103
709
  end
710
+ rescue Exception => e
711
+ errors << {message: "Ошибка модуля: #{e}"}
712
+ error_puts errors
713
+ cmd(:editor)
714
+ return
104
715
  end
105
-
106
- def ff_open(browser, name)
107
- @browsers[browser] = Watir::Browser.new name
108
- @browsers[browser].driver.manage.timeouts.implicit_wait = 3
109
- puts "Браузер #{name.to_s} c именем ':#{browser.to_s}' открыт"
110
- end
111
- def ff_close(browser)
112
- @browsers[browser].close
113
- @browsers.delete(browser)
114
- puts "Браузер с именем ':#{browser.to_s}' закрыт"
115
- end
116
- def ff_goto(browser, str)
117
- @browsers[browser].goto(str)
118
- rescue Exception => error
119
- puts "Ошибка открытия страницы #{str}: #{error}"
120
- end
121
- def ff_click(browser, str)
122
- instance_eval "Watir::Wait.until(5, '') { @browsers[:#{browser}].#{str}.exists? }; @browsers[:#{browser}].#{str}.click"
123
- rescue Exception => error
124
- puts "Ошибка нажаимя #{str}: #{error}"
125
- end
126
- def ff_set(browser, str, value)
127
- instance_eval "Watir::Wait.until(5, '') { @browsers[:#{browser}].#{str}.exists? }; @browsers[:#{browser}].#{str}.set('#{value}')"
128
- rescue Exception => error
129
- puts "Ошибка установки значения в поле #{str}: #{error}"
130
- end
131
- def ff_get(browser, str, name)
132
- instance_eval "Watir::Wait.until(5, '') { @browsers[:#{browser}].#{str}.exists? }; @browsers[:#{browser}].#{str}.#{name}"
133
- rescue Exception => error
134
- puts "Ошибка считывания значения из поля #{str}: #{error}"
135
- end
136
-
137
- def pause(secs)
138
- print "Задержка #{secs} секунд "
139
- secs.times do |i|
140
- sleep 1
141
- print '.'
142
- end
143
- print "\n"
144
- end
145
-
146
- def exec
147
-
148
- @names.each do |k, v|
149
- # begin
150
- instance_eval v
151
- puts "Программа '#{k} выполнена!'"
152
- # rescue Exception => error
153
- # puts "Ошибка в программе #{k}: #{error}"
154
- # end
716
+
717
+ refresh_vars_state
718
+ refresh_stack_state
719
+ @vm.run
720
+ end
721
+
722
+
723
+ def on_wnd_main_destroy
724
+ gtk_main_quit
725
+ end
726
+
727
+ def on_trv_files_cursor_changed(widget)
728
+ path, c = widget.cursor
729
+ iter = @ts_files.get_iter(path)
730
+ edt_openfile(iter[1])
731
+ end
732
+
733
+ def on_end_user_action(widget)
734
+ cmd(:modified) if @mode == :edit
735
+ begin
736
+ buffer_syntax_highlight widget, @options[:curr_filename]
737
+ rescue
738
+ end
739
+ end
740
+
741
+ def edt_buffer_new
742
+ buffer = Gtk::TextBuffer.new
743
+ buffer_connect_tags(buffer)
744
+ buffer.signal_connect("changed") { |widget| on_end_user_action(widget) }
745
+ return buffer
746
+ end
747
+
748
+ def edt_set_curr_filename(filename)
749
+ @options[:curr_filename] = filename
750
+ @options[:curr_extension] = filename.scan(/.*?\.([a-zA-z0-9]*)$/).flatten(1)[0]
751
+ refresh_modified
752
+ end
753
+
754
+ def edt_openfile(filename, bg = false)
755
+ filename = File.expand_path(filename)
756
+ buffer = @edt_buffers[filename]
757
+ if buffer.nil?
758
+ @edt_buffers[filename] = buffer = edt_buffer_new
759
+ if File.exist?(File.expand_path(filename))
760
+ buffer.text = File.open(File.expand_path(filename), "r:UTF-8").read
761
+ end
762
+ edt_set_curr_filename(filename) unless bg
763
+ buffer_syntax_highlight buffer, filename
764
+ buffer.modified = false
765
+ end
766
+ unless bg
767
+ edt_set_curr_filename(filename)
768
+ @txv_program.buffer = buffer
769
+ @imi_save.sensitive =
770
+ @tb_save.sensitive = buffer.modified?
771
+ end
772
+ end
773
+
774
+ def edt_save_changes
775
+ if @lb_filename.text =~ /.*?\*/
776
+ if dialog_ok_cancel("Сохранить изменения в файле '%s' ?" % @options[:curr_filename])
777
+ cmd(:save)
778
+ return true
779
+ else
780
+ return false
781
+ end
782
+ else
783
+ return true
784
+ end
785
+ end
786
+
787
+ def edt_push_state
788
+ state = {
789
+ :buffer => @txv_program.buffer,
790
+ :filename => @options[:curr_filename]
791
+ }
792
+ @state.push state
793
+ end
794
+
795
+ def edt_pop_state
796
+ return unless @state.length > 0
797
+ state = @state.pop
798
+ @txv_program.buffer = state[:buffer]
799
+ @lb_filename.text = state[:filename]
800
+ end
801
+
802
+ def refresh_modified(value = false)
803
+ modified = (value ? true : @edt_buffers[@options[:curr_filename]].modified?)
804
+ @imi_save.sensitive =
805
+ @tb_save.sensitive = modified
806
+ @lb_filename.text = @options[:curr_filename] + ( modified ? '*' : '')
807
+ end
808
+
809
+ def refresh_files
810
+ @ts_files.clear
811
+ @edt_buffers.each do |key, value|
812
+ item = @ts_files.append(nil)
813
+ item[0] = File.basename(key)
814
+ item[1] = key
815
+ @trv_files.selection.select_iter(item) if key == @options[:curr_filename]
816
+ end
817
+ end
818
+
819
+ def refresh_vars_state
820
+ @ls_variables.clear
821
+ @ids_map.each do |key, value|
822
+ next unless value[:type] == :var
823
+ item = @ls_variables.append
824
+ item[0] = key
825
+ item[1] = @vm.data[@ids_map[key][:addr]].to_s
826
+ end
827
+ end
828
+
829
+ def refresh_stack_state
830
+ @tb_stack.text = @vm.data_stack.reverse.to_s
831
+ @tb_limit.text = @vm.limit_stack.reverse.to_s
832
+ end
833
+
834
+ def refresh_console
835
+ @mi_console.active = true
836
+ @txv_console.buffer.text = @stdout_stream.string
837
+ @txv_console.scroll_to_iter(@txv_console.buffer.end_iter, 0.25, false, 0, 0)
838
+ end
839
+
840
+ def error_select(errors)
841
+ return unless errors.length > 0
842
+ puts errors
843
+ error = errors[0][:lexem]
844
+ edt_openfile(error[:filename])
845
+ refresh_files
846
+ buffer = @txv_program.buffer
847
+ b = buffer.get_iter_at_offset(error[:begin])
848
+ e = buffer.get_iter_at_offset(error[:begin]+error[:length])
849
+ buffer.apply_tag('error',b,e)
850
+ @txv_program.scroll_to_iter(b, 0.25, false, 0, 0)
851
+ end
852
+
853
+ def error_puts(errors)
854
+ # stdout_redirect
855
+ if errors.length > 0
856
+ errors.each do |e|
857
+ puts "[ошибка]: '#{e[:message]}' в строке #{e[:lexem][:line]}"
858
+ end
859
+ else
860
+ puts '[ошибок нет]'
861
+ end
862
+ refresh_console
863
+ # stdout_restore
864
+ end
865
+
866
+ def message_out(message)
867
+ # stdout_redirect
868
+ puts message
869
+ refresh_console
870
+ # stdout_restore
871
+ end
872
+
873
+ def stdout_stream_recreate
874
+ @stdout_stream = StringIO.new
875
+ @stdout_store = $stdout
876
+ end
877
+
878
+ def stdout_redirect
879
+ $stdout = @stdout_stream
880
+ end
881
+
882
+ def stdout_restore
883
+ $stdout = @stdout_store
884
+ end
885
+
886
+ def buffer_connect_tags(buffer)
887
+ buffer.create_tag("blue", {"underline" => Pango::UNDERLINE_SINGLE})
888
+ buffer.create_tag("number", {"foreground" => "#000000"})
889
+ buffer.create_tag("label", {"foreground" => "#000000"})
890
+ buffer.create_tag("brace", {"foreground" => "#000000"})
891
+ buffer.create_tag("operation", {"foreground" => "#000000"})
892
+ buffer.create_tag("var", {"foreground" => "#000000"})
893
+ buffer.create_tag("operator", {"foreground" => "#000099"})
894
+ buffer.create_tag("string", {"foreground" => "#777777"})
895
+ buffer.create_tag("word", {"foreground" => "#d93503"})
896
+ buffer.create_tag("comment", {"foreground" => "#004400"})
897
+ buffer.create_tag("error", {"foreground" => "#990000", "underline" => Pango::UNDERLINE_SINGLE })
898
+ end
899
+
900
+ def buffer_syntax_highlight(buffer, filename)
901
+ case @options[:curr_extension]
902
+ when 'rules'
903
+ hl_lexical = Rules::Lexical.new
904
+ hl_lexical.analyze(buffer.text, filename)
905
+
906
+ buffer.remove_all_tags(buffer.start_iter, buffer.end_iter)
907
+
908
+ hl_lexical.result.each do |l|
909
+ next if l[:filename] != filename
910
+ b = buffer.get_iter_at_offset(l[:begin])
911
+ e = buffer.get_iter_at_offset(l[:begin]+l[:length])
912
+ case l[:lexem]
913
+ when :label, :proc
914
+ buffer.apply_tag("label", b, e)
915
+ when :number, :float, :unary_minus
916
+ buffer.apply_tag("number", b, e)
917
+ when :l_brace, :r_brace
918
+ buffer.apply_tag("brace", b, e)
919
+ when :plus, :minus, :mul, :div
920
+ buffer.apply_tag("operation", b, e)
921
+ when :var,:wvar
922
+ buffer.apply_tag("var", b, e)
923
+ when :if_yes, :if_no, :else, :semicolon, :ret, :include, :true, :false, :ruby, :limiter
924
+ buffer.apply_tag("operator", b, e)
925
+ when :word
926
+ buffer.apply_tag("word", b, e)
927
+ when :string
928
+ buffer.apply_tag("string", b, e)
929
+ when :comment
930
+ buffer.apply_tag("comment", b, e)
931
+ end
932
+ end
933
+ end
934
+ end
935
+
936
+ def dialog_ok_cancel(message)
937
+ dialog = Gtk::MessageDialog.new(@wnd_main,
938
+ Gtk::Dialog::DESTROY_WITH_PARENT,
939
+ Gtk::MessageDialog::QUESTION,
940
+ Gtk::MessageDialog::BUTTONS_OK_CANCEL,
941
+ message)
942
+ result = (dialog.run == Gtk::Dialog::RESPONSE_OK)
943
+ dialog.destroy
944
+ return result
945
+ end
946
+
947
+ def dialog_yes_no_cancel(message)
948
+ dialog = Gtk::MessageDialog.new(@wnd_main,
949
+ Gtk::Dialog::DESTROY_WITH_PARENT,
950
+ Gtk::MessageDialog::QUESTION,
951
+ Gtk::MessageDialog::BUTTONS_NONE,
952
+ message)
953
+ dialog.add_buttons(
954
+ [Gtk::Stock::YES, Gtk::Dialog::RESPONSE_YES],
955
+ [Gtk::Stock::NO, Gtk::Dialog::RESPONSE_NO],
956
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL])
957
+ result = dialog.run
958
+ dialog.destroy
959
+ return result
960
+ end
961
+
962
+
963
+ def dialog_saveall_yes_no_cancel(message)
964
+ dialog = Gtk::MessageDialog.new(@wnd_main,
965
+ Gtk::Dialog::DESTROY_WITH_PARENT,
966
+ Gtk::MessageDialog::QUESTION,
967
+ Gtk::MessageDialog::BUTTONS_NONE,
968
+ message)
969
+ dialog.add_buttons(
970
+ ["Сохранить все", Gtk::Dialog::RESPONSE_APPLY],
971
+ [Gtk::Stock::YES, Gtk::Dialog::RESPONSE_YES],
972
+ [Gtk::Stock::NO, Gtk::Dialog::RESPONSE_NO],
973
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL])
974
+ result = dialog.run
975
+ dialog.destroy
976
+ return result
977
+ end
978
+
979
+ def progress_callback(perc)
980
+ if (perc % @a == 0) or (perc == 100)
981
+ @pb_progress.text = "#{perc}%"
982
+ @pb_progress.fraction = perc * 0.01
983
+ Gtk::main_iteration_do(blocking = false) while Gtk::events_pending?
984
+ @a = Random.rand(2...10)
985
+ end
986
+ end
987
+
988
+ def progress_reset
989
+ @pb_progress.text = " "
990
+ @pb_progress.fraction = 0
991
+ @a = 1
992
+ end
993
+ # Функция обратного вызова для VM (вызываеться на каждый шаг программы)
994
+ def debug_callback(lex)
995
+ return if @debuger_mode == :start and lex[:lexem] != :stop
996
+ # Файл текущей лексемыg
997
+ filename = lex[:filename]
998
+ buffer = @dbg_buffers[filename]
999
+ if buffer.nil?
1000
+ # Создать новый буфер
1001
+ @dbg_buffers[filename] = buffer = Gtk::TextBuffer.new
1002
+ buffer_connect_tags(buffer)
1003
+ buffer.signal_connect("changed") { |widget| on_end_user_action(widget); }
1004
+ buffer.text = File.open(lex[:filename], "r:UTF-8").read
1005
+ buffer_syntax_highlight buffer, lex[:filename]
1006
+ # Переключить отображение на созданный буффер
1007
+ unless @debuger_mode == :overstep
1008
+ @txv_program.buffer = buffer
1009
+ @lb_filename.text = filename
155
1010
  end
156
-
157
1011
  end
158
- public
159
- def run
160
- translator
161
- exec
1012
+ # Извлечь итераторы предыдущей лексемы и удалить на ней тег выделения
1013
+ @old_lex_iter[:buffer].remove_tag("blue", @old_lex_iter[:begin], @old_lex_iter[:end]) unless @old_lex_iter.nil?
1014
+ # Выделить текущую лексему
1015
+ b = buffer.get_iter_at_offset(lex[:begin])
1016
+ e = buffer.get_iter_at_offset(lex[:begin]+lex[:length])
1017
+ buffer.apply_tag("blue", b, e)
1018
+ @txv_program.scroll_to_iter(b, 0.25, false, 0, 0)
1019
+ # Сохранить буфер и итераторы текущей лексемы для последующей очистки от тегов
1020
+ @old_lex_iter = {buffer: buffer, begin: b, end: e}
1021
+
1022
+ # Если предыдущая лексема переменная, обновить ее значение в таблице переменных
1023
+ if !@old_lex.nil? and (@old_lex[:lexem] == :var or @old_lex[:lexem] == :wvar)
1024
+ @ls_variables.each do |m,p,i|
1025
+ value = (@old_lex[:lexem] == :wvar ? @old_lex[:value][1..-1] : @old_lex[:value])
1026
+ if value == i.get_value(0)
1027
+ i[1] = @vm.data[@ids_map[i.get_value(0)][:addr]].to_s
1028
+ end
1029
+ end
1030
+ Gtk::main_iteration_do(blocking = false) while Gtk::events_pending?
162
1031
  end
1032
+ # Обновить содержимое окна состояния стека
1033
+ refresh_stack_state
1034
+
1035
+ # Обработка режимов отладки
1036
+ case @debuger_mode
1037
+ when :step
1038
+ @debuger_mode = :default
1039
+ @ip = nil
1040
+ @pause_flag = true
1041
+ when :overstep
1042
+ if !@ip.nil? and @vm.ip != @ip
1043
+ @pause_flag = false
1044
+ else
1045
+ @pause_flag = true
1046
+ @ip = nil
1047
+ end
1048
+ @ip = @vm.ip + 2 if lex[:lexem] == :var and @ids_map[lex[:value]][:type] == :proc
1049
+ end
1050
+ # Если отладчик не в автоматическом режиме, подключить буфер к виджету
1051
+ if @pause_flag or @delay != 0
1052
+ @txv_program.buffer = buffer
1053
+ @lb_filename.text = filename
1054
+ end
1055
+
1056
+ # Если лексема :stop, перевести отладчи в конечное состояние
1057
+ cmd(:stop) if lex[:lexem] == :stop
1058
+ # Сохранить текущую лексему
1059
+ @old_lex = lex
1060
+
1061
+ # Задержка автоматического обхода
1062
+ if @delay > 0
1063
+ sleep @delay
1064
+ Gtk::main_iteration_do(blocking = false) while Gtk::events_pending?
1065
+ end
1066
+
1067
+ refresh_console
1068
+ # Ожидания действий пользователя
1069
+ sleep 0.1 while @pause_flag;
1070
+ end
163
1071
  end
164
- # Your code goes here...
165
- end
1072
+
1073
+ end