owl-basic 0.6.0__py3-none-any.whl

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.
Files changed (69) hide show
  1. owl_basic/__init__.py +3 -0
  2. owl_basic/algorithms.py +29 -0
  3. owl_basic/ast_utils.py +204 -0
  4. owl_basic/basic_visitor.py +55 -0
  5. owl_basic/cfg_vertex.py +65 -0
  6. owl_basic/codegen/__init__.py +0 -0
  7. owl_basic/codegen/clr/__init__.py +0 -0
  8. owl_basic/codegen/clr/cil_visitor.py +1296 -0
  9. owl_basic/codegen/clr/cts.py +56 -0
  10. owl_basic/codegen/clr/emitters.py +94 -0
  11. owl_basic/codegen/clr/generate.py +539 -0
  12. owl_basic/correlation_visitor.py +119 -0
  13. owl_basic/data_visitor.py +62 -0
  14. owl_basic/decoder.py +339 -0
  15. owl_basic/errors.py +22 -0
  16. owl_basic/flow/__init__.py +17 -0
  17. owl_basic/flow/basic_block.py +34 -0
  18. owl_basic/flow/basic_block_identifier.py +66 -0
  19. owl_basic/flow/basic_block_orderer.py +29 -0
  20. owl_basic/flow/connectors.py +19 -0
  21. owl_basic/flow/convert_sub_visitor.py +28 -0
  22. owl_basic/flow/entry_point_locator.py +55 -0
  23. owl_basic/flow/entry_point_visitor.py +48 -0
  24. owl_basic/flow/flow_analysis.py +56 -0
  25. owl_basic/flow/flow_graph_creator.py +14 -0
  26. owl_basic/flow/flowgraph_visitor.py +178 -0
  27. owl_basic/flow/longjump_converter.py +20 -0
  28. owl_basic/flow/longjump_visitor.py +53 -0
  29. owl_basic/flow/subroutine_converter.py +38 -0
  30. owl_basic/flow/traversal.py +110 -0
  31. owl_basic/gml_visitor.py +151 -0
  32. owl_basic/line_mapper.py +43 -0
  33. owl_basic/line_number_visitor.py +65 -0
  34. owl_basic/main.py +381 -0
  35. owl_basic/node.py +21 -0
  36. owl_basic/options.py +22 -0
  37. owl_basic/owltyping/__init__.py +1 -0
  38. owl_basic/owltyping/function_type_inferer.py +50 -0
  39. owl_basic/owltyping/hindley_milner.py +524 -0
  40. owl_basic/owltyping/set_function_type_visitor.py +25 -0
  41. owl_basic/owltyping/type_system.py +220 -0
  42. owl_basic/owltyping/typecheck.py +60 -0
  43. owl_basic/owltyping/typecheck_visitor.py +471 -0
  44. owl_basic/parent_visitor.py +37 -0
  45. owl_basic/process.py +36 -0
  46. owl_basic/separation_visitor.py +98 -0
  47. owl_basic/sigil.py +30 -0
  48. owl_basic/simplify_visitor.py +204 -0
  49. owl_basic/singleton.py +127 -0
  50. owl_basic/source_debugging.py +124 -0
  51. owl_basic/symbol_table_visitor.py +220 -0
  52. owl_basic/symbol_tables.py +195 -0
  53. owl_basic/syntax/__init__.py +0 -0
  54. owl_basic/syntax/ast.py +1081 -0
  55. owl_basic/syntax/ast_meta.py +228 -0
  56. owl_basic/syntax/grammar.py +1972 -0
  57. owl_basic/syntax/lexer.py +943 -0
  58. owl_basic/syntax/parser.py +77 -0
  59. owl_basic/utility.py +26 -0
  60. owl_basic/visitor.py +43 -0
  61. owl_basic/xml_blocks.py +137 -0
  62. owl_basic/xml_visitor.py +101 -0
  63. owl_basic-0.6.0.dist-info/METADATA +37 -0
  64. owl_basic-0.6.0.dist-info/RECORD +69 -0
  65. owl_basic-0.6.0.dist-info/WHEEL +5 -0
  66. owl_basic-0.6.0.dist-info/entry_points.txt +2 -0
  67. owl_basic-0.6.0.dist-info/licenses/LICENSE +21 -0
  68. owl_basic-0.6.0.dist-info/licenses/THIRD-PARTY-NOTICES.md +57 -0
  69. owl_basic-0.6.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,471 @@
1
+ # A visitor for performing type-checking over the Abstract Syntax Tree
2
+
3
+ import logging
4
+
5
+ from owl_basic.visitor import Visitor
6
+ from owl_basic.errors import *
7
+ from owl_basic.utility import underscoresToCamelCase
8
+ from owl_basic.syntax.ast import Cast, Concatenate
9
+ from owl_basic.ast_utils import elideNode
10
+ from owl_basic.owltyping.type_system import (NumericOwlType, ObjectOwlType, IntegerOwlType,
11
+ FloatOwlType, ByteOwlType, PendingOwlType,
12
+ StringOwlType, ArrayOwlType)
13
+ from owl_basic import sigil
14
+
15
+ logger = logging.getLogger('owltyping.typecheck_visitor')
16
+
17
+ class TypecheckVisitor(Visitor):
18
+ """
19
+ AST visitor for determining the actual type of each node
20
+ """
21
+ def __init__(self, entry_points):
22
+ '''
23
+ :param entry_points: A dictionary of entry_point names to AstStatements.
24
+ '''
25
+ self.__entry_points = entry_points
26
+ pass
27
+
28
+ def visit(self, node):
29
+ "Override visit to allow safe traversal of lists"
30
+ if isinstance(node, list):
31
+ for elem in node:
32
+ self.visit(elem)
33
+ else:
34
+ super(TypecheckVisitor, self).visit(node)
35
+
36
+ def visitAstNode(self, node):
37
+ node.forEachChild(self.visit)
38
+ self.checkSignature(node) # TODO: What about return types
39
+ self.insertNumericCasts(node)
40
+
41
+ def visitAstStatement(self, statement):
42
+ "Generic visitor for simple statements"
43
+ # TODO: If this is the same as above, it can be removed
44
+ statement.forEachChild(self.visit)
45
+ if not self.checkSignature(statement):
46
+ return
47
+ self.insertNumericCasts(statement)
48
+
49
+ def visitAssignment(self, assignment):
50
+ # Determine the actual type of the lValue and rValue
51
+
52
+ self.visit(assignment.lValue)
53
+ self.visit(assignment.rValue)
54
+ if isinstance(assignment.rValue, list):
55
+ # Deal with L-values which are lists
56
+ if assignment.lValue.actualType.isA(ArrayOwlType):
57
+ for item in assignment.rValue:
58
+ self.checkAndInsertRValueCast(item, assignment.lValue.actualType._getElementType())
59
+ else:
60
+ message = "List is only assignable to an array"
61
+ self.typeMismatch(assignment, message)
62
+ else:
63
+ logger.debug(assignment.lValue)
64
+ self.checkAndInsertRValueCast(assignment.rValue, assignment.lValue.actualType)
65
+
66
+ def visitForToStep(self, for_stmt):
67
+ '''
68
+ Visit FOR N=1 TO 10 STEP 2
69
+ '''
70
+ self.visit(for_stmt.identifier)
71
+ self.visit(for_stmt.first)
72
+ self.visit(for_stmt.last)
73
+ self.visit(for_stmt.step)
74
+ counter_type = for_stmt.identifier.actualType
75
+ self.checkAndInsertRValueCast(for_stmt.first, counter_type)
76
+ self.checkAndInsertRValueCast(for_stmt.last, counter_type)
77
+ self.checkAndInsertRValueCast(for_stmt.step, counter_type)
78
+
79
+ def visitBinaryNumericOperator(self, operator):
80
+ '''
81
+ Visit - * / ^
82
+ '''
83
+ self.visit(operator.lhs)
84
+ self.visit(operator.rhs)
85
+ # TODO: Propagate pending types
86
+ self.determineNumericResultType(operator)
87
+ self.promoteNumericOperands(operator)
88
+
89
+ def visitPlus(self, plus):
90
+ '''
91
+ Specialization of visitBinaryNumericOperator to handle string concatenation
92
+ '''
93
+ # Determine the actual type of sub-expressions
94
+ self.visit(plus.lhs)
95
+ self.visit(plus.rhs)
96
+
97
+ # If this is a string concatenation, convert the node and re-visit
98
+ if plus.lhs.actualType == StringOwlType() and plus.rhs.actualType == StringOwlType():
99
+ # TODO: Create a function in ast_utils to replace a node
100
+ concat = Concatenate(lhs = plus.lhs, rhs = plus.rhs)
101
+ concat.lhs.parent = concat
102
+ concat.rhs.parent = concat
103
+ concat.parent = plus.parent
104
+ plus.parent.setProperty(concat, plus.parent_property, plus.parent_index)
105
+ self.visit(concat)
106
+ return
107
+
108
+ self.determineNumericResultType(plus)
109
+ self.promoteNumericOperands(plus)
110
+
111
+ def visitRelationalOperator(self, operator):
112
+ '''
113
+ Visit = <> < > <= >=
114
+ '''
115
+ self.visit(operator.lhs)
116
+ self.visit(operator.rhs)
117
+
118
+ if not (operator.lhs.actualType.isConvertibleTo(operator.rhs.actualType) or operator.rhs.actualType.isConvertibleTo(operator.lhs.actualType)):
119
+ message = "Cannot compare %s with %s using operator %s" % (operator.lhs.actualType.__doc__, operator.rhs.actualType.__doc__, operator.__doc__)
120
+ self.typeMismatch(operator, message)
121
+
122
+ self.promoteNumericOperands(operator)
123
+ operator.actualType = IntegerOwlType()
124
+
125
+ def visitArray(self, array):
126
+ # Decode the variable name sigil into the actual type
127
+ # The sigils are one of [$%&~]
128
+ array.actualType = sigil.identifierToType(array.identifier)
129
+
130
+ def visitVariable(self, variable):
131
+ # Decode the variable name sigil into the actual type
132
+ # The sigils are one of [$%&~]
133
+ variable.actualType = sigil.identifierToType(variable.identifier)
134
+
135
+ def visitIndexer(self, indexer):
136
+ # Decode the variable name sigil into the actual type
137
+ # The sigils are one of [$%&~]
138
+ indexer.actualType = sigil.identifierToType(indexer.identifier[:-1])
139
+ for index in indexer.indices:
140
+ self.visit(index)
141
+ self.checkAndInsertRValueCast(index, IntegerOwlType())
142
+
143
+ def visitIf(self, iff):
144
+ # TODO: Does this do anything that visitAstNode doesn't do?
145
+ self.visit(iff.condition)
146
+ self.visit(iff.trueClause)
147
+ self.visit(iff.falseClause)
148
+ condition_formal_type = iff.child_infos['condition'].formalType
149
+ if iff.condition.actualType.isConvertibleTo(condition_formal_type):
150
+ self.insertCast(iff.condition, iff.condition.actualType, condition_formal_type)
151
+ else:
152
+ self.typeMismatch(iff, "Conditional expression must be convertible to %s." % condition_formal_type.__doc__)
153
+
154
+ def visitOnGoto(self, ongoto):
155
+ # TODO: Does this do anything that visitAstNode doesn't do?
156
+ self.visit(ongoto.switch)
157
+ switch_formal_type = ongoto.child_infos['switch'].formalType
158
+ if ongoto.switch.actualType.isConvertibleTo(switch_formal_type):
159
+ self.insertCast(ongoto.switch, ongoto.switch.actualType, switch_formal_type)
160
+ else:
161
+ self.typeMismatch(ongoto, "Selector expression must be convertible to %s" % switch_formal_type.__doc__)
162
+
163
+ for target in ongoto.targetLogicalLines:
164
+ self.visit(target)
165
+ if target.actualType.isConvertibleTo(IntegerOwlType()):
166
+ self.insertCast(target, target.actualType, IntegerOwlType())
167
+ else:
168
+ self.typeMismatch(ongoto, "Target expressions must be convertible to Integer")
169
+
170
+ self.visit(ongoto.outOfRangeClause)
171
+
172
+ def visitUnaryNumericOperator(self, operator):
173
+ self.visit(operator.factor)
174
+ if not self.checkSignature(operator):
175
+ return
176
+ operator.actualType = operator.factor.actualType
177
+
178
+ def visitBinaryIntegerOperator(self, operator):
179
+ self.visit(operator.lhs)
180
+ self.visit(operator.rhs)
181
+ if not self.checkSignature(operator):
182
+ return
183
+ # TODO: Pull this out into a function
184
+ if operator.lhs.actualType != IntegerOwlType():
185
+ self.insertCast(operator.lhs, source=operator.lhs.actualType, target=IntegerOwlType())
186
+ if operator.rhs.actualType != IntegerOwlType():
187
+ self.insertCast(operator.rhs, source=operator.rhs.actualType, target=IntegerOwlType())
188
+
189
+ def visitDyadicIndirection(self, dyadic):
190
+ self.visit(dyadic.base)
191
+ self.visit(dyadic.offset)
192
+ if not self.checkSignature(dyadic):
193
+ # TODO: Error?
194
+ return
195
+ self.insertNumericCasts(dyadic)
196
+
197
+
198
+ def visitUnaryNumericFunc(self, func):
199
+ self.visit(func.factor)
200
+ if not self.checkSignature(func):
201
+ # TODO: Error?
202
+ return
203
+ if func.factor.actualType == IntegerOwlType():
204
+ self.insertCast(func.factor, source=func.factor.actualType, target=FloatOwlType())
205
+
206
+ def visitAbsFunc(self, abs):
207
+ '''
208
+ Check that the argument is numeric. If so, propagate the type of the argument to
209
+ the type of the ABS function.
210
+ '''
211
+ self.visit(abs.factor)
212
+ if not self.checkSignature(abs):
213
+ # TODO: Error?
214
+ return
215
+ abs.actualType = abs.factor.actualType
216
+
217
+ def visitIntFunc(self, func):
218
+ self.visit(func.factor)
219
+ if not self.checkSignature(func):
220
+ # TODO: Error?
221
+ return
222
+ if func.factor.actualType == IntegerOwlType():
223
+ elideNode(func)
224
+
225
+ def visitNot(self, operator):
226
+ self.visit(operator.factor)
227
+ if not self.checkSignature(operator):
228
+ # TODO: Error?
229
+ return
230
+ if operator.factor.actualType != IntegerOwlType():
231
+ self.insertCast(operator.factor, source = operator.factor.actualType, target=IntegerOwlType())
232
+
233
+ def visitInstr(self, instr):
234
+ self.visit(instr.source)
235
+ self.visit(instr.subString)
236
+ self.visit(instr.startPosition)
237
+ if not self.checkSignature(instr):
238
+ # TODO: Error?
239
+ return
240
+ if instr.startPosition is not None and instr.startPosition.actualType != IntegerOwlType():
241
+ self.insertCast(instr.startPosition, source = instr.startPosition.actualType, target = IntegerOwlType())
242
+
243
+ def visitReadFunc(self, read_func):
244
+ # Infer the type of ReadFunc in x = ReadFunc from the type of x
245
+ # This depends on the type of the lValue of the assignment having been
246
+ # determined previously, and assumes that the parent of ReadFunc is always
247
+ # an Assignment
248
+ read_func.actualType = read_func.parent.lValue.actualType
249
+
250
+ def visitUserFunc(self, user_func):
251
+ if user_func.actualParameters:
252
+ self.visit(user_func.actualParameters)
253
+ # TODO: Check argument types against Procedure
254
+ # TODO: This needs different code for internal and external linkage
255
+ self.checkActualParameters(user_func)
256
+ user_func.actualType = PendingOwlType()
257
+
258
+ def visitCallProcedure(self, proc):
259
+ if proc.actualParameters:
260
+ self.visit(proc.actualParameters)
261
+ # TODO: Check argument types against Procedure
262
+ # TODO: This needs different code for internal and external linkage
263
+ self.checkActualParameters(proc)
264
+
265
+ def checkActualParameters(self, call):
266
+ '''
267
+ Check the actualParameters of 'call' against the formal parameters
268
+ of the callable.
269
+ :param call: An AstNode with an actualParameters property and a name property
270
+ :returns: True is the actual parameter types are compatible with the formal parameter types, otherwise False
271
+ '''
272
+ # Lookup the callable and retrieve its formal parameters
273
+ if call.name in self.__entry_points:
274
+ callable = self.__entry_points[call.name]
275
+ n = 1
276
+ for actual, formal in zip(call.actualParameters,
277
+ callable.formalParameters.arguments):
278
+ if formal.argument.actualType is None:
279
+ # There is no type information on the callable yet, so visit it
280
+ self.visit(callable)
281
+ if actual.actualType.isConvertibleTo(formal.argument.actualType):
282
+ self.insertCast(actual, source=actual.actualType, target=formal.argument.actualType)
283
+ else:
284
+ message = "Cannot pass actual parameter number %d of type %s to formal parameter type of %s" % (n, actual.actualType.__doc__, formal.argument.actualType.__doc__)
285
+ self.typeMismatch(call, message)
286
+ n += 1
287
+ else:
288
+ error("Did not find entry point for %s" % call.name)
289
+
290
+ # Check each formal parameter against an actual parameter
291
+ pass
292
+
293
+ def determineNumericResultType(self, operator):
294
+ if operator.lhs.actualType == PendingOwlType() or operator.rhs.actualType == PendingOwlType():
295
+ operator.actualType = PendingOwlType()
296
+ return
297
+
298
+ if not self.checkSignature(operator):
299
+ # TODO: Error?
300
+ return
301
+
302
+ def opTypes(lhs_type, rhs_type):
303
+ return operator.lhs.actualType.isA(lhs_type) and operator.rhs.actualType.isA(rhs_type)
304
+
305
+ if opTypes(ObjectOwlType(), NumericOwlType()) : operator.actualType = FloatOwlType()
306
+ elif opTypes(NumericOwlType(), ObjectOwlType()) : operator.actualType = FloatOwlType()
307
+ elif opTypes(IntegerOwlType(), FloatOwlType()) : operator.actualType = FloatOwlType()
308
+ elif opTypes(FloatOwlType(), IntegerOwlType()) : operator.actualType = FloatOwlType()
309
+ elif operator.lhs.actualType == operator.rhs.actualType:
310
+ operator.actualType = operator.lhs.actualType
311
+ else:
312
+ message = "Cannot apply operator %s to operands of type of %s and %s" % (operator.__doc__, operator.lhs.actualType.__doc__, operator.rhs.actualType.__doc__)
313
+ self.typeMismatch(operator, message)
314
+
315
+ def promoteNumericOperands(self, operator):
316
+ '''
317
+ Given a binary operator with lhs and rhs operands, if the operands are of
318
+ NumericType, insert casts as necessary to promote operands as necessary to
319
+ FloatType from IntegerType in the case of mixed operand types.
320
+ e.g. Int op Int => Int op Int
321
+ Float op Float => Float op Float
322
+ Float op Int => Float op Float
323
+ Int op FLoat => Float op Float
324
+ '''
325
+ # TODO: Handle byte types - use the precision of the types to decide how to promote...
326
+ def opTypes(lhs_type, rhs_type):
327
+ return operator.lhs.actualType.isA(lhs_type) and operator.rhs.actualType.isA(rhs_type)
328
+
329
+ if opTypes(IntegerOwlType(), FloatOwlType()):
330
+ self.insertCast(operator.lhs, source=IntegerOwlType(), target=FloatOwlType())
331
+ elif opTypes(ByteOwlType(), FloatOwlType()):
332
+ self.insertCast(operator.lhs, source=ByteOwlType(), target=FloatOwlType())
333
+ elif opTypes(FloatOwlType(), IntegerOwlType()):
334
+ self.insertCast(operator.rhs, source=IntegerOwlType(), target=FloatOwlType())
335
+ elif opTypes(FloatOwlType(), ByteOwlType()):
336
+ self.insertCast(operator.rhs, source=ByteOwlType(), target=FloatOwlType())
337
+
338
+ def insertNumericCasts(self, node):
339
+ """
340
+ Where an Integer value is being passed to a parameter of Numeric type,
341
+ insert an Integer->Float cast operation.
342
+ """
343
+ for name, child in node.children.items():
344
+ if child is not None:
345
+ if isinstance(child, list):
346
+ formal_type = node.child_infos[name][0].formalType
347
+ if formal_type is not None:
348
+ if formal_type.isA(NumericOwlType()):
349
+ for subchild in child:
350
+ self.insertCast(subchild, source=subchild.actualType, target=formal_type)
351
+ else:
352
+ sys.stderr.write("Compiler construction: Missing formal type information on %s, %s\n" % (node, name))
353
+ else:
354
+ formal_type = node.child_infos[name].formalType
355
+ if formal_type is not None:
356
+ if formal_type.isA(NumericOwlType()):
357
+ self.insertCast(child, source=child.actualType, target=formal_type)
358
+ else:
359
+ sys.stderr.write("Compiler construction: Missing formal type information on %s, %s\n" % (node, name))
360
+
361
+ def insertCast(self, child, source, target):
362
+ """Wrap the supplied node in a Cast node from source type to target type"""
363
+
364
+ if source is target:
365
+ return
366
+
367
+ if source.isA(PendingOwlType()):
368
+ logging.debug("Ignoring request to insert cast from PendingType")
369
+ return
370
+
371
+ if source.isA(target):
372
+ # Implicit conversion allowed, no cast needed
373
+ logging.debug("%s implicitly converted to %s" % (source, target))
374
+ return
375
+
376
+ if source.isA(NumericOwlType()) and target.isA(NumericOwlType()):
377
+ if target.bitsIntegerPrecision() < source.bitsIntegerPrecision():
378
+ message = "of %s to %s, possible loss of data" % (source.__doc__, target.__doc__)
379
+ self.castWarning(child, message)
380
+
381
+ parent = child.parent
382
+ parent_property = child.parent_property
383
+ parent_index = child.parent_index
384
+ cast = Cast(sourceType=source, targetType=target, value=child)
385
+ cast.lineNum = parent.lineNum
386
+ # TODO: Tidy up this redundancy!
387
+ cast.formalType = cast.targetType
388
+ cast.actualType = cast.formalType
389
+ cast.parent = parent
390
+ cast.parent_property = parent_property
391
+ cast.parent_index = parent_index
392
+ cast.value.parent = cast
393
+ cast.value.parent_property = "value"
394
+ cast.value.parent_index = None
395
+ parent.setProperty(cast, parent_property, parent_index)
396
+
397
+ def checkSignature(self, node):
398
+ """
399
+ Check the actualType of each child node against the formalType of each
400
+ child node and determine if they are of compatible type. For example,
401
+ IntegerType is compatible with NumericType, and NumericType is compatible
402
+ with ScalarType, but StringType is not compatible with NumericType.
403
+ """
404
+ result = True
405
+ for name, info in node.child_infos.items():
406
+ if isinstance(info, list):
407
+ info = info[0]
408
+ formal_type = info.formalType
409
+ child_nodes = getattr(node, underscoresToCamelCase(name))
410
+ if child_nodes is not None:
411
+ for child_node in child_nodes:
412
+ child_result = self.checkType(node, child_node, formal_type, info)
413
+ result = result and child_result
414
+ else:
415
+ formal_type = info.formalType
416
+ child_node = getattr(node, underscoresToCamelCase(name))
417
+ child_result = self.checkType(node, child_node, formal_type, info)
418
+ result = result and child_result
419
+ return result
420
+
421
+ def checkType(self, node, child_node, formal_type, info):
422
+ """
423
+ Checks that child_node of node is of formal_type.
424
+ """
425
+ if child_node is not None:
426
+ logger.debug("child_node = %s" % child_node)
427
+ actual_type = child_node.actualType
428
+ logger.debug("formal_type = %s" % formal_type)
429
+ logger.debug("actual_type = %s" % actual_type)
430
+ if formal_type is not None: # None types do not need to be checked
431
+ if actual_type is not None:
432
+ if not actual_type.isConvertibleTo(formal_type):
433
+ message = "%s of %s is incompatible with supplied parameter of type %s at line %s" % (info.description, node.description, actual_type.__doc__, node.lineNum)
434
+ self.typeMismatch(node, message)
435
+ return False
436
+ else:
437
+
438
+ message = "%s of %s has no type information" % (info.description, node.description)
439
+ self.typeError(node, message)
440
+ return False
441
+ return True
442
+
443
+ def checkAndInsertRValueCast(self, r_value, target_type):
444
+ '''
445
+ Check the value of the given r_value for compatibility with the target_type
446
+ and insert casts as necessary, or raise an error if no conversion is possible.
447
+ :param r_value: The r_value Node which is to be type checked.
448
+ :param target_type: The type to which the r_value should be converted.
449
+ '''
450
+ assert target_type is not None
451
+ if r_value is not None: # TODO Could this be an assert?
452
+ if r_value.actualType.isConvertibleTo(target_type):
453
+ if r_value.actualType is not target_type:
454
+ self.insertCast(r_value, r_value.actualType, target_type)
455
+ else:
456
+ message = "Cannot assign %s to %s" % (r_value.actualType.__doc__, target_type.__doc__)
457
+ self.typeMismatch(r_value, message)
458
+
459
+ def typeError(self, node, message):
460
+ message = "%s at line %d" % (message, node.lineNum)
461
+ internal(message)
462
+
463
+ def typeMismatch(self, node, message):
464
+ message = "Type mismatch: %s at line %s" % (message, node.lineNum)
465
+ error(message)
466
+
467
+ def castWarning(self, node, message):
468
+ message = "Implicit conversion %s at line %s" % (message, node.lineNum)
469
+ warning(message)
470
+
471
+
@@ -0,0 +1,37 @@
1
+ import logging
2
+
3
+ from owl_basic.utility import underscoresToCamelCase
4
+ from owl_basic.visitor import Visitor
5
+
6
+ class ParentVisitor(Visitor):
7
+ """
8
+ Visitor setting and verifying existing parent references on each AST node
9
+ """
10
+ def __init__(self):
11
+ pass
12
+
13
+ def visitAstNode(self, node):
14
+ # TODO: This partial function application doesn't work correctly with IronPython
15
+ #node.forEachChild(partial(self._setParent, parent = node))
16
+
17
+ # TODO: Inlining the forEachChild function works, however...
18
+ for name, child in node.children.items():
19
+ if isinstance(child, list):
20
+ for index, subchild in enumerate(child):
21
+ self._setParent(node, subchild, name, index)
22
+ else:
23
+ self._setParent(node, child, name)
24
+
25
+ node.forEachChild(self.visit)
26
+
27
+ def _setParent(self, parent, node, name, index=None):
28
+ """
29
+ Given a reference to the parent, and the name of a child value, create the
30
+ property name and attach it, together with the reference to the parent, to
31
+ the supplied node.
32
+ """
33
+ if node is not None:
34
+ node.parent = parent
35
+ node.parent_property = underscoresToCamelCase(name) # The property through which the parent can be accessed.
36
+ node.parent_index = index
37
+
owl_basic/process.py ADDED
@@ -0,0 +1,36 @@
1
+ '''Tools for subprocesses in IronPython'''
2
+ import logging
3
+
4
+ __author__ = 'rjs'
5
+
6
+ def execute(name, *args):
7
+ '''Execute an external process, and wait for it to complete.
8
+
9
+ Args:
10
+ name: The path name to the executable.
11
+
12
+ *args: Remaining positional arguments are stringified and passed in
13
+ order as command line arguments to the process.
14
+
15
+ Returns:
16
+ A 3-tuple containing an integer exit code and stdout and stderr as
17
+ strings.
18
+ '''
19
+ logging.debug("process.execute(%s)" % name)
20
+ from System.Diagnostics import Process
21
+ p = Process()
22
+ p.StartInfo.FileName = name
23
+ p.StartInfo.Arguments = ' '.join(map(str, args))
24
+ p.StartInfo.CreateNoWindow = True
25
+ p.StartInfo.UseShellExecute = False
26
+ p.StartInfo.RedirectStandardInput = True
27
+ p.StartInfo.RedirectStandardOutput = True
28
+ p.StartInfo.RedirectStandardError = True
29
+ p.Start()
30
+ p.WaitForExit()
31
+ stdout = p.StandardOutput.ReadToEnd()
32
+ stderr = p.StandardError.ReadToEnd()
33
+ exit_code = p.ExitCode
34
+ p.Close()
35
+ return exit_code, stdout, stderr
36
+
@@ -0,0 +1,98 @@
1
+ # A visitor implementation that creates an XML representation of the abstract syntax tree
2
+
3
+ from owl_basic.visitor import Visitor
4
+ from owl_basic.syntax.ast import StatementList, ScalarAssignment, Next, VariableList, Read, ReadFunc, WritableList
5
+ from owl_basic.ast_utils import replaceStatement, insertStatementBefore, removeStatement
6
+
7
+ class SeparationVisitor(Visitor):
8
+ """
9
+ AST visitor for separating complex nodes into multiple simpler nodes
10
+ """
11
+
12
+ def visitAstNode(self, node):
13
+ node.forEachChild(self.visit)
14
+
15
+ def visitDim(self, dim):
16
+ """
17
+ Split DIM i%(1), j%(2), k% 3 statements into separate AllocateArray and AllocateBlock
18
+ statement nodes.
19
+ """
20
+ #self.visit(next.identifiers)
21
+ statement_list = StatementList()
22
+ statement_list.parent = dim.parent
23
+ statement_list.parent_property = dim.parent_property
24
+ statement_list.parent_index = dim.parent_index
25
+ statement_list.statements = []
26
+
27
+ for allocator in dim.items.items:
28
+ allocator.parent = statement_list
29
+ allocator.parent_property = 'statements'
30
+ allocator.parent_index = len(statement_list.statements)
31
+ allocator.lineNum = dim.lineNum
32
+ statement_list.append(allocator)
33
+
34
+ getattr(dim.parent, dim.parent_property)[dim.parent_index] = statement_list
35
+
36
+ def visitNext(self, next):
37
+ """
38
+ Split NEXT i%, j%, k% statements into NEXT i% : NEXT j% : NEXT k%
39
+ """
40
+ self.visit(next.identifiers)
41
+ statement_list = StatementList()
42
+ statement_list.parent = next.parent
43
+ statement_list.parent_property = next.parent_property
44
+ statement_list.parent_index = next.parent_index
45
+ statement_list.statements = []
46
+
47
+ for identifier in next.identifiers.variables:
48
+ new_next = Next()
49
+ new_next.parent = statement_list
50
+ new_next.parent_property = 'statements'
51
+ new_next.parent_index = len(statement_list.statements)
52
+ new_next.lineNum = next.lineNum
53
+ statement_list.append(new_next)
54
+
55
+ variable_list = VariableList()
56
+ variable_list.parent = new_next
57
+ variable_list.parent_property = 'identifiers'
58
+ new_next.identifiers = variable_list
59
+
60
+ variable_list.variables = [identifier] if identifier is not None else []
61
+
62
+ getattr(next.parent, next.parent_property)[next.parent_index] = statement_list
63
+
64
+ # TODO: Much of this code can be factored out of this method and the above one
65
+ def visitRead(self, read):
66
+ """
67
+ Split READ A, B, C statements into assignments A = READ : B = READ : C = READ
68
+ where READ becomes a function.
69
+ """
70
+
71
+ # TODO Split READ A, B, C statements into READ A : READ B : READ C
72
+ self.visit(read.writables)
73
+ statement_list = StatementList()
74
+ statement_list.parent = read.parent
75
+ statement_list.parent_property = read.parent_property
76
+ statement_list.parent_index = read.parent_index
77
+ statement_list.statements = []
78
+
79
+ for writable in read.writables.writables:
80
+ read_func = ReadFunc()
81
+ new_assignment = ScalarAssignment(lValue=writable, rValue=read_func)
82
+
83
+ writable.parent = new_assignment
84
+ writable.parent_property = 'lValue'
85
+ writable.lineNum = read.lineNum
86
+
87
+ read_func.parent = new_assignment
88
+ read_func.parent_property = 'rValue'
89
+ read_func.lineNum = read.lineNum
90
+
91
+ new_assignment.parent = statement_list
92
+ new_assignment.parent_property = 'statements'
93
+ new_assignment.parent_index = len(statement_list.statements)
94
+ new_assignment.lineNum = read.lineNum
95
+
96
+ statement_list.append(new_assignment)
97
+
98
+ getattr(read.parent, read.parent_property)[read.parent_index] = statement_list
owl_basic/sigil.py ADDED
@@ -0,0 +1,30 @@
1
+ from owl_basic.owltyping.type_system import (StringOwlType, IntegerOwlType, ByteOwlType, ObjectOwlType,
2
+ StringArrayOwlType, IntegerArrayOwlType, ByteArrayOwlType,
3
+ ObjectArrayOwlType, FloatArrayOwlType, FloatOwlType)
4
+
5
+ def identifierToType(identifier):
6
+ """
7
+ Convert an variable name identifier to a type
8
+ """
9
+ sigil = identifier[-1]
10
+ if sigil == '$':
11
+ return StringOwlType()
12
+ elif sigil == '%':
13
+ return IntegerOwlType()
14
+ elif sigil == '&':
15
+ return ByteOwlType()
16
+ elif sigil == '~':
17
+ return ObjectOwlType()
18
+ elif sigil == '(':
19
+ sigil = identifier[-2:-1]
20
+ if sigil == '$':
21
+ return StringArrayOwlType()
22
+ elif sigil == '%':
23
+ return IntegerArrayOwlType()
24
+ elif sigil == '&':
25
+ return ByteArrayOwlType()
26
+ elif sigil == '~':
27
+ return ObjectArrayOwlType()
28
+ else:
29
+ return FloatArrayOwlType()
30
+ return FloatOwlType()