Skip to content

Commit

Permalink
[hay] Only add notes to the tree after checking for failure.
Browse files Browse the repository at this point in the history
Add unit tests.
  • Loading branch information
Andy C committed Jun 3, 2022
1 parent 599671e commit 0168304
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 60 deletions.
14 changes: 3 additions & 11 deletions core/state.py
Expand Up @@ -371,22 +371,14 @@ def PopEval(self):

if mylib.PYTHON: # TODO: hay results should be a value_t tree

def MakeResultNode(self):
# type: () -> Dict[str, Any]
def AppendResult(self, d):
# type: (Dict[str, Any]) -> None
"""Called by haynode builtin."""

d = NewDict() # type: Dict[str, Any]
assert 'children' in self.result_stack[-1], self.result_stack[-1]
self.result_stack[-1]['children'].append(d)

if 0:
log(' cur_children %s', self.cur_children)
log(' result_stack %s', self.result_stack)
return d

def Result(self):
# type: () -> Dict[str, Any]
""" Called by eval_attr_block() """
""" Called by hay eval and eval_hay() """
return self.output

def HayRegister(self):
Expand Down
75 changes: 39 additions & 36 deletions osh/builtin_pure.py
Expand Up @@ -775,7 +775,7 @@ def Run(self, cmd_val):
hay_name = None # don't validate

# Should we call hay_state.AddChild() so it can be mutated?
result = self.hay_state.MakeResultNode() # type: Dict[str, Any]
result = NewDict()

node_type, _ = arg_r.Peek2()
result['type'] = node_type
Expand All @@ -792,44 +792,47 @@ def Run(self, cmd_val):
e_usage('command node requires a block argument')
result['block'] = block # UNEVALUATED block

# Append after validation
self.hay_state.AppendResult(result)

else:
# Must be done before EvalBlock
self.hay_state.AppendResult(result)

block = typed_args.GetOneBlock(cmd_val.typed_args)
if block: # 'package foo' is OK
if node_type.isupper(): # TASK build { ... }
result['block'] = block # UNEVALUATED block
else:
result['children'] = []

# Evaluate in its own stack frame. TODO: Turn on dynamic scope?
with state.ctx_Temp(self.mem):
with state.ctx_HayNode(self.hay_state, hay_name):
# Note: we want all haynode invocations in the block to appear as
# our 'children', recursively
block_attrs = self.cmd_ev.EvalBlock(block)

attrs = NewDict() # type: Dict[str, Any]
for name, cell in iteritems(block_attrs):
val = cell.val
UP_val = val
with tagswitch(val) as case:
# similar to LookupVar in oil_lang/expr_eval.py
if case(value_e.Str):
val = cast(value__Str, UP_val)
obj = val.s # type: Any
elif case(value_e.MaybeStrArray):
val = cast(value__MaybeStrArray, UP_val)
obj = val.strs
elif case(value_e.AssocArray):
val = cast(value__AssocArray, UP_val)
obj = val.d
elif case(value_e.Obj):
val = cast(value__Obj, UP_val)
obj = val.obj
else:
e_die("Can't serialize value of type %d", val.tag_())
attrs[name] = obj

result['attrs'] = attrs
result['children'] = []

# Evaluate in its own stack frame. TODO: Turn on dynamic scope?
with state.ctx_Temp(self.mem):
with state.ctx_HayNode(self.hay_state, hay_name):
# Note: we want all haynode invocations in the block to appear as
# our 'children', recursively
block_attrs = self.cmd_ev.EvalBlock(block)

attrs = NewDict() # type: Dict[str, Any]
for name, cell in iteritems(block_attrs):
val = cell.val
UP_val = val
with tagswitch(val) as case:
# similar to LookupVar in oil_lang/expr_eval.py
if case(value_e.Str):
val = cast(value__Str, UP_val)
obj = val.s # type: Any
elif case(value_e.MaybeStrArray):
val = cast(value__MaybeStrArray, UP_val)
obj = val.strs
elif case(value_e.AssocArray):
val = cast(value__AssocArray, UP_val)
obj = val.d
elif case(value_e.Obj):
val = cast(value__Obj, UP_val)
obj = val.obj
else:
e_die("Can't serialize value of type %d", val.tag_())
attrs[name] = obj

result['attrs'] = attrs

return 0

Expand Down
61 changes: 48 additions & 13 deletions spec/oil-config.test.sh
Expand Up @@ -153,7 +153,7 @@ hay eval :result {
# Note: using jq to normalize
json write (result) | jq . > out.txt

diff out.txt - <<EOF
diff -u - out.txt <<EOF
{
"source": null,
"children": [
Expand Down Expand Up @@ -261,7 +261,7 @@ level 0 children
## END


#### haynode: node name is required
#### haynode: usage errors (name or block required)
shopt --set parse_brace parse_equals parse_proc

# should we make it name or block required?
Expand All @@ -272,23 +272,40 @@ try {
haynode package
}
}
echo "status $_status"
echo "haynode $_status"
var result = _hay()
echo "LEN $[len(result['children'])]"

try {
haynode package {
version = '1.0'
hay eval :result {
haynode package {
version = '1.0'
}
}
}
echo "status $_status"
echo "haynode $_status"
var result = _hay()
echo "LEN $[len(result['children'])]"

hay define package
try {
hay eval :result {
haynode TASK build
}
}
echo "haynode TASK $_status"
var result = _hay()
echo "LEN $[len(result['children'])]"

echo ---
hay define package TASK

try {
hay eval :result {
package
}
}
echo "status $_status"
echo "define $_status"
echo "LEN $[len(result['children'])]"

try {
hay eval :result {
Expand All @@ -297,13 +314,31 @@ try {
}
}
}
echo "status $_status"
echo "define $_status"
echo "LEN $[len(result['children'])]"

try {
hay eval :result {
TASK build
}
}
echo "define $_status"
echo "LEN $[len(result['children'])]"

## STDOUT:
status 2
status 2
status 2
status 2
haynode 2
LEN 0
haynode 2
LEN 0
haynode TASK 2
LEN 0
---
define 2
LEN 0
define 2
LEN 0
define 2
LEN 0
## END

#### haynode: shell nodes require block args; attribute nodes don't
Expand Down

0 comments on commit 0168304

Please sign in to comment.