forthic 0.2.0 → 0.3.0
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 +4 -4
- data/README.md +314 -14
- data/Rakefile +36 -7
- data/lib/forthic/decorators/docs.rb +69 -0
- data/lib/forthic/decorators/word.rb +331 -0
- data/lib/forthic/errors.rb +270 -0
- data/lib/forthic/grpc/client.rb +223 -0
- data/lib/forthic/grpc/errors.rb +149 -0
- data/lib/forthic/grpc/forthic_runtime_pb.rb +32 -0
- data/lib/forthic/grpc/forthic_runtime_services_pb.rb +31 -0
- data/lib/forthic/grpc/remote_module.rb +120 -0
- data/lib/forthic/grpc/remote_runtime_module.rb +148 -0
- data/lib/forthic/grpc/remote_word.rb +91 -0
- data/lib/forthic/grpc/runtime_manager.rb +60 -0
- data/lib/forthic/grpc/serializer.rb +184 -0
- data/lib/forthic/grpc/server.rb +361 -0
- data/lib/forthic/interpreter.rb +694 -245
- data/lib/forthic/literals.rb +170 -0
- data/lib/forthic/module.rb +383 -0
- data/lib/forthic/modules/standard/array_module.rb +940 -0
- data/lib/forthic/modules/standard/boolean_module.rb +176 -0
- data/lib/forthic/modules/standard/core_module.rb +362 -0
- data/lib/forthic/modules/standard/datetime_module.rb +349 -0
- data/lib/forthic/modules/standard/json_module.rb +55 -0
- data/lib/forthic/modules/standard/math_module.rb +365 -0
- data/lib/forthic/modules/standard/record_module.rb +203 -0
- data/lib/forthic/modules/standard/string_module.rb +170 -0
- data/lib/forthic/tokenizer.rb +224 -77
- data/lib/forthic/utils.rb +35 -0
- data/lib/forthic/websocket/handler.rb +548 -0
- data/lib/forthic/websocket/serializer.rb +160 -0
- data/lib/forthic/word_options.rb +141 -0
- data/lib/forthic.rb +30 -20
- data/protos/README.md +43 -0
- data/protos/v1/forthic_runtime.proto +200 -0
- metadata +72 -39
- data/.standard.yml +0 -3
- data/CHANGELOG.md +0 -11
- data/CLAUDE.md +0 -74
- data/Guardfile +0 -42
- data/lib/forthic/code_location.rb +0 -20
- data/lib/forthic/forthic_error.rb +0 -50
- data/lib/forthic/forthic_module.rb +0 -146
- data/lib/forthic/global_module.rb +0 -2328
- data/lib/forthic/positioned_string.rb +0 -19
- data/lib/forthic/token.rb +0 -37
- data/lib/forthic/variable.rb +0 -34
- data/lib/forthic/version.rb +0 -5
- data/lib/forthic/words/definition_word.rb +0 -38
- data/lib/forthic/words/end_array_word.rb +0 -28
- data/lib/forthic/words/end_module_word.rb +0 -16
- data/lib/forthic/words/imported_word.rb +0 -27
- data/lib/forthic/words/map_word.rb +0 -169
- data/lib/forthic/words/module_memo_bang_at_word.rb +0 -22
- data/lib/forthic/words/module_memo_bang_word.rb +0 -21
- data/lib/forthic/words/module_memo_word.rb +0 -35
- data/lib/forthic/words/module_word.rb +0 -21
- data/lib/forthic/words/push_value_word.rb +0 -21
- data/lib/forthic/words/start_module_word.rb +0 -31
- data/lib/forthic/words/word.rb +0 -30
- data/sig/forthic.rbs +0 -4
metadata
CHANGED
|
@@ -1,59 +1,92 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forthic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rino Jose
|
|
8
8
|
autorequire:
|
|
9
|
-
bindir:
|
|
9
|
+
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
12
|
-
dependencies:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
date: 2025-11-09 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rspec
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.12'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.12'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '13.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '13.0'
|
|
41
|
+
description: Forthic is a stack-based, concatenative programming language designed
|
|
42
|
+
for data manipulation and processing. This is the Ruby implementation with WebSocket
|
|
43
|
+
support for remote word execution.
|
|
16
44
|
email:
|
|
17
|
-
- rjose@
|
|
45
|
+
- rjose@gmail.com
|
|
18
46
|
executables: []
|
|
19
47
|
extensions: []
|
|
20
48
|
extra_rdoc_files: []
|
|
21
49
|
files:
|
|
22
|
-
- ".standard.yml"
|
|
23
|
-
- CHANGELOG.md
|
|
24
|
-
- CLAUDE.md
|
|
25
|
-
- Guardfile
|
|
26
50
|
- README.md
|
|
27
51
|
- Rakefile
|
|
28
52
|
- lib/forthic.rb
|
|
29
|
-
- lib/forthic/
|
|
30
|
-
- lib/forthic/
|
|
31
|
-
- lib/forthic/
|
|
32
|
-
- lib/forthic/
|
|
53
|
+
- lib/forthic/decorators/docs.rb
|
|
54
|
+
- lib/forthic/decorators/word.rb
|
|
55
|
+
- lib/forthic/errors.rb
|
|
56
|
+
- lib/forthic/grpc/client.rb
|
|
57
|
+
- lib/forthic/grpc/errors.rb
|
|
58
|
+
- lib/forthic/grpc/forthic_runtime_pb.rb
|
|
59
|
+
- lib/forthic/grpc/forthic_runtime_services_pb.rb
|
|
60
|
+
- lib/forthic/grpc/remote_module.rb
|
|
61
|
+
- lib/forthic/grpc/remote_runtime_module.rb
|
|
62
|
+
- lib/forthic/grpc/remote_word.rb
|
|
63
|
+
- lib/forthic/grpc/runtime_manager.rb
|
|
64
|
+
- lib/forthic/grpc/serializer.rb
|
|
65
|
+
- lib/forthic/grpc/server.rb
|
|
33
66
|
- lib/forthic/interpreter.rb
|
|
34
|
-
- lib/forthic/
|
|
35
|
-
- lib/forthic/
|
|
67
|
+
- lib/forthic/literals.rb
|
|
68
|
+
- lib/forthic/module.rb
|
|
69
|
+
- lib/forthic/modules/standard/array_module.rb
|
|
70
|
+
- lib/forthic/modules/standard/boolean_module.rb
|
|
71
|
+
- lib/forthic/modules/standard/core_module.rb
|
|
72
|
+
- lib/forthic/modules/standard/datetime_module.rb
|
|
73
|
+
- lib/forthic/modules/standard/json_module.rb
|
|
74
|
+
- lib/forthic/modules/standard/math_module.rb
|
|
75
|
+
- lib/forthic/modules/standard/record_module.rb
|
|
76
|
+
- lib/forthic/modules/standard/string_module.rb
|
|
36
77
|
- lib/forthic/tokenizer.rb
|
|
37
|
-
- lib/forthic/
|
|
38
|
-
- lib/forthic/
|
|
39
|
-
- lib/forthic/
|
|
40
|
-
- lib/forthic/
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
- lib/forthic/words/module_memo_word.rb
|
|
47
|
-
- lib/forthic/words/module_word.rb
|
|
48
|
-
- lib/forthic/words/push_value_word.rb
|
|
49
|
-
- lib/forthic/words/start_module_word.rb
|
|
50
|
-
- lib/forthic/words/word.rb
|
|
51
|
-
- sig/forthic.rbs
|
|
52
|
-
homepage: https://github.com/linkedin/forthic
|
|
53
|
-
licenses: []
|
|
78
|
+
- lib/forthic/utils.rb
|
|
79
|
+
- lib/forthic/websocket/handler.rb
|
|
80
|
+
- lib/forthic/websocket/serializer.rb
|
|
81
|
+
- lib/forthic/word_options.rb
|
|
82
|
+
- protos/README.md
|
|
83
|
+
- protos/v1/forthic_runtime.proto
|
|
84
|
+
homepage: https://github.com/forthix/forthic
|
|
85
|
+
licenses:
|
|
86
|
+
- MIT
|
|
54
87
|
metadata:
|
|
55
|
-
homepage_uri: https://github.com/
|
|
56
|
-
source_code_uri: https://github.com/
|
|
88
|
+
homepage_uri: https://github.com/forthix/forthic
|
|
89
|
+
source_code_uri: https://github.com/forthix/forthic
|
|
57
90
|
post_install_message:
|
|
58
91
|
rdoc_options: []
|
|
59
92
|
require_paths:
|
|
@@ -62,7 +95,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
62
95
|
requirements:
|
|
63
96
|
- - ">="
|
|
64
97
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: 3.
|
|
98
|
+
version: 3.0.0
|
|
66
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
100
|
requirements:
|
|
68
101
|
- - ">="
|
|
@@ -72,5 +105,5 @@ requirements: []
|
|
|
72
105
|
rubygems_version: 3.3.26
|
|
73
106
|
signing_key:
|
|
74
107
|
specification_version: 4
|
|
75
|
-
summary:
|
|
108
|
+
summary: Ruby implementation of the Forthic programming language
|
|
76
109
|
test_files: []
|
data/.standard.yml
DELETED
data/CHANGELOG.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
## [Unreleased]
|
|
2
|
-
|
|
3
|
-
## [0.2.0] - 2025-01-13
|
|
4
|
-
|
|
5
|
-
- Add `import_module` method to Interpreter class
|
|
6
|
-
- Add test coverage for module importing functionality
|
|
7
|
-
- Implement module importing with prefix support matching forthic-ts behavior
|
|
8
|
-
|
|
9
|
-
## [0.1.0] - 2024-12-27
|
|
10
|
-
|
|
11
|
-
- Initial release
|
data/CLAUDE.md
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Development Commands
|
|
6
|
-
|
|
7
|
-
### Testing
|
|
8
|
-
- `rake test` - Run all tests using Minitest
|
|
9
|
-
- `rake test TEST=test/test_specific_file.rb` - Run a specific test file
|
|
10
|
-
- `bundle exec guard` - Start Guard for continuous testing (watches file changes)
|
|
11
|
-
- `rake guard` - Alternative command to start Guard
|
|
12
|
-
|
|
13
|
-
### Code Quality
|
|
14
|
-
- `rake standard` - Run StandardRB linter for code formatting and style
|
|
15
|
-
- `rake standard:fix` - Auto-fix StandardRB issues where possible
|
|
16
|
-
- `rake` - Run default task (both tests and linting)
|
|
17
|
-
|
|
18
|
-
### Development
|
|
19
|
-
- `bundle install` - Install gem dependencies
|
|
20
|
-
- `bundle exec rake build` - Build the gem
|
|
21
|
-
- `bundle exec rake install` - Install the gem locally
|
|
22
|
-
- `bundle exec rake release` - Release the gem (requires proper credentials)
|
|
23
|
-
|
|
24
|
-
## Architecture Overview
|
|
25
|
-
|
|
26
|
-
This is a Ruby implementation of the Forthic programming language - a stack-based language inspired by Forth. The codebase follows a clean modular architecture:
|
|
27
|
-
|
|
28
|
-
### Core Components
|
|
29
|
-
|
|
30
|
-
**Interpreter (`lib/forthic/interpreter.rb`)**: The main execution engine that:
|
|
31
|
-
- Manages the execution stack and module stack
|
|
32
|
-
- Handles tokenization and parsing of Forthic code
|
|
33
|
-
- Provides word lookup and execution
|
|
34
|
-
- Supports profiling and debugging capabilities
|
|
35
|
-
- Manages compilation of word definitions
|
|
36
|
-
|
|
37
|
-
**Tokenizer (`lib/forthic/tokenizer.rb`)**: Lexical analyzer that breaks Forthic code into tokens (strings, words, arrays, modules, definitions, comments).
|
|
38
|
-
|
|
39
|
-
**Word System (`lib/forthic/words/`)**: Polymorphic word execution system where each word type implements an `execute` method:
|
|
40
|
-
- `Word` - Base class for all executable words
|
|
41
|
-
- `PushValueWord` - Pushes values onto the stack
|
|
42
|
-
- `DefinitionWord` - User-defined words compiled from Forthic code
|
|
43
|
-
- `EndArrayWord` - Handles array construction
|
|
44
|
-
- `ModuleWord` variants - Handle module operations and memoization
|
|
45
|
-
- `StartModuleWord`/`EndModuleWord` - Module boundary management
|
|
46
|
-
|
|
47
|
-
**Module System**:
|
|
48
|
-
- `GlobalModule` - Built-in words and core functionality
|
|
49
|
-
- `ForthicModule` - User-defined modules with isolated namespaces
|
|
50
|
-
- Module stack for hierarchical word resolution
|
|
51
|
-
|
|
52
|
-
### Key Design Patterns
|
|
53
|
-
|
|
54
|
-
- **Stack-based execution**: All operations work with a central execution stack
|
|
55
|
-
- **Autoloading**: Classes are autoloaded for better startup performance
|
|
56
|
-
- **Error handling**: Custom `ForthicError` with location tracking for debugging
|
|
57
|
-
- **Compilation**: Words can be compiled into definition words for reuse
|
|
58
|
-
- **Memoization**: Special memo words for caching expensive computations
|
|
59
|
-
|
|
60
|
-
### Testing Strategy
|
|
61
|
-
|
|
62
|
-
Uses Minitest for testing with:
|
|
63
|
-
- `test_helper.rb` sets up Minitest with SpecReporter for better output
|
|
64
|
-
- Guard for continuous testing during development
|
|
65
|
-
- Tests cover tokenizer, interpreter, and module functionality
|
|
66
|
-
- StandardRB enforces consistent code style
|
|
67
|
-
|
|
68
|
-
### File Organization
|
|
69
|
-
|
|
70
|
-
- `lib/forthic.rb` - Main entry point with autoload declarations
|
|
71
|
-
- `lib/forthic/` - Core implementation files
|
|
72
|
-
- `lib/forthic/words/` - Word implementation classes
|
|
73
|
-
- `test/` - Test files following Minitest conventions
|
|
74
|
-
- `sig/` - RBS type signatures for static analysis
|
data/Guardfile
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# A sample Guardfile
|
|
2
|
-
# More info at https://github.com/guard/guard#readme
|
|
3
|
-
|
|
4
|
-
## Uncomment and set this to only include directories you want to watch
|
|
5
|
-
# directories %w(app lib config test spec features) \
|
|
6
|
-
# .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
|
7
|
-
|
|
8
|
-
## Note: if you are using the `directories` clause above and you are not
|
|
9
|
-
## watching the project directory ('.'), then you will want to move
|
|
10
|
-
## the Guardfile to a watched dir and symlink it back, e.g.
|
|
11
|
-
#
|
|
12
|
-
# $ mkdir config
|
|
13
|
-
# $ mv Guardfile config/
|
|
14
|
-
# $ ln -s config/Guardfile .
|
|
15
|
-
#
|
|
16
|
-
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
|
17
|
-
|
|
18
|
-
guard :minitest do
|
|
19
|
-
# with Minitest::Unit
|
|
20
|
-
watch(%r{^test/(.*)/?test_(.*)\.rb$})
|
|
21
|
-
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
|
22
|
-
watch(%r{^test/test_helper\.rb$}) { "test" }
|
|
23
|
-
|
|
24
|
-
# with Minitest::Spec
|
|
25
|
-
# watch(%r{^spec/(.*)_spec\.rb$})
|
|
26
|
-
# watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
|
27
|
-
# watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
|
|
28
|
-
|
|
29
|
-
# Rails 4
|
|
30
|
-
# watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
|
|
31
|
-
# watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
|
|
32
|
-
# watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
|
|
33
|
-
# watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
|
|
34
|
-
# watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
|
|
35
|
-
# watch(%r{^test/.+_test\.rb$})
|
|
36
|
-
# watch(%r{^test/test_helper\.rb$}) { 'test' }
|
|
37
|
-
|
|
38
|
-
# Rails < 4
|
|
39
|
-
# watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" }
|
|
40
|
-
# watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" }
|
|
41
|
-
# watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" }
|
|
42
|
-
end
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Forthic
|
|
4
|
-
class CodeLocation
|
|
5
|
-
attr_accessor :screen_name, :line, :column, :start_pos, :end_pos
|
|
6
|
-
|
|
7
|
-
# @param [String] screen_name
|
|
8
|
-
# @param [Integer] line
|
|
9
|
-
# @param [Integer] column
|
|
10
|
-
# @param [Integer] start_pos
|
|
11
|
-
# @param [Integer] end_pos
|
|
12
|
-
def initialize(screen_name: "<ad-hoc>", line: 1, column: 1, start_pos: 0, end_pos: 0)
|
|
13
|
-
@screen_name = screen_name
|
|
14
|
-
@line = line
|
|
15
|
-
@column = column
|
|
16
|
-
@start_pos = start_pos
|
|
17
|
-
@end_pos = end_pos
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Forthic
|
|
4
|
-
class ForthicError < StandardError
|
|
5
|
-
attr_accessor :error_key, :title, :description, :location, :caught_error
|
|
6
|
-
|
|
7
|
-
# @param [String] error_key
|
|
8
|
-
# @param [String] title
|
|
9
|
-
# @param [String] description
|
|
10
|
-
# @param [CodeLocation, nil] location
|
|
11
|
-
def initialize(error_key, title, description, location = nil)
|
|
12
|
-
@error_key = error_key
|
|
13
|
-
@title = title
|
|
14
|
-
@description = description
|
|
15
|
-
@location = location
|
|
16
|
-
@caught_error = nil
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# @param [ForthicError] error
|
|
20
|
-
def set_caught_error(error)
|
|
21
|
-
@caught_error = error
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# @return [String]
|
|
25
|
-
def get_title
|
|
26
|
-
@title
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# @return [String]
|
|
30
|
-
def get_description
|
|
31
|
-
@description
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# @return [Array<ForthicError>]
|
|
35
|
-
def get_error_stack
|
|
36
|
-
max_depth = 100
|
|
37
|
-
cur_error = self
|
|
38
|
-
result = [cur_error]
|
|
39
|
-
|
|
40
|
-
max_depth.times do
|
|
41
|
-
break unless cur_error.caught_error
|
|
42
|
-
|
|
43
|
-
result << cur_error.caught_error
|
|
44
|
-
cur_error = cur_error.caught_error
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
result.reverse
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "set"
|
|
4
|
-
require_relative "words/word"
|
|
5
|
-
require_relative "words/module_word"
|
|
6
|
-
require_relative "words/module_memo_word"
|
|
7
|
-
require_relative "words/module_memo_bang_word"
|
|
8
|
-
require_relative "words/module_memo_bang_at_word"
|
|
9
|
-
require_relative "words/imported_word"
|
|
10
|
-
require_relative "variable"
|
|
11
|
-
|
|
12
|
-
module Forthic
|
|
13
|
-
class ForthicModule
|
|
14
|
-
attr_accessor :words, :exportable, :variables, :modules, :module_prefixes, :required_modules, :name, :forthic_code, :module_id
|
|
15
|
-
|
|
16
|
-
# @param [String] name
|
|
17
|
-
# @param [Interpreter, nil] interp
|
|
18
|
-
# @param [String] forthic_code
|
|
19
|
-
def initialize(name, interp = nil, forthic_code = "")
|
|
20
|
-
@words = []
|
|
21
|
-
@exportable = []
|
|
22
|
-
@variables = {}
|
|
23
|
-
@modules = {}
|
|
24
|
-
@module_prefixes = {}
|
|
25
|
-
@required_modules = []
|
|
26
|
-
@name = name
|
|
27
|
-
@forthic_code = forthic_code
|
|
28
|
-
@module_id = "#{name}-#{rand(1_000_000)}"
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# @return [ForthicModule]
|
|
32
|
-
def dup
|
|
33
|
-
result = ForthicModule.new(@name, @interp, @forthic_code)
|
|
34
|
-
result.words = @words.dup
|
|
35
|
-
result.exportable = @exportable.dup
|
|
36
|
-
@variables.each { |key, var| result.variables[key] = var.dup }
|
|
37
|
-
@modules.each { |key, mod| result.modules[key] = mod }
|
|
38
|
-
result.required_modules = @required_modules.dup
|
|
39
|
-
result.forthic_code = @forthic_code
|
|
40
|
-
result
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# @param [String] prefix
|
|
44
|
-
# @param [ForthicModule] mod
|
|
45
|
-
def require_module(prefix, mod)
|
|
46
|
-
@required_modules << {prefix: prefix, module: mod}
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# @param [String] name
|
|
50
|
-
# @return [ForthicModule, nil]
|
|
51
|
-
def find_module(name)
|
|
52
|
-
@modules[name]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# @param [String] word_name
|
|
56
|
-
# @param [Proc] word_func
|
|
57
|
-
def add_module_word(word_name, word_func)
|
|
58
|
-
add_exportable_word(ModuleWord.new(word_name, word_func))
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# @param [Word] word
|
|
62
|
-
def add_word(word)
|
|
63
|
-
@words << word
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# @param [Word] word
|
|
67
|
-
# @return [ModuleMemoWord]
|
|
68
|
-
def add_memo_words(word)
|
|
69
|
-
memo_word = ModuleMemoWord.new(word)
|
|
70
|
-
@words << memo_word
|
|
71
|
-
@words << ModuleMemoBangWord.new(memo_word)
|
|
72
|
-
@words << ModuleMemoBangAtWord.new(memo_word)
|
|
73
|
-
memo_word
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# @param [Array<String>] names
|
|
77
|
-
def add_exportable(names)
|
|
78
|
-
@exportable.concat(names)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# @return [Array<Word>]
|
|
82
|
-
def exportable_words
|
|
83
|
-
@words.select { |word| @exportable.include?(word.name) }
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# @param [Word] word
|
|
87
|
-
def add_exportable_word(word)
|
|
88
|
-
@words << word
|
|
89
|
-
@exportable << word.name
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# @param [String] name
|
|
93
|
-
# @param [Object, nil] value
|
|
94
|
-
def add_variable(name, value = nil)
|
|
95
|
-
@variables[name] ||= Variable.new(name, value)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# @param [Interpreter] interp
|
|
99
|
-
def initialize_modules(interp)
|
|
100
|
-
@required_modules.each do |rec|
|
|
101
|
-
import_module(rec[:prefix], rec[:module], interp)
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
# @param [String] module_name
|
|
106
|
-
# @param [String] prefix
|
|
107
|
-
# @param [ForthicModule] mod
|
|
108
|
-
def register_module(module_name, prefix, mod)
|
|
109
|
-
@modules[module_name] = mod
|
|
110
|
-
@module_prefixes[module_name] ||= Set.new
|
|
111
|
-
@module_prefixes[module_name] << prefix
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# @param [String] prefix
|
|
115
|
-
# @param [ForthicModule] mod
|
|
116
|
-
# @param [Interpreter] interp
|
|
117
|
-
def import_module(prefix, mod, interp)
|
|
118
|
-
new_module = mod.dup
|
|
119
|
-
new_module.initialize_modules(interp)
|
|
120
|
-
|
|
121
|
-
new_module.exportable_words.each do |word|
|
|
122
|
-
add_word(ImportedWord.new(word, prefix, new_module))
|
|
123
|
-
end
|
|
124
|
-
register_module(mod.name, prefix, new_module)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
# @param [String] name
|
|
128
|
-
# @return [Word, nil]
|
|
129
|
-
def find_word(name)
|
|
130
|
-
find_dictionary_word(name) || find_variable(name)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# @param [String] word_name
|
|
134
|
-
# @return [Word, nil]
|
|
135
|
-
def find_dictionary_word(word_name)
|
|
136
|
-
@words.reverse.find { |w| w.name == word_name }
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# @param [String] varname
|
|
140
|
-
# @return [PushValueWord, nil]
|
|
141
|
-
def find_variable(varname)
|
|
142
|
-
var_result = @variables[varname]
|
|
143
|
-
var_result ? PushValueWord.new(varname, var_result) : nil
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
end
|