drgdsl 1.1.0 → 1.2.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 +4 -4
- data/Gemfile.lock +1 -1
- data/bin/cache +63 -0
- data/bin/html +2 -0
- data/lib/drgdsl/ast.rb +105 -16
- data/lib/drgdsl/parser.rb +1 -1
- data/lib/drgdsl/pretty_printer.rb +14 -0
- data/lib/drgdsl/version.rb +1 -1
- data/lib/drgdsl/visitor.rb +43 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 346dd382500a954f17d93e1d1385e6cb8af10b02059298776973f0af8389686d
|
4
|
+
data.tar.gz: 3add8eaaa026e2bd054c230933be1e546592da9c919b67155e35165025a89e5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7fda718baaaa0077ed81705b6178a11b8ba8d170b19d53aa7b4fc61d1ed86f18514ec153422b9406d4b429b5d53f467fb91e92dec3e4289d2ded36f1b6eae5f
|
7
|
+
data.tar.gz: '00138b8f522e3c277163a86724a011e92e83845aae9a9fd6fdf67921b7f0bc7dde2030de8f78ed80bf4756dd2765a109057e1a41e724e8333fe907dd2394ec31'
|
data/Gemfile.lock
CHANGED
data/bin/cache
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require "bundler/setup"
|
6
|
+
require "drgdsl"
|
7
|
+
require 'benchmark'
|
8
|
+
|
9
|
+
string_printer = DrgDSL::PrettyPrinter.new(output_format: :string)
|
10
|
+
html_printer = DrgDSL::PrettyPrinter.new(output_format: :html)
|
11
|
+
bash_printer = DrgDSL::PrettyPrinter.new(output_format: :bash)
|
12
|
+
|
13
|
+
asts = File.read('./test/expressions.txt', encoding: 'utf-8')
|
14
|
+
.split("\n\n")
|
15
|
+
.map { |exp| DrgDSL.parse(exp) }
|
16
|
+
|
17
|
+
N = 2
|
18
|
+
|
19
|
+
puts "Pretty printing #{N} * #{asts.count} ASTs:"
|
20
|
+
|
21
|
+
t1 = Benchmark.realtime do
|
22
|
+
N.times do
|
23
|
+
asts.each do |ast|
|
24
|
+
ast.accept(string_printer)
|
25
|
+
ast.accept(html_printer)
|
26
|
+
ast.accept(bash_printer)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
puts "PrettyPrinter while building up cache: \t#{t1}"
|
31
|
+
|
32
|
+
t2 = Benchmark.realtime do
|
33
|
+
N.times do
|
34
|
+
asts.each do |ast|
|
35
|
+
ast.accept(string_printer)
|
36
|
+
ast.accept(html_printer)
|
37
|
+
ast.accept(bash_printer)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
puts "PrettyPrinter with cache hits only: \t#{t2}"
|
42
|
+
|
43
|
+
[string_printer, html_printer, bash_printer].each do |printer|
|
44
|
+
class << printer
|
45
|
+
def cache?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
t3 = Benchmark.realtime do
|
52
|
+
N.times do
|
53
|
+
asts.each do |ast|
|
54
|
+
ast.accept(string_printer)
|
55
|
+
ast.accept(html_printer)
|
56
|
+
ast.accept(bash_printer)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
puts "PrettyPrinter with caching disabled: \t#{t3}"
|
61
|
+
|
62
|
+
puts "Speed increase when enabling caching: \t#{(100 / t3 * (t3 - t1)).round(2)}%"
|
63
|
+
puts "Speed increase when cache fully built up: \t#{(100 / t3 * (t3 - t2)).round(2)}%"
|
data/bin/html
CHANGED
data/lib/drgdsl/ast.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DrgDSL
|
2
4
|
|
3
5
|
# Nodes in DRG logic AST.
|
4
6
|
#
|
5
7
|
# @see AstBuilder
|
6
8
|
module Ast
|
9
|
+
def self.node_classes
|
10
|
+
Node.node_classes
|
11
|
+
end
|
12
|
+
|
7
13
|
module Node
|
8
14
|
class << self
|
9
15
|
def node_classes
|
@@ -46,6 +52,19 @@ module DrgDSL
|
|
46
52
|
raise NotImplementedError
|
47
53
|
end
|
48
54
|
|
55
|
+
# @return [Integer] object hash for this AST node. Node instances for the
|
56
|
+
# same expression should always return the same hash code. This is
|
57
|
+
# useful for optimizations.
|
58
|
+
def hash
|
59
|
+
raise NotImplementedError
|
60
|
+
end
|
61
|
+
|
62
|
+
def ==(other)
|
63
|
+
type == other.type && hash == other.hash
|
64
|
+
end
|
65
|
+
|
66
|
+
alias eql? ==
|
67
|
+
|
49
68
|
def pretty_print(**pretty_printer_options)
|
50
69
|
accept PrettyPrinter.new(**pretty_printer_options)
|
51
70
|
end
|
@@ -79,6 +98,10 @@ module DrgDSL
|
|
79
98
|
def to_hash
|
80
99
|
{ or: [expressions.map(&:to_hash)] }
|
81
100
|
end
|
101
|
+
|
102
|
+
def hash
|
103
|
+
@hash ||= [type, *expressions].hash
|
104
|
+
end
|
82
105
|
end
|
83
106
|
|
84
107
|
# Represents a list of expressions joined with an "AND",
|
@@ -93,7 +116,11 @@ module DrgDSL
|
|
93
116
|
end
|
94
117
|
|
95
118
|
def to_hash
|
96
|
-
{ and: [
|
119
|
+
{ and: [expressions.map(&:to_hash)] }
|
120
|
+
end
|
121
|
+
|
122
|
+
def hash
|
123
|
+
@hash ||= [type, *expressions].hash
|
97
124
|
end
|
98
125
|
end
|
99
126
|
|
@@ -110,6 +137,10 @@ module DrgDSL
|
|
110
137
|
def to_hash
|
111
138
|
{ paren: expression.to_hash }
|
112
139
|
end
|
140
|
+
|
141
|
+
def hash
|
142
|
+
@hash ||= [type, expression].hash
|
143
|
+
end
|
113
144
|
end
|
114
145
|
|
115
146
|
# A NotExpression is a logic text of the form
|
@@ -126,6 +157,10 @@ module DrgDSL
|
|
126
157
|
def to_hash
|
127
158
|
{ not: expression.to_hash }
|
128
159
|
end
|
160
|
+
|
161
|
+
def hash
|
162
|
+
@hash ||= [type, expression].hash
|
163
|
+
end
|
129
164
|
end
|
130
165
|
|
131
166
|
# "Komplizierende_Prozeduren", "Dialyse", ...
|
@@ -141,6 +176,10 @@ module DrgDSL
|
|
141
176
|
def to_hash
|
142
177
|
{ function_call: name }
|
143
178
|
end
|
179
|
+
|
180
|
+
def hash
|
181
|
+
@hash ||= [type, name].hash
|
182
|
+
end
|
144
183
|
end
|
145
184
|
|
146
185
|
# A drg link originates from the grammar rule basic_or_drg_link
|
@@ -160,6 +199,10 @@ module DrgDSL
|
|
160
199
|
def to_hash
|
161
200
|
{ drg_link: { var: variable.to_hash, name: name } }
|
162
201
|
end
|
202
|
+
|
203
|
+
def hash
|
204
|
+
@hash ||= [type, name, variable].hash
|
205
|
+
end
|
163
206
|
end
|
164
207
|
|
165
208
|
# A BasicExpression consists of a variable and a condition
|
@@ -187,9 +230,14 @@ module DrgDSL
|
|
187
230
|
def to_hash
|
188
231
|
{ basic: { var: variable.to_hash, condition: condition.to_hash } }
|
189
232
|
end
|
233
|
+
|
234
|
+
def hash
|
235
|
+
@hash ||= [type, variable, condition].hash
|
236
|
+
end
|
190
237
|
end
|
191
238
|
|
192
|
-
# A comparison is either from a table_condition, a condition or a
|
239
|
+
# A comparison is either from a table_condition, a condition or a
|
240
|
+
# date_expression
|
193
241
|
class Comparison
|
194
242
|
include Node
|
195
243
|
|
@@ -210,6 +258,10 @@ module DrgDSL
|
|
210
258
|
}
|
211
259
|
}
|
212
260
|
end
|
261
|
+
|
262
|
+
def hash
|
263
|
+
@hash ||= [type, op, value, table_condition].hash
|
264
|
+
end
|
213
265
|
end
|
214
266
|
|
215
267
|
# Has a certain operator (i.e. not / different) and a condition
|
@@ -227,13 +279,17 @@ module DrgDSL
|
|
227
279
|
end
|
228
280
|
|
229
281
|
def to_hash
|
230
|
-
{
|
282
|
+
{
|
231
283
|
unary_condition: {
|
232
284
|
op: op,
|
233
285
|
condition: condition.to_hash
|
234
286
|
}
|
235
287
|
}
|
236
288
|
end
|
289
|
+
|
290
|
+
def hash
|
291
|
+
@hash ||= [type, op, condition].hash
|
292
|
+
end
|
237
293
|
end
|
238
294
|
|
239
295
|
class Empty
|
@@ -242,15 +298,21 @@ module DrgDSL
|
|
242
298
|
def to_hash
|
243
299
|
{ empty: nil }
|
244
300
|
end
|
301
|
+
|
302
|
+
def hash
|
303
|
+
@hash ||= type.hash
|
304
|
+
end
|
245
305
|
end
|
246
306
|
|
247
|
-
# There are 3 variants of table conditions (in_table, in_tables,
|
248
|
-
#
|
249
|
-
#
|
307
|
+
# There are 3 variants of table conditions (in_table, in_tables,
|
308
|
+
# all_in_table)
|
309
|
+
#
|
310
|
+
# A table condition can have an optional comparison. Tables refers to the
|
311
|
+
# table names (the internal names)
|
250
312
|
class TableCondition
|
251
|
-
IN_TABLE = 'in table'
|
252
|
-
IN_TABLES = 'in tables'
|
253
|
-
ALL_IN_TABLE = 'all in table'
|
313
|
+
IN_TABLE = 'in table'
|
314
|
+
IN_TABLES = 'in tables'
|
315
|
+
ALL_IN_TABLE = 'all in table'
|
254
316
|
|
255
317
|
include Node
|
256
318
|
|
@@ -273,6 +335,10 @@ module DrgDSL
|
|
273
335
|
}
|
274
336
|
}
|
275
337
|
end
|
338
|
+
|
339
|
+
def hash
|
340
|
+
@hash ||= [type, op, *tables, comparison].hash
|
341
|
+
end
|
276
342
|
end
|
277
343
|
|
278
344
|
# INFO: srg (prozedur) l (links) r (rechts) b(beidseitig)
|
@@ -294,17 +360,21 @@ module DrgDSL
|
|
294
360
|
}
|
295
361
|
}
|
296
362
|
end
|
363
|
+
|
364
|
+
def hash
|
365
|
+
@hash ||= [type, variable, condition].hash
|
366
|
+
end
|
297
367
|
end
|
298
368
|
|
299
369
|
class DateExpression
|
300
370
|
include Node
|
301
371
|
|
302
372
|
attr_reader :left_variable,
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
373
|
+
:right_variable,
|
374
|
+
:left_condition,
|
375
|
+
:right_condition,
|
376
|
+
:comparison,
|
377
|
+
:opd
|
308
378
|
|
309
379
|
# @param opd [String] E.g. "opd4" => "mind. 4 erfüllen" query
|
310
380
|
def initialize(left_variable:,
|
@@ -312,8 +382,7 @@ module DrgDSL
|
|
312
382
|
left_condition:,
|
313
383
|
right_condition: nil,
|
314
384
|
comparison:,
|
315
|
-
opd:
|
316
|
-
)
|
385
|
+
opd:)
|
317
386
|
|
318
387
|
@left_variable = left_variable
|
319
388
|
@right_variable = right_variable
|
@@ -335,6 +404,18 @@ module DrgDSL
|
|
335
404
|
}
|
336
405
|
}
|
337
406
|
end
|
407
|
+
|
408
|
+
def hash
|
409
|
+
@hash ||= [
|
410
|
+
type,
|
411
|
+
left_variable,
|
412
|
+
right_variable,
|
413
|
+
left_condition,
|
414
|
+
right_condition,
|
415
|
+
comparison,
|
416
|
+
opd
|
417
|
+
].hash
|
418
|
+
end
|
338
419
|
end
|
339
420
|
|
340
421
|
# "PDX", "AGEYEARS", ...
|
@@ -350,6 +431,10 @@ module DrgDSL
|
|
350
431
|
def to_hash
|
351
432
|
{ name: name }
|
352
433
|
end
|
434
|
+
|
435
|
+
def hash
|
436
|
+
@hash ||= [type, name].hash
|
437
|
+
end
|
353
438
|
end
|
354
439
|
|
355
440
|
# "3", "'MDC'", ...
|
@@ -369,6 +454,10 @@ module DrgDSL
|
|
369
454
|
def to_hash
|
370
455
|
{ constant: { value: value } }
|
371
456
|
end
|
457
|
+
|
458
|
+
def hash
|
459
|
+
@hash ||= [type, value].hash
|
460
|
+
end
|
372
461
|
end
|
373
462
|
end
|
374
463
|
end
|
data/lib/drgdsl/parser.rb
CHANGED
@@ -52,6 +52,20 @@ module DrgDSL
|
|
52
52
|
''
|
53
53
|
end
|
54
54
|
|
55
|
+
def cache?
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
def cache_key(n)
|
60
|
+
[
|
61
|
+
n.hash,
|
62
|
+
@indentation_level,
|
63
|
+
@indentation_string,
|
64
|
+
@output_format,
|
65
|
+
@multiline
|
66
|
+
].hash
|
67
|
+
end
|
68
|
+
|
55
69
|
private
|
56
70
|
|
57
71
|
def visit_Expression(n)
|
data/lib/drgdsl/version.rb
CHANGED
data/lib/drgdsl/visitor.rb
CHANGED
@@ -1,9 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module DrgDSL
|
4
|
+
|
4
5
|
# Mixin for Ast::Node visitors. Visits all child nodes and returns the
|
5
6
|
# visited node by default.
|
6
7
|
module Visitor
|
8
|
+
def self.included(visitor)
|
9
|
+
visitor.prepend Cache
|
10
|
+
visitor.extend ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
module Cache
|
14
|
+
# @param n [Ast::Node]
|
15
|
+
def visit(n)
|
16
|
+
return super(n) unless cache?
|
17
|
+
self.class.cache[cache_key(n)] ||= super(n)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
# @return [Hash] in-memory Ruby Hash
|
23
|
+
def cache
|
24
|
+
@cache ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear_cache!
|
28
|
+
@cache = {}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Whether this visitor should cache visit results. Note that one might need
|
33
|
+
# to override #cache_key(n) if a visit is not deterministic, e.g. when it
|
34
|
+
# depends on some instance variables.
|
35
|
+
#
|
36
|
+
# @see PrettyPrinter#cache_key
|
37
|
+
#
|
38
|
+
# @return [Boolean]
|
39
|
+
def cache?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param n [Ast::Node]
|
44
|
+
# @return [Integer] ideally an object hash
|
45
|
+
def cache_key(n)
|
46
|
+
n.hash
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param n [Ast::Node]
|
7
50
|
def visit(n)
|
8
51
|
return visit_nil if n.nil?
|
9
52
|
send("visit_#{n.type}", n)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: drgdsl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SwissDRG AG
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -138,6 +138,7 @@ files:
|
|
138
138
|
- LICENSE.txt
|
139
139
|
- README.md
|
140
140
|
- Rakefile
|
141
|
+
- bin/cache
|
141
142
|
- bin/console
|
142
143
|
- bin/html
|
143
144
|
- bin/setup
|