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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3db02cc1d2130d7a3e39ddf0ab20bebceba68a3b59d292db8993c630d6d6727d
|
|
4
|
+
data.tar.gz: 9b7e264f064f8060b5de691c575e474fe422a44ba320040ead510dba586c403f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '09cbd0212c65603d868df7bcde0fb7bb20b08c2bd8cca67c263a9fb5a58aca5a2dfe88f394afae2bf4aa6b7bd24efe5832270bd7dde5b159b334118102deb926'
|
|
7
|
+
data.tar.gz: 54b39ca84f94c52cf0b617269ba6d073450a8863ef8ddcd52bcb63ae075ee483fea9e41efd795746cd461c798f53b51c7d1887188cdb1abb0d497f3979104539
|
data/.rubocop.yml
CHANGED
|
@@ -1,8 +1,118 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
- config/default.yml
|
|
2
|
+
plugins:
|
|
3
|
+
- rubocop-boochtek
|
|
5
4
|
|
|
5
|
+
# Ignore some files. NOTE: Exclude does not add to any existing Exclude directives.
|
|
6
6
|
AllCops:
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Exclude:
|
|
8
|
+
- "church*.rb"
|
|
9
|
+
- "vendor/**/*"
|
|
10
|
+
- "**/*.stone"
|
|
11
|
+
NewCops: disable
|
|
12
|
+
|
|
13
|
+
# Allow longer lines.
|
|
14
|
+
Layout/LineLength:
|
|
15
|
+
Max: 160
|
|
16
|
+
|
|
17
|
+
# Use `{}` for blocks that return a value; otherwise use `do` and `end`.
|
|
18
|
+
# We make a few exceptions, mostly for RSpec. And for grammar and transform rules.
|
|
19
|
+
Style/BlockDelimiters:
|
|
20
|
+
EnforcedStyle: semantic
|
|
21
|
+
FunctionalMethods:
|
|
22
|
+
- expect
|
|
23
|
+
AllowedMethods:
|
|
24
|
+
- let
|
|
25
|
+
- let!
|
|
26
|
+
- subject
|
|
27
|
+
- rule
|
|
28
|
+
- rule!
|
|
29
|
+
- terminal
|
|
30
|
+
- terminal!
|
|
31
|
+
|
|
32
|
+
# Allow non-ASCII identifiers, and in comments.
|
|
33
|
+
Naming/AsciiIdentifiers:
|
|
34
|
+
Enabled: false
|
|
35
|
+
|
|
36
|
+
# Some of our classes are going to be long.
|
|
37
|
+
Metrics/ClassLength:
|
|
38
|
+
Max: 250
|
|
39
|
+
Exclude:
|
|
40
|
+
- lib/stone/transform.rb
|
|
41
|
+
- lib/stone/ast/property_access.rb
|
|
42
|
+
|
|
43
|
+
# Sometimes we need to pass a block down recursively, so allow expressing that.
|
|
44
|
+
Performance/RedundantBlockCall:
|
|
45
|
+
Enabled: false
|
|
46
|
+
|
|
47
|
+
Naming/FileName:
|
|
48
|
+
Exclude:
|
|
49
|
+
- lib/stone/type/*
|
|
50
|
+
|
|
51
|
+
# Not sure why `∧` and `∨` are problematic, even after allowing non-ASCII identifiers.
|
|
52
|
+
# Also allow `builtin_ClassName` methods.
|
|
53
|
+
Naming/MethodName:
|
|
54
|
+
Exclude:
|
|
55
|
+
- lib/extensions/boolean.rb
|
|
56
|
+
- lib/stone/top.rb
|
|
57
|
+
AllowedPatterns:
|
|
58
|
+
- as_String
|
|
59
|
+
|
|
60
|
+
# Allow numbered variables in record field comparisons (field1_0, field2_0).
|
|
61
|
+
Naming/VariableNumber:
|
|
62
|
+
Exclude:
|
|
63
|
+
- lib/stone/ast/function_call.rb
|
|
64
|
+
|
|
65
|
+
# I don't believe `module_function` should be outdented like `private`, but there's no way to turn it off for just `module_function`.
|
|
66
|
+
Layout/AccessModifierIndentation:
|
|
67
|
+
EnforcedStyle: outdent
|
|
68
|
+
Exclude:
|
|
69
|
+
- lib/stone/top.rb
|
|
70
|
+
|
|
71
|
+
# Allow `expr = expr + x` in this particular file, to parallel `expr = x + expr` that's right next to it.
|
|
72
|
+
Style/SelfAssignment:
|
|
73
|
+
Exclude:
|
|
74
|
+
- lib/stone/ast/binary_operation.rb
|
|
75
|
+
|
|
76
|
+
# The `grammar` and `transforms` methods are DSLs; don't worry about their size/complexity.
|
|
77
|
+
Metrics/AbcSize:
|
|
78
|
+
AllowedMethods:
|
|
79
|
+
- grammar
|
|
80
|
+
- transforms
|
|
81
|
+
Metrics/MethodLength:
|
|
82
|
+
AllowedMethods:
|
|
83
|
+
- grammar
|
|
84
|
+
- transforms
|
|
85
|
+
Metrics/PerceivedComplexity:
|
|
86
|
+
AllowedMethods:
|
|
87
|
+
- grammar
|
|
88
|
+
- transforms
|
|
89
|
+
Metrics/CyclomaticComplexity:
|
|
90
|
+
AllowedMethods:
|
|
91
|
+
- grammar
|
|
92
|
+
- transforms
|
|
93
|
+
|
|
94
|
+
Style/PercentLiteralDelimiters:
|
|
95
|
+
Exclude:
|
|
96
|
+
- "lib/stone/ast/binary_operation.rb"
|
|
97
|
+
|
|
98
|
+
# Be a bit more lenient with RSpec: don't require filename to match class; allow more than 1 expectation per example.
|
|
99
|
+
RSpec/SpecFilePathFormat:
|
|
100
|
+
Enabled: false
|
|
101
|
+
RSpec/DescribedClass:
|
|
102
|
+
Enabled: false
|
|
103
|
+
RSpec/DescribeClass:
|
|
104
|
+
Enabled: false
|
|
105
|
+
|
|
106
|
+
# RuboCop doesn't like the way we use the `parse_as` custom matcher.
|
|
107
|
+
RSpec/ExpectActual:
|
|
108
|
+
Exclude:
|
|
109
|
+
- "spec/unit/parser/**/**.rb"
|
|
110
|
+
|
|
111
|
+
# I like to put 2 spaces before inline comments.
|
|
112
|
+
Layout/ExtraSpacing:
|
|
113
|
+
Enabled: false
|
|
114
|
+
|
|
115
|
+
# Allow use of a single `module_function` instead of prepending it to every method.
|
|
116
|
+
# Unfortunately, we can't turn this off only for `module_function`.
|
|
117
|
+
Style/AccessModifierDeclarations:
|
|
118
|
+
Enabled: false
|
data/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
MIT License
|
|
1
|
+
# MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2018-2025 Craig Buchek
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
|
@@ -1,130 +1,77 @@
|
|
|
1
|
-
#
|
|
1
|
+
# The Stone Programming Language
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Stone is a multi-paradigm programming language. It combines the ideas of object-oriented,
|
|
4
|
+
functional, and actor-based languages. It is a typed language, with immutability by default.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
This is a *very* new language, but I've been thinking about the design of the language for
|
|
7
|
+
quite some time. The design documents can be found in [/docs/design](docs/design/README.md).
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
## Goals
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
group :development, :test do
|
|
11
|
-
gem "rubocop-boochtek", github: "boochtek/rubocop-boochtek"
|
|
12
|
-
end
|
|
13
|
-
```
|
|
11
|
+
I have several goals that I keep in mind when designing and implementing Stone. My top-level goals are:
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
- Have fun learning and creating
|
|
14
|
+
- See if I can make something useful
|
|
15
|
+
- Correctness
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
gem install rubocop-boochtek
|
|
19
|
-
```
|
|
17
|
+
For more details, see the [Goals](docs/design/Goals.md) in the design documents.
|
|
20
18
|
|
|
21
|
-
##
|
|
19
|
+
## Specifications
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
The language is described in Markdown, with code blocks showing example code.
|
|
22
|
+
The code blocks also show the expected result of evaluating the code.
|
|
23
|
+
This is also used as the language specification —
|
|
24
|
+
all the example code is checked to ensure that it evaluates to the expected result.
|
|
25
|
+
These can be found in [docs/specs](docs/specs/README.md).
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
plugins:
|
|
27
|
-
- rubocop-boochtek
|
|
28
|
-
```
|
|
27
|
+
## Building
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
We're using standard `make` to build the system.
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
Currently, we're using Ruby for all pieces of Stone, so you won't need to actually run a build step to get a `stone` binary.
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
You can verify that the specs are all passing:
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
~~~ shell
|
|
36
|
+
make verify-specs
|
|
37
|
+
~~~
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
Max: 160
|
|
39
|
+
## Running
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
NewCops: enable
|
|
45
|
-
```
|
|
41
|
+
Binaries are located in the bin directory:
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
- `stone`
|
|
44
|
+
- `stone parse` - Output parse tree
|
|
45
|
+
- `stone ast` - Output AST (abstract syntax tree)
|
|
46
|
+
- `stone mlir` - Output MLIR (multi-level intermediate representation)
|
|
47
|
+
- `stone llir` - Output LLIR (low-level intermediate representation)
|
|
48
|
+
- `stone compile` - Compile to an executable
|
|
49
|
+
- `stone run` - Compile to an executable and run it
|
|
50
|
+
- `stone eval` - Output the result of each top-level expression (non-interactive REPL)
|
|
51
|
+
- `stone verify` - Verify that results of top-level expressions match expectations in comments
|
|
52
|
+
- `stone repl` - Accept interactive manual input, and show the result of each top-level expression (default if no arguments are given)
|
|
53
|
+
- `stone specs` - Run tests/specs
|
|
54
|
+
- `stone build` - Compile an entire project
|
|
55
|
+
- `stone lint` - Check Stone code for issues
|
|
56
|
+
- `stone format` - Format Stone code
|
|
57
|
+
- `stone lsp` - Start the Language Server Protocol service
|
|
58
|
+
- `stone publish` - Publish to package repository
|
|
59
|
+
- `stone deps` - Manage project dependencies (package manager)
|
|
48
60
|
|
|
49
|
-
|
|
61
|
+
Note that most of these commands are still under development — or development has not even started on them yet.
|
|
50
62
|
|
|
51
|
-
|
|
63
|
+
## Changelog
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
# Good
|
|
55
|
-
private def my_method
|
|
56
|
-
# ...
|
|
57
|
-
end
|
|
65
|
+
See the [CHANGELOG](CHANGELOG.md) file for information about what changes have been made in each release.
|
|
58
66
|
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
|
|
62
|
-
def my_method
|
|
63
|
-
# ...
|
|
64
|
-
end
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
This makes it easier to see at a glance which methods are private, and makes moving methods around simpler.
|
|
68
|
-
|
|
69
|
-
### Semantic Block Delimiters
|
|
70
|
-
|
|
71
|
-
Use `{}` for blocks that return a value; use `do`/`end` otherwise:
|
|
72
|
-
|
|
73
|
-
```ruby
|
|
74
|
-
# Good - returns a value
|
|
75
|
-
names = users.map { |u| u.name }
|
|
76
|
-
|
|
77
|
-
# Good - side effects only
|
|
78
|
-
users.each do |user|
|
|
79
|
-
send_email(user)
|
|
80
|
-
end
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Double Quotes
|
|
84
|
-
|
|
85
|
-
We use double quotes by default for strings, as they require fewer changes when you later need interpolation.
|
|
86
|
-
|
|
87
|
-
### Other Notable Preferences
|
|
88
|
-
|
|
89
|
-
- Line length: 120 characters
|
|
90
|
-
- No frozen string literal comments required
|
|
91
|
-
- No documentation required for classes/modules
|
|
92
|
-
- `fail` for raising exceptions, `raise` for re-raising
|
|
93
|
-
- `%x[]` for shell commands (not backticks)
|
|
94
|
-
- Unicode allowed in comments and identifiers
|
|
95
|
-
|
|
96
|
-
## Adding Custom Cops
|
|
97
|
-
|
|
98
|
-
Create cops in `lib/rubocop/cop/boochtek/`:
|
|
99
|
-
|
|
100
|
-
```ruby
|
|
101
|
-
# lib/rubocop/cop/boochtek/my_custom_cop.rb
|
|
102
|
-
module RuboCop
|
|
103
|
-
module Cop
|
|
104
|
-
module Boochtek
|
|
105
|
-
class MyCustomCop < Base
|
|
106
|
-
MSG = "Custom message here"
|
|
107
|
-
|
|
108
|
-
def on_send(node)
|
|
109
|
-
# ...
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
Custom cops are auto-loaded when the gem is required.
|
|
67
|
+
## License
|
|
118
68
|
|
|
119
|
-
|
|
69
|
+
Stone is released under the MIT license. See the [LICENSE](/LICENSE.txt) file for details.
|
|
120
70
|
|
|
121
|
-
|
|
122
|
-
git clone https://github.com/boochtek/rubocop-boochtek
|
|
123
|
-
cd rubocop-boochtek
|
|
124
|
-
bundle install
|
|
125
|
-
bundle exec rake
|
|
126
|
-
```
|
|
71
|
+
## Thanks
|
|
127
72
|
|
|
128
|
-
|
|
73
|
+
Thanks to some advice from my friends in the STL Polyglots group in selecting the name.
|
|
74
|
+
Especially Deech.
|
|
129
75
|
|
|
130
|
-
|
|
76
|
+
Thanks to Claude, ChatGPT, and GitHub Copilot for lots of good advice.
|
|
77
|
+
And lots of frustration!
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class TrueClass
|
|
2
|
+
|
|
3
|
+
include Comparable
|
|
4
|
+
|
|
5
|
+
def ∧(other)
|
|
6
|
+
!!other
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def ∨(_other)
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def <=>(other)
|
|
14
|
+
return 1 if other.instance_of?(FalseClass)
|
|
15
|
+
return 0 if other.instance_of?(TrueClass)
|
|
16
|
+
fail ArgumentError, "comparison of Boolean with #{other.class} failed"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ==(other)
|
|
20
|
+
other.instance_of?(TrueClass)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FalseClass
|
|
27
|
+
|
|
28
|
+
include Comparable
|
|
29
|
+
|
|
30
|
+
def ∧(_other)
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ∨(other)
|
|
35
|
+
!!other
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def <=>(other)
|
|
39
|
+
return -1 if other.instance_of?(TrueClass)
|
|
40
|
+
return 0 if other.instance_of?(FalseClass)
|
|
41
|
+
fail ArgumentError, "comparison of Boolean with #{other.class} failed"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ==(other)
|
|
45
|
+
other.instance_of?(FalseClass)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# TODO: Get these added to the `pretty_ruby` gem, and use that. (Note that it uses refinements, not monkey-patching.)
|
|
2
|
+
|
|
3
|
+
module Enumerable
|
|
4
|
+
|
|
5
|
+
# Allow Scheme-style `rest`.
|
|
6
|
+
def rest(count = 1)
|
|
7
|
+
drop(count)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Allow Scheme-style `tail`.
|
|
11
|
+
# FIXME: Shouldn't this be the same as `rest`?
|
|
12
|
+
def tail
|
|
13
|
+
return self if empty?
|
|
14
|
+
last(size - 1)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns `true` iff all the elements are equal. Returns `false` if there are no elements.
|
|
18
|
+
def same?
|
|
19
|
+
uniq.size == 1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Like `first` or `last`, but *requires* that there be exactly one element.
|
|
23
|
+
def only
|
|
24
|
+
fail IndexError, "expected to have exactly 1 element" unless size == 1
|
|
25
|
+
first
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Allow Rails-style `second`.
|
|
29
|
+
def second
|
|
30
|
+
drop(1).first
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Prefer 1-based indexing to get the `nth` element.
|
|
34
|
+
def nth(n) # rubocop:disable Naming/MethodParameterName
|
|
35
|
+
drop(n - 1).first
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def map_dig(*)
|
|
39
|
+
map{ |a| a.dig(*) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require "llvm/core"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# Extensions to LLVM::Module to support Stone-specific features
|
|
5
|
+
#
|
|
6
|
+
# NOTE: Many of these registries are now duplicated in Stone::Scope for lexical scoping:
|
|
7
|
+
# - string_constants: types also stored via scope.declare_type(name, type: Stone::Type::String)
|
|
8
|
+
# - record_instances: types also stored via scope.declare_type(name, type: record_type)
|
|
9
|
+
# - function_aliases: values also stored via scope.define(name, value: function)
|
|
10
|
+
#
|
|
11
|
+
# The module registries remain necessary for:
|
|
12
|
+
# - Computed properties (Int@abs) which are global, not lexically scoped
|
|
13
|
+
# - Type inference via the `type` method (which doesn't have access to scope)
|
|
14
|
+
# - Property access lookups that need the actual AST node (not just the type)
|
|
15
|
+
#
|
|
16
|
+
# Future work: migrate fully to scope by updating `type` method signatures to accept scope.
|
|
17
|
+
module Stone
|
|
18
|
+
module LLVMModuleExtensions
|
|
19
|
+
|
|
20
|
+
# Get the function aliases hash, creating it if it doesn't exist
|
|
21
|
+
def function_aliases
|
|
22
|
+
@function_aliases ||= {}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Register a function alias (e.g., for lambdas assigned to constants)
|
|
26
|
+
def register_function_alias(name, function)
|
|
27
|
+
function_aliases[name] = function
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Look up a function by name, checking aliases if not found in the module's function table
|
|
31
|
+
def lookup_function(name)
|
|
32
|
+
functions[name] || function_aliases[name]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get the current lambda parameter storage context
|
|
36
|
+
def lambda_param_storage
|
|
37
|
+
@lambda_param_storage
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Set the lambda parameter storage context (used during lambda compilation)
|
|
41
|
+
def lambda_param_storage=(storage)
|
|
42
|
+
@lambda_param_storage = storage
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Track which constants are strings (for type checking during returns)
|
|
46
|
+
def string_constants
|
|
47
|
+
@string_constants ||= {}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def register_string_constant(name, string_literal)
|
|
51
|
+
string_constants[name] = string_literal
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def string_constant?(name)
|
|
55
|
+
string_constants.key?(name)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# TODO: Type system refactor needed.
|
|
59
|
+
# This ad-hoc tracking of record types and instances should be replaced
|
|
60
|
+
# with a proper Type class hierarchy where:
|
|
61
|
+
# - All types (Bool, Int, String, Records) are Type instances
|
|
62
|
+
# - Types are global constants accessible at runtime
|
|
63
|
+
# - Types have vtables for properties and polymorphic operations
|
|
64
|
+
# - typeof() can get the type of any value
|
|
65
|
+
# - User-defined types work the same as built-in types
|
|
66
|
+
|
|
67
|
+
# Track record type definitions
|
|
68
|
+
def record_types
|
|
69
|
+
@record_types ||= {}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def register_record_type(name, record_definition)
|
|
73
|
+
record_types[name] = record_definition
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def record_type?(name)
|
|
77
|
+
record_types.key?(name)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Track which variables hold record instances (maps variable name -> record type name)
|
|
81
|
+
def record_instances
|
|
82
|
+
@record_instances ||= {}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def register_record_instance(variable_name, record_type_name)
|
|
86
|
+
record_instances[variable_name] = record_type_name
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def record_instance?(variable_name)
|
|
90
|
+
record_instances.key?(variable_name)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def record_instance_type(variable_name)
|
|
94
|
+
record_instances[variable_name]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Extend LLVM::Module with our extensions
|
|
101
|
+
LLVM::Module.include(Stone::LLVMModuleExtensions)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
|
|
3
|
+
# Document methods that MUST be overridden by child classes.
|
|
4
|
+
def abstract(method_name)
|
|
5
|
+
define_method(method_name) do
|
|
6
|
+
fail NotImplementedError
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Document methods that CAN or SHOULD be overridden by child classes.
|
|
11
|
+
def overridable(method_name)
|
|
12
|
+
method_name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Document methods that are overriding a parent class.
|
|
16
|
+
def override(method_name)
|
|
17
|
+
method_name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Delegate a set of methods to another object.
|
|
21
|
+
# This is meant to be a simpler version of Rails' ActiveSupport implementation.
|
|
22
|
+
def delegate(*methods, to: nil)
|
|
23
|
+
fail ArgumentError, "Must specify target of `delegate` using `to` keyword argument." if to.nil?
|
|
24
|
+
to = to.to_sym
|
|
25
|
+
to = "self.#{to}" unless to.start_with?("@")
|
|
26
|
+
methods.each do |method|
|
|
27
|
+
define_method(method) do |*args|
|
|
28
|
+
receiver = instance_eval(to)
|
|
29
|
+
receiver.__send__(method, *args)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# TODO: Get these added to the `pretty_ruby` gem, and use that. (Note that it uses refinements, not monkey-patching.)
|
|
2
|
+
|
|
3
|
+
class String
|
|
4
|
+
|
|
5
|
+
# Allow Scheme-style `first`.
|
|
6
|
+
def first(count = 1)
|
|
7
|
+
self[0..(count - 1)]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Allow Scheme-style `rest`.
|
|
11
|
+
def rest(count = 1)
|
|
12
|
+
drop(count)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def drop(count = 1)
|
|
16
|
+
self.chars.drop(count).join
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Allow Scheme-style `tail`.
|
|
20
|
+
def tail
|
|
21
|
+
return self if size.zero?
|
|
22
|
+
last(size - 1)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def last(count = 1)
|
|
26
|
+
self.chars.last(count).join
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|