可以在已编译的ast节点上应用eval具有本地上下文

时间:2016-02-07 16:42:17

标签: python

我正在开发一个新的Python到JavaScript compiler,它为包含编译器指令的__pragma__语句生成特殊代码。为了能够做到这一点,我必须使用包含本地函数的上下文来评估Ast的一部分。

我的代码是:

  eval (compile (ast.Expression (arg), '<string>', 'eval'), globals (), locals ())

其中arg是一个表达式节点,用于调用本地函数“include”。如果我检查locals(),'include'确实存在。但'eval'抱怨道:

name 'include' is not defined.

我看了一个在Eli Bendersky's website提供的例子。他做了同样的事情,只是没有提供当地背景。谁知道我做错了什么?

[编辑]

现在一切都很完美(感谢Martijn!)。我也忘记了需要引用字典的字面键。这些天给很多JS编程......

    def emitKwargDict ():
        self.emit ('__kwargdict__ (')

        hasSeparateKeyArgs = False
        hasKwargs = False
        for keyword in node.keywords:
            if keyword.arg:
                hasSeparateKeyArgs = True
            else:
                hasKwargs = True
                break   # **kwargs is always the last arg

        if hasSeparateKeyArgs:  
            if hasKwargs:
                self.emit ('__merge__ (')
            self.emit ('{{')    # Allways if hasSeparateKeyArgs

        for keywordIndex, keyword in enumerate (node.keywords):
            if keyword.arg:
                self.emitComma (keywordIndex)
                self.emit ('{}: ', keyword.arg)
                self.visit (keyword.value)
            else:
                # It's the **kwargs arg, so the last arg
                # In JavaScript this must be an expression denoting an Object (sometimes specialized as kwargdict)
                # The keyword args in there have to be added to the __kwargdict__ as well   
                if hasSeparateKeyArgs:
                    self.emit ('}}, ')          
                self.visit (keyword.value)

        if hasSeparateKeyArgs:
            if hasKwargs:
                self.emit (')')     # Terminate merge
            else:
                self.emit ('}}')    # Only if not terminated already because hasKwargs

        self.emit (')')

    def include (fileName):
        searchedIncludePaths = []
        for searchDir in self.module.program.moduleSearchDirs:
            filePath = '{}/{}'.format (searchDir, fileName)
            if os.path.isfile (filePath):
                return open (filePath) .read ()
            else:
                searchedIncludePaths.append (filePath)
        else:
            raise utils.Error (
                moduleName = self.module.metadata.name,
                lineNr = self.lineNr,
                message = '\n\tAttempt to include file: {}\n\tCan\'t find any of:\n\t\t{}\n'.format (
                    node.args [0], '\n\t\t'. join (searchedIncludePaths)
                )
            )

    if type (node.func) == ast.Name:
        if node.func.id == 'property':
            self.emit ('{0}.call ({1}, {1}.{2}'.format (node.func.id, self.getscope (ast.ClassDef) .name, node.args [0].id))
            if len (node.args) > 1:
                self.emit (', {}.{}'.format (self.getscope (ast.ClassDef) .name, node.args [1].id))
            self.emit (')')
            return
        elif node.func.id == '__pragma__':
            if node.args [0] .s == 'kwargs':        # Start emitting kwargs code for FunctionDef's
                self.allowKeywordArgs = True
            elif node.args [0] .s == 'nokwargs':    # Stop emitting kwargs code for FunctionDef's
                self.allowKeywordArgs = False
            elif node.args [0] .s == 'js':          # Include JavaScript code literally in the output
                self.emit ('\n{}\n', node.args [1] .s.format (* [
                    eval (
                        compile (
                            ast.Expression (arg),
                            '<string>',
                            'eval'
                        ),
                        {},
                        {'include': include}
                    )
                    for arg in node.args [2:]
                ]))
            elif node.args [0] .s == 'alias':
                self.aliases [args [1]] = args [2]
            return
        elif node.func.id == '__new__':
            self.emit ('new ')
            self.visit (node.args [0])
            return

    self.visit (node.func)

    for index, expr in enumerate (node.args):
        if type (expr) == ast.Starred:
            self.emit ('.apply (null, ')    # Note that in generated a.b.f (), a.b.f is a bound function already

            for index, expr in enumerate (node.args):
                if index:
                    self.emit ('.concat (')
                if type (expr) == ast.Starred:
                    self.visit (expr)
                else:
                    self.emit ('[')
                    self.visit (expr)
                    self.emit (']')
                if index:
                    self.emit (')')

            if node.keywords:
                self.emit ('.concat ([')    # At least *args was present before this point
                emitKwargDict ()
                self.emit ('])')

            self.emit (')')         
            break;
    else:   
        self.emit (' (')
        for index, expr in enumerate (node.args):
            self.emitComma (index)
            self.visit (expr)

        if node.keywords:
            self.emitComma (len (node.args))
            emitKwargDict ()

        self.emit (')')

1 个答案:

答案 0 :(得分:1)

您有一个NameError例外,表示该名称被查找为全局,而非本地名称。将名称放在globals字典中。