Skip to content

Commit

Permalink
Merge branch 'master' into bender/SYN-8482/deprecate-lib-text
Browse files Browse the repository at this point in the history
  • Loading branch information
OCBender authored Jan 16, 2025
2 parents 28e7df6 + df25a32 commit 3526684
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 16 deletions.
6 changes: 6 additions & 0 deletions changes/303e4458db5d4c5f9f39813b5be41ad7.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
desc: Fixed an issue in Storm functions where using the return keyword in a subquery
used as a value could incorrectly change the function type.
prs: []
type: bug
...
6 changes: 6 additions & 0 deletions changes/7a4e69c153170cce7ed678912c3857a2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
desc: Fixed an issue in Storm where attempting to iterate a non-iterable object would
raise a Python exception rather than a StormRuntimeError.
prs: []
type: bug
...
81 changes: 65 additions & 16 deletions synapse/lib/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,27 +134,27 @@ def prepare(self):
pass

def hasAstClass(self, clss):
hasast = self.hasast.get(clss)
if hasast is not None:
if (hasast := self.hasast.get(clss)) is not None:
return hasast

retn = False
retn = self._hasAstClass(clss)
self.hasast[clss] = retn
return retn

def _hasAstClass(self, clss):

for kid in self.kids:

if isinstance(kid, clss):
retn = True
break
return True

if isinstance(kid, (EditPropSet, EditCondPropSet, Function, CmdOper)):
if isinstance(kid, (Edit, Function, CmdOper, SetVarOper, SetItemOper, VarListSetOper, Value, N1Walk, LiftOper)):
continue

if kid.hasAstClass(clss):
retn = True
break
return True

self.hasast[clss] = retn
return retn
return False

def optimize(self):
[k.optimize() for k in self.kids]
Expand Down Expand Up @@ -930,6 +930,9 @@ async def getCatchBlock(self, name, runt, path=None):

class CatchBlock(AstNode):

def _hasAstClass(self, clss):
return self.kids[1].hasAstClass(clss)

async def run(self, runt, genr):
async for item in self.kids[2].run(runt, genr):
yield item
Expand Down Expand Up @@ -963,6 +966,9 @@ async def catches(self, name, runt, path=None):

class ForLoop(Oper):

def _hasAstClass(self, clss):
return self.kids[2].hasAstClass(clss)

def getRuntVars(self, runt):

runtsafe = self.kids[1].isRuntSafe(runt)
Expand Down Expand Up @@ -998,6 +1004,14 @@ async def run(self, runt, genr):
valu = ()

async with contextlib.aclosing(s_coro.agen(valu)) as agen:

try:
agen, _ = await pullone(agen)
except TypeError:
styp = await s_stormtypes.totype(valu, basetypes=True)
mesg = f"'{styp}' object is not iterable: {s_common.trimText(repr(valu))}"
raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg, type=styp)) from None

async for item in agen:

if isinstance(name, (list, tuple)):
Expand Down Expand Up @@ -1064,6 +1078,13 @@ async def run(self, runt, genr):
valu = ()

async with contextlib.aclosing(s_coro.agen(valu)) as agen:
try:
agen, _ = await pullone(agen)
except TypeError:
styp = await s_stormtypes.totype(valu, basetypes=True)
mesg = f"'{styp}' object is not iterable: {s_common.trimText(repr(valu))}"
raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg, type=styp)) from None

async for item in agen:

if isinstance(name, (list, tuple)):
Expand Down Expand Up @@ -1109,6 +1130,9 @@ async def run(self, runt, genr):

class WhileLoop(Oper):

def _hasAstClass(self, clss):
return self.kids[1].hasAstClass(clss)

async def run(self, runt, genr):
subq = self.kids[1]
node = None
Expand Down Expand Up @@ -1162,20 +1186,21 @@ async def run(self, runt, genr):
await asyncio.sleep(0)

async def pullone(genr):
gotone = None
async for gotone in genr:
break
empty = False
try:
gotone = await genr.__anext__()
except StopAsyncIteration:
empty = True

async def pullgenr():

if gotone is None:
if empty:
return

yield gotone
async for item in genr:
yield item

return pullgenr(), gotone is None
return pullgenr(), empty

class CmdOper(Oper):

Expand Down Expand Up @@ -1385,6 +1410,14 @@ async def run(self, runt, genr):

class SwitchCase(Oper):

def _hasAstClass(self, clss):

for kid in self.kids[1:]:
if kid.hasAstClass(clss):
return True

return False

def prepare(self):
self.cases = {}
self.defcase = None
Expand Down Expand Up @@ -4811,6 +4844,22 @@ class IfClause(AstNode):

class IfStmt(Oper):

def _hasAstClass(self, clss):

clauses = self.kids

if not isinstance(clauses[-1], IfClause):
if clauses[-1].hasAstClass(clss):
return True

clauses = clauses[:-1]

for clause in clauses:
if clause.kids[1].hasAstClass(clss):
return True

return False

def prepare(self):
if isinstance(self.kids[-1], IfClause):
self.elsequery = None
Expand Down
8 changes: 8 additions & 0 deletions synapse/tests/test_cortex.py
Original file line number Diff line number Diff line change
Expand Up @@ -5230,6 +5230,14 @@ async def test_storm_forloop(self):
self.eq(('inet:fqdn', 'nest.com'), nodes[0].ndef)
self.eq(('inet:fqdn', 'nest.com'), nodes[1].ndef)

with self.raises(s_exc.StormRuntimeError) as err:
await core.nodes('[ it:dev:int=1 ] for $n in $node.value() { }')
self.isin("'int' object is not iterable: 1", err.exception.errinfo.get('mesg'))

with self.raises(s_exc.StormRuntimeError) as err:
await core.nodes('for $n in { .created return($node) } { }')
self.isin("'node' object is not iterable", err.exception.errinfo.get('mesg'))

async def test_storm_whileloop(self):

async with self.getTestCore() as core:
Expand Down
162 changes: 162 additions & 0 deletions synapse/tests/test_lib_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -4524,3 +4524,165 @@ async def test_ast_varlistset(self):
text = '($x, $y) = (1)'
with self.raises(s_exc.StormRuntimeError):
await core.nodes(text)

async def test_ast_functypes(self):

async with self.getTestCore() as core:

async def verify(q, isin=False):
msgs = await core.stormlist(q)
if isin:
self.stormIsInPrint('yep', msgs)
else:
self.stormNotInPrint('newp', msgs)
self.len(1, [m for m in msgs if m[0] == 'node'])
self.stormHasNoErr(msgs)

q = '''
function foo() {
for $n in { return((newp,)) } { $lib.print($n) }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
while { return((newp,)) } { $lib.print(newp) break }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
switch $lib.print({ return(newp) }) { *: { $lib.print(newp) } }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
switch $foo { *: { $lib.print(yep) return() } }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q, isin=True)

q = '''
function foo() {
if { return(newp) } { $lib.print(newp) }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
if (false) { $lib.print(newp) }
elif { return(newp) } { $lib.print(newp) }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
if (false) { $lib.print(newp) }
elif (true) { $lib.print(yep) return() }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
if (false) { $lib.print(newp) }
elif (false) { $lib.print(newp) }
else { $lib.print(yep) return() }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q, isin=True)

q = '''
function foo() {
[ it:dev:str=foo +(refs)> { $lib.print(newp) return() } ]
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
$lib.print({ return(newp) })
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
$x = { $lib.print(newp) return() }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
($x, $y) = { $lib.print(newp) return((foo, bar)) }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
$x = ({})
$x.y = { $lib.print(newp) return((foo, bar)) }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
.created -({$lib.print(newp) return(refs)})> *
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
try { $lib.raise(boom) } catch { $lib.print(newp) return(newp) } as e {}
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

q = '''
function foo() {
it:dev:str={ $lib.print(newp) return(test) }
}
[ it:dev:str=test ]
$foo()
'''
await verify(q)

0 comments on commit 3526684

Please sign in to comment.