forthic 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3faede941e29c0090a90077103892015502bb1bef7897726821932197a72be1
4
- data.tar.gz: 4393b304179b84c9b1cca818ae04af1cf6800dcd07c86ff92ec5e1b1f4fc4bbf
3
+ metadata.gz: 4ebffd3b7bf74a96a5bdbb6d178996eeea1c2d35edc22743e4dba9154e1e40f9
4
+ data.tar.gz: a34907460efd7db068214dff1410b512a9a9ad10e3eee149e120eb5b414ebc2f
5
5
  SHA512:
6
- metadata.gz: b8dea528434b695a7c272c1cd3d9b6d3885c2eb0d4acd43b876663f764abaca97b9896df81e8618dfe98612c4e4a2b18ba883ccbde93873d232cc933eb7ca28e
7
- data.tar.gz: baefe4a1a1157b5c190c7e62c703fcf7e0568aefb7103e2a463d514c798ba739a2f5eacdf35af70dd47d51e705ad546738bdac3f7b9de1c25d99d30b5e1153d5
6
+ metadata.gz: 7013c8908441bc6aaee014af8e6ac124bf0e60245474adacdcf4a8633c686ef781dc022e0f163a93222dfd3435e5e21c875ac273f13ae029909f51d354fbfdeb
7
+ data.tar.gz: 759a725d11e735ab283d99e076cf314f72ff98c086cf2dcd0ff93077f2031fa0bb27d814008f63ced3c179b6803f566a10d6b79a5e0082d9c91c30f9159b3d03
data/README.md CHANGED
@@ -1,3 +1,13 @@
1
+ > **⚠️ DEPRECATED PACKAGE**
2
+ >
3
+ > This package is from an archived repository and will not receive updates.
4
+ >
5
+ > **New repository:** https://github.com/forthix/forthic-rb
6
+ >
7
+ > Watch the new repository for announcements about updated packages.
8
+
9
+ ---
10
+
1
11
  # Forthic
2
12
 
3
13
  A Forthic interpreter that runs within Ruby.
@@ -16,5 +16,20 @@ module Forthic
16
16
  @start_pos = start_pos
17
17
  @end_pos = end_pos
18
18
  end
19
+
20
+ # @return [String]
21
+ def to_s
22
+ "#{@screen_name}:#{@line}:#{@column}"
23
+ end
24
+
25
+ # @return [Integer]
26
+ def line_number
27
+ @line
28
+ end
29
+
30
+ # @return [Integer]
31
+ def column_number
32
+ @column
33
+ end
19
34
  end
20
35
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../forthic_error"
4
+
5
+ module Forthic
6
+ module Errors
7
+ class UnknownWordError < ForthicError
8
+ attr_reader :word_name
9
+
10
+ # @param [String] word_name The name of the unknown word
11
+ # @param [CodeLocation, nil] location Where the error occurred
12
+ # @param [Array<String>] suggested_words Optional list of similar words for suggestions
13
+ def initialize(word_name, location = nil, suggested_words = [])
14
+ @word_name = word_name
15
+ @suggested_words = suggested_words
16
+
17
+ description = build_description(suggested_words)
18
+ super(ErrorCodes::WORD_NOT_FOUND, "Word '#{word_name}' not found", description, location)
19
+ end
20
+
21
+ # @return [Array<String>] List of suggested similar words
22
+ def suggested_words
23
+ @suggested_words.dup
24
+ end
25
+
26
+ private
27
+
28
+ # @param [Array<String>] suggested_words
29
+ # @return [String]
30
+ def build_description(suggested_words)
31
+ base_description = "Check for typos in the word name or ensure the word has been defined."
32
+ return base_description if suggested_words.empty?
33
+
34
+ suggestions = suggested_words.take(3).join(", ")
35
+ "#{base_description} Did you mean: #{suggestions}?"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -46,5 +46,20 @@ module Forthic
46
46
 
47
47
  result.reverse
48
48
  end
49
+
50
+ # @return [String]
51
+ def message
52
+ to_s
53
+ end
54
+
55
+ # @return [String]
56
+ def to_s
57
+ parts = [@title]
58
+ parts << "at #{@location}" if @location
59
+ if @description && !@description.empty?
60
+ parts[-1] = "#{parts[-1]}: #{@description}"
61
+ end
62
+ parts.join(" ")
63
+ end
49
64
  end
50
65
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "forthic_error"
4
+ require_relative "errors/unknown_word_error"
4
5
  require_relative "tokenizer"
5
6
  require_relative "token"
6
7
  require_relative "code_location"
@@ -220,7 +221,11 @@ module Forthic
220
221
  next if [TokenType::START_DEF, TokenType::END_DEF, TokenType::COMMENT].include?(token.type) || @execution_state.is_compiling
221
222
  end
222
223
  true
224
+ rescue ForthicError => e
225
+ # Re-raise ForthicError and its subclasses without wrapping
226
+ raise e
223
227
  rescue => e
228
+ # Wrap non-ForthicError exceptions
224
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)
225
230
  error.set_caught_error(e)
226
231
  raise error
@@ -409,7 +414,11 @@ module Forthic
409
414
  # @param [Token] token
410
415
  def handle_word_token(token)
411
416
  word = find_word(token.string)
412
- raise ForthicError.new(ErrorCodes::WORD_NOT_FOUND, "Word '#{token.string}' not found", "Check for typos in the word name or ensure the word has been defined.", 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
413
422
  handle_word(word, token.location)
414
423
  end
415
424
 
@@ -424,5 +433,86 @@ module Forthic
424
433
  word.execute(self)
425
434
  end
426
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
427
517
  end
428
518
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Forthic
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.4"
5
5
  end
data/lib/forthic.rb CHANGED
@@ -8,6 +8,10 @@ module Forthic
8
8
  autoload :Token, "forthic/token"
9
9
  autoload :PositionedString, "forthic/positioned_string"
10
10
  autoload :ForthicError, "forthic/forthic_error"
11
+
12
+ module Errors
13
+ autoload :UnknownWordError, "forthic/errors/unknown_word_error"
14
+ end
11
15
  autoload :Word, "forthic/words/word"
12
16
  autoload :PushValueWord, "forthic/words/push_value_word"
13
17
  autoload :DefinitionWord, "forthic/words/definition_word"
metadata CHANGED
@@ -1,18 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forthic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rino Jose
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-07-13 00:00:00.000000000 Z
11
+ date: 2026-01-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: This package provides a Forthic interpreter that allows you to execute
14
- Forthic code within your Ruby projects. Forthic is a stack-based programming language
15
- inspired by Forth.
13
+ description: "[ARCHIVED] This package provides a Forthic interpreter that allows you
14
+ to execute Forthic code within your Ruby projects. Forthic is a stack-based programming
15
+ language inspired by Forth. This gem is from an archived repository. Please see
16
+ https://github.com/forthix/forthic-rb for the new official repository."
16
17
  email:
17
18
  - rjose@forthix.com
18
19
  executables: []
@@ -27,6 +28,7 @@ files:
27
28
  - Rakefile
28
29
  - lib/forthic.rb
29
30
  - lib/forthic/code_location.rb
31
+ - lib/forthic/errors/unknown_word_error.rb
30
32
  - lib/forthic/forthic_error.rb
31
33
  - lib/forthic/forthic_module.rb
32
34
  - lib/forthic/global_module.rb
@@ -49,12 +51,16 @@ files:
49
51
  - lib/forthic/words/start_module_word.rb
50
52
  - lib/forthic/words/word.rb
51
53
  - sig/forthic.rbs
52
- homepage: https://github.com/linkedin/forthic
54
+ homepage: https://github.com/forthix/forthic-rb
53
55
  licenses: []
54
56
  metadata:
55
- homepage_uri: https://github.com/linkedin/forthic
56
- source_code_uri: https://github.com/linkedin/forthic
57
- post_install_message:
57
+ homepage_uri: https://github.com/forthix/forthic-rb
58
+ source_code_uri: https://github.com/forthix/forthic-rb
59
+ post_install_message: |
60
+ ⚠️ NOTICE: This gem is from an archived repository.
61
+
62
+ The Forthic project has moved to: https://github.com/forthix/forthic-rb
63
+ Please visit the new repository for updates and support.
58
64
  rdoc_options: []
59
65
  require_paths:
60
66
  - lib
@@ -72,5 +78,5 @@ requirements: []
72
78
  rubygems_version: 3.3.26
73
79
  signing_key:
74
80
  specification_version: 4
75
- summary: A Forthic interpreter that runs within Ruby.
81
+ summary: "[ARCHIVED] A Forthic interpreter that runs within Ruby - See https://github.com/forthix/forthic-rb"
76
82
  test_files: []