OLD | NEW |
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 Google Inc. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 from compiler.ast import Const | 5 from compiler.ast import Const |
6 from compiler.ast import Dict | 6 from compiler.ast import Dict |
7 from compiler.ast import Discard | 7 from compiler.ast import Discard |
8 from compiler.ast import List | 8 from compiler.ast import List |
9 from compiler.ast import Module | 9 from compiler.ast import Module |
10 from compiler.ast import Node | 10 from compiler.ast import Node |
(...skipping 982 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
993 # Convert all strings that are canonically-represented integers into integers. | 993 # Convert all strings that are canonically-represented integers into integers. |
994 if isinstance(output, list): | 994 if isinstance(output, list): |
995 for index in xrange(0, len(output)): | 995 for index in xrange(0, len(output)): |
996 if IsStrCanonicalInt(output[index]): | 996 if IsStrCanonicalInt(output[index]): |
997 output[index] = int(output[index]) | 997 output[index] = int(output[index]) |
998 elif IsStrCanonicalInt(output): | 998 elif IsStrCanonicalInt(output): |
999 output = int(output) | 999 output = int(output) |
1000 | 1000 |
1001 return output | 1001 return output |
1002 | 1002 |
| 1003 # The same condition is often evaluated over and over again so it |
| 1004 # makes sense to cache as much as possible between evaluations. |
| 1005 cached_conditions_asts = {} |
| 1006 |
| 1007 def EvalCondition(condition, conditions_key, phase, variables, build_file): |
| 1008 """Returns the dict that should be used or None if the result was |
| 1009 that nothing should be used.""" |
| 1010 if not isinstance(condition, list): |
| 1011 raise GypError(conditions_key + ' must be a list') |
| 1012 if len(condition) != 2 and len(condition) != 3: |
| 1013 # It's possible that condition[0] won't work in which case this |
| 1014 # attempt will raise its own IndexError. That's probably fine. |
| 1015 raise GypError(conditions_key + ' ' + condition[0] + |
| 1016 ' must be length 2 or 3, not ' + str(len(condition))) |
| 1017 |
| 1018 [cond_expr, true_dict] = condition[0:2] |
| 1019 false_dict = None |
| 1020 if len(condition) == 3: |
| 1021 false_dict = condition[2] |
| 1022 |
| 1023 # Do expansions on the condition itself. Since the conditon can naturally |
| 1024 # contain variable references without needing to resort to GYP expansion |
| 1025 # syntax, this is of dubious value for variables, but someone might want to |
| 1026 # use a command expansion directly inside a condition. |
| 1027 cond_expr_expanded = ExpandVariables(cond_expr, phase, variables, |
| 1028 build_file) |
| 1029 if not isinstance(cond_expr_expanded, str) and \ |
| 1030 not isinstance(cond_expr_expanded, int): |
| 1031 raise ValueError, \ |
| 1032 'Variable expansion in this context permits str and int ' + \ |
| 1033 'only, found ' + cond_expr_expanded.__class__.__name__ |
| 1034 |
| 1035 try: |
| 1036 if cond_expr_expanded in cached_conditions_asts: |
| 1037 ast_code = cached_conditions_asts[cond_expr_expanded] |
| 1038 else: |
| 1039 ast_code = compile(cond_expr_expanded, '<string>', 'eval') |
| 1040 cached_conditions_asts[cond_expr_expanded] = ast_code |
| 1041 if eval(ast_code, {'__builtins__': None}, variables): |
| 1042 return true_dict |
| 1043 return false_dict |
| 1044 except SyntaxError, e: |
| 1045 syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s ' |
| 1046 'at character %d.' % |
| 1047 (str(e.args[0]), e.text, build_file, e.offset), |
| 1048 e.filename, e.lineno, e.offset, e.text) |
| 1049 raise syntax_error |
| 1050 except NameError, e: |
| 1051 gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' % |
| 1052 (cond_expr_expanded, build_file)) |
| 1053 raise GypError(e) |
| 1054 |
1003 | 1055 |
1004 def ProcessConditionsInDict(the_dict, phase, variables, build_file): | 1056 def ProcessConditionsInDict(the_dict, phase, variables, build_file): |
1005 # Process a 'conditions' or 'target_conditions' section in the_dict, | 1057 # Process a 'conditions' or 'target_conditions' section in the_dict, |
1006 # depending on phase. | 1058 # depending on phase. |
1007 # early -> conditions | 1059 # early -> conditions |
1008 # late -> target_conditions | 1060 # late -> target_conditions |
1009 # latelate -> no conditions | 1061 # latelate -> no conditions |
1010 # | 1062 # |
1011 # Each item in a conditions list consists of cond_expr, a string expression | 1063 # Each item in a conditions list consists of cond_expr, a string expression |
1012 # evaluated as the condition, and true_dict, a dict that will be merged into | 1064 # evaluated as the condition, and true_dict, a dict that will be merged into |
(...skipping 15 matching lines...) Expand all Loading... |
1028 assert False | 1080 assert False |
1029 | 1081 |
1030 if not conditions_key in the_dict: | 1082 if not conditions_key in the_dict: |
1031 return | 1083 return |
1032 | 1084 |
1033 conditions_list = the_dict[conditions_key] | 1085 conditions_list = the_dict[conditions_key] |
1034 # Unhook the conditions list, it's no longer needed. | 1086 # Unhook the conditions list, it's no longer needed. |
1035 del the_dict[conditions_key] | 1087 del the_dict[conditions_key] |
1036 | 1088 |
1037 for condition in conditions_list: | 1089 for condition in conditions_list: |
1038 if not isinstance(condition, list): | 1090 merge_dict = EvalCondition(condition, conditions_key, phase, variables, |
1039 raise GypError(conditions_key + ' must be a list') | 1091 build_file) |
1040 if len(condition) != 2 and len(condition) != 3: | |
1041 # It's possible that condition[0] won't work in which case this | |
1042 # attempt will raise its own IndexError. That's probably fine. | |
1043 raise GypError(conditions_key + ' ' + condition[0] + | |
1044 ' must be length 2 or 3, not ' + str(len(condition))) | |
1045 | |
1046 [cond_expr, true_dict] = condition[0:2] | |
1047 false_dict = None | |
1048 if len(condition) == 3: | |
1049 false_dict = condition[2] | |
1050 | |
1051 # Do expansions on the condition itself. Since the conditon can naturally | |
1052 # contain variable references without needing to resort to GYP expansion | |
1053 # syntax, this is of dubious value for variables, but someone might want to | |
1054 # use a command expansion directly inside a condition. | |
1055 cond_expr_expanded = ExpandVariables(cond_expr, phase, variables, | |
1056 build_file) | |
1057 if not isinstance(cond_expr_expanded, str) and \ | |
1058 not isinstance(cond_expr_expanded, int): | |
1059 raise ValueError, \ | |
1060 'Variable expansion in this context permits str and int ' + \ | |
1061 'only, found ' + expanded.__class__.__name__ | |
1062 | |
1063 try: | |
1064 ast_code = compile(cond_expr_expanded, '<string>', 'eval') | |
1065 | |
1066 if eval(ast_code, {'__builtins__': None}, variables): | |
1067 merge_dict = true_dict | |
1068 else: | |
1069 merge_dict = false_dict | |
1070 except SyntaxError, e: | |
1071 syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s ' | |
1072 'at character %d.' % | |
1073 (str(e.args[0]), e.text, build_file, e.offset), | |
1074 e.filename, e.lineno, e.offset, e.text) | |
1075 raise syntax_error | |
1076 except NameError, e: | |
1077 gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' % | |
1078 (cond_expr_expanded, build_file)) | |
1079 raise GypError(e) | |
1080 | 1092 |
1081 if merge_dict != None: | 1093 if merge_dict != None: |
1082 # Expand variables and nested conditinals in the merge_dict before | 1094 # Expand variables and nested conditinals in the merge_dict before |
1083 # merging it. | 1095 # merging it. |
1084 ProcessVariablesAndConditionsInDict(merge_dict, phase, | 1096 ProcessVariablesAndConditionsInDict(merge_dict, phase, |
1085 variables, build_file) | 1097 variables, build_file) |
1086 | 1098 |
1087 MergeDicts(the_dict, merge_dict, build_file, build_file) | 1099 MergeDicts(the_dict, merge_dict, build_file, build_file) |
1088 | 1100 |
1089 | 1101 |
(...skipping 1725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2815 ValidateRunAsInTarget(target, target_dict, build_file) | 2827 ValidateRunAsInTarget(target, target_dict, build_file) |
2816 ValidateActionsInTarget(target, target_dict, build_file) | 2828 ValidateActionsInTarget(target, target_dict, build_file) |
2817 | 2829 |
2818 # Generators might not expect ints. Turn them into strs. | 2830 # Generators might not expect ints. Turn them into strs. |
2819 TurnIntIntoStrInDict(data) | 2831 TurnIntIntoStrInDict(data) |
2820 | 2832 |
2821 # TODO(mark): Return |data| for now because the generator needs a list of | 2833 # TODO(mark): Return |data| for now because the generator needs a list of |
2822 # build files that came in. In the future, maybe it should just accept | 2834 # build files that came in. In the future, maybe it should just accept |
2823 # a list, and not the whole data dict. | 2835 # a list, and not the whole data dict. |
2824 return [flat_list, targets, data] | 2836 return [flat_list, targets, data] |
OLD | NEW |