sbuilder-ial 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,160 @@
1
+ module Sbuilder
2
+ module Ial
3
+ module Action
4
+
5
+ # not catched in 'Fp'
6
+ class TranslatorException < ActionException; end
7
+ # catched in 'Fp'
8
+ class TranslatorError < ActionError; end
9
+
10
+ class Translator
11
+
12
+ PROGNAME = nil # progname for logger default class name
13
+ include Sbuilder::Ial::MyLogger # mix logger
14
+
15
+
16
+ # @attr [Hash] rules [rule->action]controlling translation
17
+ # @option rule [:Symbol] identify rule names
18
+ # @option action [Hash] actions
19
+ attr_accessor :rules
20
+
21
+ def initialize( rules, options={} )
22
+ self.rules = rules
23
+ @logger = getLogger( nil, options )
24
+ @logger.info "#{__method__}: starting options=#{options}"
25
+
26
+ end
27
+
28
+ def self.start( elementGenarator, options={} )
29
+ # elementGenarator = Sbuilder::Ial::Action::Render::TlaElementGenerator.start if elementGenarator.nil?
30
+ Translator.new( TlaRules.rules(elementGenarator), options )
31
+ end
32
+
33
+
34
+ def translate( node, rule=:start, ctx={} )
35
+
36
+ @logger.debug "#{__method__}: node=#{node}, rule=#{rule}, ctx.keys=#{ctx.keys.join(',')}" if @logger.debug?
37
+ # @logger.debug "#{__method__}: node=#{node}, ctx=#{ctx.to_yaml}" if @logger.debug?
38
+ # Lookup 'rule' from rules
39
+ raise TranslatorException, "Configuration error missing rule '#{rule}' - knonwn rules: #{rules.keys}" if rules[rule].nil?
40
+ raise TranslatorException, "Configuration error, node empty #{node.to_s}" if node.nil?
41
+ # raise TranslatorException, "Configuration error, node empty #{node.to_s}" if node.nil? or node == {}
42
+
43
+ if rules[rule][:debug]
44
+ puts <<-EOS.unindent
45
+ ------------------------------------------------------------------
46
+ #{rule}:
47
+
48
+ node=#{node}
49
+
50
+ ctx keys=#{ctx.keys.join(',')}
51
+
52
+ ctx=#{ctx.to_yaml}
53
+ EOS
54
+ end
55
+
56
+ # rule -name property in ctx holds current node, restored later
57
+ prev_rule = ctx[rule]
58
+ ctx[rule] = node;
59
+
60
+ # Collect 'navigationResults' to hash with key as
61
+ # 'navigation[:rule] and values with the result of
62
+ # translating the nodes navigated to navigation[:navigate]
63
+ navigationResults = {}
64
+
65
+ # translate :navigations (before translating current node)
66
+ navigations = rules[rule][:navigations] ? rules[rule][:navigations] : []
67
+ navigations = [ navigations ] unless navigations.is_a?( Array )
68
+ navigations.each do |navigation|
69
+
70
+ # Validate rule configration
71
+ raise TranslatorException, "Error in rule #{navigation} " if navigation[:rule].nil?
72
+
73
+ if navigation[:navigate].nil? && navigation[:iterate].nil?
74
+ # no change in node - run a new rule on current node
75
+ nodesToNaviagate = [node]
76
+ elsif navigation[:navigate]
77
+ navigateSteps = navigation[:navigate].is_a?(Array ) ? navigation[:navigate] : [ navigation[:navigate] ]
78
+ # real navigation: nodesToNaviagate must exist
79
+ begin
80
+ # walk array of navigation[:navigate] -steps
81
+ currentNode = node
82
+ navigateSteps.each do |navigateStep|
83
+ # Hash, Model: access by ':navigate' key , Struct: send message ':navigate' message
84
+ currentNode = !currentNode.is_a?( Struct ) ? currentNode[navigateStep] : currentNode.send( navigateStep )
85
+ end
86
+ nodesToNaviagate = currentNode
87
+ # nodesToNaviagate = !node.is_a?( Struct ) ? currentNote on[:navigate]] : node.send( navigation[:navigate] )
88
+ # nodesToNaviagate = !node.is_a?( Struct ) ? node[navigation[:navigate]] : node.send( navigation[:navigate] )
89
+
90
+ rescue NameError => err
91
+ raise $!, <<-EOS,
92
+ #{$!}
93
+
94
+ Error navigating to '#{navigation[:navigate]}' in node #{node}.
95
+
96
+ EOS
97
+ $!.backtrace
98
+ end
99
+ raise TranslatorError, "Navigation '#{navigation[:navigate]}' in node '#{node}' failed" if nodesToNaviagate.nil?
100
+ nodesToNaviagate = [nodesToNaviagate] unless nodesToNaviagate.is_a?(Array)
101
+ elsif navigation[:iterate]
102
+ # NB {} -node --> no iteration
103
+ nodesToNaviagate = node.keys.map { |key| node[key] }
104
+ # raise TranslatorError, "Navigation iterator '#{navigation[:iterate]}' in node '#{node}' failed" unless nodesToNaviagate.any?
105
+ else
106
+ raise TranslatorException, "Error in rule #{navigation} " if navigation[:rule].nil?
107
+ end
108
+
109
+
110
+ # nextRule possibly defined using a lamdba
111
+ traslationKey, nextRule = navigation[:rule].respond_to?( :call ) ? navigation[:rule].call( node ).flatten : [ navigation[:rule], navigation[:rule] ]
112
+ navigationResults[ traslationKey ] =
113
+ nodesToNaviagate.map do |nodeToNaviagate|
114
+ begin
115
+ # run translation
116
+ nextTranslate = nextRule ? translate( nodeToNaviagate, nextRule, ctx ) : []
117
+ rescue TranslatorError => e
118
+ msg = <<-EOS
119
+ #{e.message}
120
+
121
+ within
122
+
123
+ node: #{node}
124
+ rule: #{rule}
125
+ ctx: #{ctx.to_yaml}
126
+ EOS
127
+
128
+ raise e.class.new, msg, e.backtrace
129
+
130
+ end
131
+ nextTranslate
132
+ end
133
+ # puts "navigationResults=#{navigationResults}"
134
+
135
+ end # navigations.each
136
+
137
+ # translate current node
138
+ if rules[rule][:translator]
139
+ ret = rules[rule][:translator].call( ctx.merge( { :navigationResults => navigationResults } ))
140
+ if rules[rule][:debug]
141
+ puts <<-EOS.unindent
142
+
143
+ -----> translation
144
+
145
+ #{ret}
146
+ EOS
147
+
148
+ end
149
+
150
+ end
151
+
152
+ # out of scope
153
+ # ctx.delete(ctx[rule])
154
+ ctx[rule] = prev_rule
155
+ ret
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
data/lib/app/app.rb ADDED
@@ -0,0 +1,259 @@
1
+ # coding: utf-8
2
+ module Sbuilder
3
+ module Ial
4
+ module App
5
+ class App
6
+
7
+ PROGNAME = nil # progname for logger default class name
8
+ include Sbuilder::Ial::MyLogger # mix logger
9
+ attr_reader :logger
10
+
11
+
12
+ extend Forwardable # for easy delegation
13
+
14
+
15
+ TRANSLATION_TARGETS = [
16
+ :domains_defines
17
+ ]
18
+
19
+ SNIPPET_TEMPLATE =
20
+ <<-EOS.unindent
21
+ {|# comment |}(* {|{ comment }|} *)
22
+ {|/ comment |}{|!
23
+ Output comment (with newline)
24
+ |}{|#useEval|}{|#EVAL|}template{|/EVAL|}{|/useEval|}{|^useEval|}{|{body}|}{|/useEval|}
25
+ EOS
26
+
27
+ # @attr [Sbuilder::Ial::Action::ModelBuilder] modelBuilder sexp-> model
28
+ attr_accessor :modelBuilder
29
+
30
+ # # @attr [Sbuilder::Ial::Action::Translator] translator model -> snippet
31
+ attr_accessor :translator
32
+
33
+ # @attr [object] applicationConfiguration to pass to Ruby IAL application modules
34
+ attr_accessor :applicationConfiguration
35
+
36
+ # @attr [Sbuilder::Ial::Action::Render::Producer]
37
+ attr_accessor :gen
38
+
39
+ # # @attr [Hash] partial
40
+ # attr_accessor :partials
41
+
42
+ # @attr [Sbuilder::Ial::Action::Translator] extender snippet -> sbuilder
43
+ attr_accessor :extender
44
+
45
+ # @attr [Sbuilder::Ial::Action::Render::Renderer] renderer
46
+ attr_accessor :renderer
47
+
48
+ def_delegators :extender, # access extension point
49
+ :defineDomain,
50
+ :defineSnippet
51
+
52
+ # ------------------------------------------------------------------
53
+ # @!group Contruct & configure
54
+
55
+
56
+ def initialize( options = {} )
57
+ @logger = getLogger( nil, options )
58
+ @logger.info "#{__method__}: starting options=#{options}"
59
+ end
60
+
61
+ #
62
+ # @param [String] metatypes prefix to make specnames in TLA
63
+ # language unique
64
+ #
65
+ # @param [Object] applicationConfiguration passed to ial
66
+ # modules
67
+ #
68
+ # @return [App] app initilized with actions to implment steps
69
+ def self.start( options = {}, metatypes: nil, applicationConfiguration: nil )
70
+
71
+ app = App.new( options )
72
+
73
+ # remember configuration which will be passed to script-eval
74
+ app.applicationConfiguration = applicationConfiguration
75
+ app.logger.info "#{__method__}: applicationConfiguration=#{applicationConfiguration}"
76
+
77
+ # sexp -> model
78
+ app.modelBuilder = Sbuilder::Ial::Action::ModelBuilder.start
79
+
80
+ # produce snippets etc
81
+ app.gen = Sbuilder::Ial::Action::Render::ProducerEthereum.start( options, metatypes )
82
+ # # model -> translations
83
+ app.translator = Sbuilder::Ial::Action::Translator.start( app.gen, options )
84
+
85
+ # tempate -> data -> string
86
+ app.renderer = Sbuilder::Ial::Action::Render::Renderer.start( options )
87
+
88
+ # translation -> extension
89
+ app.extender = Sbuilder::Ial::Action::Extender.start
90
+
91
+ app
92
+ end
93
+
94
+ # @!endgroup
95
+
96
+ # ------------------------------------------------------------------
97
+ # @!group Workdflow
98
+
99
+ # Load IAL implemetations arrays from Ruby 'filenames'
100
+ #
101
+ # @return [Result|Error] Result holds an Array of Ruby IAL
102
+ # objects read, Error wraps an exception encounted when
103
+ # procesing 'filename'
104
+ def loadIalImplementation( filenames )
105
+
106
+
107
+ filenames = filenames.is_a?( Array ) ? filenames : [ filenames ]
108
+
109
+ errors = false
110
+ ret = Sequence( filenames ).
111
+ inject( [] ) do |memo,filename|
112
+ @logger.info "#{__method__}: evaluate script filename=#{filename}, applicationConfiguration=#{applicationConfiguration}"
113
+ evaluated = Sbuilder::Ial::Action::ScriptEval.script_eval( filename, applicationConfiguration )
114
+ errors ||= evaluated.isError
115
+ memo += evaluated.value.is_a?(Array) ? evaluated.value : [evaluated.value]
116
+ end
117
+ errors ? Error( ret ) : Result( ret )
118
+
119
+ end
120
+
121
+ #
122
+ # @return [Result|Error] Result wraps
123
+ # Sbuilder::Ial::Model::Model, Error wraps 'Array' (with at
124
+ # least one 'Error' ialObjects)
125
+
126
+ def buildModel( ialObjects )
127
+
128
+ return Error( "No objects to buidl model ialObjects.nil?=#{ialObjects.nil?}") if ialObjects.nil?
129
+
130
+ ret =
131
+ Sbuilder::Fp::Sequence( ialObjects ).and_then do |vo|
132
+ # modelBuilder.updateVo(vo)
133
+ # end.and_then do |vo|
134
+ # # remap Result to Sequence
135
+ # Sequence( vo )
136
+ # end.and_then do |vo|
137
+ # modelBuilder.validateVo(vo)
138
+ # end.and_then do |vo|
139
+ # # remap Result to Sequence
140
+ # Sequence( vo )
141
+ # end.and_then do |vo|
142
+ modelBuilder.defineVo(vo)
143
+ end
144
+
145
+ # # Returns 'Result' (no Error objects in block), or 'Error'
146
+ # # if sequence block found some error.
147
+
148
+ ret
149
+
150
+ end
151
+
152
+ def getModel
153
+ modelBuilder.getModelBuilt
154
+ end
155
+
156
+ # @!endgroup
157
+
158
+
159
+ # ------------------------------------------------------------------
160
+ # @!group Walk model
161
+
162
+ # Run 'translateTargets' on 'model' to return array of
163
+ # translation ':results' for tranlation types :domain,
164
+ # :snippet, :interface.
165
+ #
166
+ # @param [Sbuilder::Ial::Model::Model] model
167
+ #
168
+ # @param [:Symbol:Array] array of tranlation targets to run
169
+ #
170
+ # @return [Hash:Sequence] translations
171
+ # @option translations [:Symbol] :translation values :domain, :snippet, :interface
172
+ # @option translations [:Symbol] :results array of translation types
173
+
174
+ def translateModel( model, translateTargets=nil )
175
+
176
+ # default targets can be overridden on command line
177
+ translateTargets = TRANSLATION_TARGETS if translateTargets.nil?
178
+
179
+ # Wrap targets to a sequence, and process target in block
180
+ ret = Sbuilder::Fp::Sequence( translateTargets ).and_then do |target|
181
+
182
+ # Translate 'target' in 'model' --> { :translation=>.. , :results => [] .. }
183
+ translationResults = translator.translate( model, target )
184
+ translationResults
185
+ end
186
+
187
+ # Return
188
+ ret
189
+ end
190
+
191
+ # @!endgroup
192
+
193
+
194
+ # Render 'snippetTemplate' only if 'snippetTemplate[:template]' or 'snippetTemplate[:body]' defined
195
+ def renderSnippet( snippetTemplate )
196
+ return nil if snippetTemplate.nil? || ( snippetTemplate[:template].nil? && snippetTemplate[:body].nil? )
197
+ snippetTemplate[:useEval] = snippetTemplate[:template] ? true : false
198
+ renderer.partials = gen.partials
199
+ snippetBody = renderer.to_str( SNIPPET_TEMPLATE, snippetTemplate )
200
+ snippetBody
201
+ end
202
+
203
+ # # @return [Hash] metatypes
204
+ # # @option metatypes [Symbol|String] key metatype
205
+ # # @option metatypes [Symbol] :name
206
+ # # @option metatypes [Symbol] :prefix
207
+ def appMetatypes
208
+ gen.rule_metatypes
209
+ end
210
+
211
+ # ------------------------------------------------------------------
212
+ # @!group Pass forward
213
+
214
+ #
215
+ # @param [Result] translation with value { :translation=>..., :results=> ... }
216
+ #
217
+ def extendWithTranslations( translation )
218
+
219
+ # Extract Has from
220
+ translation = translation.value
221
+ raise "Error in translation=#{translation}" if translation.nil? || translation[:translation].nil? || translation[:results].nil?
222
+ case translation[:translation]
223
+ when :domain
224
+ translation[:results].each{ |domainDefinition| defineDomain( domainDefinition ) }
225
+ ret = Result( "Domains defined" )
226
+ when :snippet
227
+ warn "TODO: snippeet =#{translation}"
228
+ # translation[:results].each{ |snippetDefinition| defineSnippet( snippetDefinition ) }
229
+ translation[:results].each{ |snippetDefinition|
230
+ warn "snippetDefinition=#{snippetDefinition}"
231
+ metatype = 'metatype to set'
232
+ appName = 'apppi'
233
+ renderData =
234
+ {
235
+ :metatype => metatype,
236
+ :appName => appName,
237
+ :comment => 'commenttit',
238
+ :snippet => snippetDefinition
239
+ }
240
+ renderer.partials = elementGenarator.partials
241
+ snippetBody = renderer.to_str( SNIPPET_TEMPLATE, renderData )
242
+ specName = nil
243
+ defineSnippet( metatype, appName, snippetBody, specName )
244
+ }
245
+ ret = Result( "Snippets defined #{translation}" )
246
+ else
247
+ raise "Error in translation=#{translation}"
248
+ end
249
+ ret
250
+ end
251
+
252
+
253
+ # @!endgroup
254
+
255
+
256
+ end # class App
257
+ end
258
+ end
259
+ end