houndstooth 0.1.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 +7 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +49 -0
- data/README.md +99 -0
- data/bin/houndstooth.rb +183 -0
- data/fuzz/cases/x.rb +8 -0
- data/fuzz/cases/y.rb +8 -0
- data/fuzz/cases/z.rb +22 -0
- data/fuzz/ruby.dict +64 -0
- data/fuzz/run +21 -0
- data/lib/houndstooth/environment/builder.rb +260 -0
- data/lib/houndstooth/environment/type_parser.rb +149 -0
- data/lib/houndstooth/environment/types/basic/type.rb +85 -0
- data/lib/houndstooth/environment/types/basic/type_instance.rb +54 -0
- data/lib/houndstooth/environment/types/compound/union_type.rb +72 -0
- data/lib/houndstooth/environment/types/defined/base_defined_type.rb +23 -0
- data/lib/houndstooth/environment/types/defined/defined_type.rb +137 -0
- data/lib/houndstooth/environment/types/defined/pending_defined_type.rb +14 -0
- data/lib/houndstooth/environment/types/method/method.rb +79 -0
- data/lib/houndstooth/environment/types/method/method_type.rb +144 -0
- data/lib/houndstooth/environment/types/method/parameters.rb +53 -0
- data/lib/houndstooth/environment/types/method/special_constructor_method.rb +15 -0
- data/lib/houndstooth/environment/types/special/instance_type.rb +9 -0
- data/lib/houndstooth/environment/types/special/self_type.rb +9 -0
- data/lib/houndstooth/environment/types/special/type_parameter_placeholder.rb +38 -0
- data/lib/houndstooth/environment/types/special/untyped_type.rb +11 -0
- data/lib/houndstooth/environment/types/special/void_type.rb +12 -0
- data/lib/houndstooth/environment/types.rb +3 -0
- data/lib/houndstooth/environment.rb +74 -0
- data/lib/houndstooth/errors.rb +53 -0
- data/lib/houndstooth/instructions.rb +698 -0
- data/lib/houndstooth/interpreter/const_internal.rb +148 -0
- data/lib/houndstooth/interpreter/objects.rb +142 -0
- data/lib/houndstooth/interpreter/runtime.rb +309 -0
- data/lib/houndstooth/interpreter.rb +7 -0
- data/lib/houndstooth/semantic_node/control_flow.rb +218 -0
- data/lib/houndstooth/semantic_node/definitions.rb +253 -0
- data/lib/houndstooth/semantic_node/identifiers.rb +308 -0
- data/lib/houndstooth/semantic_node/keywords.rb +45 -0
- data/lib/houndstooth/semantic_node/literals.rb +226 -0
- data/lib/houndstooth/semantic_node/operators.rb +126 -0
- data/lib/houndstooth/semantic_node/parameters.rb +108 -0
- data/lib/houndstooth/semantic_node/send.rb +349 -0
- data/lib/houndstooth/semantic_node/super.rb +12 -0
- data/lib/houndstooth/semantic_node.rb +119 -0
- data/lib/houndstooth/stdlib.rb +6 -0
- data/lib/houndstooth/type_checker.rb +462 -0
- data/lib/houndstooth.rb +53 -0
- data/spec/ast_to_node_spec.rb +889 -0
- data/spec/environment_spec.rb +323 -0
- data/spec/instructions_spec.rb +291 -0
- data/spec/integration_spec.rb +785 -0
- data/spec/interpreter_spec.rb +170 -0
- data/spec/self_spec.rb +7 -0
- data/spec/spec_helper.rb +50 -0
- data/test/ruby_interpreter_test.rb +162 -0
- data/types/stdlib.htt +170 -0
- metadata +110 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
RSpec.describe Houndstooth::Interpreter do
|
2
|
+
Iptr = Houndstooth::Interpreter
|
3
|
+
|
4
|
+
def interpret(code, local=nil)
|
5
|
+
env = Houndstooth::Environment.new
|
6
|
+
Houndstooth::Stdlib.add_types(env)
|
7
|
+
|
8
|
+
Houndstooth.process_file('(test)', code, env)
|
9
|
+
|
10
|
+
block = code_to_block(code)
|
11
|
+
runtime = Iptr::Runtime.new(env: env)
|
12
|
+
runtime.execute_block(
|
13
|
+
block,
|
14
|
+
self_type: nil,
|
15
|
+
self_object: nil,
|
16
|
+
lexical_context: Houndstooth::Environment::BaseDefinedType.new,
|
17
|
+
type_arguments: {},
|
18
|
+
)
|
19
|
+
|
20
|
+
if Houndstooth::Errors.errors.any?
|
21
|
+
raise "Errors occurred during interpretation:\n#{Houndstooth::Errors.errors.map(&:format).join("\n")}"
|
22
|
+
end
|
23
|
+
|
24
|
+
if local
|
25
|
+
[env, runtime.variables.find { |var, t| var.ruby_identifier == local }[1]]
|
26
|
+
else
|
27
|
+
[env, runtime]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'can unwrap primitive values' do
|
32
|
+
env = Houndstooth::Environment.new
|
33
|
+
Houndstooth::Stdlib.add_types(env)
|
34
|
+
|
35
|
+
# Unwrap where value given
|
36
|
+
known_int = Iptr::InterpreterObject.new(
|
37
|
+
type: env.resolve_type('Integer'),
|
38
|
+
env: env,
|
39
|
+
primitive_value: [true, 3],
|
40
|
+
)
|
41
|
+
expect(known_int.unwrap_primitive_value).to eq 3
|
42
|
+
|
43
|
+
# Unwrap where value not given (e.g. created with .new)
|
44
|
+
default_int = Iptr::InterpreterObject.new(
|
45
|
+
type: env.resolve_type('Integer'),
|
46
|
+
env: env,
|
47
|
+
)
|
48
|
+
expect(default_int.unwrap_primitive_value).to eq 0
|
49
|
+
|
50
|
+
# Can't unwrap non-primitive
|
51
|
+
expect do
|
52
|
+
Iptr::InterpreterObject.new(
|
53
|
+
type: env.resolve_type('Object'),
|
54
|
+
env: env,
|
55
|
+
).unwrap_primitive_value
|
56
|
+
end.to raise_error(RuntimeError)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'assigns objects truthiness' do
|
60
|
+
env = Houndstooth::Environment.new
|
61
|
+
Houndstooth::Stdlib.add_types(env)
|
62
|
+
|
63
|
+
fals = Iptr::InterpreterObject.new(
|
64
|
+
type: env.resolve_type('FalseClass'),
|
65
|
+
env: env,
|
66
|
+
)
|
67
|
+
expect(fals.truthy?).to eq false
|
68
|
+
|
69
|
+
nl = Iptr::InterpreterObject.new(
|
70
|
+
type: env.resolve_type('NilClass'),
|
71
|
+
env: env,
|
72
|
+
)
|
73
|
+
expect(nl.truthy?).to eq false
|
74
|
+
|
75
|
+
tru = Iptr::InterpreterObject.new(
|
76
|
+
type: env.resolve_type('TrueClass'),
|
77
|
+
env: env,
|
78
|
+
)
|
79
|
+
expect(tru.truthy?).to eq true
|
80
|
+
|
81
|
+
int = Iptr::InterpreterObject.new(
|
82
|
+
type: env.resolve_type('Integer'),
|
83
|
+
env: env,
|
84
|
+
)
|
85
|
+
expect(int.truthy?).to eq true
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'can execute basic literal evaluations' do
|
89
|
+
env, x = interpret('x = 3', 'x')
|
90
|
+
expect(x).to m(Iptr::InterpreterObject,
|
91
|
+
type: env.resolve_type('Integer'),
|
92
|
+
primitive_value: [true, 3]
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'can send to const internal methods' do
|
97
|
+
env, x = interpret('x = 2 + 3', 'x')
|
98
|
+
expect(x).to m(Iptr::InterpreterObject,
|
99
|
+
type: env.resolve_type('Integer'),
|
100
|
+
primitive_value: [true, 5]
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'recurses into definitions' do
|
105
|
+
env, x = interpret('class X; class Y; x = 3; end; end', 'x')
|
106
|
+
expect(x).to m(Iptr::InterpreterObject,
|
107
|
+
type: env.resolve_type('Integer'),
|
108
|
+
primitive_value: [true, 3]
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'can call const methods defined in Ruby' do
|
113
|
+
# No parameters
|
114
|
+
env, x = interpret('
|
115
|
+
module X
|
116
|
+
#: () -> Integer
|
117
|
+
#!const
|
118
|
+
def self.good_enough_pi
|
119
|
+
3
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
x = X.good_enough_pi
|
124
|
+
', 'x')
|
125
|
+
expect(x).to m(Iptr::InterpreterObject,
|
126
|
+
type: env.resolve_type('Integer'),
|
127
|
+
primitive_value: [true, 3]
|
128
|
+
)
|
129
|
+
|
130
|
+
# Parameters
|
131
|
+
env, x = interpret('
|
132
|
+
module X
|
133
|
+
#: (Integer, Integer) -> Integer
|
134
|
+
#!const
|
135
|
+
def self.add_two(x, y)
|
136
|
+
x + y
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
x = X.add_two(2, 3)
|
141
|
+
', 'x')
|
142
|
+
expect(x).to m(Iptr::InterpreterObject,
|
143
|
+
type: env.resolve_type('Integer'),
|
144
|
+
primitive_value: [true, 5]
|
145
|
+
)
|
146
|
+
|
147
|
+
# Working `self`
|
148
|
+
env, x = interpret('
|
149
|
+
module X
|
150
|
+
#: (Integer, Integer, Integer) -> Integer
|
151
|
+
#!const
|
152
|
+
def self.add_three(x, y, z)
|
153
|
+
add_two(add_two(x, y), z)
|
154
|
+
end
|
155
|
+
|
156
|
+
#: (Integer, Integer) -> Integer
|
157
|
+
#!const
|
158
|
+
def self.add_two(x, y)
|
159
|
+
x + y
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
x = X.add_three(1, 2, 3)
|
164
|
+
', 'x')
|
165
|
+
expect(x).to m(Iptr::InterpreterObject,
|
166
|
+
type: env.resolve_type('Integer'),
|
167
|
+
primitive_value: [true, 6]
|
168
|
+
)
|
169
|
+
end
|
170
|
+
end
|
data/spec/self_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start if defined?(RSpec)
|
3
|
+
|
4
|
+
require_relative '../lib/houndstooth'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.expect_with :rspec do |expectations|
|
8
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
9
|
+
end
|
10
|
+
|
11
|
+
config.mock_with :rspec do |mocks|
|
12
|
+
mocks.verify_partial_doubles = true
|
13
|
+
end
|
14
|
+
|
15
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
16
|
+
|
17
|
+
config.before :each do
|
18
|
+
Houndstooth::Errors.reset
|
19
|
+
end
|
20
|
+
|
21
|
+
config.after :each do
|
22
|
+
if Houndstooth::Errors.errors.any?
|
23
|
+
errors = Houndstooth::Errors.errors.map { |e| e.format }.join("\n")
|
24
|
+
raise "Errors occurred during test:\n#{errors}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end if defined?(RSpec)
|
28
|
+
|
29
|
+
def m(type, **attrs)
|
30
|
+
if attrs.length > 0
|
31
|
+
be_a(type) & have_attributes(**attrs)
|
32
|
+
else
|
33
|
+
be_a(type)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def code_to_semantic_node(code)
|
38
|
+
buffer = Parser::Source::Buffer.new("arg")
|
39
|
+
buffer.source = code
|
40
|
+
|
41
|
+
ast_node, comments = Parser::Ruby30.new.parse_with_comments(buffer)
|
42
|
+
$comments = comments
|
43
|
+
Houndstooth::SemanticNode.from_ast(ast_node)
|
44
|
+
end
|
45
|
+
|
46
|
+
def code_to_block(code)
|
47
|
+
block = I::InstructionBlock.new(has_scope: true, parent: nil)
|
48
|
+
code_to_semantic_node(code).to_instructions(block)
|
49
|
+
block
|
50
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require_relative '../lib/houndstooth'
|
2
|
+
require_relative '../spec/spec_helper' # contains code_to_X methods
|
3
|
+
|
4
|
+
def run(command)
|
5
|
+
out = `#{command}`
|
6
|
+
abort "command failed: #{command}" unless $?.success?
|
7
|
+
out
|
8
|
+
end
|
9
|
+
|
10
|
+
# Perform a sparse checkout of the Ruby repository to grab bootstraptest
|
11
|
+
ruby_dir = File.join(__dir__, "ruby")
|
12
|
+
if Dir.exist?(ruby_dir)
|
13
|
+
puts "Ruby directory already exists, skipping checkout"
|
14
|
+
else
|
15
|
+
puts "Sparse-checking out Ruby..."
|
16
|
+
Dir.mkdir(ruby_dir)
|
17
|
+
Dir.chdir(ruby_dir) do
|
18
|
+
run("git init")
|
19
|
+
run("git remote add -f origin https://github.com/ruby/ruby.git")
|
20
|
+
run("git config core.sparseCheckout true")
|
21
|
+
File.write(File.join(ruby_dir, ".git", "info", "sparse-checkout"), "bootstraptest/")
|
22
|
+
run("git pull origin master")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
I = Houndstooth::Instructions
|
27
|
+
|
28
|
+
# Required for Houndstooth.process_file, which expects to be run from the binary
|
29
|
+
def abort_on_error!
|
30
|
+
if Houndstooth::Errors.errors.any?
|
31
|
+
raise "Errors occurred during interpretation:\n#{Houndstooth::Errors.errors.map(&:format).join("\n")}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def interpreter_execute(code)
|
36
|
+
# Create environment
|
37
|
+
env = Houndstooth::Environment.new
|
38
|
+
Houndstooth::Stdlib.add_types(env)
|
39
|
+
|
40
|
+
# Process input
|
41
|
+
Houndstooth.process_file('(test)', code, env)
|
42
|
+
|
43
|
+
# Process and evaluate input
|
44
|
+
block = code_to_block(code)
|
45
|
+
runtime = Houndstooth::Interpreter::Runtime.new(env: env)
|
46
|
+
runtime.execute_block(
|
47
|
+
block,
|
48
|
+
self_type: nil,
|
49
|
+
self_object: nil,
|
50
|
+
lexical_context: Houndstooth::Environment::BaseDefinedType.new,
|
51
|
+
type_arguments: {},
|
52
|
+
)
|
53
|
+
|
54
|
+
# If an error occurred, throw
|
55
|
+
abort_on_error!
|
56
|
+
|
57
|
+
# Get return value
|
58
|
+
runtime.variables[block.instructions.last.result]
|
59
|
+
end
|
60
|
+
|
61
|
+
$bootstrap_test_passes = Hash.new { |h, k| h[k] = [] }
|
62
|
+
$bootstrap_test_failures = Hash.new { |h, k| h[k] = [] }
|
63
|
+
$bootstrap_test_crashes = Hash.new { |h, k| h[k] = [] }
|
64
|
+
$bootstrap_test_unimplemented = Hash.new { |h, k| h[k] = [] }
|
65
|
+
|
66
|
+
module BootstrapTestHarness
|
67
|
+
def self.clear_errors
|
68
|
+
Houndstooth::Errors.errors.clear
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.target_platform
|
72
|
+
""
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.assert_equal(expected_result, code, *_)
|
76
|
+
clear_errors
|
77
|
+
|
78
|
+
actual_result = interpreter_execute(code)
|
79
|
+
if actual_result.ruby_inspect == expected_result
|
80
|
+
$bootstrap_test_passes[$bootstrap_test_current_file] << [expected_result, code]
|
81
|
+
else
|
82
|
+
$bootstrap_test_failures[$bootstrap_test_current_file] << [expected_result, actual_result.ruby_inspect, code]
|
83
|
+
end
|
84
|
+
rescue => e
|
85
|
+
$bootstrap_test_crashes[$bootstrap_test_current_file] << [expected_result, code]
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.assert_match(matcher, code, *_)
|
89
|
+
clear_errors
|
90
|
+
|
91
|
+
actual_result = interpreter_execute(code)
|
92
|
+
if matcher === actual_result.ruby_inspect
|
93
|
+
$bootstrap_test_passes[$bootstrap_test_current_file] << [matcher, code]
|
94
|
+
else
|
95
|
+
$bootstrap_test_failures[$bootstrap_test_current_file] << [matcher, actual_result, code]
|
96
|
+
end
|
97
|
+
rescue
|
98
|
+
$bootstrap_test_crashes[$bootstrap_test_current_file] << [matcher, code]
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.assert_not_match(matcher, code, *_)
|
102
|
+
clear_errors
|
103
|
+
|
104
|
+
actual_result = interpreter_execute(code)
|
105
|
+
if !(matcher === actual_result.ruby_inspect)
|
106
|
+
$bootstrap_test_passes[$bootstrap_test_current_file] << [matcher, code]
|
107
|
+
else
|
108
|
+
$bootstrap_test_failures[$bootstrap_test_current_file] << [matcher, actual_result, code]
|
109
|
+
end
|
110
|
+
rescue
|
111
|
+
$bootstrap_test_crashes[$bootstrap_test_current_file] << [matcher, code]
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.assert_normal_exit(code, message="(normal exit)", *_)
|
115
|
+
clear_errors
|
116
|
+
interpreter_execute(code)
|
117
|
+
rescue
|
118
|
+
$bootstrap_test_crashes[$bootstrap_test_current_file] << [message, code]
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.assert_valid_syntax(code, *_)
|
122
|
+
clear_errors
|
123
|
+
assert_normal_exit(code, "(valid syntax)")
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.assert_finish(code, *_)
|
127
|
+
clear_errors
|
128
|
+
assert_normal_exit(code, "(finish)")
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.method_missing(*a)
|
132
|
+
$bootstrap_test_unimplemented[$bootstrap_test_current_file] << a
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
files = Dir[File.join(ruby_dir, "bootstraptest", "test_*.rb")]
|
137
|
+
files.each do |file|
|
138
|
+
puts file
|
139
|
+
test = File.read(file)
|
140
|
+
$bootstrap_test_current_file = file
|
141
|
+
BootstrapTestHarness.instance_eval(test, file)
|
142
|
+
end
|
143
|
+
|
144
|
+
puts
|
145
|
+
puts "== RESULTS =="
|
146
|
+
puts
|
147
|
+
files.each do |file|
|
148
|
+
print File.split(file)[1]
|
149
|
+
print ": "
|
150
|
+
print "#{$bootstrap_test_passes[file].length} passed, "
|
151
|
+
print "#{$bootstrap_test_failures[file].length} failed, "
|
152
|
+
print "#{$bootstrap_test_crashes[file].length} crashed, "
|
153
|
+
print "#{$bootstrap_test_unimplemented[file].length} unimplemented"
|
154
|
+
puts
|
155
|
+
end
|
156
|
+
|
157
|
+
puts
|
158
|
+
puts "== TOTALS =="
|
159
|
+
puts "Passes: #{$bootstrap_test_passes.values.map(&:length).sum}"
|
160
|
+
puts "Failures: #{$bootstrap_test_failures.values.map(&:length).sum}"
|
161
|
+
puts "Crashes: #{$bootstrap_test_crashes.values.map(&:length).sum}"
|
162
|
+
puts "Unimplemented tests: #{$bootstrap_test_unimplemented.values.map(&:length).sum}"
|
data/types/stdlib.htt
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# Useful reference:
|
2
|
+
# https://tiagodev.wordpress.com/2013/04/16/eigenclasses-for-lunch-the-ruby-object-model/
|
3
|
+
|
4
|
+
#!magic basicobject
|
5
|
+
class BasicObject
|
6
|
+
#: () -> void
|
7
|
+
def initialize; end
|
8
|
+
|
9
|
+
#: (Class) -> Boolean
|
10
|
+
def is_a?(_); end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Class < Module
|
14
|
+
#: () -> Class
|
15
|
+
def superclass; end
|
16
|
+
|
17
|
+
#: () -> void
|
18
|
+
def initialize; end
|
19
|
+
|
20
|
+
#: () -> Object
|
21
|
+
# Special case of `new` being defined as a method rather than magically - this only affects the
|
22
|
+
# rather rare usage `Class.new.new`, not anything else e.g. `Object.new`
|
23
|
+
def new; end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Object < BasicObject
|
27
|
+
#: () -> String
|
28
|
+
def inspect; end
|
29
|
+
|
30
|
+
#: (Object) -> Boolean
|
31
|
+
def ==(other); end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Module
|
35
|
+
#: () -> Array[Module]
|
36
|
+
def nesting; end
|
37
|
+
|
38
|
+
# The RBS syntax doesn't support any nicer way of doing this :(
|
39
|
+
#: [ R] (Symbol) { () -> R } -> Symbol
|
40
|
+
#: [A1, R] (Symbol) { (A1) -> R } -> Symbol
|
41
|
+
#: [A1, A2, R] (Symbol) { (A1, A2) -> R } -> Symbol
|
42
|
+
#: [A1, A2, A3, R] (Symbol) { (A1, A2, A3) -> R } -> Symbol
|
43
|
+
#: [A1, A2, A3, A4, R] (Symbol) { (A1, A2, A3, A4) -> R } -> Symbol
|
44
|
+
#: [A1, A2, A3, A4, A5, R] (Symbol) { (A1, A2, A3, A4, A5) -> R } -> Symbol
|
45
|
+
#: [A1, A2, A3, A4, A5, A6, R] (Symbol) { (A1, A2, A3, A4, A5, A6) -> R } -> Symbol
|
46
|
+
#: [A1, A2, A3, A4, A5, A6, A7, R] (Symbol) { (A1, A2, A3, A4, A5, A6, A7) -> R } -> Symbol
|
47
|
+
#: [A1, A2, A3, A4, A5, A6, A7, A8, R] (Symbol) { (A1, A2, A3, A4, A5, A6, A7, A8) -> R } -> Symbol
|
48
|
+
#: [A1, A2, A3, A4, A5, A6, A7, A8, A9, R] (Symbol) { (A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R } -> Symbol
|
49
|
+
#: [A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R] (Symbol) { (A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R } -> Symbol
|
50
|
+
#!const required_internal
|
51
|
+
def define_method(name, *); end
|
52
|
+
|
53
|
+
#: [T] (Symbol) -> void
|
54
|
+
#!const required_internal
|
55
|
+
def attr_reader(name); end
|
56
|
+
|
57
|
+
#: [T] (Symbol) -> void
|
58
|
+
#!const required_internal
|
59
|
+
def attr_writer(name); end
|
60
|
+
|
61
|
+
# TODO: Method visibility setters are only supported in their argument-taking form
|
62
|
+
|
63
|
+
#: (Symbol) -> void
|
64
|
+
#!const required_internal
|
65
|
+
def private(name); end
|
66
|
+
|
67
|
+
#: (Symbol) -> void
|
68
|
+
#!const required_internal
|
69
|
+
def protected(name); end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Numeric
|
73
|
+
#: (Numeric) -> Numeric
|
74
|
+
#!const internal
|
75
|
+
def +(other); end
|
76
|
+
|
77
|
+
#: (Numeric) -> Boolean
|
78
|
+
def >(other); end
|
79
|
+
|
80
|
+
#: (Numeric) -> Boolean
|
81
|
+
def >=(other); end
|
82
|
+
|
83
|
+
#: (Numeric) -> Boolean
|
84
|
+
def <(other); end
|
85
|
+
|
86
|
+
#: (Numeric) -> Boolean
|
87
|
+
def <=(other); end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Integer < Numeric
|
91
|
+
#: (Integer) -> Integer
|
92
|
+
#: (Float) -> Float
|
93
|
+
#!const internal
|
94
|
+
def +(other); end
|
95
|
+
|
96
|
+
#: () { (Integer) -> void } -> Integer
|
97
|
+
#!const internal
|
98
|
+
def times; end
|
99
|
+
|
100
|
+
#: () -> Integer
|
101
|
+
def abs; end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Float < Numeric
|
105
|
+
#: (Integer) -> Float
|
106
|
+
#: (Float) -> Float
|
107
|
+
#!const internal
|
108
|
+
def +(other); end
|
109
|
+
|
110
|
+
#: () -> Float
|
111
|
+
def abs; end
|
112
|
+
end
|
113
|
+
|
114
|
+
class String
|
115
|
+
#: (String) -> String
|
116
|
+
#!const internal
|
117
|
+
def +(other); end
|
118
|
+
|
119
|
+
#: () -> Integer
|
120
|
+
def length; end
|
121
|
+
|
122
|
+
#: () -> Symbol
|
123
|
+
#!const internal
|
124
|
+
def to_sym; end
|
125
|
+
end
|
126
|
+
|
127
|
+
class Symbol; end
|
128
|
+
|
129
|
+
#!param T
|
130
|
+
class Array
|
131
|
+
#: () -> void
|
132
|
+
#!const internal
|
133
|
+
def initialize; end
|
134
|
+
|
135
|
+
#: (T) -> Array[T]
|
136
|
+
#!const internal
|
137
|
+
def <<(item); end
|
138
|
+
|
139
|
+
# TODO: should be nilable
|
140
|
+
#: (Integer) -> T
|
141
|
+
def [](index); end
|
142
|
+
|
143
|
+
#: () -> Integer
|
144
|
+
def length; end
|
145
|
+
|
146
|
+
#: () { (T) -> void } -> Array[T]
|
147
|
+
#!const internal
|
148
|
+
def each; end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Doesn't actually exist, but we need some kind of boolean type
|
152
|
+
class Boolean; end
|
153
|
+
class TrueClass < Boolean; end
|
154
|
+
class FalseClass < Boolean; end
|
155
|
+
|
156
|
+
class NilClass; end
|
157
|
+
|
158
|
+
class Kernel
|
159
|
+
#: (?Float) -> Float
|
160
|
+
#: (Integer) -> Integer
|
161
|
+
def self.rand(max=nil); end
|
162
|
+
|
163
|
+
#!const internal
|
164
|
+
#: (?untyped) -> void
|
165
|
+
def self.puts(message=nil); end
|
166
|
+
|
167
|
+
#!const internal
|
168
|
+
#: (?untyped) -> void
|
169
|
+
def self.print(message=nil); end
|
170
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: houndstooth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Christiansen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-04-28 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- aaronc20000@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".gitignore"
|
21
|
+
- ".rspec"
|
22
|
+
- ".ruby-version"
|
23
|
+
- Gemfile
|
24
|
+
- Gemfile.lock
|
25
|
+
- README.md
|
26
|
+
- bin/houndstooth.rb
|
27
|
+
- fuzz/cases/x.rb
|
28
|
+
- fuzz/cases/y.rb
|
29
|
+
- fuzz/cases/z.rb
|
30
|
+
- fuzz/ruby.dict
|
31
|
+
- fuzz/run
|
32
|
+
- lib/houndstooth.rb
|
33
|
+
- lib/houndstooth/environment.rb
|
34
|
+
- lib/houndstooth/environment/builder.rb
|
35
|
+
- lib/houndstooth/environment/type_parser.rb
|
36
|
+
- lib/houndstooth/environment/types.rb
|
37
|
+
- lib/houndstooth/environment/types/basic/type.rb
|
38
|
+
- lib/houndstooth/environment/types/basic/type_instance.rb
|
39
|
+
- lib/houndstooth/environment/types/compound/union_type.rb
|
40
|
+
- lib/houndstooth/environment/types/defined/base_defined_type.rb
|
41
|
+
- lib/houndstooth/environment/types/defined/defined_type.rb
|
42
|
+
- lib/houndstooth/environment/types/defined/pending_defined_type.rb
|
43
|
+
- lib/houndstooth/environment/types/method/method.rb
|
44
|
+
- lib/houndstooth/environment/types/method/method_type.rb
|
45
|
+
- lib/houndstooth/environment/types/method/parameters.rb
|
46
|
+
- lib/houndstooth/environment/types/method/special_constructor_method.rb
|
47
|
+
- lib/houndstooth/environment/types/special/instance_type.rb
|
48
|
+
- lib/houndstooth/environment/types/special/self_type.rb
|
49
|
+
- lib/houndstooth/environment/types/special/type_parameter_placeholder.rb
|
50
|
+
- lib/houndstooth/environment/types/special/untyped_type.rb
|
51
|
+
- lib/houndstooth/environment/types/special/void_type.rb
|
52
|
+
- lib/houndstooth/errors.rb
|
53
|
+
- lib/houndstooth/instructions.rb
|
54
|
+
- lib/houndstooth/interpreter.rb
|
55
|
+
- lib/houndstooth/interpreter/const_internal.rb
|
56
|
+
- lib/houndstooth/interpreter/objects.rb
|
57
|
+
- lib/houndstooth/interpreter/runtime.rb
|
58
|
+
- lib/houndstooth/semantic_node.rb
|
59
|
+
- lib/houndstooth/semantic_node/control_flow.rb
|
60
|
+
- lib/houndstooth/semantic_node/definitions.rb
|
61
|
+
- lib/houndstooth/semantic_node/identifiers.rb
|
62
|
+
- lib/houndstooth/semantic_node/keywords.rb
|
63
|
+
- lib/houndstooth/semantic_node/literals.rb
|
64
|
+
- lib/houndstooth/semantic_node/operators.rb
|
65
|
+
- lib/houndstooth/semantic_node/parameters.rb
|
66
|
+
- lib/houndstooth/semantic_node/send.rb
|
67
|
+
- lib/houndstooth/semantic_node/super.rb
|
68
|
+
- lib/houndstooth/stdlib.rb
|
69
|
+
- lib/houndstooth/type_checker.rb
|
70
|
+
- spec/ast_to_node_spec.rb
|
71
|
+
- spec/environment_spec.rb
|
72
|
+
- spec/instructions_spec.rb
|
73
|
+
- spec/integration_spec.rb
|
74
|
+
- spec/interpreter_spec.rb
|
75
|
+
- spec/self_spec.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- test/ruby_interpreter_test.rb
|
78
|
+
- types/stdlib.htt
|
79
|
+
homepage: https://github.com/AaronC81/houndstooth
|
80
|
+
licenses:
|
81
|
+
- MIT
|
82
|
+
metadata: {}
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubygems_version: 3.2.22
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: Experimental type checker
|
102
|
+
test_files:
|
103
|
+
- spec/ast_to_node_spec.rb
|
104
|
+
- spec/environment_spec.rb
|
105
|
+
- spec/instructions_spec.rb
|
106
|
+
- spec/integration_spec.rb
|
107
|
+
- spec/interpreter_spec.rb
|
108
|
+
- spec/self_spec.rb
|
109
|
+
- spec/spec_helper.rb
|
110
|
+
- test/ruby_interpreter_test.rb
|