Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / third_party / cython / src / Cython / Compiler / UtilityCode.py
blobb7de364f9180616c46bfc252015d6258e1f6a652
1 from TreeFragment import parse_from_strings, StringParseContext
2 import Symtab
3 import Naming
4 import Code
6 class NonManglingModuleScope(Symtab.ModuleScope):
8 def __init__(self, prefix, *args, **kw):
9 self.prefix = prefix
10 self.cython_scope = None
11 Symtab.ModuleScope.__init__(self, *args, **kw)
13 def add_imported_entry(self, name, entry, pos):
14 entry.used = True
15 return super(NonManglingModuleScope, self).add_imported_entry(
16 name, entry, pos)
18 def mangle(self, prefix, name=None):
19 if name:
20 if prefix in (Naming.typeobj_prefix, Naming.func_prefix, Naming.var_prefix, Naming.pyfunc_prefix):
21 # Functions, classes etc. gets a manually defined prefix easily
22 # manually callable instead (the one passed to CythonUtilityCode)
23 prefix = self.prefix
24 return "%s%s" % (prefix, name)
25 else:
26 return Symtab.ModuleScope.mangle(self, prefix)
28 class CythonUtilityCodeContext(StringParseContext):
29 scope = None
31 def find_module(self, module_name, relative_to = None, pos = None,
32 need_pxd = 1):
34 if module_name != self.module_name:
35 if module_name not in self.modules:
36 raise AssertionError("Only the cython cimport is supported.")
37 else:
38 return self.modules[module_name]
40 if self.scope is None:
41 self.scope = NonManglingModuleScope(self.prefix,
42 module_name,
43 parent_module=None,
44 context=self)
46 return self.scope
49 class CythonUtilityCode(Code.UtilityCodeBase):
50 """
51 Utility code written in the Cython language itself.
53 The @cname decorator can set the cname for a function, method of cdef class.
54 Functions decorated with @cname('c_func_name') get the given cname.
56 For cdef classes the rules are as follows:
57 obj struct -> <cname>_obj
58 obj type ptr -> <cname>_type
59 methods -> <class_cname>_<method_cname>
61 For methods the cname decorator is optional, but without the decorator the
62 methods will not be prototyped. See Cython.Compiler.CythonScope and
63 tests/run/cythonscope.pyx for examples.
64 """
66 is_cython_utility = True
68 def __init__(self, impl, name="__pyxutil", prefix="", requires=None,
69 file=None, from_scope=None, context=None):
70 # 1) We need to delay the parsing/processing, so that all modules can be
71 # imported without import loops
72 # 2) The same utility code object can be used for multiple source files;
73 # while the generated node trees can be altered in the compilation of a
74 # single file.
75 # Hence, delay any processing until later.
76 if context is not None:
77 impl = Code.sub_tempita(impl, context, file, name)
78 self.impl = impl
79 self.name = name
80 self.file = file
81 self.prefix = prefix
82 self.requires = requires or []
83 self.from_scope = from_scope
85 def get_tree(self, entries_only=False, cython_scope=None):
86 from AnalysedTreeTransforms import AutoTestDictTransform
87 # The AutoTestDictTransform creates the statement "__test__ = {}",
88 # which when copied into the main ModuleNode overwrites
89 # any __test__ in user code; not desired
90 excludes = [AutoTestDictTransform]
92 import Pipeline, ParseTreeTransforms
93 context = CythonUtilityCodeContext(self.name)
94 context.prefix = self.prefix
95 context.cython_scope = cython_scope
96 #context = StringParseContext(self.name)
97 tree = parse_from_strings(self.name, self.impl, context=context,
98 allow_struct_enum_decorator=True)
99 pipeline = Pipeline.create_pipeline(context, 'pyx', exclude_classes=excludes)
101 if entries_only:
102 p = []
103 for t in pipeline:
104 p.append(t)
105 if isinstance(p, ParseTreeTransforms.AnalyseDeclarationsTransform):
106 break
108 pipeline = p
110 transform = ParseTreeTransforms.CnameDirectivesTransform(context)
111 # InterpretCompilerDirectives already does a cdef declarator check
112 #before = ParseTreeTransforms.DecoratorTransform
113 before = ParseTreeTransforms.InterpretCompilerDirectives
114 pipeline = Pipeline.insert_into_pipeline(pipeline, transform,
115 before=before)
117 if self.from_scope:
118 def scope_transform(module_node):
119 module_node.scope.merge_in(self.from_scope)
120 return module_node
122 transform = ParseTreeTransforms.AnalyseDeclarationsTransform
123 pipeline = Pipeline.insert_into_pipeline(pipeline, scope_transform,
124 before=transform)
126 (err, tree) = Pipeline.run_pipeline(pipeline, tree, printtree=False)
127 assert not err, err
128 return tree
130 def put_code(self, output):
131 pass
133 @classmethod
134 def load_as_string(cls, util_code_name, from_file=None, **kwargs):
136 Load a utility code as a string. Returns (proto, implementation)
138 util = cls.load(util_code_name, from_file, **kwargs)
139 return util.proto, util.impl # keep line numbers => no lstrip()
141 def declare_in_scope(self, dest_scope, used=False, cython_scope=None,
142 whitelist=None):
144 Declare all entries from the utility code in dest_scope. Code will only
145 be included for used entries. If module_name is given, declare the
146 type entries with that name.
148 tree = self.get_tree(entries_only=True, cython_scope=cython_scope)
150 entries = tree.scope.entries
151 entries.pop('__name__')
152 entries.pop('__file__')
153 entries.pop('__builtins__')
154 entries.pop('__doc__')
156 for name, entry in entries.iteritems():
157 entry.utility_code_definition = self
158 entry.used = used
160 original_scope = tree.scope
161 dest_scope.merge_in(original_scope, merge_unused=True,
162 whitelist=whitelist)
163 tree.scope = dest_scope
165 for dep in self.requires:
166 if dep.is_cython_utility:
167 dep.declare_in_scope(dest_scope)
169 return original_scope
171 def declare_declarations_in_scope(declaration_string, env, private_type=True,
172 *args, **kwargs):
174 Declare some declarations given as Cython code in declaration_string
175 in scope env.
177 CythonUtilityCode(declaration_string, *args, **kwargs).declare_in_scope(env)