rubocop-boochtek 0.2.0 → 0.2.1
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/.rubocop.yml +115 -5
- data/LICENSE.md +2 -2
- data/README.md +53 -106
- data/lib/disable_ssl_verify.rb +5 -0
- data/lib/extensions/argf.rb +8 -0
- data/lib/extensions/boolean.rb +48 -0
- data/lib/extensions/class.rb +10 -0
- data/lib/extensions/enumerable.rb +42 -0
- data/lib/extensions/integer.rb +7 -0
- data/lib/extensions/llvm_module.rb +101 -0
- data/lib/extensions/module.rb +34 -0
- data/lib/extensions/string.rb +29 -0
- data/lib/stone/ast/block.rb +88 -0
- data/lib/stone/ast/boolean_literal.rb +43 -0
- data/lib/stone/ast/computed_property_definition.rb +32 -0
- data/lib/stone/ast/constant_definition.rb +124 -0
- data/lib/stone/ast/expression.rb +12 -0
- data/lib/stone/ast/function_call.rb +291 -0
- data/lib/stone/ast/function_type_annotation.rb +31 -0
- data/lib/stone/ast/integer_literal.rb +46 -0
- data/lib/stone/ast/lambda.rb +126 -0
- data/lib/stone/ast/null_literal.rb +29 -0
- data/lib/stone/ast/program_unit/top_function.rb +209 -0
- data/lib/stone/ast/program_unit.rb +412 -0
- data/lib/stone/ast/property_access.rb +557 -0
- data/lib/stone/ast/record_definition.rb +180 -0
- data/lib/stone/ast/record_instantiation.rb +141 -0
- data/lib/stone/ast/reference.rb +145 -0
- data/lib/stone/ast/string_literal.rb +79 -0
- data/lib/stone/ast/two_phase_processing.rb +36 -0
- data/lib/stone/ast/type_annotation.rb +26 -0
- data/lib/stone/ast/type_declaration.rb +28 -0
- data/lib/stone/ast/type_of_expression.rb +41 -0
- data/lib/stone/ast/type_reference.rb +28 -0
- data/lib/stone/ast/union_type_annotation.rb +26 -0
- data/lib/stone/ast.rb +64 -0
- data/lib/stone/built_ins.rb +245 -0
- data/lib/stone/error/argument_error.rb +7 -0
- data/lib/stone/error/arity_error.rb +7 -0
- data/lib/stone/error/overflow.rb +18 -0
- data/lib/stone/error/property_error.rb +7 -0
- data/lib/stone/error/reference_error.rb +4 -0
- data/lib/stone/error/type_error.rb +7 -0
- data/lib/stone/error.rb +12 -0
- data/lib/stone/grammar.rb +124 -0
- data/lib/stone/libc.rb +27 -0
- data/lib/stone/prelude.stone +11 -0
- data/lib/stone/rtti.rb +182 -0
- data/lib/stone/scope.rb +85 -0
- data/lib/stone/transform.rb +410 -0
- data/lib/stone/type.rb +323 -0
- data/lib/stone/type_context.rb +38 -0
- data/lib/stone/type_registry.rb +73 -0
- data/lib/stone/types.rb +104 -0
- data/lib/stone.rb +70 -0
- metadata +54 -24
- data/CHANGELOG.md +0 -28
- data/Rakefile +0 -5
- data/config/default.yml +0 -277
- data/lib/rubocop/boochtek/plugin.rb +0 -43
- data/lib/rubocop/boochtek/version.rb +0 -7
- data/lib/rubocop/boochtek.rb +0 -18
- data/lib/rubocop/cop/boochtek/compact_endless_methods.rb +0 -103
- data/lib/rubocop-boochtek.rb +0 -3
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require "stone/ast/expression"
|
|
2
|
+
require "stone/ast/block"
|
|
3
|
+
require "stone/types"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
module Stone
|
|
7
|
+
class AST
|
|
8
|
+
class Lambda < Stone::AST::Expression
|
|
9
|
+
|
|
10
|
+
attr_reader :parameters, :block
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
attr_accessor :lambda_count
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@lambda_count = 0
|
|
17
|
+
|
|
18
|
+
def initialize(parameters, statements)
|
|
19
|
+
@name = :lambda
|
|
20
|
+
@parameters = parameters
|
|
21
|
+
@block = Block.new(statements)
|
|
22
|
+
@lambda_id = next_lambda_id
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_llir(_builder, mod, scope = Stone::Scope.top_level)
|
|
26
|
+
# Check if function already exists (happens if to_llir called multiple times on same lambda).
|
|
27
|
+
mod.functions[function_name] || create_function(mod, function_name, function_type, scope)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_s
|
|
31
|
+
"λ(#{parameters.join(', ')}) { #{block.statements.join("\n")} }"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def type(context = nil)
|
|
35
|
+
return_type = @block.type(context) || Stone::Type::Int
|
|
36
|
+
param_types = parameters.map { Stone::Type::Int }
|
|
37
|
+
Stone::Type.function(param_types:, return_type:)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private def next_lambda_id
|
|
41
|
+
self.class.lambda_count += 1
|
|
42
|
+
self.class.lambda_count
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private def function_type
|
|
46
|
+
# For now, we assume all functions return an i64.
|
|
47
|
+
LLVM::Type.function(param_types, I64)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private def param_types
|
|
51
|
+
# For now, we assume all parameters are i64.
|
|
52
|
+
[I64] * parameters.size
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private def function_name
|
|
56
|
+
"__#{function_prefix}_#{@lambda_id}__"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private def function_prefix
|
|
60
|
+
"lambda"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private def create_function(mod, function_name, function_type, scope)
|
|
64
|
+
mod.functions.add(function_name, function_type).tap do |func|
|
|
65
|
+
name_parameters(func)
|
|
66
|
+
build_function_body(func, mod, scope)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private def name_parameters(func)
|
|
71
|
+
func.params.each_with_index do |param, i|
|
|
72
|
+
param.name = parameters[i]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private def build_function_body(func, mod, scope)
|
|
77
|
+
func.basic_blocks.append("entry").build do |lambda_builder|
|
|
78
|
+
args = argument_storage(func, lambda_builder)
|
|
79
|
+
|
|
80
|
+
# Create child scope with lambda parameters for type resolution
|
|
81
|
+
lambda_scope = scope.child
|
|
82
|
+
bind_parameters_in_scope(lambda_scope)
|
|
83
|
+
|
|
84
|
+
with_parameter_context(mod, args) do
|
|
85
|
+
evaluate_body_and_return(lambda_builder, mod, lambda_scope)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Bind lambda parameters in scope so they can be resolved as types in annotations.
|
|
91
|
+
# The value :type_parameter is a placeholder - only the presence in scope matters
|
|
92
|
+
# for type resolution. Runtime access uses lambda_param_storage instead.
|
|
93
|
+
private def bind_parameters_in_scope(scope)
|
|
94
|
+
@parameters.each do |param|
|
|
95
|
+
scope.define(param, value: :type_parameter)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Store arguments on the stack so they are treated the same as local variables.
|
|
100
|
+
private def argument_storage(func, builder)
|
|
101
|
+
{}.tap do |storage|
|
|
102
|
+
parameters.each_with_index do |param_name, i|
|
|
103
|
+
alloca = builder.alloca(LLVM::Int64.type, param_name)
|
|
104
|
+
builder.store(func.params[i], alloca)
|
|
105
|
+
storage[param_name] = alloca
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Temporarily set module's parameter context so Reference nodes within the block can resolve parameter names.
|
|
111
|
+
private def with_parameter_context(mod, args)
|
|
112
|
+
original = mod.lambda_param_storage
|
|
113
|
+
mod.lambda_param_storage = args
|
|
114
|
+
yield
|
|
115
|
+
ensure
|
|
116
|
+
mod.lambda_param_storage = original
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Lambda parameters use lambda_param_storage (not scope) for stack alloca loading.
|
|
120
|
+
private def evaluate_body_and_return(builder, mod, scope)
|
|
121
|
+
@block.evaluate_body_and_return(builder, mod, scope)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "stone/ast/expression"
|
|
2
|
+
|
|
3
|
+
module Stone
|
|
4
|
+
class AST
|
|
5
|
+
class NullLiteral < Stone::AST::Expression
|
|
6
|
+
|
|
7
|
+
def self.parse(_text, _location)
|
|
8
|
+
new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@name = :null_literal
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_llir(_builder, _mod, _scope = Stone::Scope.top_level)
|
|
16
|
+
LLVM::Type.ptr.null
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
"NULL"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def type(_context = nil)
|
|
24
|
+
Stone::Type::Null
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
require "llvm/core"
|
|
2
|
+
require "stone/libc"
|
|
3
|
+
require "stone/scope"
|
|
4
|
+
require "stone/ast/two_phase_processing"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module Stone
|
|
8
|
+
class AST
|
|
9
|
+
class ProgramUnit < Stone::AST
|
|
10
|
+
class TopFunction
|
|
11
|
+
include TwoPhaseProcessing
|
|
12
|
+
|
|
13
|
+
def initialize(children)
|
|
14
|
+
@children = children
|
|
15
|
+
@mod = nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def generate(mod, scope = Stone::Scope.top_level)
|
|
19
|
+
@mod = mod
|
|
20
|
+
@scope = scope
|
|
21
|
+
register_all_types(mod, scope)
|
|
22
|
+
mod.functions.add("__top__", function_type) { |func| build_function_body(func, mod, scope) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private def register_all_types(mod, scope)
|
|
26
|
+
register_type_declarations(scope)
|
|
27
|
+
register_record_types(mod, scope)
|
|
28
|
+
register_function_types
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private def build_function_body(func, mod, scope)
|
|
32
|
+
func.basic_blocks.append("entry").build do |builder|
|
|
33
|
+
compiled = compile_children(builder, mod, scope)
|
|
34
|
+
build_return(builder, compiled&.last)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private def function_type
|
|
39
|
+
# Return type is determined at compile time based on the last expression
|
|
40
|
+
# - Pointers are returned as-is (CHERI-safe, no ptr2int)
|
|
41
|
+
# - Integers and bools are returned as i64
|
|
42
|
+
LLVM::Type.function([], compute_return_type, varargs: false)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private def compute_return_type
|
|
46
|
+
last_child = other_statements.last
|
|
47
|
+
return LLVM::Int64.type unless last_child
|
|
48
|
+
|
|
49
|
+
# Check if the result will be a pointer
|
|
50
|
+
return LLVM::Type.pointer if returns_pointer?(last_child)
|
|
51
|
+
|
|
52
|
+
LLVM::Int64.type
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private def returns_pointer?(node)
|
|
56
|
+
tagged_union_field_access?(node) ||
|
|
57
|
+
node.is_a?(Stone::AST::StringLiteral) ||
|
|
58
|
+
reference_to_string_constant?(node) ||
|
|
59
|
+
string_returning_property?(node) ||
|
|
60
|
+
returns_pointer_by_type?(node)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private def returns_pointer_by_type?(node)
|
|
64
|
+
stone_type = safe_get_type(node)
|
|
65
|
+
stone_type == Stone::Type::String || stone_type&.record?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private def tagged_union_field_access?(node)
|
|
69
|
+
return false unless node.is_a?(Stone::AST::PropertyAccess)
|
|
70
|
+
return false unless node.respond_to?(:union_field_access?)
|
|
71
|
+
return false unless node.union_field_access?(@mod)
|
|
72
|
+
|
|
73
|
+
union_type = get_union_type_for(node)
|
|
74
|
+
union_type&.needs_runtime_type_tag?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# PropertyAccess patterns that return string pointers
|
|
78
|
+
private def string_returning_property?(node)
|
|
79
|
+
return false unless node.is_a?(Stone::AST::PropertyAccess)
|
|
80
|
+
|
|
81
|
+
property = node.property
|
|
82
|
+
# Type.as_String returns a string pointer
|
|
83
|
+
return true if property == "as_String"
|
|
84
|
+
# FieldList.name returns a string pointer
|
|
85
|
+
return true if property == "name"
|
|
86
|
+
|
|
87
|
+
false
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private def safe_get_type(node)
|
|
91
|
+
node.type(@mod)
|
|
92
|
+
rescue Stone::PropertyError, Stone::TypeError
|
|
93
|
+
# Type couldn't be determined at this stage - default to non-pointer (i64)
|
|
94
|
+
nil
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private def reference_to_string_constant?(node)
|
|
98
|
+
return false unless node.is_a?(Stone::AST::Reference)
|
|
99
|
+
|
|
100
|
+
# Look in children for a constant definition with this name that has a string value
|
|
101
|
+
find_string_constant_value(node.identifier)&.is_a?(Stone::AST::StringLiteral)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private def mixed_union_field_access?(node)
|
|
105
|
+
return false unless node.is_a?(Stone::AST::PropertyAccess)
|
|
106
|
+
return false unless node.respond_to?(:union_field_access?)
|
|
107
|
+
return false unless node.union_field_access?(@mod)
|
|
108
|
+
|
|
109
|
+
union_type = get_union_type_for(node)
|
|
110
|
+
union_type && !union_type.homogeneous?
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private def get_union_type_for(property_access)
|
|
114
|
+
record_type_name = property_access.get_record_type_name(@mod)
|
|
115
|
+
return nil unless record_type_name
|
|
116
|
+
|
|
117
|
+
record_def = @mod.record_types[record_type_name]
|
|
118
|
+
return nil unless record_def
|
|
119
|
+
|
|
120
|
+
annotation = record_def.field_type_annotation(property_access.property)
|
|
121
|
+
return nil unless Stone::AST::FieldHelpers.union_annotation?(annotation)
|
|
122
|
+
|
|
123
|
+
Stone::AST::FieldHelpers.resolve_field_type({type: annotation})
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private def build_return(builder, last_value)
|
|
127
|
+
builder.ret(return_value_for(builder, last_value))
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Convert return value based on target return type.
|
|
131
|
+
# - No ptr2int conversions (CHERI-safe)
|
|
132
|
+
# - Integers/bools return as i64
|
|
133
|
+
# - Pointers return as-is
|
|
134
|
+
private def return_value_for(builder, value)
|
|
135
|
+
return LLVM::Int64.from_i(0) if value.nil?
|
|
136
|
+
return builder.zext(value, LLVM::Int64.type, "bool_to_i64") if value.type.to_s == "i1"
|
|
137
|
+
|
|
138
|
+
# Pointers stay as pointers - no ptr2int
|
|
139
|
+
value
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
private def compile_children(builder, mod, scope)
|
|
143
|
+
# Type declarations already registered in generate()
|
|
144
|
+
compile_statements(builder, mod, scope)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private def compile_statements(builder, mod, scope)
|
|
148
|
+
other_statements.select { |child| child.respond_to?(:to_llir) }.map { |child| child.to_llir(builder, mod, scope) }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private def all_statements
|
|
152
|
+
@all_statements ||= Array(@children).compact
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private def find_string_constant_value(name)
|
|
156
|
+
@children&.find { |c| string_constant_definition?(c) && c.identifier == name }&.value_expression
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private def string_constant_definition?(node)
|
|
160
|
+
node.is_a?(Stone::AST::ConstantDefinition) && node.value_expression.is_a?(Stone::AST::StringLiteral)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private def register_record_types(mod, scope)
|
|
164
|
+
@children&.each do |child|
|
|
165
|
+
next unless child.is_a?(Stone::AST::ConstantDefinition)
|
|
166
|
+
|
|
167
|
+
register_record_type_definition(child, mod, scope)
|
|
168
|
+
register_record_instance_if_needed(child, mod)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
private def register_record_type_definition(child, mod, scope)
|
|
173
|
+
return unless child.value_expression.is_a?(Stone::AST::RecordDefinition)
|
|
174
|
+
|
|
175
|
+
record_def = child.value_expression
|
|
176
|
+
record_def.assigned_name = child.identifier
|
|
177
|
+
mod.register_record_type(child.identifier, record_def)
|
|
178
|
+
register_record_type_in_registry(child.identifier, record_def, mod, scope)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
private def register_record_type_in_registry(name, record_def, mod, scope)
|
|
182
|
+
fields = record_def.fields.map { |f| {name: f[:name], type: f[:type]} }
|
|
183
|
+
type = Stone::Type.record(name:, fields:, llvm_type: record_def.llvm_type(mod, scope))
|
|
184
|
+
Stone::Type::Registry.register(type)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
private def register_record_instance_if_needed(child, mod)
|
|
188
|
+
if child.value_expression.is_a?(Stone::AST::RecordInstantiation)
|
|
189
|
+
record_type_name = child.value_expression.record_type_name
|
|
190
|
+
mod.register_record_instance(child.identifier, record_type_name)
|
|
191
|
+
elsif child.value_expression.is_a?(Stone::AST::FunctionCall) && mod.record_type?(child.value_expression.function_name)
|
|
192
|
+
mod.register_record_instance(child.identifier, child.value_expression.function_name)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
private def register_function_types
|
|
197
|
+
@children&.each do |child|
|
|
198
|
+
next unless child.is_a?(Stone::AST::ConstantDefinition)
|
|
199
|
+
next unless child.value_expression.is_a?(Stone::AST::Lambda)
|
|
200
|
+
|
|
201
|
+
func_type = child.value_expression.type
|
|
202
|
+
Stone::Type::Registry.register_as(child.identifier, func_type)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|