executePredicate <- function (predicate, state, event) { for (i in 1L:length(predicate)) { ## Need to do this by number as names might not be unique. state <- do.call(names(predicate)[[i]],list(predicate[[i]],state,event)) } return (state) } buildMessages <- function (predicate, state, event) { ## These should all be !send, but might be something else. lapply(names(predicate), function (op) do.call(op,list(predicate[[op]],state,event))) } "!set" <- function (predicate, state, event) { for (name in names(predicate)) { value <- predicate[[name]] if (is.character(value) && grepl("^(state|event)\\.",value) ) value <- getJS(value,state,event) state <- setJS(name,state,timestamp(event),asif.difftime(value)) } state } ## The \texttt{!unset} operator is an inverse. For this the ## \textit{value} should be one of \texttt{"NULL"}, \texttt{"NA"}, or ## \texttt{"Delete"}. The first two set the values to NULL and NA (not ## applicable) respectively. The rules for these values are ## implementation dependent. The third removes the flag or observable ## from the state object. "!unset" <- function (predicate, state, event) { for (name in names(predicate)) { value <- predicate[[name]] if (is.character(value) && grepl("^(state|event)\\.",value) ) value <- asif.difftime(getJS(value,state,event)) if (is.null(value) || isTRUE(toupper(value)=="NULL")) state <- setJS(name,state,timestamp(event),NULL) else if (is.na(value) || isTRUE(toupper(value)=="NA")) state <- setJS(name,state,timestamp(event),NA) else state <- removeJS(name,state) } state } modify <- function (predicate, state, event, op) { for (name in names(predicate)) { curr <- getJS(name,state,event) value <- predicate[[name]] if (is.character(value) && grepl("^(state|event)\\.",value) ) value <- asif.difftime(getJS(value,state,event)) result <- do.call(op,list(curr,value)) state <- setJS(name,state,timestamp(event),result) } state } "!incr" <- function (predicate, state, event) modify(predicate,state,event,"+") "!decr" <- function (predicate, state, event) modify(predicate,state,event,"-") "!mult" <- function (predicate, state, event) modify(predicate,state,event,"*") "!div" <- function (predicate, state, event) modify(predicate,state,event,"/") "!min" <- function (predicate, state, event) modify(predicate,state,event,"min") "!max" <- function (predicate, state, event) modify(predicate,state,event,"max") "!addToSet" <- function (predicate, state, event) modify(predicate,state,event, function(curr,val){ if (val %in% curr) curr else c(curr,val) }) "!setKeyValue" <- function (predicate, state, event) { for (name in names(predicate)) { curr <- getJS(name,state,event) arg <- predicate[[name]] key <- arg[["key"]] value <- arg[["value"]] if (is.character(key) && grepl("^(state|event)\\.",key) ) key <- getJS(key,state,event) if (is.character(value) && grepl("^(state|event)\\.",value) ) value <- getJS(value,state,event) if (!is.numeric(key) && nchar(key)==0L) { flog.warn("Blank key while executing: ",precicate,capture=TRUE) } else { curr[[key]] <- value state <- setJS(name,state,timestamp(event),curr) } } state } "!pullFromSet" <- function (predicate, state, event) modify(predicate,state,event,setdiff) "!push" <- function (predicate, state, event) modify(predicate,state,event, function (curr,val) c(val,curr)) "!pop" <- function (predicate, state, event) { for (name in names(predicate)) { curr <- getJS(name,state,event) value <- predicate[[name]] if (is.character(value) && grepl("^state\\.",value) ) { v1 <- getJS(paste(name,'[1]',sep=""),state,event) state <- setJS(value,state,timestamp(event),v1) value <- 1 } value <- as.integer(value) state <- setJS(name,state,timestamp(event),curr[-(1:value)]) } state } ## Timers are treated specially by the \texttt{!set} operator. In ## particular, there are two fields of the timer object which can be ## set, \texttt{state.timers.\textit{name}.value} and ## \texttt{state.timers.\textit{name}.running}. The latter value can ## be set to \texttt{true} or \texttt{false} which causes it to resume ## or pause respectively. The \texttt{.value} field of the timer sets ## the current time; this is assumed if the field is omitted. This can ## be treated like a numeric value with the time in seconds, or it can ## be set as an object of the form \texttt{\{time:\textit{number}, ## units:\textit{unit}\}}, where \textit{unit} is one of ## \texttt{"sec"}, \texttt{"min"}, \texttt{"hr"}, \texttt{"day"} and so ## forth. Example~\ref{json:time} gives a few examples: ## !start & !reset are treated specially. A number of cases: ## !start: ## !start: {: