diff --git a/transcrypt/development/automated_tests/transcrypt/operator_overloading/__init__.py b/transcrypt/development/automated_tests/transcrypt/operator_overloading/__init__.py index fff10fc2c..225eafb8e 100644 --- a/transcrypt/development/automated_tests/transcrypt/operator_overloading/__init__.py +++ b/transcrypt/development/automated_tests/transcrypt/operator_overloading/__init__.py @@ -259,4 +259,15 @@ def __init__ (self): a.b ['c'] += 'e' __pragma__('noopov') - autoTester.check (a.b ['c']) \ No newline at end of file + autoTester.check (a.b ['c']) + + # nested __pragma__ context managers + + with __pragma__ ('opov'): + autoTester.check ((2, 1, 3) == (1, 2, 3)) + autoTester.check ([2, 1, 3] == [1, 2, 3]) + with __pragma__ ('opov'): + autoTester.check ((1, 2, 3) != (1, 2, 3)) + autoTester.check ([1, 2, 3] != [1, 2, 3]) + autoTester.check ((1, 2, 3) == (1, 2, 3)) + autoTester.check ([1, 2, 3] == [1, 2, 3]) diff --git a/transcrypt/modules/org/transcrypt/compiler.py b/transcrypt/modules/org/transcrypt/compiler.py index 5f999e64f..2de4ae03f 100644 --- a/transcrypt/modules/org/transcrypt/compiler.py +++ b/transcrypt/modules/org/transcrypt/compiler.py @@ -520,9 +520,33 @@ def walk (name, value, tabLevel): with utils.create (self.treePath) as treeFile: treeFile.write (self.textTree) +class PragmaFlag: + def __get__ (self, obj, owner=None): + return obj.pragmaFlagsStack[self.name] + + def __set__ (self, obj, value): + obj.pragmaFlagsStack[self.name] = value + + def __set_name__ (self, owner, name): + self.name = name + class Generator (ast.NodeVisitor): # Terms like parent, child, ancestor and descendant refer to the parse tree here, not to inheritance + allowKeywordArgs = PragmaFlag () + allowOperatorOverloading = PragmaFlag () + allowConversionToIterable = PragmaFlag () + allowConversionToTruthValue = PragmaFlag () + allowKeyCheck = PragmaFlag () + allowDebugMap = PragmaFlag () + allowDocAttribs = PragmaFlag () + allowGlobals = PragmaFlag () + allowJavaScriptIter = PragmaFlag () + allowJavaScriptCall = PragmaFlag () + allowJavaScriptKeys = PragmaFlag () + allowJavaScriptMod = PragmaFlag () + allowMemoizeCalls = PragmaFlag () + def __init__ (self, module): self.module = module @@ -649,6 +673,8 @@ def __init__ (self, module): # Lowest precedence } + self.pragmaFlagsStack = collections.ChainMap({}) + self.allowKeywordArgs = utils.commandArgs.kwargs self.allowOperatorOverloading = utils.commandArgs.opov self.allowConversionToIterable = utils.commandArgs.iconv @@ -684,6 +710,13 @@ def __init__ (self, module): message = '\n\tTemporary variables leak in code generator: {}'.format (self.tempIndices) ) + def pushPragmas(self): + self.pragmaFlagsStack.maps.insert(0, {}) + + def popPragmas(self): + if len(self.pragmaFlagsStack.maps) > 0: + self.pragmaFlagsStack.maps.pop(0) + def visitSubExpr (self, node, child): def getPriority (exprNode): if type (exprNode) in (ast.BinOp, ast.BoolOp): @@ -1513,7 +1546,11 @@ def include (fileName): return # __pragma__'s in many varieties, syntactically calls, but semantically compile time directives elif node.func.id == '__pragma__': - if node.args [0] .s == 'alias': + if node.args[0].s == 'push': + self.pushPragmas () + elif node.args[0].s == 'pop': + self.popPragmas () + elif node.args [0] .s == 'alias': self.aliases.insert (0, (node.args [1] .s, node.args [2] .s)) elif node.args [0] .s == 'noalias': if len (node.args) == 1: @@ -3522,17 +3559,10 @@ def itemContext (item): @contextmanager def pragmaContext (item): - expr = item.context_expr - - name = expr.args[0].s - if name.startswith('no'): - revName = name[2:] - else: - revName = 'no' + name - - self.visit(expr) + self.pushPragmas () + self.visit (item.context_expr) yield - self.visit(ast.Call (expr.func, [ast.Str (revName)] + expr.args[1:])) + self.popPragmas () @contextmanager def skipContext (item): diff --git a/transcrypt/modules/org/transcrypt/stubs/browser.py b/transcrypt/modules/org/transcrypt/stubs/browser.py index 1069660b9..53a983d29 100644 --- a/transcrypt/modules/org/transcrypt/stubs/browser.py +++ b/transcrypt/modules/org/transcrypt/stubs/browser.py @@ -46,6 +46,15 @@ def __new__ (constructedObject): def __set_stubsymbols__ (symbols): global __symbols__ __symbols__ = symbols + + +class PragmaCtx: + def __enter__ (self): + pass + + def __exit__ (self, a, b, c): + pass + def __pragma__ (*args): if args [0] == 'defined': @@ -53,4 +62,6 @@ def __pragma__ (*args): if arg in __symbols__: return True return False + else: + return PragmaCtx()