Validate an odin model. This function is closer to odin_parse_ than odin_parse because it does not do any quoting of the code. It is primarily intended for use within other applications.
odin_validate(x, type = NULL, options = NULL)
An expression, character vector or filename with the odin code
An optional string indicating the the type of input -
must be one of expression
, file
or text
if
provided. This skips the type detection code used by odin and
makes validating user input easier.
odin options; see odin_options. The
primary options that affect the parse stage are validate
and pretty
.
odin_validate
will always return a list with the same
elements:
A boolean, TRUE
if validation was successful
The intermediate representation, as returned by
odin_parse_, if the validation was successful,
otherwise NULL
An error object if the validation was unsuccessful,
otherwise NULL
. This may be a classed odin error, in which
case it will contain source location information - see the
examples for details.
A list of messages, if the validation returned any. At present this is only non-fatal information about unused variables.
# A successful validation:
odin::odin_validate(c("deriv(x) <- 1", "initial(x) <- 1"))
#> $success
#> [1] TRUE
#>
#> $result
#> {"version":"1.5.11","config":{"base":"odin","include":null,"custom":null},"meta":{"internal":"internal","user":"user","state":"state","result":"dstatedt","output":"output","time":"t","initial_time":"initial_t"},"features":{"continuous":true,"discrete":false,"mixed":false,"has_array":false,"has_output":false,"has_user":false,"has_delay":false,"has_interpolate":false,"has_stochastic":false,"has_data":false,"has_compare":false,"has_include":false,"has_debug":false,"has_derivative":false,"initial_time_dependent":false},"data":{"elements":[{"name":"initial_x","location":"internal","storage_type":"double","rank":0,"dimnames":null,"stage":"constant"},{"name":"x","location":"variable","storage_type":"double","rank":0,"dimnames":null,"stage":"time"}],"variable":{"length":1,"contents":[{"name":"x","offset":0,"initial":"initial_x"}]},"output":{"length":0,"contents":[]}},"equations":[{"name":"deriv_x","type":"expression_scalar","source":[1],"depends":null,"lhs":"x","rhs":{"value":1}},{"name":"initial_x","type":"expression_scalar","source":[2],"depends":null,"lhs":"initial_x","rhs":{"value":1}}],"debug":[],"components":{"create":{"variables":[],"equations":["initial_x"]},"user":{"variables":[],"equations":[]},"initial":{"variables":[],"equations":[]},"rhs":{"variables":[],"equations":["deriv_x"]},"update_stochastic":{"variables":[],"equations":[]},"output":{"variables":[],"equations":[]},"compare":{"variables":[],"equations":[]}},"user":[],"interpolate":{"min":[],"max":[],"critical":[]},"source":["deriv(x) <- 1","initial(x) <- 1"]}
#>
#> $error
#> NULL
#>
#> $messages
#> list()
#>
# A complete failure:
odin::odin_validate("")
#> $success
#> [1] FALSE
#>
#> $result
#> NULL
#>
#> $error
#> <simpleError in odin_preprocess_detect(x, type): '' looks like a filename, but file does not exist>
#>
#> $messages
#> list()
#>
# A more interesting failure
code <- c("deriv(x) <- a", "initial(x) <- 1")
res <- odin::odin_validate(code)
res
#> $success
#> [1] FALSE
#>
#> $result
#> NULL
#>
#> $error
#> <odin_error: Unknown variable a
#> deriv(x) <- a # (line 1)>
#>
#> $messages
#> list()
#>
# The object 'res$error' is an 'odin_error' object:
res$error
#> <odin_error: Unknown variable a
#> deriv(x) <- a # (line 1)>
# It contains information that might be used to display to a
# user information about the error:
unclass(res$error)
#> $message
#> [1] "Unknown variable a\n\tderiv(x) <- a # (line 1)"
#>
#> $msg
#> [1] "Unknown variable a"
#>
#> $line
#> [1] 1
#>
#> $expr
#> [1] "deriv(x) <- a"
#>
#> $type
#> [1] "error"
#>
# Notes are raised in a similar way:
code <- c("deriv(x) <- 1", "initial(x) <- 1", "a <- 1")
res <- odin::odin_validate(code)
res$messages[[1]]
#> $message
#> [1] "Unused equation: a\n\ta <- 1 # (line 3)"
#>
#> $msg
#> [1] "Unused equation: a"
#>
#> $line
#> [1] 3
#>
#> $expr
#> [1] "a <- 1"
#>
#> $type
#> [1] "message"
#>