Rev 85992 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
# Automatically generated from ../noweb/compiler.nw.## File src/library/compiler/R/cmp.R# Part of the R package, https://www.R-project.org# Copyright (C) 2001-2014 Luke Tierney## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## A copy of the GNU General Public License is available at# https://www.R-project.org/Licenses/#### Compiler options##compilerOptions <- new.env(hash = TRUE, parent = emptyenv())compilerOptions$optimize <- 2compilerOptions$suppressAll <- TRUEcompilerOptions$suppressNoSuperAssignVar <- FALSEcompilerOptions$suppressUndefined <-c(".Generic", ".Method", ".Random.seed", ".self")getCompilerOption <- function(name, options = NULL) {if (name %in% names(options))options[[name]]elseget(name, compilerOptions)}#### General Utilities##pasteExpr <- function(e, prefix = "\n ") {de <- deparse(e)if (length(de) == 1) sQuote(de)else paste(prefix, deparse(e), collapse="")}dots.or.missing <- function(args) {for (i in 1:length(args)) {a <-args[[i]]if (missing(a)) return(TRUE) #**** better test?if (identical(a, quote(`...`))) return(TRUE)}return(FALSE)}anyDots <- function(args) {for (i in 1:length(args)) {a <-args[[i]]if (! missing(a) && identical(a, quote(`...`)))return(TRUE)}return(FALSE)}is.ddsym <- function(name) {(is.symbol(name) || is.character(name)) &&length(grep("^\\.\\.[0-9]+$", as.character(name))) != 0}missingArgs <- function(args) {val <- logical(length(args))for (i in seq_along(args)) {a <- args[[i]]if (missing(a))val[i] <- TRUEelseval[i] <- FALSE}val}#### Environment utilities##frameTypes <- function(env) {top <- topenv(env)empty <- emptyenv()nl <- 0while (! identical(env, top)) {if (isNamespace(env))stop("namespace found within local environments")env <- parent.env(env)nl <- nl + 1if (identical(env, empty))stop("not a proper evaluation environment")}nn <- 0if (isNamespace(env)) {while (! identical(env, .GlobalEnv)) {if (!isNamespace(env)) {name <- attr(env, "name")if (!is.character(name) || !startsWith(name, "imports:"))stop("non-namespace found within namespace environments")}env <- parent.env(env)nn <- nn + 1if (identical(env, empty))stop("not a proper evaluation environment")}}ng <- 0while (! identical(env, empty)) {if (isNamespace(env))stop("namespace found within global environments")env <- parent.env(env)ng <- ng + 1}rep(c("local", "namespace", "global"), c(nl, nn, ng))}## Given a symbol name and a namespace environment (or a namespace## imports environment) find the namespace in which the symbol's value## was originally defined. Returns NULL if the symbol is not found via## the namespace.findHomeNS <- function(sym, ns, cntxt) {if (! isNamespace(ns)) {## As a convenience this allows for 'ns' to be the imports fame## of a namespace. It appears that these now have a 'name'## attribute of the form 'imports:foo' if 'foo' is the## namespace.name <- attr(ns, "name")if (is.null(name))cntxt$stop("'ns' must be a namespace or a namespace imports environment",cntxt)ns <- getNamespace(sub("imports:", "", attr(ns, "name")))}if (exists(sym, ns, inherits = FALSE))nselse if (exists(".__NAMESPACE__.", ns, inherits = FALSE)) {imports <- get(".__NAMESPACE__.", ns)$importsfor (i in rev(seq_along(imports))) {iname <- names(imports)[i]ins <- getNamespace(iname)if (identical(imports[[i]], TRUE)) {if (identical(ins, .BaseNamespaceEnv))exports <- .BaseNamespaceEnvelseexports <- get(".__NAMESPACE__.", ins)$exportsif (exists(sym, exports, inherits = FALSE))return(findHomeNS(sym, ins, cntxt))}else {exports <- imports[[i]]pos <- match(sym, names(exports), 0)if (pos) {## If renaming has been used things get too## confusing so return NULL. (It is not clear if## renaming this is still supported by the## namespace code.)if (sym == exports[pos])return(findHomeNS(sym, ins, cntxt))elsereturn(NULL)}}}NULL}else NULL}packFrameName <- function(frame) {fname <- attr(frame, "name")if (is.character(fname))sub("package:", "", fname)else if (identical(frame , baseenv()))"base"else ""}nsName <- function(ns) {if (identical(ns, .BaseNamespaceEnv))"base"else {name <- ns$.__NAMESPACE__.$spec["name"]if (is.character(name))as.character(name) ## strip off nameselse ""}}#### Finding possible local variables##getAssignedVar <- function(e, cntxt) {v <- e[[2]]if (missing(v))cntxt$stop(gettextf("bad assignment: %s", pasteExpr(e)), cntxt)else if (typeof(v) %in% c("symbol", "character"))as.character(v)else {while (typeof(v) == "language") {if (length(v) < 2)cntxt$stop(gettextf("bad assignment: %s", pasteExpr(e)), cntxt)v <- v[[2]]if (missing(v))cntxt$stop(gettextf("bad assignment: %s", pasteExpr(e)), cntxt)}if (typeof(v) != "symbol")cntxt$stop(gettextf("bad assignment: %s", pasteExpr(e)), cntxt)as.character(v)}}addVar <- function(v, vars) assign(v, 1, envir = vars)findLocals1 <- function(e, shadowed = character(0), cntxt, vars) {if (typeof(e) == "language") {if (typeof(e[[1]]) %in% c("symbol", "character")) {v <- as.character(e[[1]])switch(v,"=" =,"<-" = { addVar(getAssignedVar(e, cntxt), vars); e[-1] },"for" = { addVar(as.character(e[2]), vars); e[-2] },"delayedAssign" =,"assign" = if (length(e) == 3 &&is.character(e[[2]]) &&length(e[[2]]) == 1) {addVar(e[[2]], vars); list(e[[3]])}else e[1],"function" = character(0),"~" = character(0),"local" = if (! v %in% shadowed && length(e) == 2)NULLelse e[-1],"expression" =,"quote" = if (! v %in% shadowed)NULLelse e[-1],e[-1])}else e}else NULL}findLocalsList1 <- function(elist, shadowed, cntxt) {todo <- elistvars <- new.env()while(length(todo) > 0) {newtodo <- list()lapply(todo, function(e)lapply(findLocals1(e, shadowed, cntxt, vars),function(x)if (typeof(x) == "language")newtodo <<- append(newtodo, x)))todo <- newtodo}ls(vars, all.names=T)}findLocals <- function(e, cntxt)findLocalsList(list(e), cntxt)findLocalsList <- function(elist, cntxt) {initialShadowedFuns <- c("expression", "local", "quote")shadowed <- Filter(function(n) ! isBaseVar(n, cntxt), initialShadowedFuns)specialSyntaxFuns <- c("~", "<-", "=", "for", "function")sf <- initialShadowedFunsnsf <- length(sf)repeat {vals <- findLocalsList1(elist, sf, cntxt)redefined <- sf %in% valslast.nsf <- nsfsf <- unique(c(shadowed, sf[redefined]))nsf <- length(sf)## **** need to fix the termination condition used in codetools!!!if (last.nsf == nsf) {rdsf <- vals %in% specialSyntaxFunsif (any(rdsf))## cannot get location info (source reference) herenotifyAssignSyntacticFun(vals[rdsf], cntxt)return(vals)}}}#### Compilation environment implementation#### Create a new compiler environment## **** need to explain the structuremakeCenv <- function(env) {structure(list(extra = list(character(0)),env = env,ftypes = frameTypes(env)),class = "compiler_environment")}## Add vars to the top compiler environment frameaddCenvVars <- function(cenv, vars) {cenv$extra[[1]] <- union(cenv$extra[[1]], vars)cenv}## Add a new frame to a compiler environmentaddCenvFrame <- function(cenv, vars) {cenv$extra <- c(list(character(0)), cenv$extra)cenv$env <- new.env(parent = cenv$env)cenv$ftypes <- c("local", cenv$ftypes)if (missing(vars))cenvelseaddCenvVars(cenv, vars)}## Find binding information for a variable (character or name).## If a binding is found, return a list containing components## ftype -- one of "local", "namespace", "global"## value -- current value if available## frame -- frame containing the binding (not useful for "local" variables)## index -- index of the frame (1 for top, 2, for next one, etc.)## Return NULL if no binding is found.## **** drop the index, maybe value, to reduce cost? (query as needed?)findCenvVar <- function(var, cenv) {if (typeof(var) == "symbol")var <- as.character(var)extra <- cenv$extraenv <- cenv$envframe <- NULLfor (i in seq_along(cenv$extra)) {if (var %in% extra[[i]] || exists(var, env, inherits = FALSE)) {frame <- envbreak}elseenv <- parent.env(env)}if (is.null(frame)) {empty <- emptyenv()while (! identical(env, empty)) {i <- i + 1if (exists(var, env, inherits = FALSE)) {frame <- envbreak}elseenv <- parent.env(env)}}if (! is.null(frame)) {if (exists(var, frame, inherits = FALSE) && var != "...") {value <- new.env(parent = emptyenv())delayedAssign("value", get(var, frame, inherits = FALSE),assign.env = value)}elsevalue <- NULLlist(frame = frame, ftype = cenv$ftypes[i], value = value, index = i)}elseNULL}isBaseVar <- function(var, cntxt) {info <- getInlineInfo(var, cntxt)(! is.null(info) &&(identical(info$frame, .BaseNamespaceEnv) ||identical(info$frame, baseenv())))}## augment compiler environment with function args and localsfunEnv <- function(forms, body, cntxt) {cntxt$env <- addCenvFrame(cntxt$env, names(forms))locals <- findLocalsList(c(forms, body), cntxt)addCenvVars(cntxt$env, locals)}## test whether a local version of a variable might existfindLocVar <- function(var, cntxt) {cenv <- cntxt$envinfo <- findCenvVar(var, cenv)! is.null(info) && info$ftype == "local"}## **** should this check for local functions as well?findFunDef <- function(fun, cntxt) {cenv <- cntxt$envinfo <- findCenvVar(fun, cenv)if (! is.null(info$value) && is.function(info$value$value))info$value$valueelseNULL}findVar <- function(var, cntxt) {cenv <- cntxt$envinfo <- findCenvVar(var, cenv)! is.null(info)}#### Constant folding##maxConstSize <- 10constModes <- c("numeric", "logical", "NULL", "complex", "character")constNames <- c("pi", "T", "F")checkConst <- function(e) {if (mode(e) %in% constModes && length(e) <= maxConstSize)list(value = e)elseNULL}## Assumes all constants will be defined in base.## Eventually allow other packages to define constants.## Any variable with locked binding could be used if type is right.## Allow local declaration of optimize, notinline declaration.constantFoldSym <- function(var, cntxt) {var <- as.character(var)if (var %in% constNames && isBaseVar(var, cntxt))checkConst(get(var, .BaseNamespaceEnv))else NULL}## For now assume all foldable functions are in basegetFoldFun <- function(var, cntxt) {var <- as.character(var)if (var %in% foldFuns && isBaseVar(var, cntxt)) {val <- get(var, .BaseNamespaceEnv)if (is.function(val))valelseNULL}else NULL}constantFoldCall <- function(e, cntxt) {fun <- e[[1]]if (typeof(fun) == "symbol") {ffun <- getFoldFun(fun, cntxt)if (! is.null(ffun)) {args <- as.list(e[-1])for (i in seq_along(args)) {a <- args[[i]]if (missing(a))return(NULL)val <- constantFold(a, cntxt)if (! is.null(val))args[i] <- list(val$value) ## **** in case value is NULLelse return(NULL)}modes <- unlist(lapply(args, mode))if (all(modes %in% constModes)) {tryCatch(checkConst(do.call(ffun, args)),error = function(e) NULL, warning = function(w) NULL)## **** issue warning??}else NULL}else NULL}else NULL}## **** rewrite using switch??constantFold <- function(e, cntxt, loc = NULL) {type = typeof(e)if (type == "language")constantFoldCall(e, cntxt)else if (type == "symbol")constantFoldSym(e, cntxt)else if (type == "promise")cntxt$stop(gettext("cannot constant fold literal promises"),cntxt, loc = loc)else if (type == "bytecode")cntxt$stop(gettext("cannot constant fold literal bytecode objects"),cntxt, loc = loc)else checkConst(e)}foldFuns <- c("+", "-", "*", "/", "^", "(",">", ">=", "==", "!=", "<", "<=", "||", "&&", "!","|", "&", "%%","c", "rep", ":","abs", "acos", "acosh", "asin", "asinh", "atan", "atan2","atanh", "ceiling", "choose", "cos", "cosh", "exp", "expm1","floor", "gamma", "lbeta", "lchoose", "lgamma", "log", "log10","log1p", "log2", "max", "min", "prod", "range", "round","seq_along", "seq.int", "seq_len", "sign", "signif","sin", "sinh", "sqrt", "sum", "tan", "tanh", "trunc","baseenv", "emptyenv", "globalenv","Arg", "Conj", "Im", "Mod", "Re")languageFuns <- c("^", "~", "<", "<<-", "<=", "<-", "=", "==", ">", ">=","|", "||", "-", ":", "!", "!=", "/", "(", "[", "[<-", "[[","[[<-", "{", "@", "$", "$<-", "*", "&", "&&", "%/%", "%*%","%%", "+","::", ":::", "@<-","break", "for", "function", "if", "next", "repeat", "while","local", "return", "switch")#### Opcode constants##Opcodes.argc <- list(BCMISMATCH.OP = 0,RETURN.OP = 0,GOTO.OP = 1,BRIFNOT.OP = 2,POP.OP = 0,DUP.OP = 0,PRINTVALUE.OP = 0,STARTLOOPCNTXT.OP = 2,ENDLOOPCNTXT.OP = 1,DOLOOPNEXT.OP = 0,DOLOOPBREAK.OP = 0,STARTFOR.OP = 3,STEPFOR.OP = 1,ENDFOR.OP = 0,SETLOOPVAL.OP = 0,INVISIBLE.OP = 0,LDCONST.OP = 1,LDNULL.OP = 0,LDTRUE.OP = 0,LDFALSE.OP = 0,GETVAR.OP = 1,DDVAL.OP = 1,SETVAR.OP = 1,GETFUN.OP = 1,GETGLOBFUN.OP = 1,GETSYMFUN.OP = 1,GETBUILTIN.OP = 1,GETINTLBUILTIN.OP = 1,CHECKFUN.OP = 0,MAKEPROM.OP = 1,DOMISSING.OP = 0,SETTAG.OP = 1,DODOTS.OP = 0,PUSHARG.OP = 0,PUSHCONSTARG.OP = 1,PUSHNULLARG.OP = 0,PUSHTRUEARG.OP = 0,PUSHFALSEARG.OP = 0,CALL.OP = 1,CALLBUILTIN.OP = 1,CALLSPECIAL.OP = 1,MAKECLOSURE.OP = 1,UMINUS.OP = 1,UPLUS.OP = 1,ADD.OP = 1,SUB.OP = 1,MUL.OP = 1,DIV.OP = 1,EXPT.OP = 1,SQRT.OP = 1,EXP.OP = 1,EQ.OP = 1,NE.OP = 1,LT.OP = 1,LE.OP = 1,GE.OP = 1,GT.OP = 1,AND.OP = 1,OR.OP = 1,NOT.OP = 1,DOTSERR.OP = 0,STARTASSIGN.OP = 1,ENDASSIGN.OP = 1,STARTSUBSET.OP = 2,DFLTSUBSET.OP = 0,STARTSUBASSIGN.OP = 2,DFLTSUBASSIGN.OP = 0,STARTC.OP = 2,DFLTC.OP = 0,STARTSUBSET2.OP = 2,DFLTSUBSET2.OP = 0,STARTSUBASSIGN2.OP = 2,DFLTSUBASSIGN2.OP = 0,DOLLAR.OP = 2,DOLLARGETS.OP = 2,ISNULL.OP = 0,ISLOGICAL.OP = 0,ISINTEGER.OP = 0,ISDOUBLE.OP = 0,ISCOMPLEX.OP = 0,ISCHARACTER.OP = 0,ISSYMBOL.OP = 0,ISOBJECT.OP = 0,ISNUMERIC.OP = 0,VECSUBSET.OP = 1,MATSUBSET.OP = 1,VECSUBASSIGN.OP = 1,MATSUBASSIGN.OP = 1,AND1ST.OP = 2,AND2ND.OP = 1,OR1ST.OP = 2,OR2ND.OP = 1,GETVAR_MISSOK.OP = 1,DDVAL_MISSOK.OP = 1,VISIBLE.OP = 0,SETVAR2.OP = 1,STARTASSIGN2.OP = 1,ENDASSIGN2.OP = 1,SETTER_CALL.OP = 2,GETTER_CALL.OP = 1,SWAP.OP = 0,DUP2ND.OP = 0,SWITCH.OP = 4,RETURNJMP.OP = 0,STARTSUBSET_N.OP = 2,STARTSUBASSIGN_N.OP = 2,VECSUBSET2.OP = 1,MATSUBSET2.OP = 1,VECSUBASSIGN2.OP = 1,MATSUBASSIGN2.OP = 1,STARTSUBSET2_N.OP = 2,STARTSUBASSIGN2_N.OP = 2,SUBSET_N.OP = 2,SUBSET2_N.OP = 2,SUBASSIGN_N.OP = 2,SUBASSIGN2_N.OP = 2,LOG.OP = 1,LOGBASE.OP = 1,MATH1.OP = 2,DOTCALL.OP = 2,COLON.OP = 1,SEQALONG.OP = 1,SEQLEN.OP = 1,BASEGUARD.OP = 2,INCLNK.OP = 0,DECLNK.OP = 0,DECLNK_N.OP = 1,INCLNKSTK.OP = 0,DECLNKSTK.OP = 0)Opcodes.names <- names(Opcodes.argc)BCMISMATCH.OP <- 0RETURN.OP <- 1GOTO.OP <- 2BRIFNOT.OP <- 3POP.OP <- 4DUP.OP <- 5PRINTVALUE.OP <- 6STARTLOOPCNTXT.OP <- 7ENDLOOPCNTXT.OP <- 8DOLOOPNEXT.OP <- 9DOLOOPBREAK.OP <- 10STARTFOR.OP <- 11STEPFOR.OP <- 12ENDFOR.OP <- 13SETLOOPVAL.OP <- 14INVISIBLE.OP <- 15LDCONST.OP <- 16LDNULL.OP <- 17LDTRUE.OP <- 18LDFALSE.OP <- 19GETVAR.OP <- 20DDVAL.OP <- 21SETVAR.OP <- 22GETFUN.OP <- 23GETGLOBFUN.OP <- 24GETSYMFUN.OP <- 25GETBUILTIN.OP <- 26GETINTLBUILTIN.OP <- 27CHECKFUN.OP <- 28MAKEPROM.OP <- 29DOMISSING.OP <- 30SETTAG.OP <- 31DODOTS.OP <- 32PUSHARG.OP <- 33PUSHCONSTARG.OP <- 34PUSHNULLARG.OP <- 35PUSHTRUEARG.OP <- 36PUSHFALSEARG.OP <- 37CALL.OP <- 38CALLBUILTIN.OP <- 39CALLSPECIAL.OP <- 40MAKECLOSURE.OP <- 41UMINUS.OP <- 42UPLUS.OP <- 43ADD.OP <- 44SUB.OP <- 45MUL.OP <- 46DIV.OP <- 47EXPT.OP <- 48SQRT.OP <- 49EXP.OP <- 50EQ.OP <- 51NE.OP <- 52LT.OP <- 53LE.OP <- 54GE.OP <- 55GT.OP <- 56AND.OP <- 57OR.OP <- 58NOT.OP <- 59DOTSERR.OP <- 60STARTASSIGN.OP <- 61ENDASSIGN.OP <- 62STARTSUBSET.OP <- 63DFLTSUBSET.OP <- 64STARTSUBASSIGN.OP <- 65DFLTSUBASSIGN.OP <- 66STARTC.OP <- 67DFLTC.OP <- 68STARTSUBSET2.OP <- 69DFLTSUBSET2.OP <- 70STARTSUBASSIGN2.OP <- 71DFLTSUBASSIGN2.OP <- 72DOLLAR.OP <- 73DOLLARGETS.OP <- 74ISNULL.OP <- 75ISLOGICAL.OP <- 76ISINTEGER.OP <- 77ISDOUBLE.OP <- 78ISCOMPLEX.OP <- 79ISCHARACTER.OP <- 80ISSYMBOL.OP <- 81ISOBJECT.OP <- 82ISNUMERIC.OP <- 83VECSUBSET.OP <- 84MATSUBSET.OP <- 85VECSUBASSIGN.OP <- 86MATSUBASSIGN.OP <- 87AND1ST.OP <- 88AND2ND.OP <- 89OR1ST.OP <- 90OR2ND.OP <- 91GETVAR_MISSOK.OP <- 92DDVAL_MISSOK.OP <- 93VISIBLE.OP <- 94SETVAR2.OP <- 95STARTASSIGN2.OP <- 96ENDASSIGN2.OP <- 97SETTER_CALL.OP <- 98GETTER_CALL.OP <- 99SWAP.OP <- 100DUP2ND.OP <- 101SWITCH.OP <- 102RETURNJMP.OP <- 103STARTSUBSET_N.OP <- 104STARTSUBASSIGN_N.OP <- 105VECSUBSET2.OP <- 106MATSUBSET2.OP <- 107VECSUBASSIGN2.OP <- 108MATSUBASSIGN2.OP <- 109STARTSUBSET2_N.OP <- 110STARTSUBASSIGN2_N.OP <- 111SUBSET_N.OP <- 112SUBSET2_N.OP <- 113SUBASSIGN_N.OP <- 114SUBASSIGN2_N.OP <-115LOG.OP <- 116LOGBASE.OP <- 117MATH1.OP <- 118DOTCALL.OP <- 119COLON.OP <- 120SEQALONG.OP <- 121SEQLEN.OP <- 122BASEGUARD.OP <- 123INCLNK.OP <- 124DECLNK.OP <- 125DECLNK_N.OP <- 126INCLNKSTK.OP <- 127DECLNKSTK.OP <- 128#### Code buffer implementation##extractSrcref <- function(sref, idx) {if (is.list(sref) && length(sref) >= idx)sref[[idx]]else if (is.integer(sref) && length(sref) >= 6)srefelseNULL}getExprSrcref <- function(expr) {sattr <- attr(expr, "srcref")extractSrcref(sattr, 1)}# if block is a block srcref, get its idx'th entry# if block is a single srcref, return this srcrefgetBlockSrcref <- function(block, idx) {extractSrcref(block, idx)}addLocString <- function(msg, loc) {if (is.null(loc$srcref))msgelsepaste0(msg, " at ", utils::getSrcFilename(loc$srcref), ":",utils::getSrcLocation(loc$srcref, "line"))}make.codeBuf <- function(expr, loc = NULL) {exprTrackingOn <- TRUEsrcrefTrackingOn <- TRUEif (is.null(loc)) {curExpr <- exprcurSrcref <- getExprSrcref(expr)} else {curExpr <- loc$exprcurSrcref <- loc$srcref}if (is.null(curSrcref))## when top-level srcref is null, we speculate there will be no## source references within the compiled expressions either,## disabling the tracking makes the resulting constant pool## smallersrcrefTrackingOn <- FALSEexprBuf <- NA ## exprBuf will have the same length as codeBufsrcrefBuf <- NA ## srcrefBuf will have the same length as codeBufif (!exprTrackingOn) {curExpr <- NULLexprBuf <- NULL}if (!srcrefTrackingOn) {curSrcref <- NULLsrcrefBuf <- NULL}## set the current expression## also update the srcref according to expr, if expr has srcref attribute## (note: never clears current srcref)setcurexpr <- function(expr) {if (exprTrackingOn) {curExpr <<- expr}if (srcrefTrackingOn) {sref <- getExprSrcref(expr)if (!is.null(sref) && srcrefTrackingOn)curSrcref <<- sref}}## unconditionally sets the current expression and srcrefssetcurloc <- function(expr, sref) {if (exprTrackingOn)curExpr <<- exprif (srcrefTrackingOn)curSrcref <<- sref}## add location information (current expressions, srcrefs) to the constant poolcommitlocs <- function() {if (exprTrackingOn) {exprs <- exprBuf[1:codeCount]class(exprs) <- "expressionsIndex"putconst(exprs)}if (srcrefTrackingOn) {srefs <- srcrefBuf[1:codeCount]class(srefs) <- "srcrefsIndex"putconst(srefs)}## these entries will be at the end of the constant pool, assuming only the compiler## uses these two classesNULL}savecurloc <- function() {list(expr = curExpr, srcref = curSrcref)}restorecurloc <- function(saved) {if (exprTrackingOn) curExpr <<- saved$exprif (srcrefTrackingOn) curSrcref <<- saved$srcref}codeBuf <- list(.Internal(bcVersion()))codeCount <- 1putcode <- function(...) {new <- list(...)newLen <- length(new)while (codeCount + newLen > length(codeBuf)) {codeBuf <<- c(codeBuf, vector("list", length(codeBuf)))if (exprTrackingOn)exprBuf <<- c(exprBuf, vector("integer", length(exprBuf)))if (srcrefTrackingOn)srcrefBuf <<- c(srcrefBuf, vector("integer", length(srcrefBuf)))}codeRange <- (codeCount + 1) : (codeCount + newLen)codeBuf[codeRange] <<- newif (exprTrackingOn) { ## put current expression into the constant poolei <- putconst(curExpr)exprBuf[codeRange] <<- ei}if (srcrefTrackingOn) { ## put current srcref into the constant poolsi <- putconst(curSrcref)srcrefBuf[codeRange] <<- si}codeCount <<- codeCount + newLen}getcode <- function() as.integer(codeBuf[1 : codeCount])constBuf <- vector("list", 1)constCount <- 0putconst <- function(x) {if (constCount == length(constBuf))constBuf <<- .Internal(growconst(constBuf))i <- .Internal(putconst(constBuf, constCount, x))if (i == constCount)constCount <<- constCount + 1i}getconst <- function().Internal(getconst(constBuf, constCount))idx <- 0labels <- vector("list")makelabel <- function() { idx <<- idx + 1; paste0("L", idx) }putlabel <- function(name) labels[[name]] <<- codeCountpatchlabels <- function(cntxt) {offset <- function(lbl) {if (is.null(labels[[lbl]]))cntxt$stop(gettextf("no offset recorded for label \"%s\"", lbl),cntxt)labels[[lbl]]}for (i in 1 : codeCount) {v <- codeBuf[[i]]if (is.character(v))codeBuf[[i]] <<- offset(v)else if (typeof(v) == "list") {off <- as.integer(lapply(v, offset))ci <- putconst(off)codeBuf[[i]] <<- ci}}}cb <- list(code = getcode,const = getconst,putcode = putcode,putconst = putconst,makelabel = makelabel,putlabel = putlabel,patchlabels = patchlabels,setcurexpr = setcurexpr,setcurloc = setcurloc,commitlocs = commitlocs,savecurloc = savecurloc,restorecurloc = restorecurloc)cb$putconst(expr) ## insert expression as first constant.## NOTE: this will also insert the srcref directly into the constant## poolcb}codeBufCode <- function(cb, cntxt) {cb$patchlabels(cntxt)cb$commitlocs().Internal(mkCode(cb$code(), cb$const()))}genCode <- function(e, cntxt, gen = NULL, loc = NULL) {cb <- make.codeBuf(e, loc)if (is.null(gen))cmp(e, cb, cntxt, setloc = FALSE)elsegen(cb, cntxt)codeBufCode(cb, cntxt)}#### Compiler contexts##make.toplevelContext <- function(cenv, options = NULL)structure(list(toplevel = TRUE,tailcall = TRUE,needRETURNJMP = FALSE,env = cenv,optimize = getCompilerOption("optimize", options),suppressAll = getCompilerOption("suppressAll", options),suppressNoSuperAssignVar =getCompilerOption("suppressNoSuperAssignVar", options),suppressUndefined = getCompilerOption("suppressUndefined",options),call = NULL,stop = function(msg, cntxt, loc = NULL)stop(simpleError(addLocString(msg, loc), cntxt$call)),warn = function(x, cntxt, loc = NULL)cat(paste("Note:", addLocString(x, loc), "\n"))),class = "compiler_context")make.callContext <- function(cntxt, call) {cntxt$call <- callcntxt}make.promiseContext <- function(cntxt) {cntxt$toplevel <- FALSEcntxt$tailcall <- TRUEcntxt$needRETURNJMP <- TRUEif (! is.null(cntxt$loop))cntxt$loop$gotoOK <- FALSEcntxt}make.functionContext <- function(cntxt, forms, body) {nenv <- funEnv(forms, body, cntxt)ncntxt <- make.toplevelContext(nenv)ncntxt$optimize <- cntxt$optimizencntxt$suppressAll <- cntxt$suppressAllncntxt$suppressNoSuperAssignVar <- cntxt$suppressNoSuperAssignVarncntxt$suppressUndefined <- cntxt$suppressUndefinedncntxt}make.nonTailCallContext <- function(cntxt) {cntxt$tailcall <- FALSEcntxt}make.argContext <- function(cntxt) {cntxt$toplevel <- FALSEcntxt$tailcall <- FALSEif (! is.null(cntxt$loop))cntxt$loop$gotoOK <- FALSEcntxt}make.noValueContext <- function(cntxt) {cntxt$tailcall <- FALSEcntxt}make.loopContext <- function(cntxt, loop.label, end.label) {ncntxt <- make.noValueContext(cntxt)ncntxt$loop <- list(loop = loop.label, end = end.label, gotoOK = TRUE)ncntxt}#### Compiler top level##cmp <- function(e, cb, cntxt, missingOK = FALSE, setloc = TRUE) {if (setloc) {sloc <- cb$savecurloc()cb$setcurexpr(e)}ce <- constantFold(e, cntxt, loc = cb$savecurloc())if (is.null(ce)) {if (typeof(e) == "language")cmpCall(e, cb, cntxt)else if (typeof(e) == "symbol")cmpSym(e, cb, cntxt, missingOK)else if (typeof(e) == "bytecode")cntxt$stop(gettext("cannot compile byte code literals in code"),cntxt, loc = cb$savecurloc())else if (typeof(e) == "promise")cntxt$stop(gettext("cannot compile promise literals in code"),cntxt, loc = cb$savecurloc())elsecmpConst(e, cb, cntxt)}elsecmpConst(ce$value, cb, cntxt)if (setloc)cb$restorecurloc(sloc)}cmpConst <- function(val, cb, cntxt) {if (identical(val, NULL))cb$putcode(LDNULL.OP)else if (identical(val, TRUE))cb$putcode(LDTRUE.OP)else if (identical(val, FALSE))cb$putcode(LDFALSE.OP)else {ci <- cb$putconst(val)cb$putcode(LDCONST.OP, ci)}if (cntxt$tailcall) cb$putcode(RETURN.OP)}cmpSym <- function(sym, cb, cntxt, missingOK = FALSE) {if (identical(sym, quote(`...`))) {notifyWrongDotsUse("...", cntxt, loc = cb$savecurloc())cb$putcode(DOTSERR.OP)}else if (is.ddsym(sym)) {if (! findLocVar("...", cntxt))notifyWrongDotsUse(sym, cntxt, loc = cb$savecurloc())ci <- cb$putconst(sym)if (missingOK)cb$putcode(DDVAL_MISSOK.OP, ci)elsecb$putcode(DDVAL.OP, ci)if (cntxt$tailcall) cb$putcode(RETURN.OP)}else {if (! findVar(sym, cntxt))notifyUndefVar(sym, cntxt, loc = cb$savecurloc())ci <- cb$putconst(sym)if (missingOK)cb$putcode(GETVAR_MISSOK.OP, ci)elsecb$putcode(GETVAR.OP, ci)if (cntxt$tailcall) cb$putcode(RETURN.OP)}}cmpCall <- function(call, cb, cntxt, inlineOK = TRUE) {sloc <- cb$savecurloc()cb$setcurexpr(call)cntxt <- make.callContext(cntxt, call)fun <- call[[1]]args <- call[-1]if (typeof(fun) == "symbol") {if (! (inlineOK && tryInline(call, cb, cntxt))) {if (findLocVar(fun, cntxt))notifyLocalFun(fun, cntxt, loc = cb$savecurloc())else {def <- findFunDef(fun, cntxt)if (is.null(def))notifyUndefFun(fun, cntxt, loc = cb$savecurloc())elsecheckCall(def, call,function(w) notifyBadCall(w, cntxt, loc = cb$savecurloc()))}cmpCallSymFun(fun, args, call, cb, cntxt)}}else {## **** this hack is needed for now because of the way the## **** parser handles break() and next() callsif (typeof(fun) == "language" && typeof(fun[[1]]) == "symbol" &&as.character(fun[[1]]) %in% c("break", "next"))return(cmp(fun, cb, cntxt))cmpCallExprFun(fun, args, call, cb, cntxt)}cb$restorecurloc(sloc)}maybeNSESymbols <- c("bquote")cmpCallSymFun <- function(fun, args, call, cb, cntxt) {ci <- cb$putconst(fun)cb$putcode(GETFUN.OP, ci)nse <- as.character(fun) %in% maybeNSESymbolscmpCallArgs(args, cb, cntxt, nse)ci <- cb$putconst(call)cb$putcode(CALL.OP, ci)if (cntxt$tailcall) cb$putcode(RETURN.OP)}cmpCallExprFun <- function(fun, args, call, cb, cntxt) {ncntxt <- make.nonTailCallContext(cntxt)cmp(fun, cb, ncntxt)cb$putcode(CHECKFUN.OP)nse <- FALSEcmpCallArgs(args, cb, cntxt, nse)ci <- cb$putconst(call)cb$putcode(CALL.OP, ci)if (cntxt$tailcall) cb$putcode(RETURN.OP)}cmpCallArgs <- function(args, cb, cntxt, nse = FALSE) {names <- names(args)pcntxt <- make.promiseContext(cntxt)for (i in seq_along(args)) {a <- args[[i]]n <- names[[i]]if (missing(a)) { ## better test for missing??cb$putcode(DOMISSING.OP)cmpTag(n, cb)}else if (identical(a, quote(`...`))) {if (! findLocVar("...", cntxt))notifyWrongDotsUse("...", cntxt, loc = cb$savecurloc())cb$putcode(DODOTS.OP)}else if (typeof(a) == "bytecode")cntxt$stop(gettext("cannot compile byte code literals in code"),cntxt, loc = cb$savecurloc())else if (typeof(a) == "promise")cntxt$stop(gettext("cannot compile promise literals in code"),cntxt, loc = cb$savecurloc())else {if (is.symbol(a) || typeof(a) == "language") {if (nse)ci <- cb$putconst(a)elseci <- cb$putconst(genCode(a, pcntxt, loc = cb$savecurloc()))cb$putcode(MAKEPROM.OP, ci)}elsecmpConstArg(a, cb, cntxt)cmpTag(n, cb)}}}cmpConstArg <- function(a, cb, cntxt) {if (identical(a, NULL))cb$putcode(PUSHNULLARG.OP)else if (identical(a, TRUE))cb$putcode(PUSHTRUEARG.OP)else if (identical(a, FALSE))cb$putcode(PUSHFALSEARG.OP)else {ci <- cb$putconst(a)cb$putcode(PUSHCONSTARG.OP, ci)}}## **** figure out how to handle multi-line deparses## **** e.g. checkCall(`{`, quote({}))## **** better design would capture error object, wrap it up, and pass it on## **** use approach from codetools to capture partial argument match## **** warnings if enabled?checkCall <- function(def, call, signal = warning) {if (typeof(def) %in% c("builtin", "special"))def <- args(def)if (typeof(def) != "closure" || anyDots(call))NAelse {msg <- tryCatch({match.call(def, call); NULL},error = function(e) conditionMessage(e))if (! is.null(msg)) {emsg <- gettextf("possible error in '%s': %s",deparse(call, 20)[1], msg)if (! is.null(signal)) signal(emsg)FALSE}else TRUE}}## **** need to handle ... and ..n arguments specially## **** separate call opcode for calls with named args?## **** for (a in e[[-1]]) ... goes into infinite loopcmpTag <- function(n, cb) {if (! is.null(n) && n != "") {ci <- cb$putconst(as.name(n))cb$putcode(SETTAG.OP, ci)}}mayCallBrowser <- function(e, cntxt) {if (typeof(e) == "language") {fun <- e[[1]]if (typeof(fun) == "symbol") {fname <- as.character(fun)if (fname == "browser") ## not checking isBaseVar to err on the## positiveTRUEelse if (fname == "function" && isBaseVar(fname, cntxt))FALSEelsemayCallBrowserList(e[-1], cntxt)}elsemayCallBrowserList(e, cntxt)}else FALSE}mayCallBrowserList <- function(elist, cntxt) {for (a in as.list(elist))if (! missing(a) && mayCallBrowser(a, cntxt))return(TRUE)FALSE}#### Inlining mechanism##inlineHandlers <- new.env(hash = TRUE, parent = emptyenv())setInlineHandler <- function(name, h, package = "base") {if (exists(name, inlineHandlers, inherits = FALSE)) {entry <- get(name, inlineHandlers)if (entry$package != package) {fmt <- "handler for '%s' is already defined for another package"stop(gettextf(fmt, name), domain = NA)}}entry <- list(handler = h, package = package)assign(name, entry, inlineHandlers)}getInlineHandler <- function(name, package = "base") {if (exists(name, inlineHandlers, inherits = FALSE)) {hinfo <- get(name, inlineHandlers)if (hinfo$package == package)hinfo$handlerelse NULL}else NULL}haveInlineHandler <- function(name, package = "base") {if (exists(name, inlineHandlers, inherits = FALSE)) {hinfo <- get(name, inlineHandlers)package == hinfo$package}else FALSE}## tryInline implements the rule permitting inlining as they stand now:## Inlining is controlled by the optimize compiler option, with possible## values 0, 1, 2, 3.noInlineSymbols <- c("standardGeneric")getInlineInfo <- function(name, cntxt, guardOK = FALSE) {optimize <- cntxt$optimizeif (optimize > 0 && ! (name %in% noInlineSymbols)) {info <- findCenvVar(name, cntxt$env)if (is.null(info))NULLelse {ftype <- info$ftypeframe <- info$frameif (ftype == "namespace") {if (! isNamespace(frame)) {## should be the import frame of the current topenvtop <- topenv(cntxt$env$env)if (! isNamespace(top) ||! identical(frame, parent.env(top)))cntxt$stop(gettext("bad namespace import frame"))frame <- top}info$package <- nsName(findHomeNS(name, frame, cntxt))info$guard <- FALSEinfo}else if (ftype == "global" &&(optimize >= 3 ||(optimize >= 2 && name %in% languageFuns))) {info$package <- packFrameName(frame)info$guard <- FALSEinfo}else if (guardOK && ftype == "global" &&packFrameName(frame) == "base") {info$package <- packFrameName(frame)info$guard <- TRUEinfo}else NULL}}else NULL}tryInline <- function(e, cb, cntxt) {name <- as.character(e[[1]])info <- getInlineInfo(name, cntxt, guardOK = TRUE)if (is.null(info))FALSEelse {h <- getInlineHandler(name, info$package)if (! is.null(h)) {if (info$guard) {tailcall <- cntxt$tailcallif (tailcall) cntxt$tailcall <- FALSEexpridx <- cb$putconst(e)endlabel <- cb$makelabel()cb$putcode(BASEGUARD.OP, expridx, endlabel)if (! h(e, cb, cntxt))cmpCall(e, cb, cntxt, inlineOK = FALSE)cb$putlabel(endlabel)if (tailcall) cb$putcode(RETURN.OP)TRUE}else h(e, cb, cntxt)}else FALSE}}#### Inline handlers for some SPECIAL functions##setInlineHandler("function", function(e, cb, cntxt) {forms <- e[[2]]body <- e[[3]]sref <- if (length(e) > 3) e[[4]] else NULLncntxt <- make.functionContext(cntxt, forms, body)if (mayCallBrowser(body, cntxt))return(FALSE)cbody <- genCode(body, ncntxt, loc = cb$savecurloc())ci <- cb$putconst(list(forms, cbody, sref))cb$putcode(MAKECLOSURE.OP, ci)if (cntxt$tailcall) cb$putcode(RETURN.OP)TRUE})setInlineHandler("{", function(e, cb, cntxt) {n <- length(e)if (n == 1)cmp(NULL, cb, cntxt)else {sloc <- cb$savecurloc()bsrefs <- attr(e, "srcref")if (n > 2) {ncntxt <- make.noValueContext(cntxt)for (i in 2 : (n - 1)) {subexp <- e[[i]]cb$setcurloc(subexp, getBlockSrcref(bsrefs, i))cmp(subexp, cb, ncntxt, setloc = FALSE)cb$putcode(POP.OP)}}subexp <- e[[n]]cb$setcurloc(subexp, getBlockSrcref(bsrefs, n))cmp(subexp, cb, cntxt, setloc = FALSE)cb$restorecurloc(sloc)}TRUE})setInlineHandler("if", function(e, cb, cntxt) {## **** test for missing, ...test <- e[[2]]then.expr <- e[[3]]if (length(e) == 4) {have.else.expr <- TRUEelse.expr <- e[[4]]}else have.else.expr <- FALSEct <- constantFold(test, cntxt, loc = cb$savecurloc())if (! is.null(ct) && is.logical(ct$value) && length(ct$value) == 1&& ! is.na(ct$value)) {if (ct$value)cmp(then.expr, cb, cntxt)else if (have.else.expr)cmp(else.expr, cb, cntxt)else if (cntxt$tailcall) {cb$putcode(LDNULL.OP)cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}else cb$putcode(LDNULL.OP)return(TRUE)}ncntxt <- make.nonTailCallContext(cntxt)cmp(test, cb, ncntxt)callidx <- cb$putconst(e)else.label <- cb$makelabel()cb$putcode(BRIFNOT.OP, callidx, else.label)cmp(then.expr, cb, cntxt)if (cntxt$tailcall) {cb$putlabel(else.label)if (have.else.expr)cmp(else.expr, cb, cntxt)else {cb$putcode(LDNULL.OP)cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}}else {end.label <- cb$makelabel()cb$putcode(GOTO.OP, end.label)cb$putlabel(else.label)if (have.else.expr)cmp(else.expr, cb, cntxt)elsecb$putcode(LDNULL.OP)cb$putlabel(end.label)}TRUE})setInlineHandler("&&", function(e, cb, cntxt) {## **** arity check??ncntxt <- make.argContext(cntxt)callidx <- cb$putconst(e)label <- cb$makelabel()cmp(e[[2]], cb, ncntxt)cb$putcode(AND1ST.OP, callidx, label)cmp(e[[3]], cb, ncntxt)cb$putcode(AND2ND.OP, callidx)cb$putlabel(label)if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE})setInlineHandler("||", function(e, cb, cntxt) {## **** arity check??ncntxt <- make.argContext(cntxt)callidx <- cb$putconst(e)label <- cb$makelabel()cmp(e[[2]], cb, ncntxt)cb$putcode(OR1ST.OP, callidx, label)cmp(e[[3]], cb, ncntxt)cb$putcode(OR2ND.OP, callidx)cb$putlabel(label)if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE})#### Inline handlers for assignment expressions##setterInlineHandlers <- new.env(hash = TRUE, parent = emptyenv())setSetterInlineHandler <- function(name, h, package = "base") {if (exists(name, setterInlineHandlers, inherits = FALSE)) {entry <- get(name, setterInlineHandlers)if (entry$package != package) {fmt <- "handler for '%s' is already defined for another package"stop(gettextf(fmt, name), domain = NA)}}entry <- list(handler = h, package = package)assign(name, entry, setterInlineHandlers)}getSetterInlineHandler <- function(name, package = "base") {if (exists(name, setterInlineHandlers, inherits = FALSE)) {hinfo <- get(name, setterInlineHandlers)if (hinfo$package == package)hinfo$handlerelse NULL}else NULL}trySetterInline <- function(afun, place, origplace, call, cb, cntxt) {name <- as.character(afun)info <- getInlineInfo(name, cntxt)if (is.null(info))FALSEelse {h <- getSetterInlineHandler(name, info$package)if (! is.null(h))h(afun, place, origplace, call, cb, cntxt)else FALSE}}getterInlineHandlers <- new.env(hash = TRUE, parent = emptyenv())setGetterInlineHandler <- function(name, h, package = "base") {if (exists(name, getterInlineHandlers, inherits = FALSE)) {entry <- get(name, getterInlineHandlers)if (entry$package != package) {fmt <- "handler for '%s' is already defined for another package"stop(gettextf(fmt, name), domain = NA)}}entry <- list(handler = h, package = package)assign(name, entry, getterInlineHandlers)}getGetterInlineHandler <- function(name, package = "base") {if (exists(name, getterInlineHandlers, inherits = FALSE)) {hinfo <- get(name, getterInlineHandlers)if (hinfo$package == package)hinfo$handlerelse NULL}else NULL}tryGetterInline <- function(call, cb, cntxt) {name <- as.character(call[[1]])info <- getInlineInfo(name, cntxt)if (is.null(info))FALSEelse {h <- getGetterInlineHandler(name, info$package)if (! is.null(h))h(call, cb, cntxt)else FALSE}}cmpAssign <- function(e, cb, cntxt) {## if (! cntxt$toplevel)## return(cmpSpecial(e, cb, cntxt))if (! checkAssign(e, cntxt, loc = cb$savecurloc()))return(cmpSpecial(e, cb, cntxt))superAssign <- identical(e[[1]], quote(`<<-`))lhs <- e[[2]]value <- e[[3]]symbol <- as.name(getAssignedVar(e, cntxt))if (superAssign && ! findVar(symbol, cntxt))notifyNoSuperAssignVar(symbol, cntxt, loc = cb$savecurloc())if (is.name(lhs) || is.character(lhs))cmpSymbolAssign(symbol, value, superAssign, cb, cntxt)else if (typeof(lhs) == "language")cmpComplexAssign(symbol, lhs, value, superAssign, cb, cntxt)else cmpSpecial(e, cb, cntxt) # punt for now}flattenPlace <- function(place, cntxt, loc = NULL) {places <- NULLorigplaces <- NULLwhile (typeof(place) == "language") {if (length(place) < 2)cntxt$stop(gettext("bad assignment 1"), cntxt, loc = loc)origplaces <- c(origplaces, list(place))tplace <- placetplace[[2]] <- as.name("*tmp*")places <- c(places, list(tplace))place <- place[[2]]}if (typeof(place) != "symbol")cntxt$stop(gettext("bad assignment 2"), cntxt, loc = loc)list(places = places, origplaces = origplaces)}cmpGetterCall <- function(place, origplace, cb, cntxt) {ncntxt <- make.callContext(cntxt, place)sloc <- cb$savecurloc()cb$setcurexpr(origplace)fun <- place[[1]]if (typeof(fun) == "symbol") {if (! tryGetterInline(place, cb, ncntxt)) {ci <- cb$putconst(fun)cb$putcode(GETFUN.OP, ci)cb$putcode(PUSHNULLARG.OP)cmpCallArgs(place[-c(1, 2)], cb, ncntxt)cci <- cb$putconst(place)cb$putcode(GETTER_CALL.OP, cci)cb$putcode(SWAP.OP)}}else {cmp(fun, cb, ncntxt)cb$putcode(CHECKFUN.OP)cb$putcode(PUSHNULLARG.OP)cmpCallArgs(place[-c(1, 2)], cb, ncntxt)cci <- cb$putconst(place)cb$putcode(GETTER_CALL.OP, cci)cb$putcode(SWAP.OP)}cb$restorecurloc(sloc)}checkAssign <- function(e, cntxt, loc = NULL) {if (length(e) != 3)FALSEelse {place <- e[[2]]if (typeof(place) == "symbol" ||(typeof(place) == "character" && length(place) == 1))TRUEelse {while (typeof(place) == "language") {fun <- place[[1]]if (typeof(fun) != "symbol" &&! (typeof(fun) == "language" && length(fun) == 3 &&typeof(fun[[1]]) == "symbol" &&as.character(fun[[1]]) %in% c("::", ":::"))) {notifyBadAssignFun(fun, cntxt, loc)return(FALSE)}place = place[[2]]}if (typeof(place) == "symbol")TRUEelse FALSE}}}cmpSymbolAssign <- function(symbol, value, superAssign, cb, cntxt) {ncntxt <- make.nonTailCallContext(cntxt)cmp(value, cb, ncntxt)ci <- cb$putconst(symbol)if (superAssign)cb$putcode(SETVAR2.OP, ci)elsecb$putcode(SETVAR.OP, ci)if (cntxt$tailcall) {cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}TRUE}cmpComplexAssign <- function(symbol, lhs, value, superAssign, cb, cntxt) {if (superAssign) {startOP <- STARTASSIGN2.OPendOP <- ENDASSIGN2.OP}else {if (! findVar(symbol, cntxt))notifyUndefVar(symbol, cntxt, loc = cb$savecurloc())startOP <- STARTASSIGN.OPendOP <- ENDASSIGN.OP}if (! cntxt$toplevel) cb$putcode(INCLNKSTK.OP)ncntxt <- make.nonTailCallContext(cntxt)cmp(value, cb, ncntxt)csi <- cb$putconst(symbol)cb$putcode(startOP, csi)ncntxt <- make.argContext(cntxt)flat <- flattenPlace(lhs, cntxt, loc = cb$savecurloc())flatOrigPlace <- flat$origplacesflatPlace <- flat$placesflatPlaceIdxs <- seq_along(flatPlace)[-1]for (i in rev(flatPlaceIdxs))cmpGetterCall(flatPlace[[i]], flatOrigPlace[[i]], cb, ncntxt)cmpSetterCall(flatPlace[[1]], flatOrigPlace[[1]], value, cb, ncntxt)for (i in flatPlaceIdxs)cmpSetterCall(flatPlace[[i]], flatOrigPlace[[i]], as.name("*vtmp*"), cb, ncntxt)cb$putcode(endOP, csi)if (! cntxt$toplevel) cb$putcode(DECLNKSTK.OP)if (cntxt$tailcall) {cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}TRUE;}cmpSetterCall <- function(place, origplace, vexpr, cb, cntxt) {afun <- getAssignFun(place[[1]])acall <- as.call(c(afun, as.list(place[-1]), list(value = vexpr)))acall[[2]] <- as.name("*tmp*")ncntxt <- make.callContext(cntxt, acall)sloc <- cb$savecurloc()cexpr <- as.call(c(afun, as.list(origplace[-1]), list(value = vexpr)))cb$setcurexpr(cexpr)if (is.null(afun))## **** warn instead and arrange for cmpSpecial?## **** or generate code to signal runtime error?cntxt$stop(gettext("invalid function in complex assignment"),loc = cb$savecurloc())else if (typeof(afun) == "symbol") {if (! trySetterInline(afun, place, origplace, acall, cb, ncntxt)) {ci <- cb$putconst(afun)cb$putcode(GETFUN.OP, ci)cb$putcode(PUSHNULLARG.OP)cmpCallArgs(place[-c(1, 2)], cb, ncntxt)cci <- cb$putconst(acall)cvi <- cb$putconst(vexpr)cb$putcode(SETTER_CALL.OP, cci, cvi)}}else {cmp(afun, cb, ncntxt)cb$putcode(CHECKFUN.OP)cb$putcode(PUSHNULLARG.OP)cmpCallArgs(place[-c(1, 2)], cb, ncntxt)cci <- cb$putconst(acall)cvi <- cb$putconst(vexpr)cb$putcode(SETTER_CALL.OP, cci, cvi)}cb$restorecurloc(sloc)}getAssignFun <- function(fun) {if (typeof(fun) == "symbol")as.name(paste0(fun, "<-"))else {## check for and handle foo::bar(x) <- y assignments hereif (typeof(fun) == "language" && length(fun) == 3 &&(as.character(fun[[1]]) %in% c("::", ":::")) &&typeof(fun[[2]]) == "symbol" && typeof(fun[[3]]) == "symbol") {afun <- funafun[[3]] <- as.name(paste0(fun[[3]],"<-"))afun}else NULL}}cmpSetterDispatch <- function(start.op, dflt.op, afun, place, call, cb, cntxt) {if (anyDots(place))FALSE ## puntelse {ci <- cb$putconst(call)end.label <- cb$makelabel()cb$putcode(start.op, ci, end.label)if (length(place) > 2) {args <- place[-(1:2)]cmpBuiltinArgs(args, names(args), cb, cntxt, TRUE)}cb$putcode(dflt.op)cb$putlabel(end.label)TRUE}}setInlineHandler("<-", cmpAssign)setInlineHandler("=", cmpAssign)setInlineHandler("<<-", cmpAssign)setSetterInlineHandler("$<-", function(afun, place, origplace, call, cb, cntxt) {if (anyDots(place) || length(place) != 3)FALSEelse {sym <- place[[3]]if (is.character(sym))sym <- as.name(sym)if (is.name(sym)) {ci <- cb$putconst(call)csi <- cb$putconst(sym)cb$putcode(DOLLARGETS.OP, ci, csi)TRUE}else FALSE}})# **** this is now handled differently; see "Improved subset ..."# setSetterInlineHandler("[<-", function(afun, place, origplace, call, cb, cntxt)# cmpSetterDispatch(STARTSUBASSIGN.OP, DFLTSUBASSIGN.OP,# afun, place, call, cb, cntxt))# setSetterInlineHandler("[[<-", function(afun, place, origplace, call, cb, cntxt)# cmpSetterDispatch(STARTSUBASSIGN2.OP, DFLTSUBASSIGN2.OP,# afun, place, call, cb, cntxt))cmpGetterDispatch <- function(start.op, dflt.op, call, cb, cntxt) {if (anyDots(call))FALSE ## puntelse {ci <- cb$putconst(call)end.label <- cb$makelabel()cb$putcode(DUP2ND.OP)cb$putcode(start.op, ci, end.label)if (length(call) > 2) {args <- call[-(1:2)]cmpBuiltinArgs(args, names(args), cb, cntxt, TRUE)}cb$putcode(dflt.op)cb$putlabel(end.label)cb$putcode(SWAP.OP)TRUE}}setGetterInlineHandler("$", function(call, cb, cntxt) {if (anyDots(call) || length(call) != 3)FALSEelse {sym <- call[[3]]if (is.character(sym))sym <- as.name(sym)if (is.name(sym)) {ci <- cb$putconst(call)csi <- cb$putconst(sym)cb$putcode(DUP2ND.OP)cb$putcode(DOLLAR.OP, ci, csi)cb$putcode(SWAP.OP)TRUE}else FALSE}})# **** this is now handled differently; see "Improved subset ..."# setGetterInlineHandler("[", function(call, cb, cntxt)# cmpGetterDispatch(STARTSUBSET.OP, DFLTSUBSET.OP, call, cb, cntxt))# setGetterInlineHandler("[[", function(call, cb, cntxt)# cmpGetterDispatch(STARTSUBSET2.OP, DFLTSUBSET2.OP, call, cb, cntxt))#### Inline handlers for loops##setInlineHandler("break", function(e, cb, cntxt) {if (is.null(cntxt$loop)) {notifyWrongBreakNext("break", cntxt, loc = cb$savecurloc())cmpSpecial(e, cb, cntxt)}else if (cntxt$loop$gotoOK) {cb$putcode(GOTO.OP, cntxt$loop$end)TRUE}else cmpSpecial(e, cb, cntxt)})setInlineHandler("next", function(e, cb, cntxt) {if (is.null(cntxt$loop)) {notifyWrongBreakNext("next", cntxt, loc = cb$savecurloc())cmpSpecial(e, cb, cntxt)}else if (cntxt$loop$gotoOK) {cb$putcode(GOTO.OP, cntxt$loop$loop)TRUE}else cmpSpecial(e, cb, cntxt)})isLoopStopFun <- function(fname, cntxt)(fname %in% c("function", "for", "while", "repeat") &&isBaseVar(fname, cntxt))isLoopTopFun <- function(fname, cntxt)(fname %in% c("(", "{", "if") &&isBaseVar(fname, cntxt))checkSkipLoopCntxtList <- function(elist, cntxt, breakOK) {for (a in as.list(elist))if (! missing(a) && ! checkSkipLoopCntxt(a, cntxt, breakOK))return(FALSE)TRUE}checkSkipLoopCntxt <- function(e, cntxt, breakOK = TRUE) {if (typeof(e) == "language") {fun <- e[[1]]if (typeof(fun) == "symbol") {fname <- as.character(fun)if (! breakOK && fname %in% c("break", "next"))FALSEelse if (isLoopStopFun(fname, cntxt))TRUEelse if (isLoopTopFun(fname, cntxt))checkSkipLoopCntxtList(e[-1], cntxt, breakOK)else if (fname %in% c("eval", "evalq", "source"))FALSEelsecheckSkipLoopCntxtList(e[-1], cntxt, FALSE)}elsecheckSkipLoopCntxtList(e, cntxt, FALSE)}else TRUE}setInlineHandler("repeat", function(e, cb, cntxt) {body <- e[[2]]if (checkSkipLoopCntxt(body, cntxt))cmpRepeatBody(body, cb, cntxt)else {cntxt$needRETURNJMP <- TRUE ## **** do this a better wayljmpend.label <- cb$makelabel()cb$putcode(STARTLOOPCNTXT.OP, 0, ljmpend.label)cmpRepeatBody(body, cb, cntxt)cb$putlabel(ljmpend.label)cb$putcode(ENDLOOPCNTXT.OP, 0)}cb$putcode(LDNULL.OP)if (cntxt$tailcall) {cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}TRUE})cmpRepeatBody <- function(body, cb, cntxt) {loop.label <- cb$makelabel()end.label <- cb$makelabel()cb$putlabel(loop.label)lcntxt <- make.loopContext(cntxt, loop.label, end.label)cmp(body, cb, lcntxt)cb$putcode(POP.OP)cb$putcode(GOTO.OP, loop.label)cb$putlabel(end.label)}setInlineHandler("while", function(e, cb, cntxt) {cond <- e[[2]]body <- e[[3]]if (checkSkipLoopCntxt(cond, cntxt) && checkSkipLoopCntxt(body, cntxt))cmpWhileBody(e, cond, body, cb, cntxt)else {cntxt$needRETURNJMP <- TRUE ## **** do this a better wayljmpend.label <- cb$makelabel()cb$putcode(STARTLOOPCNTXT.OP, 0, ljmpend.label)cmpWhileBody(e, cond, body, cb, cntxt)cb$putlabel(ljmpend.label)cb$putcode(ENDLOOPCNTXT.OP, 0)}cb$putcode(LDNULL.OP)if (cntxt$tailcall) {cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}TRUE})cmpWhileBody <- function(call, cond, body, cb, cntxt) {loop.label <- cb$makelabel()end.label <- cb$makelabel()cb$putlabel(loop.label)lcntxt <- make.loopContext(cntxt, loop.label, end.label)cmp(cond, cb, lcntxt)callidx <- cb$putconst(call)cb$putcode(BRIFNOT.OP, callidx, end.label)cmp(body, cb, lcntxt)cb$putcode(POP.OP)cb$putcode(GOTO.OP, loop.label)cb$putlabel(end.label)}setInlineHandler("for", function(e, cb, cntxt) {sym <- e[[2]]seq <- e[[3]]body <- e[[4]]if (! is.name(sym)) {## not worth warning here since the parser should not allow thisreturn(FALSE)}ncntxt <- make.nonTailCallContext(cntxt)cmp(seq, cb, ncntxt)ci <- cb$putconst(sym)callidx <- cb$putconst(e)if (checkSkipLoopCntxt(body, cntxt))cmpForBody(callidx, body, ci, cb, cntxt)else {cntxt$needRETURNJMP <- TRUE ## **** do this a better wayctxt.label <- cb$makelabel()cb$putcode(STARTFOR.OP, callidx, ci, ctxt.label)cb$putlabel(ctxt.label)ljmpend.label <- cb$makelabel()cb$putcode(STARTLOOPCNTXT.OP, 1, ljmpend.label)cmpForBody(NULL, body, NULL, cb, cntxt)cb$putlabel(ljmpend.label)cb$putcode(ENDLOOPCNTXT.OP, 1)}cb$putcode(ENDFOR.OP)if (cntxt$tailcall) {cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}TRUE})cmpForBody <- function(callidx, body, ci, cb, cntxt) {body.label <- cb$makelabel()loop.label <- cb$makelabel()end.label <- cb$makelabel()if (is.null(ci))cb$putcode(GOTO.OP, loop.label)elsecb$putcode(STARTFOR.OP, callidx, ci, loop.label)cb$putlabel(body.label)lcntxt <- make.loopContext(cntxt, loop.label, end.label)cmp(body, cb, lcntxt)cb$putcode(POP.OP)cb$putlabel(loop.label)cb$putcode(STEPFOR.OP, body.label)cb$putlabel(end.label)}#### Inline handlers for one and two argument primitives##cmpPrim1 <- function(e, cb, op, cntxt) {if (dots.or.missing(e[-1]))cmpBuiltin(e, cb, cntxt)else if (length(e) != 2) {notifyWrongArgCount(e[[1]], cntxt, loc = cb$savecurloc())cmpBuiltin(e, cb, cntxt)}else {ncntxt <- make.nonTailCallContext(cntxt)cmp(e[[2]], cb, ncntxt);ci <- cb$putconst(e)cb$putcode(op, ci)if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE}}checkNeedsInc <- function(e, cntxt)return(FALSE)cmpPrim2 <- function(e, cb, op, cntxt) {if (dots.or.missing(e[-1]))cmpBuiltin(e, cb, cntxt)else if (length(e) != 3) {notifyWrongArgCount(e[[1]], cntxt, loc = cb$savecurloc())cmpBuiltin(e, cb, cntxt)}else {needInc <- checkNeedsInc(e[[3]], cntxt)ncntxt <- make.nonTailCallContext(cntxt)cmp(e[[2]], cb, ncntxt);if (needInc) cb$putcode(INCLNK.OP)ncntxt <- make.argContext(cntxt)cmp(e[[3]], cb, ncntxt)if (needInc) cb$putcode(DECLNK.OP)ci <- cb$putconst(e)cb$putcode(op, ci)if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE}}setInlineHandler("+", function(e, cb, cntxt) {if (length(e) == 3)cmpPrim2(e, cb, ADD.OP, cntxt)elsecmpPrim1(e, cb, UPLUS.OP, cntxt)})setInlineHandler("-", function(e, cb, cntxt) {if (length(e) == 3)cmpPrim2(e, cb, SUB.OP, cntxt)elsecmpPrim1(e, cb, UMINUS.OP, cntxt)})setInlineHandler("*", function(e, cb, cntxt)cmpPrim2(e, cb, MUL.OP, cntxt))setInlineHandler("/", function(e, cb, cntxt)cmpPrim2(e, cb, DIV.OP, cntxt))setInlineHandler("^", function(e, cb, cntxt)cmpPrim2(e, cb, EXPT.OP, cntxt))setInlineHandler("exp", function(e, cb, cntxt)cmpPrim1(e, cb, EXP.OP, cntxt))setInlineHandler("sqrt", function(e, cb, cntxt)cmpPrim1(e, cb, SQRT.OP, cntxt))setInlineHandler("log", function(e, cb, cntxt) {if (dots.or.missing(e) || ! is.null(names(e)) ||length(e) < 2 || length(e) > 3)cmpSpecial(e, cb, cntxt)else {ci <- cb$putconst(e)ncntxt <- make.nonTailCallContext(cntxt)cmp(e[[2]], cb, ncntxt);if (length(e) == 2)cb$putcode(LOG.OP, ci)else {needInc <- checkNeedsInc(e[[3]], cntxt)if (needInc) cb$putcode(INCLNK.OP)ncntxt <- make.argContext(cntxt)cmp(e[[3]], cb, ncntxt)if (needInc) cb$putcode(DECLNK.OP)cb$putcode(LOGBASE.OP, ci)}if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE}})## Keep the order consistent with the order in the internal byte code## interpreter!math1funs <- c("floor", "ceiling", "sign","expm1", "log1p","cos", "sin", "tan", "acos", "asin", "atan","cosh", "sinh", "tanh", "acosh", "asinh", "atanh","lgamma", "gamma", "digamma", "trigamma","cospi", "sinpi", "tanpi")cmpMath1 <- function(e, cb, cntxt) {if (dots.or.missing(e[-1]))cmpBuiltin(e, cb, cntxt)else if (length(e) != 2) {notifyWrongArgCount(e[[1]], cntxt, loc = cb$savecurloc())cmpBuiltin(e, cb, cntxt)}else {name <- as.character(e[[1]])idx <- match(name, math1funs) - 1if (is.na(idx))cntxt$stop(paste(sQuote(name), "is not a registered math1 function"),cntxt, loc = cb$savecurloc())ncntxt <- make.nonTailCallContext(cntxt)cmp(e[[2]], cb, ncntxt);ci <- cb$putconst(e)cb$putcode(MATH1.OP, ci, idx)if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE}}for (name in math1funs)setInlineHandler(name, cmpMath1)setInlineHandler("==", function(e, cb, cntxt)cmpPrim2(e, cb, EQ.OP, cntxt))setInlineHandler("!=", function(e, cb, cntxt)cmpPrim2(e, cb, NE.OP, cntxt))setInlineHandler("<", function(e, cb, cntxt)cmpPrim2(e, cb, LT.OP, cntxt))setInlineHandler("<=", function(e, cb, cntxt)cmpPrim2(e, cb, LE.OP, cntxt))setInlineHandler(">=", function(e, cb, cntxt)cmpPrim2(e, cb, GE.OP, cntxt))setInlineHandler(">", function(e, cb, cntxt)cmpPrim2(e, cb, GT.OP, cntxt))setInlineHandler("&", function(e, cb, cntxt)cmpPrim2(e, cb, AND.OP, cntxt))setInlineHandler("|", function(e, cb, cntxt)cmpPrim2(e, cb, OR.OP, cntxt))setInlineHandler("!", function(e, cb, cntxt)cmpPrim1(e, cb, NOT.OP, cntxt))#### Inline handlers for the left parenthesis function##setInlineHandler("(", function(e, cb, cntxt) {if (anyDots(e))cmpBuiltin(e, cb, cntxt) ## puntelse if (length(e) != 2) {notifyWrongArgCount("(", cntxt, loc = cb$savecurloc())cmpBuiltin(e, cb, cntxt) ## punt}else if (cntxt$tailcall) {ncntxt <- make.nonTailCallContext(cntxt)cmp(e[[2]], cb, ncntxt)cb$putcode(VISIBLE.OP)cb$putcode(RETURN.OP)TRUE}else {cmp(e[[2]], cb, cntxt)TRUE}})#### Inline handlers for general BUILTIN and SPECIAL functions##cmpBuiltin <- function(e, cb, cntxt, internal = FALSE) {fun <- e[[1]]args <- e[-1]names <- names(args)if (dots.or.missing(args))FALSEelse {ci <- cb$putconst(fun)if (internal)cb$putcode(GETINTLBUILTIN.OP, ci)elsecb$putcode(GETBUILTIN.OP, ci)cmpBuiltinArgs(args, names, cb, cntxt)ci <- cb$putconst(e)cb$putcode(CALLBUILTIN.OP, ci)if (cntxt$tailcall) cb$putcode(RETURN.OP)TRUE}}cmpBuiltinArgs <- function(args, names, cb, cntxt, missingOK = FALSE) {ncntxt <- make.argContext(cntxt)for (i in seq_along(args)) {a <- args[[i]]n <- names[[i]]if (missing(a)) {if (missingOK) {cb$putcode(DOMISSING.OP)cmpTag(n, cb)}elsecntxt$stop(gettext("missing arguments are not allowed"), cntxt,loc = cb$savecurloc())}## **** handle ... here ??else if (typeof(a) == "bytecode")cntxt$stop(gettext("cannot compile byte code literals in code"),cntxt, loc = cb$savecurloc())else if (typeof(a) == "promise")cntxt$stop(gettext("cannot compile promise literals in code"),cntxt, loc = cb$savecurloc())else {if (is.symbol(a)) {ca <- constantFold(a, cntxt, loc = cb$savecurloc())if (is.null(ca)) {cmpSym(a, cb, ncntxt, missingOK)cb$putcode(PUSHARG.OP)}elsecmpConstArg(ca$value, cb, cntxt)}else if (typeof(a) == "language") {cmp(a, cb, ncntxt)cb$putcode(PUSHARG.OP)}elsecmpConstArg(a, cb, cntxt)cmpTag(n, cb)}}}cmpSpecial <- function(e, cb, cntxt) {fun <- e[[1]]if (typeof(fun) == "character")fun <- as.name(fun)ci <- cb$putconst(e)cb$putcode(CALLSPECIAL.OP, ci)if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE}cmpDotInternalCall <- function(e, cb, cntxt) {ee <- e[[2]]sym <- ee[[1]]if (.Internal(is.builtin.internal(sym)))cmpBuiltin(ee, cb, cntxt, internal = TRUE)elsecmpSpecial(e, cb, cntxt)}setInlineHandler(".Internal", cmpDotInternalCall)#### Inline handlers for subsetting and related operators##cmpDispatch <- function(start.op, dflt.op, e, cb, cntxt, missingOK = TRUE) {if ((missingOK && anyDots(e)) ||(! missingOK && dots.or.missing(e)) ||length(e) == 1)cmpSpecial(e, cb, cntxt) ## puntelse {ne <- length(e)oe <- e[[2]]if (missing(oe))cmpSpecial(e, cb, cntxt) ## puntelse {ncntxt <- make.argContext(cntxt)cmp(oe, cb, ncntxt)ci <- cb$putconst(e)end.label <- cb$makelabel()cb$putcode(start.op, ci, end.label)if (ne > 2)cmpBuiltinArgs(e[-(1:2)], names(e)[-(1:2)], cb, cntxt,missingOK)cb$putcode(dflt.op)cb$putlabel(end.label)if (cntxt$tailcall) cb$putcode(RETURN.OP)TRUE}}}# **** this is now handled differently; see "Improved subset ..."# setInlineHandler("[", function(e, cb, cntxt)# cmpDispatch(STARTSUBSET.OP, DFLTSUBSET.OP, e, cb, cntxt))# **** c() is now a BUILTIN# setInlineHandler("c", function(e, cb, cntxt)# cmpDispatch(STARTC.OP, DFLTC.OP, e, cb, cntxt, FALSE))# **** this is now handled differently; see "Improved subset ..."# setInlineHandler("[[", function(e, cb, cntxt)# cmpDispatch(STARTSUBSET2.OP, DFLTSUBSET2.OP, e, cb, cntxt))setInlineHandler("$", function(e, cb, cntxt) {if (anyDots(e) || length(e) != 3)cmpSpecial(e, cb, cntxt)else {sym <- if (is.character(e[[3]]) && length(e[[3]]) == 1&& e[[3]] != "")as.name(e[[3]]) else e[[3]]if (is.name(sym)) {ncntxt <- make.argContext(cntxt)cmp(e[[2]], cb, ncntxt)ci <- cb$putconst(e)csi <- cb$putconst(sym)cb$putcode(DOLLAR.OP, ci, csi)if (cntxt$tailcall) cb$putcode(RETURN.OP)TRUE}else cmpSpecial(e, cb, cntxt)}})#### Inline handler for local() and return() functions##setInlineHandler("local", function(e, cb, cntxt) {if (length(e) == 2) {ee <- as.call(list(as.call(list(as.name("function"), NULL, e[[2]], NULL))))cmp(ee, cb, cntxt)TRUE}else FALSE})setInlineHandler("return", function(e, cb, cntxt) {if (dots.or.missing(e) || length(e) > 2)cmpSpecial(e, cb, cntxt) ## **** punt for nowelse {if (length(e) == 1)val <- NULLelseval <- e[[2]]ncntxt <- make.nonTailCallContext(cntxt)cmp(val, cb, ncntxt)if (cntxt$needRETURNJMP)cb$putcode(RETURNJMP.OP)elsecb$putcode(RETURN.OP)}TRUE})#### Inline handlers for the family of is.xyz primitives##cmpIs <- function(op, e, cb, cntxt) {if (anyDots(e) || length(e) != 2)cmpBuiltin(e, cb, cntxt)else {## **** check that the function is a builtin somewhere??s<-make.argContext(cntxt)cmp(e[[2]], cb, s)cb$putcode(op)if (cntxt$tailcall) cb$putcode(RETURN.OP)TRUE}}setInlineHandler("is.character", function(e, cb, cntxt)cmpIs(ISCHARACTER.OP, e, cb, cntxt))setInlineHandler("is.complex", function(e, cb, cntxt)cmpIs(ISCOMPLEX.OP, e, cb, cntxt))setInlineHandler("is.double", function(e, cb, cntxt)cmpIs(ISDOUBLE.OP, e, cb, cntxt))setInlineHandler("is.integer", function(e, cb, cntxt)cmpIs(ISINTEGER.OP, e, cb, cntxt))setInlineHandler("is.logical", function(e, cb, cntxt)cmpIs(ISLOGICAL.OP, e, cb, cntxt))setInlineHandler("is.name", function(e, cb, cntxt)cmpIs(ISSYMBOL.OP, e, cb, cntxt))setInlineHandler("is.null", function(e, cb, cntxt)cmpIs(ISNULL.OP, e, cb, cntxt))setInlineHandler("is.object", function(e, cb, cntxt)cmpIs(ISOBJECT.OP, e, cb, cntxt))setInlineHandler("is.symbol", function(e, cb, cntxt)cmpIs(ISSYMBOL.OP, e, cb, cntxt))#### Default inline handlers for BUILTIN and SPECIAL functions##local({basevars <- ls('package:base', all.names = TRUE)types <- sapply(basevars, function(n) typeof(get(n)))for (s in basevars[types == "special"])if (! haveInlineHandler(s, "base"))setInlineHandler(s, cmpSpecial)for (b in basevars[types == "builtin"])if (! haveInlineHandler(b, "base"))setInlineHandler(b, cmpBuiltin)})#### Inline handlers for some .Internal functions##simpleFormals <- function(def) {forms <- formals(def)if ("..." %in% names(forms))return(FALSE)for (d in as.list(forms)) {if (! missing(d)) {## **** check constant foldingif (typeof(d) %in% c("symbol", "language", "promise", "bytecode"))return(FALSE)}}TRUE}simpleArgs <- function(icall, fnames) {for (a in as.list(icall[-1])) {if (missing(a))return(FALSE)else if (typeof(a) == "symbol") {if (! (as.character(a) %in% fnames))return(FALSE)}else if (typeof(a) %in% c("language", "promise", "bytecode"))return(FALSE)}TRUE}is.simpleInternal <- function(def) {if (typeof(def) == "closure" && simpleFormals(def)) {b <- body(def)if (typeof(b) == "language" &&length(b) == 2 &&identical(b[[1]], quote(`{`)))b <- b[[2]]if (typeof(b) == "language" &&identical(b[[1]], quote(.Internal))) {icall <- b[[2]]ifun <- icall[[1]]typeof(ifun) == "symbol" &&.Internal(is.builtin.internal(as.name(ifun))) &&simpleArgs(icall, names(formals(def)))}else FALSE}else FALSE}inlineSimpleInternalCall <- function(e, def) {if (! dots.or.missing(e) && is.simpleInternal(def)) {forms <- formals(def)b <- body(def)if (typeof(b) == "language" &&length(b) == 2 &&identical(b[[1]], quote(`{`)))b <- b[[2]]icall <- b[[2]]defaults <- forms ## **** could strip missings but OK not to?cenv <- c(as.list(match.call(def, e, F))[-1], defaults)subst <- function(n)if (typeof(n) == "symbol") cenv[[as.character(n)]] else nargs <- lapply(as.list(icall[-1]), subst)as.call(list(quote(.Internal), as.call(c(icall[[1]], args))))}else NULL}cmpSimpleInternal <- function(e, cb, cntxt) {if (anyDots(e))FALSEelse {name <- as.character(e[[1]])def <- findFunDef(name, cntxt)if (! checkCall(def, e, NULL)) return(FALSE)call <- inlineSimpleInternalCall(e, def)if (is.null(call))FALSEelsecmpDotInternalCall(call, cb, cntxt)}}safeBaseInternals <- c("atan2", "besselY", "beta", "choose","drop", "inherits", "is.vector", "lbeta", "lchoose","nchar", "polyroot", "typeof", "vector", "which.max","which.min", "is.loaded", "identical","match", "rep.int", "rep_len")for (i in safeBaseInternals) setInlineHandler(i, cmpSimpleInternal)safeStatsInternals <- c("dbinom", "dcauchy", "dgeom", "dhyper", "dlnorm","dlogis", "dnorm", "dpois", "dunif", "dweibull","fft", "mvfft", "pbinom", "pcauchy","pgeom", "phyper", "plnorm", "plogis", "pnorm","ppois", "punif", "pweibull", "qbinom", "qcauchy","qgeom", "qhyper", "qlnorm", "qlogis", "qnorm","qpois", "qunif", "qweibull", "rbinom", "rcauchy","rgeom", "rhyper", "rlnorm", "rlogis", "rnorm","rpois", "rsignrank", "runif", "rweibull","rwilcox", "ptukey", "qtukey")for (i in safeStatsInternals) setInlineHandler(i, cmpSimpleInternal, "stats")#### Inline handler for switch##findActionIndex <- function(name, nm, miss) {start <- match(name, nm)aidx <- c(which(! miss), length(nm) + 1)min(aidx[aidx >= start])}setInlineHandler("switch", function(e, cb, cntxt) {if (length(e) < 2 || anyDots(e))cmpSpecial(e, cb, cntxt)else {## **** check name on EXPR, if any, partially matches EXPR?expr <- e[[2]]cases <-e[-c(1, 2)]if (is.null(cases))notifyNoSwitchcases(cntxt, loc = cb$savecurloc())miss <- missingArgs(cases)nm <- names(cases)## allow for corner cases like switch(x, 1) which always## returns 1 if x is a character scalar.if (is.null(nm) && length(cases) == 1)nm <- ""## collect information on named alternatives and check for## multiple default cases.if (! is.null(nm)) {haveNames <- TRUEndflt <- sum(nm == "")if (ndflt > 1) {notifyMultipleSwitchDefaults(ndflt, cntxt, loc = cb$savecurloc())## **** punt back to interpreted version for now to get## **** runtime error message for multiple defaultscmpSpecial(e, cb, cntxt)return(TRUE)}if (ndflt > 0)haveCharDflt <- TRUEelsehaveCharDflt <- FALSE}else {haveNames <- FALSEhaveCharDflt <- FALSE}## create the labelsif (any(miss))missLabel <- cb$makelabel()dfltLabel <- cb$makelabel()lab <- function(m)if (m) missLabelelse cb$makelabel()labels <- c(lapply(miss, lab), list(dfltLabel))if (! cntxt$tailcall)endLabel <- cb$makelabel()## create the map from names to labels for a character switchif (haveNames) {unm <- unique(nm[nm != ""])if (haveCharDflt)unm <- c(unm, "")nlabels <- labels[unlist(lapply(unm, findActionIndex, nm, miss))]## if there is no unnamed case to act as a default for a## character switch then the numeric default becomes the## character default as well.if (! haveCharDflt) {unm <- c(unm, "")nlabels <- c(nlabels, list(dfltLabel))}}else {unm <- NULLnlabels <- NULL}## compile the EXPR argumentncntxt <- make.nonTailCallContext(cntxt)cmp(expr, cb, ncntxt)## emit the SWITCH instructioncei <- cb$putconst(e)if (haveNames) {cni <- cb$putconst(unm)cb$putcode(SWITCH.OP, cei, cni, nlabels, labels)}else {cni <- cb$putconst(NULL)cb$putcode(SWITCH.OP, cei, cni, cni, labels)}## emit code to signal an error if a numeric switch hist an## empty alternative (fall through, as for character, might## make more sense but that isn't the way switch() works)if (any(miss)) {cb$putlabel(missLabel)cmp(quote(stop("empty alternative in numeric switch")), cb, cntxt)}## emit code for the default casecb$putlabel(dfltLabel)cb$putcode(LDNULL.OP)if (cntxt$tailcall) {cb$putcode(INVISIBLE.OP)cb$putcode(RETURN.OP)}elsecb$putcode(GOTO.OP, endLabel)## emit code for the non-empty alternativesfor (i in seq_along(cases)) {if (! miss[i]) {cb$putlabel(labels[[i]])cmp(cases[[i]], cb, cntxt)if (! cntxt$tailcall)cb$putcode(GOTO.OP, endLabel)}}if (! cntxt$tailcall)cb$putlabel(endLabel)}TRUE})#### Inline handler for .Call##setInlineHandler(".Call", function(e, cb, cntxt) {nargsmax <- 16 ## should match DOTCALL_MAX in eval.cif (dots.or.missing(e[-1]) || ! is.null(names(e)) ||length(e) < 2 || length(e) > nargsmax + 2)cmpBuiltin(e, cb, cntxt) ## puntelse {ncntxt <- make.nonTailCallContext(cntxt)cmp(e[[2]], cb, ncntxt);nargs <- length(e) - 2if (nargs > 0) {ncntxt <- make.argContext(cntxt)for (a in as.list(e[-(1:2)]))cmp(a, cb, ncntxt);}ci <- cb$putconst(e)cb$putcode(DOTCALL.OP, ci, nargs)if (cntxt$tailcall)cb$putcode(RETURN.OP)TRUE}})#### Inline handlers for generating integer sequences##setInlineHandler(":", function(e, cb, cntxt)cmpPrim2(e, cb, COLON.OP, cntxt))setInlineHandler("seq_along", function(e, cb, cntxt)cmpPrim1(e, cb, SEQALONG.OP, cntxt))setInlineHandler("seq_len", function(e, cb, cntxt)cmpPrim1(e, cb, SEQLEN.OP, cntxt))#### Inline handlers to control warnings##cmpMultiColon <- function(e, cb, cntxt) {if (! dots.or.missing(e) && length(e) == 3) {goodType <- function(a)typeof(a) == "symbol" ||(typeof(a) == "character" && length(a) == 1)fun <- e[[1]]x <- e[[2]]y <- e[[3]]if (goodType(x) && goodType(y)) {args <- list(as.character(x), as.character(y))cmpCallSymFun(fun, args, e, cb, cntxt)TRUE}else FALSE}else FALSE}setInlineHandler("::", cmpMultiColon)setInlineHandler(":::", cmpMultiColon)setSetterInlineHandler("@<-", function(afun, place, origplace, acall, cb, cntxt) {if (! dots.or.missing(place) && length(place) == 3 &&typeof(place[[3]]) == "symbol") {place[[3]] <- as.character(place[[3]])vexpr <- acall[[length(acall)]]cmpSetterCall(place, origplace, vexpr, cb, cntxt)TRUE}else FALSE})setInlineHandler("with", function(e, cb, cntxt) {cntxt$suppressUndefined <- TRUEcmpCallSymFun(e[[1]], e[-1], e, cb, cntxt)TRUE})setInlineHandler("require", function(e, cb, cntxt) {cntxt$suppressUndefined <- TRUEcmpCallSymFun(e[[1]], e[-1], e, cb, cntxt)TRUE})#### Compiler warnings##suppressAll <- function(cntxt)identical(cntxt$suppressAll, TRUE)suppressNoSuperAssignVar <- function(cntxt)isTRUE(cntxt$suppressNoSuperAssignVar)suppressUndef <- function(name, cntxt) {if (identical(cntxt$suppressAll, TRUE))TRUEelse {suppress <- cntxt$suppressUndefinedif (is.null(suppress))FALSEelse if (identical(suppress, TRUE))TRUEelse if (is.character(suppress) && as.character(name) %in% suppress)TRUEelse FALSE}}notifyLocalFun <- function(fun, cntxt, loc = NULL) {if (! suppressAll(cntxt))NULL}notifyUndefFun <- function(fun, cntxt, loc = NULL) {if (! suppressUndef(fun, cntxt)) {msg <- gettextf("no visible global function definition for '%s'",as.character(fun))cntxt$warn(msg, cntxt, loc)}}notifyUndefVar <- function(var, cntxt, loc = NULL) {if (! suppressUndef(var, cntxt)) {msg <- gettextf("no visible binding for global variable '%s'",as.character(var))cntxt$warn(msg, cntxt, loc)}}notifyNoSuperAssignVar <- function(symbol, cntxt, loc = NULL) {if (! suppressAll(cntxt) && ! suppressNoSuperAssignVar(cntxt)) {msg <- gettextf("no visible binding for '<<-' assignment to '%s'",as.character(symbol))cntxt$warn(msg, cntxt, loc)}}notifyWrongArgCount <- function(fun, cntxt, loc = NULL) {if (! suppressAll(cntxt)) {msg <- gettextf("wrong number of arguments to '%s'",as.character(fun))cntxt$warn(msg, cntxt, loc)}}notifyWrongDotsUse <- function(var, cntxt, loc = NULL) {if (! suppressAll(cntxt)) {msg <- paste(var, "may be used in an incorrect context")cntxt$warn(msg, cntxt, loc)}}notifyWrongBreakNext <- function(fun, cntxt, loc = NULL) {if (! suppressAll(cntxt)) {msg <- paste(fun, "used in wrong context: no loop is visible")cntxt$warn(msg, cntxt, loc)}}notifyBadCall <- function(w, cntxt, loc = NULL) {if (! suppressAll(cntxt))cntxt$warn(w, cntxt, loc)}notifyBadAssignFun <- function(fun, cntxt, loc = NULL) {if (! suppressAll(cntxt)) {msg <- gettext("invalid function in complex assignment")cntxt$warn(msg, cntxt, loc)}}notifyMultipleSwitchDefaults <- function(ndflt, cntxt, loc = NULL)if (! suppressAll(cntxt)) {msg <- gettext("more than one default provided in switch() call")cntxt$warn(msg, cntxt, loc)}notifyNoSwitchcases <- function(cntxt, loc = NULL)if (! suppressAll(cntxt)) {msg <- gettext("'switch' with no alternatives")cntxt$warn(msg, cntxt, loc)}notifyAssignSyntacticFun <- function(funs, cntxt, loc = NULL) {if (! suppressAll(cntxt)) {msg <- ngettext(length(funs),"local assignment to syntactic function: ","local assignments to syntactic functions: ")cntxt$warn(paste(msg, paste(funs, collapse = ", ")),cntxt, loc)}}notifyCompilerError <- function(msg)if (!compilerOptions$suppressAll)cat(paste(gettext("Error: compilation failed - "), msg, "\n"))#### Compiler interface##compile <- function(e, env = .GlobalEnv, options = NULL, srcref = NULL) {cenv <- makeCenv(env)cntxt <- make.toplevelContext(cenv, options)cntxt$env <- addCenvVars(cenv, findLocals(e, cntxt))if (mayCallBrowser(e, cntxt))## NOTE: compilation will be attempted repeatedlyeelse if (is.null(srcref))genCode(e, cntxt)elsegenCode(e, cntxt, loc = list(expr = e, srcref = srcref))}cmpfun <- function(f, options = NULL) {type <- typeof(f)if (type == "closure") {cntxt <- make.toplevelContext(makeCenv(environment(f)), options)ncntxt <- make.functionContext(cntxt, formals(f), body(f))if (mayCallBrowser(body(f), ncntxt))return(f)if (typeof(body(f)) != "language" ||! identical(body(f)[[1]], quote(`{`)))loc <- list(expr = body(f), srcref = getExprSrcref(f))elseloc <- NULLb <- genCode(body(f), ncntxt, loc = loc)val <- .Internal(bcClose(formals(f), b, environment(f)))attrs <- attributes(f)if (! is.null(attrs))attributes(val) <- attrsif (isS4(f)) ## **** should this really be needed??val <- asS4(val)val}else if (type == "builtin" || type == "special")felse stop("cannot compile a non-function")}tryCmpfun <- function(f)tryCatch(cmpfun(f), error = function(e) {notifyCompilerError(paste(e$message, "at", deparse(e$call)))f})tryCompile <- function(e, ...)tryCatch(compile(e, ...), error = function(err) {notifyCompilerError(paste(err$message, "at", deparse(err$call)))e})cmpframe <- function(inpos, file) {expr.needed <- 1000expr.old <- getOption("expressions")if (expr.old < expr.needed)options(expressions = expr.needed)on.exit(options(expressions = expr.old))attach(NULL, name="<compiled>")inpos <- inpos + 1outpos <- 2on.exit(detach(pos=outpos), add=TRUE)for (f in ls(pos = inpos, all.names = TRUE)) {def <- get(f, pos = inpos)if (typeof(def) == "closure") {cat(gettextf("compiling '%s'", f), "\n", sep = "")fc <- cmpfun(def)assign(f, fc, pos=outpos)}}cat(gettextf("saving to file \"%s\" ... ", file))save(list = ls(pos = outpos, all.names = TRUE), file = file)cat(gettext("done"), "\n", sep = "")}cmplib <- function(package, file) {package <- as.character(substitute(package))pkgname <- paste("package", package, sep = ":")pos <- match(pkgname, search());if (missing(file))file <- paste0(package,".Rc")if (is.na(pos)) {library(package, character.only = TRUE)pos <- match(pkgname, search());on.exit(detach(pos=match(pkgname, search())))}cmpframe(pos, file)}cmpfile <- function(infile, outfile, ascii = FALSE, env = .GlobalEnv,verbose = FALSE, options = NULL, version = NULL) {if (! is.environment(env) || ! identical(env, topenv(env)))stop("'env' must be a top level environment")if (missing(outfile)) {basename <- sub("\\.[a-zA-Z0-9]$", "", infile)outfile <- paste0(basename, ".Rc")}if (infile == outfile)stop("input and output file names are the same")forms <- parse(infile)nforms <- length(forms)srefs <- attr(forms, "srcref")if (nforms > 0) {expr.needed <- 1000expr.old <- getOption("expressions")if (expr.old < expr.needed) {options(expressions = expr.needed)on.exit(options(expressions = expr.old))}cforms <- vector("list", nforms)cenv <- makeCenv(env)cntxt <- make.toplevelContext(cenv, options)cntxt$env <- addCenvVars(cenv, findLocalsList(forms, cntxt))for (i in 1:nforms) {e <- forms[[i]]sref <- srefs[[i]]if (verbose) {if (typeof(e) == "language" &&identical(e[[1]], quote(`<-`)) &&typeof(e[[3]]) == "language" &&identical(e[[3]][[1]], quote(`function`)))cat(paste0("compiling function \"", e[[2]], "\"\n"))elsecat(paste("compiling expression", deparse(e, 20)[1],"...\n"))}if (!mayCallBrowser(e, cntxt))cforms[[i]] <- genCode(e, cntxt,loc = list(expr = e, srcref = sref))}cat(gettextf("saving to file \"%s\" ... ", outfile)).Internal(save.to.file(cforms, outfile, ascii, version))cat(gettext("done"), "\n", sep = "")}else warning("empty input file; no output written");invisible(NULL)}loadcmp <- function (file, envir = .GlobalEnv, chdir = FALSE) {if (!(is.character(file) && file.exists(file)))stop(gettextf("file '%s' does not exist", file), domain = NA)exprs <- .Internal(load.from.file(file))if (length(exprs) == 0)return(invisible())if (chdir && (path <- dirname(file)) != ".") {owd <- getwd()on.exit(setwd(owd), add = TRUE)setwd(path)}for (i in exprs) {eval(i, envir)}invisible()}enableJIT <- function(level).Internal(enableJIT(level))compilePKGS <- function(enable).Internal(compilePKGS(enable))setCompilerOptions <- function(...) {options <- list(...)nm <- names(options)for (n in nm)if (! exists(n, compilerOptions))stop(gettextf("'%s' is not a valid compiler option", n),domain = NA)old <- list()newOptions <- as.list(compilerOptions) # copy optionsfor (n in nm) {op <- options[[n]]switch(n,optimize = {op <- as.integer(op)if (length(op) == 1 && 0 <= op && op <= 3) {old <- c(old, list(optimize =compilerOptions$optimize))newOptions$optimize <- op}},suppressAll = {if (identical(op, TRUE) || identical(op, FALSE)) {old <- c(old, list(suppressAll =compilerOptions$suppressAll))newOptions$suppressAll <- op}},suppressNoSuperAssignVar = {if (isTRUE(op) || isFALSE(op)) {old <- c(old, list(suppressNoSuperAssignVar =compilerOptions$suppressNoSuperAssignVar))newOptions$suppressNoSuperAssignVar <- op}},suppressUndefined = {if (identical(op, TRUE) || identical(op, FALSE) ||is.character(op)) {old <- c(old, list(suppressUndefined =compilerOptions$suppressUndefined))newOptions$suppressUndefined <- op}})}jitEnabled <- enableJIT(-1)if (checkCompilerOptions(jitEnabled, newOptions))for(n in names(newOptions)) # commit the new optionsassign(n, newOptions[[n]], compilerOptions)invisible(old)}.onLoad <- function(libname, pkgname) {envAsLogical <- function(varName) {value = Sys.getenv(varName)if (value == "")NAelseswitch(value,"1"=, "TRUE"=, "true"=, "True"=, "yes"=, "Yes"= TRUE,"0"=, "FALSE"=,"false"=,"False"=, "no"=, "No" = FALSE,stop(gettextf("invalid environment variable value: %s==%s",varName, value)))}val <- envAsLogical("R_COMPILER_SUPPRESS_ALL")if (!is.na(val))setCompilerOptions(suppressAll = val)val <- envAsLogical("R_COMPILER_SUPPRESS_UNDEFINED")if (!is.na(val))setCompilerOptions(suppressUndefined = val)val <- envAsLogical("R_COMPILER_SUPPRESS_NO_SUPER_ASSIGN_VAR")if (!is.na(val))setCompilerOptions(suppressNoSuperAssignVar = val)if (Sys.getenv("R_COMPILER_OPTIMIZE") != "")tryCatch({lev <- as.integer(Sys.getenv("R_COMPILER_OPTIMIZE"))if (0 <= lev && lev <= 3)setCompilerOptions(optimize = lev)}, error = function(e) e, warning = function(w) w)}checkCompilerOptions <- function(jitEnabled, options = NULL) {optimize <- getCompilerOption("optimize", options)if (jitEnabled <= 2 || optimize >= 2)TRUEelse {stop(gettextf("invalid compiler options: optimize(==%d)<2 and jitEnabled(==%d)>2",optimize, jitEnabled))FALSE}}#### Disassembler##bcDecode <- function(code) {n <- length(code)ncode <- vector("list", n)ncode[[1]] <- code[1] # version numberi <- 2while (i <= n) {name<-Opcodes.names[code[i]+1]argc<-Opcodes.argc[[code[i]+1]]ncode[[i]] <- as.name(name)i<-i+1if (argc > 0)for (j in 1:argc) {ncode[[i]]<-code[i]i<-i+1}}ncode}disassemble <- function(code) {.CodeSym <- as.name(".Code")disasm.const<-function(x)if (typeof(x)=="list" && length(x) > 0 && identical(x[[1]], .CodeSym))disasm(x) else xdisasm <-function(code) {code[[2]]<-bcDecode(code[[2]])code[[3]]<-lapply(code[[3]], disasm.const)code}if (typeof(code)=="closure") {code <- .Internal(bodyCode(code))if (typeof(code) != "bytecode")stop("function is not compiled")}dput(disasm(.Internal(disassemble(code))))}#### Experimental Utilities##bcprof <- function(expr) {.Internal(bcprofstart())tryCatch(expr,finally = .Internal(bcprofstop()))val <- structure(.Internal(bcprofcounts()),names = Opcodes.names)hits <- sort(val[val > 0], decreasing = TRUE)pct <- round(100 * hits / sum(hits), 1)data.frame(hits = hits, pct = pct)}asm <- function(e, gen, env = .GlobalEnv, options = NULL) {cenv <- makeCenv(env)cntxt <- make.toplevelContext(cenv, options)cntxt$env <- addCenvVars(cenv, findLocals(e, cntxt))genCode(e, cntxt, gen = gen)}#### Improved subset and subassign handling##cmpIndices <- function(indices, cb, cntxt) {n <- length(indices)needInc <- FALSEfor (i in seq_along(indices))if (i > 1 && checkNeedsInc(indices[[i]], cntxt)) {needInc <- TRUEbreak}for (i in seq_along(indices)) {cmp(indices[[i]], cb, cntxt, TRUE)if (needInc && i < n) cb$putcode(INCLNK.OP)}if (needInc) {if (n == 2) cb$putcode(DECLNK.OP)else if (n > 2) cb$putcode(DECLNK_N.OP, n - 1)}}cmpSubsetDispatch <- function(start.op, dflt.op, e, cb, cntxt) {if (dots.or.missing(e) || ! is.null(names(e)) || length(e) < 3)cntxt$stop(gettext("cannot compile this expression"), cntxt,loc = cb$savecurloc())else {oe <- e[[2]]if (missing(oe))cntxt$stop(gettext("cannot compile this expression"), cntxt,loc = cb$savecurloc())ncntxt <- make.argContext(cntxt)ci <- cb$putconst(e)label <- cb$makelabel()cmp(oe, cb, ncntxt)cb$putcode(start.op, ci, label)indices <- e[-c(1, 2)]cmpIndices(indices, cb, ncntxt)if (dflt.op$rank) cb$putcode(dflt.op$code, ci, length(indices))else cb$putcode(dflt.op$code, ci)cb$putlabel(label)if (cntxt$tailcall) cb$putcode(RETURN.OP)TRUE}}setInlineHandler("[", function(e, cb, cntxt) {if (dots.or.missing(e) || ! is.null(names(e)) || length(e) < 3)cmpDispatch(STARTSUBSET.OP, DFLTSUBSET.OP, e, cb, cntxt) ## puntelse {nidx <- length(e) - 2;if (nidx == 1)dflt.op <- list(code = VECSUBSET.OP, rank = FALSE)else if (nidx == 2)dflt.op <- list(code = MATSUBSET.OP, rank = FALSE)elsedflt.op <- list(code = SUBSET_N.OP, rank = TRUE)cmpSubsetDispatch(STARTSUBSET_N.OP, dflt.op, e, cb, cntxt)}})setInlineHandler("[[", function(e, cb, cntxt) {if (dots.or.missing(e) || ! is.null(names(e)) || length(e) < 3)cmpDispatch(STARTSUBSET2.OP, DFLTSUBSET2.OP, e, cb, cntxt) ## puntelse {nidx <- length(e) - 2;if (nidx == 1)dflt.op <- list(code = VECSUBSET2.OP, rank = FALSE)else if (nidx == 2)dflt.op <- list(code = MATSUBSET2.OP, rank = FALSE)elsedflt.op <- list(code = SUBSET2_N.OP, rank = TRUE)cmpSubsetDispatch(STARTSUBSET2_N.OP, dflt.op, e, cb, cntxt)}})cmpSubassignDispatch <- function(start.op, dflt.op, afun, place, call, cb,cntxt) {if (dots.or.missing(place) || ! is.null(names(place)) || length(place) < 3)cntxt$stop(gettext("cannot compile this expression"), cntxt,loc = cb$savecurloc())else {ci <- cb$putconst(call)label <- cb$makelabel()cb$putcode(start.op, ci, label)indices <- place[-c(1, 2)]cmpIndices(indices, cb, cntxt)if (dflt.op$rank) cb$putcode(dflt.op$code, ci, length(indices))else cb$putcode(dflt.op$code, ci)cb$putlabel(label)TRUE}}setSetterInlineHandler("[<-", function(afun, place, origplace, call, cb, cntxt) {if (dots.or.missing(place) || ! is.null(names(place)) || length(place) < 3)cmpSetterDispatch(STARTSUBASSIGN.OP, DFLTSUBASSIGN.OP,afun, place, call, cb, cntxt) ## puntelse {nidx <- length(place) - 2if (nidx == 1)dflt.op <- list(code = VECSUBASSIGN.OP, rank = FALSE)else if (nidx == 2)dflt.op <- list(code = MATSUBASSIGN.OP, rank = FALSE)elsedflt.op <- list(code = SUBASSIGN_N.OP, rank = TRUE)cmpSubassignDispatch(STARTSUBASSIGN_N.OP, dflt.op, afun, place, call,cb, cntxt)}})setSetterInlineHandler("[[<-", function(afun, place, origplace, call, cb, cntxt) {if (dots.or.missing(place) || ! is.null(names(place)) || length(place) < 3)cmpSetterDispatch(STARTSUBASSIGN2.OP, DFLTSUBASSIGN2.OP,afun, place, call, cb, cntxt) ## puntelse {nidx <- length(place) - 2if (nidx == 1)dflt.op <- list(code = VECSUBASSIGN2.OP, rank = FALSE)else if (nidx == 2)dflt.op <- list(code = MATSUBASSIGN2.OP, rank = FALSE)elsedflt.op <- list(code = SUBASSIGN2_N.OP, rank = TRUE)cmpSubassignDispatch(STARTSUBASSIGN2_N.OP, dflt.op, afun, place, call,cb, cntxt)}})cmpSubsetGetterDispatch <- function(start.op, dflt.op, call, cb, cntxt) {if (dots.or.missing(call) || ! is.null(names(call)) || length(call) < 3)cntxt$stop(gettext("cannot compile this expression"), cntxt,loc = cb$savecurloc())else {ci <- cb$putconst(call)end.label <- cb$makelabel()cb$putcode(DUP2ND.OP)cb$putcode(start.op, ci, end.label)indices <- call[-c(1, 2)]cmpIndices(indices, cb, cntxt)if (dflt.op$rank)cb$putcode(dflt.op$code, ci, length(indices))elsecb$putcode(dflt.op$code, ci)cb$putlabel(end.label)cb$putcode(SWAP.OP)TRUE}}setGetterInlineHandler("[", function(call, cb, cntxt) {if (dots.or.missing(call) || ! is.null(names(call)) || length(call) < 3)cmpGetterDispatch(STARTSUBSET.OP, DFLTSUBSET.OP, call, cb, cntxt)else {nidx <- length(call) - 2;if (nidx == 1)dflt.op <- list(code = VECSUBSET.OP, rank = FALSE)else if (nidx == 2)dflt.op <- list(code = MATSUBSET.OP, rank = FALSE)elsedflt.op <- list(code = SUBSET_N.OP, rank = TRUE)cmpSubsetGetterDispatch(STARTSUBSET_N.OP, dflt.op, call, cb, cntxt)}})setGetterInlineHandler("[[", function(call, cb, cntxt) {if (dots.or.missing(call) || ! is.null(names(call)) || length(call) < 3)cmpGetterDispatch(STARTSUBSET2.OP, DFLTSUBSET2.OP, call, cb, cntxt)else {nidx <- length(call) - 2;if (nidx == 1)dflt.op <- list(code = VECSUBSET2.OP, rank = FALSE)else if (nidx == 2)dflt.op <- list(code = MATSUBSET2.OP, rank = FALSE)elsedflt.op <- list(code = SUBSET2_N.OP, rank = TRUE)cmpSubsetGetterDispatch(STARTSUBSET2_N.OP, dflt.op, call, cb, cntxt)}})