starlark_compiler 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b74a86696f726f3151ccdd78309c4b1ebea7bf398cb9208798a52e673be4051
4
- data.tar.gz: 365d6a79086a1dd56e173ab2f849f6ce35369a39c377fe135251efcd495a2433
3
+ metadata.gz: 663c6958d605dfe906b15293619e97fff4040f4fa57568b88c5d76a343a04083
4
+ data.tar.gz: c04c32107df5dfd72be317e48f3f6b96683a21c02b648c8e1f8932859c9b8072
5
5
  SHA512:
6
- metadata.gz: e8c9cfde13ec42a01be510b584b63a8316b0cdeefbd9c6c507d6c25aa60915db40d03102ef4bde0d4dbb2d6333195adb943114d14d3707991781858d73ca1512
7
- data.tar.gz: a2f8569be65150c0f0ee30ccc20a0ec8d6b4f1dd03b5879e9349d07ac25e6c424d3207d8c816befa387018325bfd9f4b45207aa548e31d65ba7ff2331a7b2a8a
6
+ metadata.gz: 7cfa2e574e4a1be840990253089e61680d58232e9370af894e1cbb502ff8ba1aa145961c2161dd157e0c5d49cdf9bbdf1e2618cbb2c4b0ee18ee146a5dc2e59a
7
+ data.tar.gz: d12126d5aecf51ff166c650372620b6171791df5704aea2cf7a8e8e5d5cb68730cd2d0a42c892ec7b58a9c82128893fbc0b51f89cebc1e0f3835f92d3bd96d95
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- starlark_compiler (0.2.0)
4
+ starlark_compiler (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -48,4 +48,4 @@ DEPENDENCIES
48
48
  starlark_compiler!
49
49
 
50
50
  BUNDLED WITH
51
- 2.1.2
51
+ 2.1.4
@@ -6,5 +6,6 @@ module StarlarkCompiler
6
6
  class Error < StandardError; end
7
7
 
8
8
  require_relative 'starlark_compiler/ast'
9
+ require_relative 'starlark_compiler/build_file'
9
10
  require_relative 'starlark_compiler/writer'
10
11
  end
@@ -12,34 +12,37 @@ module StarlarkCompiler
12
12
  @toplevel << node
13
13
  end
14
14
 
15
- def self.build(&blk)
16
- Class.new do
17
- def const_name_for(str)
18
- str = str.to_s
19
- return str if str !~ /_/ && str =~ /[A-Z]+.*/
15
+ class Builder
16
+ def const_name_for(str)
17
+ str = str.to_s
18
+ return str if str !~ /_/ && str =~ /[A-Z]+.*/
20
19
 
21
- str.split('_').map(&:capitalize).join.to_sym
22
- end
20
+ str.split('_').map(&:capitalize).join.to_sym
21
+ end
23
22
 
24
- def respond_to_missing?(name)
25
- AST.constants.include?(const_name_for(name))
26
- end
23
+ def respond_to_missing?(name)
24
+ AST.constants.include?(const_name_for(name))
25
+ end
27
26
 
28
- def method_missing(name, *args, **kwargs)
29
- const_name = const_name_for(name)
30
- begin
31
- v = AST.const_get(const_name)
32
- rescue NameError
33
- super
27
+ def method_missing(name, *args, **kwargs)
28
+ const_name = const_name_for(name)
29
+ begin
30
+ v = AST.const_get(const_name)
31
+ rescue NameError
32
+ super
33
+ else
34
+ if kwargs.empty?
35
+ v.new(*args)
34
36
  else
35
- if kwargs.empty?
36
- v.new(*args)
37
- else
38
- v.new(*args, **kwargs)
39
- end
37
+ v.new(*args, **kwargs)
40
38
  end
41
39
  end
42
- end.new.instance_exec(&blk)
40
+ end
41
+ end
42
+ private_constant :Builder
43
+
44
+ def self.build(&blk)
45
+ Builder.new.instance_exec(&blk)
43
46
  end
44
47
 
45
48
  class Node
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'starlark_compiler/ast'
4
+ require 'starlark_compiler/writer'
5
+
6
+ module StarlarkCompiler
7
+ class BuildFile
8
+ def initialize(package:, workspace: Dir.pwd)
9
+ @loads = Hash.new { |h, k| h[k] = Set.new }
10
+ @targets = {}
11
+ @package = package
12
+ @workspace = workspace
13
+ @path = File.join(@workspace, @package, 'BUILD.bazel')
14
+ end
15
+
16
+ def add_load(from:, of:) # rubocop:disable Naming/MethodParameterName
17
+ @loads[from] |= Array(of)
18
+ end
19
+
20
+ def add_target(function_call)
21
+ name = function_call.kwargs.fetch(:name)
22
+ if @targets[name]
23
+ raise Error, "Target named #{name.inspect} already exists in #{package}"
24
+ end
25
+
26
+ @targets[name] = function_call
27
+ end
28
+
29
+ def save!
30
+ File.open(@path, 'w') do |f|
31
+ Writer.write(ast: to_starlark, io: f)
32
+ end
33
+ end
34
+
35
+ def to_starlark
36
+ loads = @loads
37
+ .sort_by { |k, _| k }
38
+ .map { |f, fn| AST.build { function_call('load', f, *fn.sort) } }
39
+ targets = @targets
40
+ .sort_by { |k, _| k }
41
+ .map { |_f, fn| normalize_function_call_kwargs(fn) }
42
+ AST.new(toplevel: loads + targets)
43
+ end
44
+
45
+ private
46
+
47
+ # from https://github.com/bazelbuild/buildtools/blob/90de5e7001fbdfec29d4128bb508e01169f46950/tables/tables.go#L171-L202
48
+ KWARG_NAME_PRIORITY = {
49
+ name: -99,
50
+ gwt_name: -98,
51
+ package_name: -97,
52
+ visible_node_name: -96,
53
+ size: -95,
54
+ timeout: -94,
55
+ testonly: -93,
56
+ src: -92,
57
+ srcdir: -91,
58
+ srcs: -90,
59
+ out: -89,
60
+ outs: -88,
61
+ hdrs: -87,
62
+ has_services: -86,
63
+ include: -85,
64
+ of: -84,
65
+ baseline: -83,
66
+ # All others sort here, at 0.
67
+ destdir: 1,
68
+ exports: 2,
69
+ runtime_deps: 3,
70
+ deps: 4,
71
+ implementation: 5,
72
+ implements: 6,
73
+ alwayslink: 7
74
+ }.freeze
75
+ private_constant :KWARG_NAME_PRIORITY
76
+
77
+ def normalize_function_call_kwargs(func)
78
+ kwargs = func.kwargs.sort_by do |k, _v|
79
+ [KWARG_NAME_PRIORITY.fetch(k, 0), k]
80
+ end.to_h
81
+ func.kwargs.replace(kwargs)
82
+ func
83
+ end
84
+ end
85
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StarlarkCompiler
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -24,7 +24,10 @@ module StarlarkCompiler
24
24
  case ast
25
25
  when AST
26
26
  ast.toplevel.each_with_index do |o, i|
27
- io << "\n\n" unless i.zero?
27
+ unless i.zero?
28
+ write_newline
29
+ write_newline unless o.is_a?(AST::FunctionCall) && o.name == 'load'
30
+ end
28
31
  write_node(o)
29
32
  end
30
33
  when AST::Node
@@ -32,16 +35,16 @@ module StarlarkCompiler
32
35
  else
33
36
  raise Error, "Trying to write unknown object #{ast.inspect}"
34
37
  end
35
- io << "\n"
38
+ write_newline
36
39
  end
37
40
 
38
- def write_node(node, start_of_line: true)
39
- write_start_of_line if start_of_line
41
+ def write_node(node)
40
42
  delegate('write_%s', node)
41
43
  end
42
44
 
43
- def write_start_of_line
44
- io << ' ' * indent
45
+ def write_newline
46
+ io << "\n"
47
+ io << ' ' * indent
45
48
  end
46
49
 
47
50
  def write_string(str)
@@ -73,65 +76,63 @@ module StarlarkCompiler
73
76
  def write_function_call(call)
74
77
  single_line = single_line?(call)
75
78
  io << call.name << '('
76
- io << "\n" unless single_line
77
79
  final_index = single_line && call.kwargs.empty? && call.args.size.pred
78
80
  call.args.each_with_index do |arg, idx|
79
- indented do
80
- write_node(arg, start_of_line: !single_line)
81
- unless final_index == idx
82
- io << ','
83
- io << (single_line ? ' ' : "\n")
84
- end
81
+ indented(single_line: single_line) do |indenter|
82
+ indenter.write_newline
83
+ write_node(arg)
84
+ indenter.write_comma unless final_index == idx
85
85
  end
86
86
  end
87
87
  final_index = single_line && call.kwargs.size.pred
88
88
  call.kwargs.each_with_index do |(k, v), idx|
89
- indented do
90
- write_start_of_line unless single_line
89
+ indented(single_line: single_line) do |indenter|
90
+ indenter.write_newline
91
91
  io << "#{k} = "
92
- write_node(v, start_of_line: false)
93
- unless final_index == idx
94
- io << ','
95
- io << (single_line ? ' ' : "\n")
96
- end
92
+ write_node(v)
93
+ indenter.write_comma unless final_index == idx
97
94
  end
98
95
  end
99
- write_start_of_line unless single_line
96
+ write_newline unless single_line
100
97
  io << ')'
101
98
  end
102
99
 
103
100
  def write_array(array)
104
101
  single_line = single_line?(array)
105
102
  io << '['
103
+ end_index = array.elements.size.pred
106
104
  array.elements.each_with_index do |node, i|
107
- unless i.zero?
108
- io << ','
109
- io << "\n" unless single_line
105
+ indented(single_line: single_line) do |indenter|
106
+ indenter.write_newline
107
+ write_node(node)
108
+ indenter.write_comma unless i == end_index && single_line
110
109
  end
111
- write_node(node, start_of_line: !single_line)
112
110
  end
111
+ write_newline unless single_line
113
112
  io << ']'
114
113
  end
115
114
 
116
115
  def write_dictionary(dictionary)
117
116
  single_line = single_line?(dictionary)
118
117
  io << '{'
118
+ end_index = dictionary.elements.size.pred
119
119
  dictionary.elements.each_with_index do |(key, value), i|
120
- unless i.zero?
121
- io << ','
122
- io << "\n" unless single_line
120
+ indented(single_line: single_line) do |indenter|
121
+ indenter.write_newline
122
+ write_node(key)
123
+ io << ': '
124
+ write_node(value)
125
+ indenter.write_comma unless i == end_index && single_line
123
126
  end
124
- write_node(key, start_of_line: !single_line)
125
- io << ': '
126
- write_node(value, start_of_line: false)
127
127
  end
128
+ write_newline unless single_line
128
129
  io << '}'
129
130
  end
130
131
 
131
132
  def write_binary_operator(operator)
132
- write_node(operator.lhs, start_of_line: false)
133
+ write_node(operator.lhs)
133
134
  io << " #{operator.operator} "
134
- write_node(operator.rhs, start_of_line: false)
135
+ write_node(operator.rhs)
135
136
  end
136
137
 
137
138
  def write_none(_none)
@@ -143,14 +144,26 @@ module StarlarkCompiler
143
144
  end
144
145
 
145
146
  def write_false(_none)
146
- io << 'True'
147
+ io << 'False'
147
148
  end
148
149
 
149
- def indented
150
- @indent += 1
151
- yield
150
+ Indenter = Struct.new(:writer, :should_indent) do
151
+ def write_newline
152
+ writer.write_newline if should_indent
153
+ end
154
+
155
+ def write_comma
156
+ writer.io << (should_indent ? ',' : ', ')
157
+ end
158
+ end
159
+ private_constant :Indenter
160
+
161
+ def indented(single_line:)
162
+ should_indent = !single_line
163
+ @indent += 1 if should_indent
164
+ yield Indenter.new(self, should_indent)
152
165
  ensure
153
- @indent -= 1
166
+ @indent -= 1 if should_indent
154
167
  end
155
168
 
156
169
  def single_line?(node)
@@ -182,16 +195,13 @@ module StarlarkCompiler
182
195
  end
183
196
 
184
197
  def single_line_array?(array)
185
- if array.elements.all? { |e| e.is_a?(AST::String) }
186
- array.elements.sum { |s| s.str.length } < 50
187
- else
188
- array.elements.size <= 1 && array.elements.all?(&method(:single_line?))
189
- end
198
+ array.elements.size <= 1 &&
199
+ array.elements.all?(&method(:single_line?))
190
200
  end
191
201
 
192
202
  def single_line_dictionary?(dictionary)
193
203
  dictionary.elements.size <= 1 &&
194
- dictionary.elements.each_value.all?(&method(:single_line?))
204
+ dictionary.elements.each_key.all?(&method(:single_line?))
195
205
  end
196
206
  end
197
207
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: starlark_compiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Giddins
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-24 00:00:00.000000000 Z
11
+ date: 2020-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -45,6 +45,7 @@ files:
45
45
  - bin/setup
46
46
  - lib/starlark_compiler.rb
47
47
  - lib/starlark_compiler/ast.rb
48
+ - lib/starlark_compiler/build_file.rb
48
49
  - lib/starlark_compiler/version.rb
49
50
  - lib/starlark_compiler/writer.rb
50
51
  - starlark_compiler.gemspec