Beispiel #1
0
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'])
Beispiel #2
0
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'])
Beispiel #3
0
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
Beispiel #4
0
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