forthic 0.1.0 → 0.2.4

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.
@@ -1,49 +1,138 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'forthic_error'
4
- require_relative 'tokenizer'
5
- require_relative 'token'
6
- require_relative 'code_location'
7
- require_relative 'positioned_string'
8
- require_relative 'words/word'
9
- require_relative 'words/push_value_word'
10
- require_relative 'words/start_module_word'
11
- require_relative 'words/end_module_word'
12
- require_relative 'words/end_array_word'
13
- require_relative 'words/definition_word'
14
- require_relative 'global_module'
3
+ require_relative "forthic_error"
4
+ require_relative "errors/unknown_word_error"
5
+ require_relative "tokenizer"
6
+ require_relative "token"
7
+ require_relative "code_location"
8
+ require_relative "positioned_string"
9
+ require_relative "words/word"
10
+ require_relative "words/push_value_word"
11
+ require_relative "words/start_module_word"
12
+ require_relative "words/end_module_word"
13
+ require_relative "words/end_array_word"
14
+ require_relative "words/definition_word"
15
+ require_relative "global_module"
15
16
 
16
17
  module Forthic
17
- class Interpreter
18
- attr_accessor :stack, :global_module, :app_module, :module_stack, :registered_modules,
19
- :is_compiling, :should_stop, :is_memo_definition, :cur_definition,
20
- :screens, :default_module_flags, :module_flags, :string_location,
21
- :word_counts, :is_profiling, :start_profile_time, :timestamps
18
+ # Error codes used throughout the interpreter
19
+ module ErrorCodes
20
+ SCREEN_NOT_FOUND = "screen-not-found"
21
+ EXECUTION_ERROR = "execution-error"
22
+ MODULE_NOT_FOUND = "module-not-found"
23
+ STACK_UNDERFLOW = "stack-underflow"
24
+ MODULE_EXECUTION_ERROR = "module-execution-error"
25
+ UNKNOWN_TOKEN = "unknown-token"
26
+ NESTED_DEFINITION = "nested-definition"
27
+ NESTED_MEMO_DEFINITION = "nested-memo-definition"
28
+ DEFINITION_WITHOUT_START = "definition-without-start"
29
+ MISSING_DEFINITION = "missing-definition"
30
+ WORD_NOT_FOUND = "word-not-found"
31
+ end
22
32
 
23
- def initialize
33
+ # Manages execution state for the interpreter
34
+ class ExecutionState
35
+ attr_accessor :stack, :module_stack, :is_compiling, :should_stop,
36
+ :is_memo_definition, :cur_definition, :string_location
37
+
38
+ def initialize(app_module)
24
39
  @stack = []
25
- @registered_modules = {}
40
+ @module_stack = [app_module]
26
41
  @is_compiling = false
27
42
  @should_stop = false
28
43
  @is_memo_definition = false
29
44
  @cur_definition = nil
30
- @screens = {}
31
- @default_module_flags = {}
32
- @module_flags = {}
33
45
  @string_location = nil
46
+ end
34
47
 
35
- @global_module = GlobalModule.new(self)
36
- @app_module = ForthicModule.new("", self)
37
- @module_stack = [@app_module]
48
+ def reset(app_module)
49
+ @stack = []
50
+ @module_stack = [app_module]
51
+ @is_compiling = false
52
+ @is_memo_definition = false
53
+ @cur_definition = nil
54
+ @string_location = nil
55
+ end
56
+ end
57
+
58
+ # Manages profiling state and operations
59
+ class ProfilingState
60
+ attr_reader :word_counts, :is_profiling, :start_profile_time, :timestamps
38
61
 
62
+ def initialize
39
63
  @word_counts = {}
40
64
  @is_profiling = false
41
65
  @start_profile_time = nil
42
66
  @timestamps = []
43
67
  end
44
68
 
69
+ def start_profiling
70
+ @is_profiling = true
71
+ @timestamps = []
72
+ @start_profile_time = Time.now
73
+ add_timestamp("START")
74
+ @word_counts = {}
75
+ end
76
+
77
+ def stop_profiling
78
+ add_timestamp("END")
79
+ @is_profiling = false
80
+ end
81
+
82
+ def count_word(word)
83
+ return unless @is_profiling
84
+ @word_counts[word.name] ||= 0
85
+ @word_counts[word.name] += 1
86
+ end
87
+
88
+ def add_timestamp(label)
89
+ return unless @is_profiling
90
+ timestamp = {label: label, time_ms: (Time.now - @start_profile_time) * 1000}
91
+ @timestamps.push(timestamp)
92
+ end
93
+
94
+ def word_histogram
95
+ @word_counts.map { |name, count| {word: name, count: count} }.sort_by { |item| -item[:count] }
96
+ end
97
+ end
98
+
99
+ class Interpreter
100
+ # Core interpreter components
101
+ attr_reader :global_module, :app_module, :registered_modules
102
+ # Screen and module management
103
+ attr_accessor :screens, :default_module_flags, :module_flags
104
+ # State objects
105
+ attr_reader :execution_state, :profiling_state
106
+
107
+ # Token handler lookup table
108
+ TOKEN_HANDLERS = {
109
+ TokenType::STRING => :handle_string_token,
110
+ TokenType::COMMENT => :handle_comment_token,
111
+ TokenType::START_ARRAY => :handle_start_array_token,
112
+ TokenType::END_ARRAY => :handle_end_array_token,
113
+ TokenType::START_MODULE => :handle_start_module_token,
114
+ TokenType::END_MODULE => :handle_end_module_token,
115
+ TokenType::START_DEF => :handle_start_definition_token,
116
+ TokenType::START_MEMO => :handle_start_memo_token,
117
+ TokenType::END_DEF => :handle_end_definition_token,
118
+ TokenType::WORD => :handle_word_token
119
+ }.freeze
120
+
121
+ def initialize
122
+ @registered_modules = {}
123
+ @screens = {}
124
+ @default_module_flags = {}
125
+ @module_flags = {}
126
+
127
+ @global_module = GlobalModule.new(self)
128
+ @app_module = ForthicModule.new("", self)
129
+
130
+ @execution_state = ExecutionState.new(@app_module)
131
+ @profiling_state = ProfilingState.new
132
+ end
133
+
45
134
  def halt
46
- @should_stop = true
135
+ @execution_state.should_stop = true
47
136
  end
48
137
 
49
138
  # @return [ForthicModule]
@@ -53,7 +142,28 @@ module Forthic
53
142
 
54
143
  # @return [CodeLocation, nil]
55
144
  def get_string_location
56
- @string_location
145
+ @execution_state.string_location
146
+ end
147
+
148
+ # Delegation methods for execution state
149
+ def stack
150
+ @execution_state.stack
151
+ end
152
+
153
+ def stack=(new_stack)
154
+ @execution_state.stack = new_stack
155
+ end
156
+
157
+ def module_stack
158
+ @execution_state.module_stack
159
+ end
160
+
161
+ def is_compiling
162
+ @execution_state.is_compiling
163
+ end
164
+
165
+ def cur_definition
166
+ @execution_state.cur_definition
57
167
  end
58
168
 
59
169
  # @param [String] module_id
@@ -80,20 +190,15 @@ module Forthic
80
190
  end
81
191
 
82
192
  def reset
83
- @stack = []
84
193
  @app_module.variables = {}
85
- @module_stack = [@app_module]
86
- @is_compiling = false
87
- @is_memo_definition = false
88
- @cur_definition = nil
89
- @string_location = nil
194
+ @execution_state.reset(@app_module)
90
195
  end
91
196
 
92
197
  # @param [String] screen_name
93
198
  # @return [String]
94
199
  def get_screen_forthic(screen_name)
95
200
  screen = @screens[screen_name]
96
- raise ForthicError.new("interpreter-199", "Unable to find screen \"#{screen_name}\"", "Hmmm...something went wrong. Please file a ticket if this continues to happen") unless screen
201
+ raise ForthicError.new(ErrorCodes::SCREEN_NOT_FOUND, "Unable to find screen \"#{screen_name}\"", "Screen not found. Check the screen name for typos or ensure it has been properly registered.") unless screen
97
202
  screen
98
203
  end
99
204
 
@@ -112,63 +217,82 @@ module Forthic
112
217
  loop do
113
218
  token = tokenizer.next_token
114
219
  handle_token(token)
115
- break if token.type == TokenType::EOS || @should_stop
116
- next if [TokenType::START_DEF, TokenType::END_DEF, TokenType::COMMENT].include?(token.type) || @is_compiling
220
+ break if token.type == TokenType::EOS || @execution_state.should_stop
221
+ next if [TokenType::START_DEF, TokenType::END_DEF, TokenType::COMMENT].include?(token.type) || @execution_state.is_compiling
117
222
  end
118
223
  true
119
- # rescue => e
120
- # error = ForthicError.new("interpreter-213", "Ran into an error executing this '#{token.string}'", "If there is an unknown error in the stack details, please file a ticket so we can resolve it.", token.location)
121
- # error.set_caught_error(e)
122
- # raise error
224
+ rescue ForthicError => e
225
+ # Re-raise ForthicError and its subclasses without wrapping
226
+ raise e
227
+ rescue => e
228
+ # Wrap non-ForthicError exceptions
229
+ error = ForthicError.new(ErrorCodes::EXECUTION_ERROR, "Error executing token '#{token&.string}'", "An unexpected error occurred during execution. Check the token syntax and try again.", token&.location)
230
+ error.set_caught_error(e)
231
+ raise error
123
232
  end
124
233
 
125
234
  # @return [ForthicModule]
126
235
  def cur_module
127
- @module_stack.last
236
+ @execution_state.module_stack.last
128
237
  end
129
238
 
130
239
  # @param [String] name
131
240
  # @return [ForthicModule]
132
241
  def find_module(name)
242
+ raise ArgumentError, "Module name cannot be nil" if name.nil?
243
+ raise ArgumentError, "Module name cannot be empty" if name.empty?
244
+
133
245
  result = @registered_modules[name]
134
- raise ForthicError.new("interpreter-236", "Couldn't find '#{name}' module", "This is most likely a typo in your Forthic code. Please check to see if '#{name}' is properly spelled and that you have permission to access it") unless result
246
+ raise ForthicError.new(ErrorCodes::MODULE_NOT_FOUND, "Module '#{name}' not found", "Check the module name for typos and ensure it has been properly registered.") unless result
135
247
  result
136
248
  end
137
249
 
138
250
  # @param [Object] val
139
251
  def stack_push(val)
140
- @stack.push(val)
252
+ @execution_state.stack.push(val)
141
253
  end
142
254
 
143
255
  # @return [Object]
144
256
  def stack_pop
145
- raise ForthicError.new("interpreter-251", "Stack underflow", "This happens when we expect something to be on the stack, but it's empty. This is caused by a logical error in the Forthic and can be resolved through debugging.") if @stack.empty?
146
- result = @stack.pop
147
- @string_location = result.is_a?(PositionedString) ? result.location : nil
257
+ raise ForthicError.new(ErrorCodes::STACK_UNDERFLOW, "Stack underflow", "Attempted to pop from an empty stack. This indicates a logical error in the Forthic code.") if @execution_state.stack.empty?
258
+ result = @execution_state.stack.pop
259
+ @execution_state.string_location = result.is_a?(PositionedString) ? result.location : nil
148
260
  result.is_a?(PositionedString) ? result.value_of : result
149
261
  end
150
262
 
151
263
  # @param [ForthicModule] mod
152
264
  def module_stack_push(mod)
153
- @module_stack.push(mod)
265
+ raise ArgumentError, "Module cannot be nil" if mod.nil?
266
+ @execution_state.module_stack.push(mod)
154
267
  end
155
268
 
156
269
  def module_stack_pop
157
- @module_stack.pop
270
+ @execution_state.module_stack.pop
158
271
  end
159
272
 
160
273
  # @param [ForthicModule] mod
161
274
  def register_module(mod)
275
+ raise ArgumentError, "Module cannot be nil" if mod.nil?
276
+ raise ArgumentError, "Module must respond to :name" unless mod.respond_to?(:name)
162
277
  @registered_modules[mod.name] = mod
163
278
  end
164
279
 
280
+ # @param [ForthicModule] mod
281
+ # @param [String] prefix
282
+ def import_module(mod, prefix = "")
283
+ raise ArgumentError, "Module cannot be nil" if mod.nil?
284
+ register_module(mod)
285
+ @app_module.import_module(prefix, mod, self)
286
+ end
287
+
165
288
  # @param [ForthicModule] mod
166
289
  def run_module_code(mod)
290
+ raise ArgumentError, "Module cannot be nil" if mod.nil?
167
291
  module_stack_push(mod)
168
292
  run(mod.forthic_code)
169
293
  module_stack_pop
170
294
  rescue => e
171
- error = ForthicError.new("interpreter-278", "Something went wrong when running the module #{mod.name}", "TODO: File a ticket")
295
+ error = ForthicError.new(ErrorCodes::MODULE_EXECUTION_ERROR, "Error executing module '#{mod.name}'", "An error occurred while running the module code. Check the module implementation for syntax errors.")
172
296
  error.set_caught_error(e)
173
297
  raise error
174
298
  end
@@ -177,7 +301,7 @@ module Forthic
177
301
  # @return [Word, nil]
178
302
  def find_word(name)
179
303
  result = nil
180
- @module_stack.reverse_each do |m|
304
+ @execution_state.module_stack.reverse_each do |m|
181
305
  result = m.find_word(name)
182
306
  break if result
183
307
  end
@@ -185,59 +309,40 @@ module Forthic
185
309
  result
186
310
  end
187
311
 
312
+ # Delegation methods for profiling
188
313
  def start_profiling
189
- @is_profiling = true
190
- @timestamps = []
191
- @start_profile_time = Time.now
192
- add_timestamp("START")
193
- @word_counts = {}
314
+ @profiling_state.start_profiling
194
315
  end
195
316
 
196
- # @param [Word] word
197
- def count_word(word)
198
- return unless @is_profiling
199
- @word_counts[word.name] ||= 0
200
- @word_counts[word.name] += 1
317
+ def stop_profiling
318
+ @profiling_state.stop_profiling
201
319
  end
202
320
 
203
- def stop_profiling
204
- add_timestamp("END")
205
- @is_profiling = false
321
+ def count_word(word)
322
+ @profiling_state.count_word(word)
206
323
  end
207
324
 
208
- # @param [String] label
209
325
  def add_timestamp(label)
210
- return unless @is_profiling
211
- timestamp = { label: label, time_ms: (Time.now - @start_profile_time) * 1000 }
212
- @timestamps.push(timestamp)
326
+ @profiling_state.add_timestamp(label)
213
327
  end
214
328
 
215
- # @return [Array<Hash>]
216
329
  def word_histogram
217
- @word_counts.map { |name, count| { word: name, count: count } }.sort_by { |item| -item[:count] }
330
+ @profiling_state.word_histogram
218
331
  end
219
332
 
220
- # @return [Array<Hash>]
221
333
  def profile_timestamps
222
- @timestamps
334
+ @profiling_state.timestamps
223
335
  end
224
336
 
225
337
  # @param [Token] token
226
338
  def handle_token(token)
227
- case token.type
228
- when TokenType::STRING then handle_string_token(token)
229
- when TokenType::COMMENT then handle_comment_token(token)
230
- when TokenType::START_ARRAY then handle_start_array_token(token)
231
- when TokenType::END_ARRAY then handle_end_array_token(token)
232
- when TokenType::START_MODULE then handle_start_module_token(token)
233
- when TokenType::END_MODULE then handle_end_module_token(token)
234
- when TokenType::START_DEF then handle_start_definition_token(token)
235
- when TokenType::START_MEMO then handle_start_memo_token(token)
236
- when TokenType::END_DEF then handle_end_definition_token(token)
237
- when TokenType::WORD then handle_word_token(token)
238
- when TokenType::EOS then return
339
+ return if token.type == TokenType::EOS
340
+
341
+ handler = TOKEN_HANDLERS[token.type]
342
+ if handler
343
+ send(handler, token)
239
344
  else
240
- raise ForthicError.new("interpreter-362", "Hmmm...the interpreter doesn't know what to make of '#{token.string}'", "This is most likely caused by a typo in the Forthic code and can be resolved by debugging.", token.location)
345
+ raise ForthicError.new(ErrorCodes::UNKNOWN_TOKEN, "Unknown token type '#{token.string}'", "This token type is not recognized. Check for typos or unsupported syntax.", token.location)
241
346
  end
242
347
  end
243
348
 
@@ -250,7 +355,7 @@ module Forthic
250
355
  # @param [Token] token
251
356
  def handle_start_module_token(token)
252
357
  word = StartModuleWord.new(token.string)
253
- @cur_definition.add_word(word) if @is_compiling
358
+ @execution_state.cur_definition.add_word(word) if @execution_state.is_compiling
254
359
  count_word(word)
255
360
  word.execute(self)
256
361
  end
@@ -258,7 +363,7 @@ module Forthic
258
363
  # @param [Token] _token
259
364
  def handle_end_module_token(_token)
260
365
  word = EndModuleWord.new
261
- @cur_definition.add_word(word) if @is_compiling
366
+ @execution_state.cur_definition.add_word(word) if @execution_state.is_compiling
262
367
  count_word(word)
263
368
  word.execute(self)
264
369
  end
@@ -280,49 +385,134 @@ module Forthic
280
385
 
281
386
  # @param [Token] token
282
387
  def handle_start_definition_token(token)
283
- raise ForthicError.new("interpreter-407", "A definition was started while an existing definition was not ended", "This is probably caused by a missing semicolon. To resolve, ensure that all word definitions end with semicolons.", token.location) if @is_compiling
284
- @cur_definition = DefinitionWord.new(token.string)
285
- @is_compiling = true
286
- @is_memo_definition = false
388
+ raise ForthicError.new(ErrorCodes::NESTED_DEFINITION, "Nested definition not allowed", "A definition was started while another definition is active. Ensure all definitions end with semicolons.", token.location) if @execution_state.is_compiling
389
+ @execution_state.cur_definition = DefinitionWord.new(token.string)
390
+ @execution_state.is_compiling = true
391
+ @execution_state.is_memo_definition = false
287
392
  end
288
393
 
289
394
  # @param [Token] token
290
395
  def handle_start_memo_token(token)
291
- raise ForthicError.new("interpreter-420", "A memo definition was started while an existing definition was not ended", "This is probably caused by a missing semicolon. To resolve, ensure that all word definitions end with semicolons.", token.location) if @is_compiling
292
- @cur_definition = DefinitionWord.new(token.string)
293
- @is_compiling = true
294
- @is_memo_definition = true
396
+ raise ForthicError.new(ErrorCodes::NESTED_MEMO_DEFINITION, "Nested memo definition not allowed", "A memo definition was started while another definition is active. Ensure all definitions end with semicolons.", token.location) if @execution_state.is_compiling
397
+ @execution_state.cur_definition = DefinitionWord.new(token.string)
398
+ @execution_state.is_compiling = true
399
+ @execution_state.is_memo_definition = true
295
400
  end
296
401
 
297
402
  # @param [Token] token
298
403
  def handle_end_definition_token(token)
299
- raise ForthicError.new("interpreter-433", "A definition was ended when one hadn't been started yet", "This is probably caused by an extra semicolon. To resolve, ensure that there are no spurious semicolons in the Forthic code.", token.location) unless @is_compiling
300
- raise ForthicError.new("interpreter-440", "Cannot finish definition because there is no current definition", "Please file a ticket", token.location) unless @cur_definition
301
- if @is_memo_definition
302
- cur_module.add_memo_words(@cur_definition)
404
+ raise ForthicError.new(ErrorCodes::DEFINITION_WITHOUT_START, "Definition ended without start", "A definition was ended when none was active. Check for extra semicolons.", token.location) unless @execution_state.is_compiling
405
+ raise ForthicError.new(ErrorCodes::MISSING_DEFINITION, "No current definition to end", "Internal error: definition state is inconsistent.", token.location) unless @execution_state.cur_definition
406
+ if @execution_state.is_memo_definition
407
+ cur_module.add_memo_words(@execution_state.cur_definition)
303
408
  else
304
- cur_module.add_word(@cur_definition)
409
+ cur_module.add_word(@execution_state.cur_definition)
305
410
  end
306
- @is_compiling = false
411
+ @execution_state.is_compiling = false
307
412
  end
308
413
 
309
414
  # @param [Token] token
310
415
  def handle_word_token(token)
311
416
  word = find_word(token.string)
312
- raise ForthicError.new("interpreter-458", "Could not find word: #{token.string}", "Check to see if you have a typo in your word or the definition of that word", token.location) unless word
417
+ unless word
418
+ # Generate suggested words for better error messages
419
+ suggested_words = find_similar_words(token.string)
420
+ raise Errors::UnknownWordError.new(token.string, token.location, suggested_words)
421
+ end
313
422
  handle_word(word, token.location)
314
423
  end
315
424
 
316
425
  # @param [Word] word
317
426
  # @param [CodeLocation, nil] location
318
427
  def handle_word(word, location = nil)
319
- if @is_compiling
428
+ if @execution_state.is_compiling
320
429
  word.set_location(location)
321
- @cur_definition.add_word(word)
430
+ @execution_state.cur_definition.add_word(word)
322
431
  else
323
432
  count_word(word)
324
433
  word.execute(self)
325
434
  end
326
435
  end
436
+
437
+ private
438
+
439
+ # Find words similar to the given word name for error suggestions
440
+ # @param [String] word_name The unknown word to find suggestions for
441
+ # @return [Array<String>] Array of similar word names
442
+ def find_similar_words(word_name)
443
+ return [] if word_name.nil? || word_name.empty?
444
+
445
+ all_words = collect_available_words
446
+
447
+ # Find words with similar names using simple string distance
448
+ suggestions = all_words.select do |available_word|
449
+ levenshtein_distance(word_name.downcase, available_word.downcase) <= 2
450
+ end
451
+
452
+ # If no close matches, try prefix matching
453
+ if suggestions.empty?
454
+ suggestions = all_words.select do |available_word|
455
+ available_word.downcase.start_with?(word_name[0, 2].downcase) ||
456
+ word_name.downcase.start_with?(available_word[0, 2].downcase)
457
+ end
458
+ end
459
+
460
+ suggestions.take(3)
461
+ end
462
+
463
+ # Collect all available word names from all modules in scope
464
+ # @return [Array<String>] Array of all available word names
465
+ def collect_available_words
466
+ words = []
467
+
468
+ # Collect from global module (hardcoded common words since GlobalModule uses methods)
469
+ global_words = %w[
470
+ POP DUP SWAP >STR CONCAT SPLIT JOIN /N /R /T LOWERCASE UPPERCASE
471
+ APPEND REVERSE UNIQUE MAP FOREACH KEYS VALUES LENGTH RANGE SLICE
472
+ SELECT TAKE DROP NTH LAST FLATTEN REDUCE + - * / MOD
473
+ == != > >= < <= OR AND NOT IN BOOL INT FLOAT
474
+ VARIABLES ! @ !@ INTERPRET EXPORT USE-MODULES REC
475
+ ]
476
+ words.concat(global_words)
477
+
478
+ # Collect from module stack
479
+ @execution_state.module_stack.each do |mod|
480
+ if mod.respond_to?(:words) && mod.words
481
+ words.concat(mod.words.map(&:name))
482
+ end
483
+ end
484
+
485
+ words.uniq.compact
486
+ end
487
+
488
+ # Calculate Levenshtein distance between two strings
489
+ # @param [String] str1
490
+ # @param [String] str2
491
+ # @return [Integer] The edit distance between the strings
492
+ def levenshtein_distance(str1, str2)
493
+ return str2.length if str1.empty?
494
+ return str1.length if str2.empty?
495
+
496
+ # Create matrix
497
+ matrix = Array.new(str1.length + 1) { Array.new(str2.length + 1, 0) }
498
+
499
+ # Initialize first row and column
500
+ (0..str1.length).each { |i| matrix[i][0] = i }
501
+ (0..str2.length).each { |j| matrix[0][j] = j }
502
+
503
+ # Fill matrix
504
+ (1..str1.length).each do |i|
505
+ (1..str2.length).each do |j|
506
+ cost = (str1[i - 1] == str2[j - 1]) ? 0 : 1
507
+ matrix[i][j] = [
508
+ matrix[i - 1][j] + 1, # deletion
509
+ matrix[i][j - 1] + 1, # insertion
510
+ matrix[i - 1][j - 1] + cost # substitution
511
+ ].min
512
+ end
513
+ end
514
+
515
+ matrix[str1.length][str2.length]
516
+ end
327
517
  end
328
- end
518
+ end
data/lib/forthic/token.rb CHANGED
@@ -16,7 +16,6 @@ module Forthic
16
16
  end
17
17
  end
18
18
 
19
-
20
19
  module Forthic
21
20
  class Token
22
21
  attr_reader :type, :value, :location
@@ -35,4 +34,4 @@ module Forthic
35
34
  @value
36
35
  end
37
36
  end
38
- end
37
+ end
@@ -3,8 +3,8 @@
3
3
  module Forthic
4
4
  class Tokenizer
5
5
  attr_accessor :reference_location, :line, :column, :input_string, :input_pos,
6
- :whitespace, :quote_chars, :token_start_pos, :token_end_pos,
7
- :token_line, :token_column, :token_string
6
+ :whitespace, :quote_chars, :token_start_pos, :token_end_pos,
7
+ :token_line, :token_column, :token_string
8
8
 
9
9
  # @param [String] string
10
10
  # @param [CodeLocation, nil] reference_location
@@ -302,4 +302,4 @@ module Forthic
302
302
  Token.new(TokenType::WORD, @token_string, get_token_location)
303
303
  end
304
304
  end
305
- end
305
+ end
@@ -31,4 +31,4 @@ module Forthic
31
31
  Variable.new(@name, @value)
32
32
  end
33
33
  end
34
- end
34
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Forthic
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.4"
5
5
  end
@@ -1,7 +1,7 @@
1
- # # frozen_string_literal: true
1
+ # frozen_string_literal: true
2
2
 
3
- require_relative 'word'
4
- require_relative '../forthic_error'
3
+ require_relative "word"
4
+ require_relative "../forthic_error"
5
5
 
6
6
  module Forthic
7
7
  class DefinitionWord < Word
@@ -9,7 +9,7 @@ module Forthic
9
9
 
10
10
  # @param [String] name
11
11
  def initialize(name)
12
- super(name)
12
+ super
13
13
  @words = []
14
14
  @cur_index = 0
15
15
  end
@@ -22,19 +22,17 @@ module Forthic
22
22
  # @param [Interpreter] interp
23
23
  def execute(interp)
24
24
  @words.each do |word|
25
- begin
26
- word.execute(interp)
27
- rescue => e
28
- error = ForthicError.new(
29
- "definition_word-29",
30
- "Error executing word #{word.name}",
31
- "Error in #{self.name} definition",
32
- interp.get_string_location
33
- )
34
- error.set_caught_error(e)
35
- raise error
36
- end
25
+ word.execute(interp)
26
+ rescue => e
27
+ error = ForthicError.new(
28
+ "definition_word-29",
29
+ "Error executing word #{word.name}",
30
+ "Error in #{name} definition",
31
+ interp.get_string_location
32
+ )
33
+ error.set_caught_error(e)
34
+ raise error
37
35
  end
38
36
  end
39
37
  end
40
- end
38
+ end