toylang 0.2.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.
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ toylang_class = ToyLangClass.new
4
+ toylang_class.runtime_class = toylang_class
5
+ object_class = ToyLangClass.new
6
+ object_class.runtime_class = toylang_class
7
+
8
+ Runtime = Context.new(object_class.new)
9
+
10
+ Runtime['Class'] = toylang_class
11
+ Runtime['Object'] = object_class
12
+ Runtime['Number'] = ToyLangClass.new(Runtime['Object'])
13
+ Runtime['String'] = ToyLangClass.new(Runtime['Object'])
14
+
15
+ Runtime['TrueClass'] = ToyLangClass.new(Runtime['Object'])
16
+ Runtime['FalseClass'] = ToyLangClass.new(Runtime['Object'])
17
+ Runtime['NilClass'] = ToyLangClass.new(Runtime['Object'])
18
+
19
+ Runtime['true'] = Runtime['TrueClass'].new_with_value(true)
20
+ Runtime['false'] = Runtime['FalseClass'].new_with_value(false)
21
+ Runtime['nil'] = Runtime['NilClass'].new_with_value(nil)
22
+
23
+ # Add the `new` method to classes, used to instantiate a class
24
+ Runtime['Class'].runtime_methods['new'] = proc do |receiver, _arguments|
25
+ receiver.new
26
+ end
27
+
28
+ # Print an object to the console.
29
+ Runtime['Object'].runtime_methods['print'] = proc do |receiver, arguments|
30
+ if arguments.size.zero?
31
+ print receiver.ruby_value
32
+ else
33
+ arguments.each do |arg|
34
+ print arg.ruby_value
35
+ end
36
+ end
37
+ Runtime['nil']
38
+ end
39
+
40
+ # Print an object to the console with new line.
41
+ Runtime['Object'].runtime_methods['println'] = proc do |receiver, arguments|
42
+ if arguments.size.zero?
43
+ puts receiver.ruby_value
44
+ else
45
+ puts arguments.map(&:ruby_value)
46
+ end
47
+ Runtime['nil']
48
+ end
49
+
50
+ # Object to string
51
+ Runtime['Object'].runtime_methods['to_string'] = proc do |receiver, _arguments|
52
+ Runtime['String'].new_with_value(receiver.ruby_value.to_s)
53
+ end
54
+
55
+ Runtime['Object'].runtime_methods['inspect'] = proc do |receiver, _arguments|
56
+ Runtime['String'].new_with_value(receiver.ruby_value.inspect)
57
+ end
58
+
59
+ ### Numbers
60
+ # Binary operators
61
+ %w[+ * / % < <= == > >= != & | ^ >> << || &&].each do |operator|
62
+ Runtime['Number'].runtime_methods[operator] = proc do |receiver, arguments|
63
+ result = eval("#{receiver.ruby_value} #{operator} #{arguments.first.ruby_value}") # rubocop:disable Security/Eval, Style/EvalWithLocation
64
+ Runtime['Number'].new_with_value(result)
65
+ end
66
+ end
67
+
68
+ Runtime['Number'].runtime_methods['**'] = proc do |receiver, arguments|
69
+ rec = if receiver.ruby_value.negative? && arguments.first.ruby_value.even?
70
+ receiver.ruby_value.abs
71
+ else
72
+ receiver.ruby_value
73
+ end
74
+ result = rec**arguments.first.ruby_value
75
+ Runtime['Number'].new_with_value(result)
76
+ end
77
+
78
+ # Unary operators
79
+ %w[! ~].each do |operator|
80
+ Runtime['Number'].runtime_methods[operator] = proc do |receiver, _arguments|
81
+ result = eval("#{operator}#{receiver.ruby_value}") # rubocop:disable Security/Eval, Style/EvalWithLocation
82
+ Runtime['Number'].new_with_value(result)
83
+ end
84
+ end
85
+
86
+ Runtime['Number'].runtime_methods['-'] = proc do |receiver, arguments|
87
+ result = if arguments.size.zero?
88
+ -receiver.ruby_value
89
+ else
90
+ receiver.ruby_value - arguments.first.ruby_value
91
+ end
92
+ Runtime['Number'].new_with_value(result)
93
+ end
94
+
95
+ ### Booleans
96
+ boolean_operators = %w[== != && & || | ^]
97
+ %w[TrueClass FalseClass].each do |boolean|
98
+ boolean_operators.each do |operator|
99
+ Runtime[boolean].runtime_methods[operator] = proc do |receiver, arguments|
100
+ result = eval("#{receiver.ruby_value} #{operator} #{arguments.first.ruby_value}") # rubocop:disable Security/Eval, Style/EvalWithLocation
101
+ Runtime[boolean].new_with_value(result)
102
+ end
103
+ end
104
+ Runtime[boolean].runtime_methods['!'] = proc do |receiver, _arguments|
105
+ result = !receiver.ruby_value
106
+ Runtime[boolean].new_with_value(result)
107
+ end
108
+ end
109
+
110
+ ### Strings
111
+ Runtime['String'].runtime_methods['+'] = proc do |receiver, arguments|
112
+ result = receiver.ruby_value + arguments.first.ruby_value
113
+ Runtime['String'].new_with_value(result)
114
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ToyLangClass < ToyLangObject
4
+ attr_reader :runtime_methods
5
+
6
+ def initialize(superclass = nil)
7
+ @runtime_methods = {}
8
+ @runtime_class = Runtime['Class'] if defined?(Runtime)
9
+ @runtime_superclass = superclass
10
+ super(runtime_class)
11
+ end
12
+
13
+ def lookup(method_name)
14
+ method = @runtime_methods[method_name]
15
+ unless method
16
+ return @runtime_superclass.lookup(method_name) if @runtime_superclass
17
+
18
+ raise "Method not found: #{method_name}"
19
+ end
20
+
21
+ method
22
+ end
23
+
24
+ def def(name, &block)
25
+ @runtime_methods[name.to_s] = block
26
+ end
27
+
28
+ def new
29
+ ToyLangObject.new(self)
30
+ end
31
+
32
+ def new_with_value(value)
33
+ ToyLangObject.new(self, value)
34
+ end
35
+
36
+ def inspect
37
+ "#<ToyLangClass class=#{@runtime_class} superclass=#{@runtime_superclass}"
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Context
4
+ attr_reader :locals, :current_self, :current_class
5
+
6
+ def initialize(current_self, current_class = current_self.runtime_class)
7
+ @locals = {}
8
+ @constants = {}
9
+ @current_self = current_self
10
+ @current_class = current_class
11
+ end
12
+
13
+ def [](name)
14
+ @constants[name]
15
+ end
16
+
17
+ def []=(name, value)
18
+ @constants[name] = value
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ToyLangMethod
4
+ def initialize(params, body)
5
+ @params = params
6
+ @body = body
7
+ end
8
+
9
+ def call(receiver, arguments)
10
+ context = Context.new(receiver)
11
+
12
+ @params.each_with_index do |param, index|
13
+ context.locals[param] = arguments[index]
14
+ end
15
+
16
+ @body.eval(context)
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ToyLangObject
4
+ attr_accessor :runtime_class, :ruby_value
5
+
6
+ def initialize(runtime_class, ruby_value = self)
7
+ @runtime_class = runtime_class
8
+ @ruby_value = ruby_value
9
+ end
10
+
11
+ def call(method, arguments = [])
12
+ @runtime_class.lookup(method).call(self, arguments)
13
+ end
14
+
15
+ def inspect
16
+ "#<ToyLangObject class=#{@runtime_class} ruby_value=#{@ruby_value}"
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Toylang
4
+ VERSION = '0.2.0'
5
+ end
data/lib/toylang.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'toylang/version'
4
+ require_relative 'toylang/monkey_patching/string'
5
+ require_relative 'toylang/ast/nodes'
6
+ require_relative 'toylang/lexer/lexer'
7
+ require_relative 'toylang/parser/parser'
8
+ require_relative 'toylang/runtime/object'
9
+ require_relative 'toylang/runtime/class'
10
+ require_relative 'toylang/runtime/method'
11
+ require_relative 'toylang/runtime/context'
12
+ require_relative 'toylang/runtime/bootstrap'
13
+ require_relative 'toylang/interpreter/interpreter'
14
+ require_relative 'toylang/interpreter/evaluation'
15
+
16
+ module Toylang
17
+ class Error < StandardError; end
18
+ # Your code goes here...
19
+ end
data/toylang.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/toylang/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'toylang'
7
+ spec.version = Toylang::VERSION
8
+ spec.authors = ['maxbarsukov']
9
+ spec.email = ['maximbarsukov@bk.ru']
10
+
11
+ spec.summary = ':teddy_bear: Toy OOP Language'
12
+ spec.description = 'Simple Interpreter for Python-like OOP programming language'
13
+ spec.homepage = 'https://rubygems.org/gems/toylang'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = '>= 2.5.0'
16
+
17
+ spec.metadata['homepage_uri'] = spec.homepage
18
+ spec.metadata['source_code_uri'] = 'https://github.com/maxbarsukov/toylang'
19
+ spec.metadata['changelog_uri'] = 'https://github.com/maxbarsukov/toylang/blob/master/CHANGELOG.md'
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ end
27
+ end
28
+ spec.bindir = 'bin'
29
+ spec.executables << 'toylang'
30
+ spec.require_paths = ['lib']
31
+
32
+ # Dependencies
33
+ spec.add_dependency 'racc', '~> 1.6'
34
+
35
+ # Development dependencies
36
+ spec.add_development_dependency 'codecov', '~> 0.6.0'
37
+ spec.add_development_dependency 'rake', '~> 13.0'
38
+ spec.add_development_dependency 'rspec', '~> 3.0'
39
+ spec.add_development_dependency 'rubocop', '~> 1.21'
40
+ spec.add_development_dependency 'rubocop-performance', '~> 1.13'
41
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6.0'
42
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.7'
43
+ spec.add_development_dependency 'simplecov', '~> 0.21.2'
44
+ end
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toylang
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - maxbarsukov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: racc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: codecov
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.6.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.21'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.21'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-performance
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.13'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.13'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.6.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.6.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.7'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.7'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.21.2
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.21.2
139
+ description: Simple Interpreter for Python-like OOP programming language
140
+ email:
141
+ - maximbarsukov@bk.ru
142
+ executables:
143
+ - toylang
144
+ extensions: []
145
+ extra_rdoc_files: []
146
+ files:
147
+ - ".rspec"
148
+ - ".rubocop.yml"
149
+ - CHANGELOG.md
150
+ - CODE_OF_CONDUCT.md
151
+ - Gemfile
152
+ - LICENSE.txt
153
+ - README.md
154
+ - Rakefile
155
+ - bin/toylang
156
+ - lib/toylang.rb
157
+ - lib/toylang/ast/nodes.rb
158
+ - lib/toylang/grammar/grammar.y
159
+ - lib/toylang/interpreter/evaluation.rb
160
+ - lib/toylang/interpreter/interpreter.rb
161
+ - lib/toylang/lexer/lexer.rb
162
+ - lib/toylang/monkey_patching/string.rb
163
+ - lib/toylang/parser/parser.rb
164
+ - lib/toylang/runtime/bootstrap.rb
165
+ - lib/toylang/runtime/class.rb
166
+ - lib/toylang/runtime/context.rb
167
+ - lib/toylang/runtime/method.rb
168
+ - lib/toylang/runtime/object.rb
169
+ - lib/toylang/version.rb
170
+ - toylang.gemspec
171
+ homepage: https://rubygems.org/gems/toylang
172
+ licenses:
173
+ - MIT
174
+ metadata:
175
+ homepage_uri: https://rubygems.org/gems/toylang
176
+ source_code_uri: https://github.com/maxbarsukov/toylang
177
+ changelog_uri: https://github.com/maxbarsukov/toylang/blob/master/CHANGELOG.md
178
+ post_install_message:
179
+ rdoc_options: []
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: 2.5.0
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubygems_version: 3.2.22
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: ":teddy_bear: Toy OOP Language"
197
+ test_files: []