@@ -116,6 +116,12 @@ func (p *PyACTR) WriteModel(path, initialGoal string) (outputFileName string, er
116
116
117
117
p .outputAuthors ()
118
118
119
+ if p .model .HasPrintStatement () {
120
+ // We use csv to parse the print text we are generating.
121
+ // This is just simpler than writing it ourselves (i.e. handling "foo, bar ", 66).
122
+ p .Writeln ("import csv" )
123
+ }
124
+
119
125
p .Writeln ("import pyactr as actr" )
120
126
121
127
if p .model .HasPrintStatement () {
@@ -137,20 +143,6 @@ func (p *PyACTR) WriteModel(path, initialGoal string) (outputFileName string, er
137
143
138
144
p .Write ("%s = actr.ACTRModel(%s)\n \n " , p .className , strings .Join (additionalInit , ", " ))
139
145
140
- if p .model .HasPrintStatement () {
141
- p .Writeln (`
142
- # Monkey patch Buffer to add a new method.
143
- # Currently we can only output simple strings.
144
- def print_text(*args):
145
- text = ''.join(args[1:])
146
- text = text.strip("'")
147
- print(text)
148
-
149
-
150
- Buffer.print_text = print_text
151
- ` )
152
- }
153
-
154
146
// chunks
155
147
for _ , chunk := range p .model .Chunks {
156
148
if chunk .IsInternal () {
@@ -218,13 +210,6 @@ Buffer.print_text = print_text
218
210
if production .DoStatements != nil {
219
211
for _ , statement := range production .DoStatements {
220
212
if statement .Print != nil {
221
- if ! onlyStrings (statement .Print .Values ) {
222
- warning := fmt .Sprintf ("Warning: ('%s') pyactr currently cannot print variables from productions" , production .Name )
223
- warnings = append (warnings , warning )
224
-
225
- continue
226
- }
227
-
228
213
numPrintStatements ++
229
214
if numPrintStatements > 1 {
230
215
warning := fmt .Sprintf ("Warning: ('%s') pyactr currently only supports one print statement per production" , production .Name )
@@ -233,7 +218,7 @@ Buffer.print_text = print_text
233
218
}
234
219
}
235
220
236
- p .outputStatement (statement )
221
+ p .outputStatement (production , statement )
237
222
}
238
223
}
239
224
@@ -250,12 +235,80 @@ Buffer.print_text = print_text
250
235
251
236
p .Writeln ("" )
252
237
238
+ if p .model .HasPrintStatement () {
239
+ // We add some python code to monkey patch the model and the buffer.
240
+ // This lets us output strings, numbers, and the contents of buffer slots.
241
+
242
+ p .Writeln (`
243
+ # Monkey patch ACTRModel to add a new method.
244
+ def get_buffer(self, buffer_name: str) -> Buffer:
245
+ if buffer_name == 'goal':
246
+ return self._ACTRModel__buffers['goal']
247
+ if buffer_name == 'retrieval':
248
+ return self._ACTRModel__buffers["retrieval"]
249
+
250
+ print('ERROR: Buffer \'' + buffer_name + '\' not found')
251
+
252
+
253
+ actr.ACTRModel.get_buffer = get_buffer
254
+
255
+
256
+ # Monkey patch Buffer to add a new methods.
257
+ def get_slot_contents(self, buffer_name: str, slot_name: str) -> str:
258
+ if self._data:
259
+ chunk = self._data.copy().pop()
260
+ else:
261
+ chunk = None
262
+ try:
263
+ return str(getattr(chunk, slot_name))
264
+ except AttributeError:
265
+ print('ERROR: no slot named \'' + slot_name +
266
+ '\' in buffer \'' + buffer_name + '\'')
267
+
268
+ return ''
269
+
270
+
271
+ def print_text(*args):
272
+ text = ''.join(args[1:]).strip('"')
273
+ output = '' # build up our output in this buffer
274
+
275
+ for itemlist in csv.reader([text]):
276
+ for item in itemlist:
277
+ item = item.strip(' ')
278
+
279
+ # Handle string
280
+ if item[0] == '\'' or item[0] == '"':
281
+ output += item[1:-1]
282
+ else:
283
+ # Handle number
284
+ try:
285
+ float(item)
286
+ output += item
287
+ except ValueError:
288
+ # If we are here, we should have a buffer.slotname
289
+ ids = item.split('.')
290
+ if len(ids) != 2:
291
+ print(
292
+ 'ERROR: expected <buffer>.<slot_name>, found \'' + item + '\'')
293
+ else:
294
+ buffer = %s.get_buffer(ids[0])
295
+ output += buffer.get_slot_contents(ids[0], ids[1])
296
+
297
+ print(output)
298
+
299
+
300
+ Buffer.get_slot_contents = get_slot_contents
301
+ Buffer.print_text = print_text
302
+ ` , p .className )
303
+ }
304
+
253
305
// ...add our code to run
306
+ p .Writeln ("# Main" )
254
307
p .Writeln ("if __name__ == '__main__':" )
255
308
p .Writeln ("\t sim = %s.simulation()" , p .className )
256
309
p .Writeln ("\t sim.run()" )
257
310
// TODO: Add some intelligent output when logging level is info or detail
258
- p .Writeln ("\t if goal.test_buffer('full') == True:" )
311
+ p .Writeln ("\t if goal.test_buffer('full') is True:" )
259
312
p .Writeln ("\t \t print('final goal: ' + str(goal.pop()))" )
260
313
261
314
return
@@ -335,7 +388,7 @@ func addPatternSlot(tabbedItems *framework.KeyValueList, slotName string, patter
335
388
}
336
389
}
337
390
338
- func (p * PyACTR ) outputStatement (s * actr.Statement ) {
391
+ func (p * PyACTR ) outputStatement (production * actr. Production , s * actr.Statement ) {
339
392
if s .Set != nil {
340
393
buffer := s .Set .Buffer
341
394
bufferName := buffer .GetName ()
@@ -367,27 +420,31 @@ func (p *PyACTR) outputStatement(s *actr.Statement) {
367
420
p .Writeln ("\t +retrieval>" )
368
421
p .outputPattern (s .Recall .Pattern , 2 )
369
422
} else if s .Print != nil {
423
+ // Using "goal" here is arbitrary because of the way we monkey patch the python code.
424
+ // Our "print_text" statement handles its own formatting and lookup.
370
425
p .Writeln ("\t !goal>" )
371
- values := framework .PythonValuesToStrings (s .Print .Values , true )
372
- p .Writeln ("\t \t print_text %s" , strings .Join (values , " " ))
426
+
427
+ str := make ([]string , len (* s .Print .Values ))
428
+
429
+ for index , val := range * s .Print .Values {
430
+ if val .Var != nil {
431
+ varIndex := production .VarIndexMap [* val .Var ]
432
+ str [index ] = fmt .Sprintf ("%s.%s" , varIndex .Buffer .GetName (), varIndex .SlotName )
433
+ } else if val .Str != nil {
434
+ str [index ] = fmt .Sprintf ("'%s'" , * val .Str )
435
+ } else if val .Number != nil {
436
+ str [index ] = * val .Number
437
+ }
438
+ }
439
+
440
+ p .Writeln ("\t \t print_text \" %s\" " , strings .Join (str , ", " ))
373
441
} else if s .Clear != nil {
374
442
for _ , name := range s .Clear .BufferNames {
375
443
p .Writeln ("\t ~%s>" , name )
376
444
}
377
445
}
378
446
}
379
447
380
- func onlyStrings (values * []* actr.Value ) bool {
381
- for _ , v := range * values {
382
- if v .Var != nil {
383
- return false
384
- }
385
- // v.ID should not be possible because of validation
386
- }
387
-
388
- return true
389
- }
390
-
391
448
// removeWarning will remove the long warning whenever pyactr is run without tkinter.
392
449
func removeWarning (text []byte ) []byte {
393
450
str := string (text )
0 commit comments