houndstooth 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|