Skip to content

Commit

Permalink
支持?:与if else混合使用
Browse files Browse the repository at this point in the history
  • Loading branch information
wukan1986 committed Nov 7, 2024
1 parent 5355208 commit 4c7cb28
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 13 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ df = codegen_exec(df, _code_block_1, _code_block_2) # 只执行,不保存代

## 特别语法

1. `(A<B)*-1`,底层将转换成`int_(A<B)*-1`
2. 支持`C?T:F`三元表达式(只能在字符串中使用),Python只支持`T if C else F`, 而在本项目中会自动转成`if_else(C,T,F)`
1. 支持`C?T:F`三元表达式(仅可字符串中使用),底层会先转成`C or True if( T )else F`,然后修正成`T if C else F`,最后转成`if_else(C,T,F)`。支持与`if else`混用
2. `(A<B)*-1`,底层将转换成`int_(A<B)*-1`
3. 为防止`A==B``sympy`替换成`False`,底层会换成`Eq(A,B)`
4. `A^B`的含义与`convert_xor`参数有关,`convert_xor=True`底层会转换成`Pow(A,B)`,反之为`Xor(A,B)`。默认为`False`,用`**`表示乘方
5. 支持`A&B&C`,但不支持`A==B==C`。如果C是布尔,AB是数值,可手工替换成`(A==B)==C`。如果ABC是数值需手工替换成`(A==B)&(B==C)`
Expand Down
20 changes: 12 additions & 8 deletions expr_codegen/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ def visit_Compare(self, node):
return node

def visit_IfExp(self, node):
# 三元表达式。需要在外部提前替换成if else
# OPEN>=CLOSE?1:0
# OPEN>CLOSE?A==B?3:DE>FG?5:6:0
# 三元表达式。需要在外部提前替换成or True if else
# 只要body区域,出现了or True,就认为是特殊处理过的
if isinstance(node.body, ast.BoolOp) and isinstance(node.body.op, ast.Or):
if isinstance(node.body.values[-1], ast.Constant):
if node.body.values[-1].value == True:
node.test, node.body = node.body.values[0], node.test

node = ast.Call(
func=ast.Name(id='if_else', ctx=ast.Load()),
args=[node.body, node.test, node.orelse],
args=[node.test, node.body, node.orelse],
keywords=[],
)

Expand Down Expand Up @@ -299,13 +303,13 @@ def sources_to_asts(*sources, convert_xor: bool):
return '\n'.join(raw), assigns, funcs_new, args_new, targets_new


def source_replace(source):
def source_replace(source: str) -> str:
# 三元表达式转换成 错误版if( )else,一定得在Transformer中修正
num = 1
while num > 0:
# A == B?D == E?1: 2:0 + 0
# 其实会导致?与:错配,但无所谓,只要多执行几次即可
source, num = re.subn(r'\?(.+?):(.+?)', r' if( \1 )else \2', source, flags=re.S)
# 利用or 的优先级最低,构造特殊的if else,只要出现,就认为位置要替换
# C?T:F --> C or True if( T )else F
source, num = re.subn(r'\?(.+?):(.+?)', r' or True if( \1 )else \2', source, flags=re.S)
# break
# 或、与
source = source.replace('||', '|').replace('&&', '&')
Expand Down
5 changes: 2 additions & 3 deletions tests/formula_transformer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import ast

from expr_codegen.codes import SympyTransformer, source_replace
from expr_codegen.codes import source_replace, RenameTransformer

source = """
OPEN>=CLOSE?1:0
Expand Down Expand Up @@ -36,9 +36,8 @@
# D = _A
"""

tree = ast.parse(source_replace(source))
t = SympyTransformer()
t = RenameTransformer()

funcs_map = {'abs': 'abs_',
'max': 'max_',
Expand Down

0 comments on commit 4c7cb28

Please sign in to comment.