Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: pylib/gyp/input.py

Issue 232773004: gyp: cache conditional ASTs for 3 CPU seconds (5%) gain. (Closed) Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: Fixing error message. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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]
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698