Skip to content

Commit

Permalink
[json] Able to handle encode/decode errors with _error
Browse files Browse the repository at this point in the history
Document it.

OK this was pretty easy to implement.  But it could be more extensible.
  • Loading branch information
Andy C committed Dec 31, 2023
1 parent c26ccc8 commit c4d9299
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 30 deletions.
27 changes: 19 additions & 8 deletions builtin/func_misc.py
Expand Up @@ -416,10 +416,17 @@ def Call(self, rd):
rd.Done()

buf = mylib.BufWriter()
if self.is_j8:
self.j8print.PrintMessage(val, buf, -1)
else:
self.j8print.PrintJsonMessage(val, buf, -1)
try:
if self.is_j8:
self.j8print.PrintMessage(val, buf, -1)
else:
self.j8print.PrintJsonMessage(val, buf, -1)
except error.Encode as e:
# TODO: This isn't a UserError, it's more like a structured error
# or DictError.
#
# status code 4 is special, for encode/decode errors.
raise error.UserError(4, e.Message(), rd.LeftParenToken())

return value.Str(buf.getvalue())

Expand All @@ -439,10 +446,14 @@ def Call(self, rd):
if mylib.PYTHON: # TODO: translate j8.Parser
p = j8.Parser(s)

if self.is_j8:
val = p.ParseJ8()
else:
val = p.ParseJson()
try:
if self.is_j8:
val = p.ParseJ8()
else:
val = p.ParseJson()
except error.Decode as e:
# status code 4 is special, for encode/decode errors.
raise error.UserError(4, e.Message(), rd.LeftParenToken())
else:
val = value.Null

Expand Down
10 changes: 7 additions & 3 deletions doc/ref/chap-builtin-cmd.md
Expand Up @@ -75,6 +75,8 @@ Set the `_status` variable to the exit status of the block, and returns 0.
(*) echo "error $_status" ;;
esac

It may also set the `_error` register.

### boolstatus

Runs a command and requires the exit code to be 0 or 1.
Expand All @@ -88,7 +90,7 @@ Runs a command and requires the exit code to be 0 or 1.
### error

The `error` builtin raises a fatal error. In YSH, it's customary to use it
instead of `return 1`:
instead of `return 1`, since it provides more information:

proc p {
if ! test -d /tmp {
Expand All @@ -98,8 +100,10 @@ instead of `return 1`:

The error can be caught with `try`:

try p
if (_status !== 0 {
try {
p
}
if (_status !== 0) {
echo 'failed'
}

Expand Down
26 changes: 20 additions & 6 deletions doc/ref/chap-special-var.md
Expand Up @@ -36,20 +36,34 @@ It's useful for "relative imports".

## YSH Status

### _status
### `_status`

Set by the `try` builtin.
An `Int` that's set by the `try` builtin.

try ls /bad
if (_status !== 0) {
try {
ls /bad # exits with status 2
}
if (_status !== 0) { # _status is 2
echo 'failed'
}

### _pipeline_status
### `_error`

A `Dict` that's set by the `try` builtin when catching certain errors.

Such errors include JSON/J8 encoding/decoding errors, and user errors from the
`error` builtin.

try {
echo $[toJ8( /d+/ )] # invalid Eggex type
}
echo "failed: $[_error.message]" # => failed: Can't serialize ...

### `_pipeline_status`

Alias for [PIPESTATUS]($osh-help).

### _process_sub_status
### `_process_sub_status`

The exit status of all the process subs in the last command.

Expand Down
5 changes: 3 additions & 2 deletions doc/ref/toc-ysh.md
Expand Up @@ -115,7 +115,7 @@ Siblings: [OSH Topics](toc-osh.html), [Data Topics](toc-data.html)
```chapter-links-builtin-cmd
[Memory] append Add elements to end of array
pp asdl cell X gc-stats line proc
[Handle Errors] try Run with errexit and set _status
[Handle Errors] try Run with errexit, set _status _error
boolstatus Enforce 0 or 1 exit status
error error 'failed' (status=2)
[Shell State] ysh-cd ysh-shopt compatible, and takes a block
Expand Down Expand Up @@ -219,7 +219,8 @@ X [External Lang] BEGIN END when (awk)
```chapter-links-special-var
[YSH Vars] ARGV X ENV X _ESCAPE
_this_dir
[YSH Status] _status _pipeline_status _process_sub_status
[YSH Status] _status _error
_pipeline_status _process_sub_status
[YSH Tracing] SHX_indent SHX_punct SHX_pid_str
[YSH read] _reply
[History] YSH_HISTFILE
Expand Down
26 changes: 15 additions & 11 deletions spec/ysh-json.test.sh
@@ -1,4 +1,4 @@
## oils_failures_allowed: 4
## oils_failures_allowed: 2
## tags: dev-minimal

#### usage errors
Expand Down Expand Up @@ -360,13 +360,16 @@ pp line (fromJ8(message))
## END

#### User can handle errors - toJson() toJ8()
shopt -s ysh:upgrade

var obj = []
call obj->append(obj)

try echo $[toJson(obj)]
try {
echo $[toJson(obj)]
}
echo status=$_status
echo "encode error $[_error.message]"
echo "encode error $[_error.message]" | sed 's/0x[a-f0-9]\+/(object id)/'

try { # use different style
echo $[toJ8( /d+/ )]
Expand All @@ -379,36 +382,37 @@ echo $[toJson(obj)]

## status: 4
## STDOUT:
status=4 # special encode/decode error?
encode error CYCLE
status=4
encode error TYPE
encode error Can't encode List (object id) in object cycle
status=4
encode error Can't serialize object of type Eggex
## END

#### User can handle errors - fromJson() fromJ8()
shopt -s ysh:upgrade

var message ='[42,1.5,null,true,"hi"'

try {
var obj = fromJson(message)
}
echo status=$_status
echo decode error $[_error.message]
echo "decode error $[_error.message]" | egrep -o '.*Expected.*RBracket'

try {
var obj = fromJ8(message)
}
echo status=$_status
echo decode error $[_error.message]
echo "decode error $[_error.message]" | egrep -o '.*Expected.*RBracket'

# This makes the interpreter fail with a message
var obj = fromJson(message)

## status: 4
## STDOUT:
status=4 # special encode/decode error?
decode error CYCLE
status=4
decode error TYPE
decode error Expected Id.J8_RBracket
status=4
decode error Expected Id.J8_RBracket
## END

0 comments on commit c4d9299

Please sign in to comment.