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

Side by Side Diff: grit/node/base.py

Issue 156443002: Provide defines as local variables in if-expressions. (Closed) Base URL: http://grit-i18n.googlecode.com/svn/trunk
Patch Set: rebased past is_posix fix, fixed is_posix again and updated unittests Created 6 years, 10 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 | Annotate | Revision Log
« no previous file with comments | « grit/grd_reader_unittest.py ('k') | grit/node/base_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 '''Base types for nodes in a GRIT resource tree. 6 '''Base types for nodes in a GRIT resource tree.
7 ''' 7 '''
8 8
9 import collections 9 import ast
10 import os 10 import os
11 import sys
12 import types 11 import types
13 from xml.sax import saxutils 12 from xml.sax import saxutils
14 13
15 from grit import clique 14 from grit import clique
16 from grit import exception 15 from grit import exception
17 from grit import util 16 from grit import util
18 17
19 18
20 class Node(object): 19 class Node(object):
21 '''An item in the tree that has children.''' 20 '''An item in the tree that has children.'''
22 21
23 # Valid content types that can be returned by _ContentType() 22 # Valid content types that can be returned by _ContentType()
24 _CONTENT_TYPE_NONE = 0 # No CDATA content but may have children 23 _CONTENT_TYPE_NONE = 0 # No CDATA content but may have children
25 _CONTENT_TYPE_CDATA = 1 # Only CDATA, no children. 24 _CONTENT_TYPE_CDATA = 1 # Only CDATA, no children.
26 _CONTENT_TYPE_MIXED = 2 # CDATA and children, possibly intermingled 25 _CONTENT_TYPE_MIXED = 2 # CDATA and children, possibly intermingled
27 26
28 # Default nodes to not whitelist skipped 27 # Default nodes to not whitelist skipped
29 _whitelist_marked_as_skip = False 28 _whitelist_marked_as_skip = False
30 29
31 # A class-static cache to memoize EvaluateExpression(). 30 # A class-static cache to speed up EvaluateExpression().
32 # It has a 2 level nested dict structure. The outer dict has keys 31 # Keys are expressions (e.g. 'is_ios and lang == "fr"'). Values are tuples
33 # of tuples which define the environment in which the expression 32 # (code, variables_in_expr) where code is the compiled expression and can be
34 # will be evaluated. The inner dict is map of expr->result. 33 # directly eval'd, and variables_in_expr is the list of variable and method
35 eval_expr_cache = collections.defaultdict(dict) 34 # names used in the expression (e.g. ['is_ios', 'lang']).
35 eval_expr_cache = {}
36 36
37 def __init__(self): 37 def __init__(self):
38 self.children = [] # A list of child elements 38 self.children = [] # A list of child elements
39 self.mixed_content = [] # A list of u'' and/or child elements (this 39 self.mixed_content = [] # A list of u'' and/or child elements (this
40 # duplicates 'children' but 40 # duplicates 'children' but
41 # is needed to preserve markup-type content). 41 # is needed to preserve markup-type content).
42 self.name = u'' # The name of this element 42 self.name = u'' # The name of this element
43 self.attrs = {} # The set of attributes (keys to values) 43 self.attrs = {} # The set of attributes (keys to values)
44 self.parent = None # Our parent unless we are the root element. 44 self.parent = None # Our parent unless we are the root element.
45 self.uberclique = None # Allows overriding uberclique for parts of tree 45 self.uberclique = None # Allows overriding uberclique for parts of tree
(...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 return [child for child in self if isinstance(child, type)] 435 return [child for child in self if isinstance(child, type)]
436 436
437 def GetTextualIds(self): 437 def GetTextualIds(self):
438 '''Returns a list of the textual ids of this node. 438 '''Returns a list of the textual ids of this node.
439 ''' 439 '''
440 if 'name' in self.attrs: 440 if 'name' in self.attrs:
441 return [self.attrs['name']] 441 return [self.attrs['name']]
442 return [] 442 return []
443 443
444 @classmethod 444 @classmethod
445 def GetPlatformAssertion(cls, target_platform): 445 def EvaluateExpression(cls, expr, defs, target_platform, extra_variables={}):
446 '''If the platform is a specific well-known platform, this returns 446 '''Worker for EvaluateCondition (below) and conditions in XTB files.'''
447 the is_xyz string representing that platform (e.g. is_linux), 447 if expr in cls.eval_expr_cache:
448 otherwise the empty string. 448 code, variables_in_expr = cls.eval_expr_cache[expr]
449 ''' 449 else:
450 platform = '' 450 # Get a list of all variable and method names used in the expression.
451 if target_platform == 'darwin': 451 syntax_tree = ast.parse(expr, mode='eval')
452 platform = 'is_macosx' 452 variables_in_expr = [node.id for node in ast.walk(syntax_tree) if
453 elif target_platform.startswith('linux'): 453 isinstance(node, ast.Name) and node.id not in ('True', 'False')]
454 platform = 'is_linux' 454 code = compile(syntax_tree, filename='<string>', mode='eval')
455 elif target_platform in ('cygwin', 'win32'): 455 cls.eval_expr_cache[expr] = code, variables_in_expr
456 platform = 'is_win'
457 elif target_platform in ('android', 'ios'):
458 platform = 'is_%s' % target_platform
459 return platform
460 456
461 @classmethod 457 # Set values only for variables that are needed to eval the expression.
462 def EvaluateExpression(cls, expr, defs, target_platform, extra_variables=None) : 458 variable_map = {}
463 '''Worker for EvaluateCondition (below) and conditions in XTB files.''' 459 for name in variables_in_expr:
464 cache_dict = cls.eval_expr_cache[ 460 if name == 'os':
465 (tuple(defs.iteritems()), target_platform, extra_variables)] 461 value = target_platform
466 if expr in cache_dict: 462 elif name == 'defs':
467 return cache_dict[expr] 463 value = defs
468 def pp_ifdef(symbol):
469 return symbol in defs
470 def pp_if(symbol):
471 return defs.get(symbol, False)
472 variable_map = {
473 'defs' : defs,
474 'os': target_platform,
475 464
476 # One of these is_xyz assertions gets set to True in the line 465 elif name == 'is_linux':
477 # following this initializer block. 466 value = target_platform.startswith('linux')
478 'is_linux': False, 467 elif name == 'is_macosx':
479 'is_macosx': False, 468 value = target_platform == 'darwin'
480 'is_win': False, 469 elif name == 'is_win':
481 'is_android': False, 470 value = target_platform in ('cygwin', 'win32')
482 'is_ios': False, 471 elif name == 'is_android':
472 value = target_platform == 'android'
473 elif name == 'is_ios':
474 value = target_platform == 'ios'
475 elif name == 'is_posix':
476 value = (target_platform in ('darwin', 'linux2', 'linux3', 'sunos5',
477 'android', 'ios')
478 or 'bsd' in target_platform)
483 479
484 # is_posix is not mutually exclusive of the others and gets 480 elif name == 'pp_ifdef':
485 # set here, not below. 481 def pp_ifdef(symbol):
486 'is_posix': (target_platform in ('darwin', 'linux2', 'linux3', 'sunos5', 482 return symbol in defs
487 'android', 'ios') 483 value = pp_ifdef
488 or 'bsd' in target_platform), 484 elif name == 'pp_if':
485 def pp_if(symbol):
486 return defs.get(symbol, False)
487 value = pp_if
489 488
490 'pp_ifdef' : pp_ifdef, 489 elif name in defs:
491 'pp_if' : pp_if, 490 value = defs[name]
492 } 491 elif name in extra_variables:
493 variable_map[Node.GetPlatformAssertion(target_platform)] = True 492 value = extra_variables[name]
493 else:
494 # Undefined variables default to False.
495 value = False
494 496
495 if extra_variables: 497 variable_map[name] = value
496 variable_map.update(extra_variables) 498
497 eval_result = cache_dict[expr] = eval(expr, {}, variable_map) 499 eval_result = eval(code, {}, variable_map)
500 assert isinstance(eval_result, bool)
498 return eval_result 501 return eval_result
499 502
500 def EvaluateCondition(self, expr): 503 def EvaluateCondition(self, expr):
501 '''Returns true if and only if the Python expression 'expr' evaluates 504 '''Returns true if and only if the Python expression 'expr' evaluates
502 to true. 505 to true.
503 506
504 The expression is given a few local variables: 507 The expression is given a few local variables:
505 - 'lang' is the language currently being output 508 - 'lang' is the language currently being output
506 (the 'lang' attribute of the <output> element). 509 (the 'lang' attribute of the <output> element).
507 - 'context' is the current output context 510 - 'context' is the current output context
508 (the 'context' attribute of the <output> element). 511 (the 'context' attribute of the <output> element).
509 - 'defs' is a map of C preprocessor-style symbol names to their values. 512 - 'defs' is a map of C preprocessor-style symbol names to their values.
510 - 'os' is the current platform (likely 'linux2', 'win32' or 'darwin'). 513 - 'os' is the current platform (likely 'linux2', 'win32' or 'darwin').
511 - 'pp_ifdef(symbol)' is a shorthand for "symbol in defs". 514 - 'pp_ifdef(symbol)' is a shorthand for "symbol in defs".
512 - 'pp_if(symbol)' is a shorthand for "symbol in defs and defs[symbol]". 515 - 'pp_if(symbol)' is a shorthand for "symbol in defs and defs[symbol]".
513 - 'is_linux', 'is_macosx', 'is_win', 'is_posix' are true if 'os' 516 - 'is_linux', 'is_macosx', 'is_win', 'is_posix' are true if 'os'
514 matches the given platform. 517 matches the given platform.
515 ''' 518 '''
516 root = self.GetRoot() 519 root = self.GetRoot()
517 lang = getattr(root, 'output_language', '') 520 lang = getattr(root, 'output_language', '')
518 context = getattr(root, 'output_context', '') 521 context = getattr(root, 'output_context', '')
519 defs = getattr(root, 'defines', {}) 522 defs = getattr(root, 'defines', {})
520 target_platform = getattr(root, 'target_platform', '') 523 target_platform = getattr(root, 'target_platform', '')
521 extra_variables = ( 524 extra_variables = {
522 ('lang', lang), 525 'lang': lang,
523 ('context', context), 526 'context': context,
524 ) 527 }
525 return Node.EvaluateExpression( 528 return Node.EvaluateExpression(
526 expr, defs, target_platform, extra_variables) 529 expr, defs, target_platform, extra_variables)
527 530
528 def OnlyTheseTranslations(self, languages): 531 def OnlyTheseTranslations(self, languages):
529 '''Turns off loading of translations for languages not in the provided list. 532 '''Turns off loading of translations for languages not in the provided list.
530 533
531 Attrs: 534 Attrs:
532 languages: ['fr', 'zh_cn'] 535 languages: ['fr', 'zh_cn']
533 ''' 536 '''
534 for node in self: 537 for node in self:
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
584 def ExpandVariables(self): 587 def ExpandVariables(self):
585 '''Whether we need to expand variables on a given node.''' 588 '''Whether we need to expand variables on a given node.'''
586 return False 589 return False
587 590
588 591
589 class ContentNode(Node): 592 class ContentNode(Node):
590 '''Convenience baseclass for nodes that can have content.''' 593 '''Convenience baseclass for nodes that can have content.'''
591 def _ContentType(self): 594 def _ContentType(self):
592 return self._CONTENT_TYPE_MIXED 595 return self._CONTENT_TYPE_MIXED
593 596
OLDNEW
« no previous file with comments | « grit/grd_reader_unittest.py ('k') | grit/node/base_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698