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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +115 -5
  3. data/LICENSE.md +2 -2
  4. data/README.md +53 -106
  5. data/lib/disable_ssl_verify.rb +5 -0
  6. data/lib/extensions/argf.rb +8 -0
  7. data/lib/extensions/boolean.rb +48 -0
  8. data/lib/extensions/class.rb +10 -0
  9. data/lib/extensions/enumerable.rb +42 -0
  10. data/lib/extensions/integer.rb +7 -0
  11. data/lib/extensions/llvm_module.rb +101 -0
  12. data/lib/extensions/module.rb +34 -0
  13. data/lib/extensions/string.rb +29 -0
  14. data/lib/stone/ast/block.rb +88 -0
  15. data/lib/stone/ast/boolean_literal.rb +43 -0
  16. data/lib/stone/ast/computed_property_definition.rb +32 -0
  17. data/lib/stone/ast/constant_definition.rb +124 -0
  18. data/lib/stone/ast/expression.rb +12 -0
  19. data/lib/stone/ast/function_call.rb +291 -0
  20. data/lib/stone/ast/function_type_annotation.rb +31 -0
  21. data/lib/stone/ast/integer_literal.rb +46 -0
  22. data/lib/stone/ast/lambda.rb +126 -0
  23. data/lib/stone/ast/null_literal.rb +29 -0
  24. data/lib/stone/ast/program_unit/top_function.rb +209 -0
  25. data/lib/stone/ast/program_unit.rb +412 -0
  26. data/lib/stone/ast/property_access.rb +557 -0
  27. data/lib/stone/ast/record_definition.rb +180 -0
  28. data/lib/stone/ast/record_instantiation.rb +141 -0
  29. data/lib/stone/ast/reference.rb +145 -0
  30. data/lib/stone/ast/string_literal.rb +79 -0
  31. data/lib/stone/ast/two_phase_processing.rb +36 -0
  32. data/lib/stone/ast/type_annotation.rb +26 -0
  33. data/lib/stone/ast/type_declaration.rb +28 -0
  34. data/lib/stone/ast/type_of_expression.rb +41 -0
  35. data/lib/stone/ast/type_reference.rb +28 -0
  36. data/lib/stone/ast/union_type_annotation.rb +26 -0
  37. data/lib/stone/ast.rb +64 -0
  38. data/lib/stone/built_ins.rb +245 -0
  39. data/lib/stone/error/argument_error.rb +7 -0
  40. data/lib/stone/error/arity_error.rb +7 -0
  41. data/lib/stone/error/overflow.rb +18 -0
  42. data/lib/stone/error/property_error.rb +7 -0
  43. data/lib/stone/error/reference_error.rb +4 -0
  44. data/lib/stone/error/type_error.rb +7 -0
  45. data/lib/stone/error.rb +12 -0
  46. data/lib/stone/grammar.rb +124 -0
  47. data/lib/stone/libc.rb +27 -0
  48. data/lib/stone/prelude.stone +11 -0
  49. data/lib/stone/rtti.rb +182 -0
  50. data/lib/stone/scope.rb +85 -0
  51. data/lib/stone/transform.rb +410 -0
  52. data/lib/stone/type.rb +323 -0
  53. data/lib/stone/type_context.rb +38 -0
  54. data/lib/stone/type_registry.rb +73 -0
  55. data/lib/stone/types.rb +104 -0
  56. data/lib/stone.rb +70 -0
  57. metadata +54 -24
  58. data/CHANGELOG.md +0 -28
  59. data/Rakefile +0 -5
  60. data/config/default.yml +0 -277
  61. data/lib/rubocop/boochtek/plugin.rb +0 -43
  62. data/lib/rubocop/boochtek/version.rb +0 -7
  63. data/lib/rubocop/boochtek.rb +0 -18
  64. data/lib/rubocop/cop/boochtek/compact_endless_methods.rb +0 -103
  65. 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