def check_shortcut1(): x = parse_wrap_check('requires x, y, z [Nat] "comment"', Syntax.res_shortcut5) rnames = [_.value for _ in get_odd_ops(unwrap_list(x.rnames))] assert_equal(rnames, ['x','y','z']) s = parse_wrap_check('provides x, y, z [Nat] "comment"', Syntax.fun_shortcut5) rnames = [_.value for _ in get_odd_ops(unwrap_list(s.fnames))] assert_equal(rnames, ['x','y','z'])
def check_shortcut1(): x = parse_wrap_check('requires x, y, z [Nat] "comment"', Syntax.res_shortcut5) rnames = [_.value for _ in get_odd_ops(unwrap_list(x.rnames))] assert_equal(rnames, ['x', 'y', 'z']) s = parse_wrap_check('provides x, y, z [Nat] "comment"', Syntax.fun_shortcut5) rnames = [_.value for _ in get_odd_ops(unwrap_list(s.fnames))] assert_equal(rnames, ['x', 'y', 'z'])
def infer_types_of_variables(line_exprs, context): constants = set() # These are the resources and functions defined by the model resources = set() functions = set() variables = set() # These are new derived resources and functions deriv_resources = set() deriv_functions = set() def found_fname(fname): check_isinstance(fname, CDP.FName) infer_debug('found fname: %s' % fname.value) _ = fname.value if _ in functions: msg = 'Repeated function %r.' % _ raise DPSemanticError(msg, where=fname.where) if _ in deriv_resources: msg = 'The name %r is already used.' % _ raise DPSemanticError(msg, where=fname.where) if _ in variables: msg = 'The name %r is already used by a variable.' % _ raise DPSemanticError(msg, where=fname.where) functions.add(fname.value) def found_rname(rname): check_isinstance(rname, CDP.RName) _ = rname.value if _ in resources: msg = 'Repeated resource %r.' % _ raise DPSemanticError(msg, where=rname.where) if _ in deriv_resources: msg = 'The name %r is already used.' % _ raise DPSemanticError(msg, where=rname.where) if _ in variables: msg = 'The name %r is already used by a variable.' % _ raise DPSemanticError(msg, where=rname.where) resources.add(rname.value) def found_cname(cname): check_isinstance(cname, CDP.CName) infer_debug('found constant: %s' % cname.value) if cname.value in constants: msg = 'Duplicated constants?' raise DPInternalError(msg, where=cname.where) constants.add(cname.value) def found_vname(vname): check_isinstance(vname, CDP.VName) # print('found variable: %s' % vname.value) # TODO: check not already exists variables.add(vname.value) def is_constant(vref): check_isinstance(vref, CDP.VariableRef) it_is = vref.name in constants # if it_is: # print(' [yes, %r is constant]' % vref.name) return it_is def check_all_constant(rvalue): """ Checks that all VariableRefs are constant """ class Tmp: verified = True def visit_to_check(x, parents): # @UnusedVariable assert isnamedtuplewhere(x), type(x) not_allowed = CDP.FName, CDP.RName, CDP.UncertainRes, CDP.UncertainFun if isinstance(x, not_allowed): Tmp.verified = False if isinstance(x, CDP.VariableRef): if not is_constant(x): Tmp.verified = False else: pass return x namedtuple_visitor_ext(rvalue, visit_to_check) return Tmp.verified UNDEFINED, FVALUE, RVALUE, CONFLICTING, EITHER =\ 'undefined', 'fvalue', 'rvalue', 'conflicting', 'either' def get_flavour(xx): class Flavors: fvalue = set() rvalue = set() undefined = set() either = set() def visit_to_check2(x): # print(' visit_to_check2(%s) %s %s' % (nt_string(x), type(x).__name__, x)) if isinstance(x, CDP.Resource): l = x.dp.value + '.' + x.s.value Flavors.rvalue.add(l) elif isinstance(x, CDP.Function): l = x.dp.value + '.' + x.s.value Flavors.fvalue.add(l) elif isinstance(x, CDP.VName): Flavors.either.add(x.value) elif isinstance(x, CDP.VariableRef): if x.name in functions and x.name in resources: # ambiguous Flavors.either.add(x.name) # not other flavor elif x.name in functions or x.name in deriv_resources: # print('%r contributes to Flavors.rvalue' % x.name) Flavors.rvalue.add(x.name) # not other flavor elif x.name in resources or x.name in deriv_functions: # print('%r contributes to Flavors.fvalue' % x.name) Flavors.fvalue.add(x.name) # not other flavor elif x.name in variables: # print('%r contributes to Flavors.either' % x.name) Flavors.either.add(x.name) elif x.name in constants: # print('%r constant contributes to Flavors.either' % x.name) Flavors.either.add(x.name) else: msg = 'Could not resolve reference to %r.' % x.name raise DPSemanticError(msg, where=x.where) namedtuple_visitor_only_visit(xx, visit_to_check2) infer_debug('Results of %r: rv %s; fv %s; undef %s; either %s' % ( nt_string(rvalue), Flavors.rvalue, Flavors.fvalue, Flavors.undefined, Flavors.either)) if Flavors.rvalue and Flavors.fvalue: return CONFLICTING if Flavors.undefined: return UNDEFINED if Flavors.rvalue and Flavors.fvalue: return CONFLICTING if not Flavors.rvalue and Flavors.fvalue: return FVALUE if not Flavors.fvalue and Flavors.rvalue: return RVALUE return EITHER def can_be_treated_as_rvalue(x): res = get_flavour(x) infer_debug('Results of %r -> %s' % (nt_string(x), res)) return res in [RVALUE, EITHER] def can_be_treated_as_fvalue(x): res = get_flavour(x) infer_debug('Results of %r -> %s' % (nt_string(x), res)) return res in [FVALUE, EITHER] for i, l in enumerate(line_exprs): infer_debug('\n\n--- line %r (%s)' % ( l.where.string[l.where.character:l.where.character_end], type(l))) from .syntax import Syntax # mark functions, resources, variables, and constants if isinstance(l, (CDP.FunStatement, CDP.FunShortcut1, CDP.FunShortcut2)): found_fname(l.fname) elif isinstance(l, (CDP.ResStatement, CDP.ResShortcut1, CDP.ResShortcut2)): found_rname(l.rname) elif isinstance(l, (#CDP.ResShortcut4, CDP.ResShortcut5, CDP.ResShortcut1m)): for _ in get_odd_ops(unwrap_list(l.rnames)): found_rname(_) elif isinstance(l, (#CDP.FunShortcut4, CDP.FunShortcut5, CDP.FunShortcut1m)): for _ in get_odd_ops(unwrap_list(l.fnames)): found_fname(_) if isinstance(l, CDP.SetNameConstant): found_cname(l.name) if isinstance(l, CDP.VarStatement): for _ in get_odd_ops(unwrap_list(l.vnames)): found_vname(_) if isinstance(l, CDP.FunShortcut2): pass elif isinstance(l, CDP.ResShortcut2): rvalue = l.rvalue elif isinstance(l, CDP.SetNameRValue): # first of all, chech if all the references on the right # are constant. rvalue = l.right_side all_constant = check_all_constant(rvalue) if all_constant: # This can become simply a constant infer_debug('The value %r can be recognized as constant' % str(l.name.value)) constants.add(l.name.value) else: # This is a special case, because it is the place # where the syntax is ambiguous. # # x = Nat: 1 + r # # could be interpreted with r being a functionality # or a resource. # # By default it is parsed as SetNameRValue, and so we get here. # try: w = l.where s = w.string[w.character:w.character_end] from .parse_actions import parse_wrap alt0 = parse_wrap(Syntax.setname_fvalue, s)[0] assert isinstance(alt0, CDP.SetNameFValue), alt0 alt = move_where(alt0, w.string, w.character, w.character_end) except DPSyntaxError as _: #print "No, it does not parse: %s" % traceback.format_exc(e) alt = None if alt: #logger.info('Ambiguous') # both are feasible; check covariance one_ok = can_be_treated_as_rvalue(l.right_side) two_ok = can_be_treated_as_fvalue(alt.right_side) # print('can be rvalue %s fvalue %s' % (one_ok, two_ok)) if (not one_ok) and (not two_ok): msg = ('This expression cannot be interpreted either' ' as a functionality or as a resource.') raise DPSemanticError(msg, where=l.right_side.where) if one_ok and two_ok: if isinstance(l.right_side, CDP.UncertainRes): msg = ('This expression is ambiguous. I will interpret it as a resource.') warn_language(l.right_side, MCDPWarnings.LANGUAGE_AMBIGUOS_EXPRESSION, msg, context=context) deriv_resources.add(l.name.value) else: msg = ('This expression is truly ambiguous, and I cannot ' 'judge whether it is a functionality or resource.') e = DPSemanticError(msg, where=l.right_side.where) raise e elif one_ok and not two_ok: # we have concluded this can be a rvalue #print('setting %r as deriv_resources' % l.name.value) deriv_resources.add(l.name.value) elif two_ok and not one_ok: #print('setting %r as deriv_functions' % l.name.value) deriv_functions.add(l.name.value) # we replace the line line_exprs[i] = alt else: # print('setting %r as deriv_resources' % l.name.value) deriv_resources.add(l.name.value) elif isinstance(l, CDP.SetNameFValue): deriv_functions.add(l.name.value) elif isinstance(l, CDP.SetNameConstant): pass elif isinstance(l, (CDP.FunStatement, CDP.ResStatement)): pass else: # print('line %s' % type(l).__name__) pass refine0 = lambda x, parents: refine(x, parents, constants, resources, functions, variables, deriv_resources, deriv_functions, context=context) line_exprs = [namedtuple_visitor_ext(_, refine0) for _ in line_exprs] # for l in line_exprs: # print recursive_print(l) return line_exprs
def infer_types_of_variables(line_exprs, context, si): check_isinstance(si, SemanticInformation) # These are the resources and functions defined by the model resources = set() functions = set() variables = set() # These are new derived resources and functions deriv_resources = set() deriv_functions = set() def found_fname(fname): if isinstance(fname, CDP.Placeholder): return check_isinstance(fname, CDP.FName) infer_debug('found fname: %s' % fname.value) _ = fname.value if _ in functions: msg = 'Repeated function %r.' % _ raise DPSemanticError(msg, where=fname.where) if _ in deriv_resources: msg = 'The name %r is already used.' % _ raise DPSemanticError(msg, where=fname.where) if _ in variables: msg = 'The name %r is already used by a variable.' % _ raise DPSemanticError(msg, where=fname.where) functions.add(fname.value) def found_rname(rname): if isinstance(rname, CDP.Placeholder): return check_isinstance(rname, CDP.RName) _ = rname.value if _ in resources: msg = 'Repeated resource %r.' % _ raise DPSemanticError(msg, where=rname.where) if _ in deriv_resources: msg = 'The name %r is already used.' % _ raise DPSemanticError(msg, where=rname.where) if _ in variables: msg = 'The name %r is already used by a variable.' % _ raise DPSemanticError(msg, where=rname.where) resources.add(rname.value) def found_vname(vname): check_isinstance(vname, CDP.VName) variables.add(vname.value) def is_constant(vref): check_isinstance(vref, CDP.VariableRef) it_is = si.is_constant(vref.name) return it_is def check_all_constant(rvalue): """ Checks that all VariableRefs are constant """ class Tmp(): verified = True def visit_to_check(x, parents): # @UnusedVariable assert isnamedtuplewhere(x), type(x) not_allowed = CDP.FName, CDP.RName, CDP.UncertainRes, CDP.UncertainFun if isinstance(x, not_allowed): Tmp.verified = False if isinstance(x, CDP.VariableRef): if not is_constant(x): Tmp.verified = False else: pass return x namedtuple_visitor_ext(rvalue, visit_to_check) return Tmp.verified UNDEFINED, FVALUE, RVALUE, CONFLICTING, EITHER =\ 'undefined', 'fvalue', 'rvalue', 'conflicting', 'either' def get_flavour(xx): class Flavors: fvalue = set() rvalue = set() undefined = set() either = set() def visit_to_check2(x): # print(' visit_to_check2(%s) %s %s' % (nt_string(x), type(x).__name__, x)) if isinstance(x, CDP.Resource): l = x.dp.value + '.' + x.s.value Flavors.rvalue.add(l) elif isinstance(x, CDP.Function): l = x.dp.value + '.' + x.s.value Flavors.fvalue.add(l) elif isinstance(x, CDP.VName): Flavors.either.add(x.value) elif isinstance(x, CDP.VariableRef): if x.name in functions and x.name in resources: # ambiguous Flavors.either.add(x.name) # not other flavor elif x.name in functions or x.name in deriv_resources: # print('%r contributes to Flavors.rvalue' % x.name) Flavors.rvalue.add(x.name) # not other flavor elif x.name in resources or x.name in deriv_functions: # print('%r contributes to Flavors.fvalue' % x.name) Flavors.fvalue.add(x.name) # not other flavor elif x.name in variables: # print('%r contributes to Flavors.either' % x.name) Flavors.either.add(x.name) elif si.is_constant(x.name): # print('%r constant contributes to Flavors.either' % x.name) Flavors.either.add(x.name) else: msg = 'Could not resolve reference to %r.' % x.name raise DPSemanticError(msg, where=x.where) namedtuple_visitor_only_visit(xx, visit_to_check2) infer_debug('Results of %r: rv %s; fv %s; undef %s; either %s' % ( nt_string(rvalue), Flavors.rvalue, Flavors.fvalue, Flavors.undefined, Flavors.either)) if Flavors.rvalue and Flavors.fvalue: return CONFLICTING if Flavors.undefined: return UNDEFINED if Flavors.rvalue and Flavors.fvalue: return CONFLICTING if not Flavors.rvalue and Flavors.fvalue: return FVALUE if not Flavors.fvalue and Flavors.rvalue: return RVALUE return EITHER def can_be_treated_as_rvalue(x): res = get_flavour(x) infer_debug('Results of %r -> %s' % (nt_string(x), res)) return res in [RVALUE, EITHER] def can_be_treated_as_fvalue(x): res = get_flavour(x) infer_debug('Results of %r -> %s' % (nt_string(x), res)) return res in [FVALUE, EITHER] for i, l in enumerate(line_exprs): infer_debug('\n\n--- line %r (%s)' % ( l.where.string[l.where.character:l.where.character_end], type(l))) from .syntax import Syntax # mark functions, resources, variables, and constants if isinstance(l, CDP.SetNameNDPInstance): si.found_instance(l.name.value, l.name) elif isinstance(l, (CDP.FunStatement, CDP.FunShortcut1, CDP.FunShortcut2)): found_fname(l.fname) elif isinstance(l, (CDP.ResStatement, CDP.ResShortcut1, CDP.ResShortcut2)): found_rname(l.rname) elif isinstance(l, (#CDP.ResShortcut4, CDP.ResShortcut5, CDP.ResShortcut1m)): for _ in get_odd_ops(unwrap_list(l.rnames)): found_rname(_) elif isinstance(l, (#CDP.FunShortcut4, CDP.FunShortcut5, CDP.FunShortcut1m)): for _ in get_odd_ops(unwrap_list(l.fnames)): found_fname(_) if isinstance(l, CDP.SetNameConstant): si.found_constant(l.name.value, l) if isinstance(l, CDP.SetNameUncertainConstant): si.found_uncertain_constant(l.name.value, l) if isinstance(l, CDP.VarStatement): for _ in get_odd_ops(unwrap_list(l.vnames)): found_vname(_) if isinstance(l, CDP.FunShortcut2): pass elif isinstance(l, CDP.ResShortcut2): rvalue = l.rvalue elif isinstance(l, CDP.SetNameRValue): # first of all, chech if all the references on the right # are constant. rvalue = l.right_side all_constant = check_all_constant(rvalue) if all_constant: # This can become simply a constant infer_debug('The value %r can be recognized as constant' % str(l.name.value)) si.found_constant(l.name.value, l) else: # This is a special case, because it is the place # where the syntax is ambiguous. # # x = Nat: 1 + r # # could be interpreted with r being a functionality # or a resource. # # By default it is parsed as SetNameRValue, and so we get here. try: w = l.where s = w.string[w.character:w.character_end] from .parse_actions import parse_wrap alt0 = parse_wrap(Syntax.setname_fvalue, s)[0] assert isinstance(alt0, CDP.SetNameFValue), alt0 alt = move_where(alt0, w.string, w.character, w.character_end) except DPSyntaxError as _: #print "No, it does not parse: %s" % traceback.format_exc(e) alt = None if alt: #logger.info('Ambiguous') # both are feasible; check covariance one_ok = can_be_treated_as_rvalue(l.right_side) two_ok = can_be_treated_as_fvalue(alt.right_side) # print('can be rvalue %s fvalue %s' % (one_ok, two_ok)) if (not one_ok) and (not two_ok): msg = ('This expression cannot be interpreted either' ' as a functionality or as a resource.') raise DPSemanticError(msg, where=l.right_side.where) if one_ok and two_ok: if isinstance(l.right_side, CDP.UncertainRes): msg = ('This expression is ambiguous. I will interpret it as a resource.') warn_language(l.right_side, MCDPWarnings.LANGUAGE_AMBIGUOS_EXPRESSION, msg, context=context) deriv_resources.add(l.name.value) else: msg = ('This expression is truly ambiguous, and I cannot ' 'judge whether it is a functionality or resource.') e = DPSemanticError(msg, where=l.right_side.where) raise e elif one_ok and not two_ok: # we have concluded this can be a rvalue #print('setting %r as deriv_resources' % l.name.value) deriv_resources.add(l.name.value) elif two_ok and not one_ok: #print('setting %r as deriv_functions' % l.name.value) deriv_functions.add(l.name.value) # we replace the line line_exprs[i] = alt else: # print('setting %r as deriv_resources' % l.name.value) deriv_resources.add(l.name.value) elif isinstance(l, CDP.SetNameFValue): deriv_functions.add(l.name.value) elif isinstance(l, CDP.SetNameConstant): pass elif isinstance(l, (CDP.FunStatement, CDP.ResStatement)): pass else: # print('line %s' % type(l).__name__) pass refine0 = lambda x, parents: refine(x, parents, si, None, resources, functions, variables, deriv_resources, deriv_functions, context=context) line_exprs = [namedtuple_visitor_ext(_, refine0) for _ in line_exprs] return line_exprs