bets 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
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