starlark_compiler 0.2.0 → 0.3.0

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