16978

Get last evaluated expression inside function

Question:

This is related to this other question:

<a href="https://stackoverflow.com/questions/23897320/last-evaluated-expression-in-javascript" rel="nofollow">Last evaluated expression in Javascript</a>

But I wanted to provide more details about what I wanted to do and show how I finally solved the problem as some users requested in the comments.

I have snippets of Javascript that are written by users of my app. This snippets need to go to a kind of template like this:

var foo1 = function(data, options) { <snippet of code written by user> } var foo2 = function(data, options) { <snippet of code written by user> } ...

Expressions can be very different, from simple things like this:

data.price * data.qty

To more complex tings like this:

if (data.isExternal) { data.email; } else { data.userId; }

The value returned by the function should be always the last evaluated expression.

Before we had something like this:

var foo1 = function(data, options) { return eval(<snippet of code written by user>); }

But due to optimizations and changes we are making, we cannot keep using eval, but we need to return the last evaluated expression.

Just adding a 'return' keyword won't work because expressions can have several statements. So I need to make those functions return the last evaluated expressions.

Restrictions and clarification:

<ul><li>I cannot force users to add the 'return' keyword to all the scripts they have because there are many scripts written already and it is not very intuitive for simple expressions like 'a * b'.</li> <li>I'm using Java and Rhino to run Javascripts on server side.</li> </ul>

Answer1:

As people pointed out in <a href="https://stackoverflow.com/questions/23897320/last-evaluated-expression-in-javascript" rel="nofollow">Last evaluated expression in Javascript</a>, getting the last evaluated expression is not possible in standard Javascript.

What I finally ended up doing, as suggested by FelixKling, was to manipulate the AST of the script written by the user. This way I store the user written script and the modified version, which is the one I finally run.

For manipulating the AST I used Rhino and basically modify all EXPR_RESULT nodes to store the result in a variable that I finally return at the end of the script. Here is the code to do that:

public class ScriptsManipulationService { private static final Logger logger = LoggerFactory.getLogger(ScriptsManipulationService.class);

public String returnLastExpressionEvaluated(String script) { Parser jsParser = new Parser(); try { AstRoot ast = jsParser.parse(script, "script", 1); ast.getType(); ast.visitAll(new NodeVisitor() { @Override public boolean visit(AstNode node) { if (node.getType() == Token.EXPR_RESULT) { ExpressionStatement exprNode = (ExpressionStatement) node; Assignment assignmentNode = createAssignmentNode("_returnValue", exprNode.getExpression()); assignmentNode.setParent(exprNode); exprNode.setExpression(assignmentNode); } return true; } }); StringBuilder result = new StringBuilder(); result.append("var _returnValue;\n"); result.append(ast.toSource()); result.append("return _returnValue;\n"); return result.toString(); } catch (Exception e) { logger.debug(LogUtils.format("Error parsing script"), e); return script; } } private Assignment createAssignmentNode(String varName, AstNode rightNode) { Assignment assignmentNode = new Assignment(); assignmentNode.setType(Token.ASSIGN); Name leftNode = new Name(); leftNode.setType(Token.NAME); leftNode.setIdentifier(varName); leftNode.setParent(assignmentNode); assignmentNode.setLeft(leftNode); rightNode.setParent(assignmentNode); assignmentNode.setRight(rightNode); return assignmentNode; }

}

This way, if you pass the following script:

data.price * data.qty;

You will get back:

var _returnValue; _returnValue = data.price * data.qty; return _returnValue;

Or if you pass:

var _returnValue; if (data.isExternal) { _returnValue = data.email; } else { _returnValue = data.userId; } return _returnValue;

Please keep in mind that I haven't done an exhaustive testing and will be polishing it over time, but this should show the general idea.

Recommend

  • using pi and e constants from Z3 API
  • using pi and e constants from Z3 API
  • HTML String Inside Nested String
  • Error with large numerics in dcast.data.table
  • How could i display a Graph on WindowsForms?
  • Plotting Noncontinuous Function ggplot2
  • “unable to resolve class groovy.io.FileType” error
  • Advantages of Migrating Flex3 App to Flex4
  • ggplot2 log scale of y axis causing curved lines
  • Simplify function interpretation in model
  • Remove elements at positions n and n-1 in a Haskell list, when n fits a predicate
  • F#: Expand a list of tuples of form (string*string list) list using a key
  • Ping website URL before loading it in WebView in Android Kotlin
  • How do I add SE error bars to my barplot in ggplot2?
  • F# missing type constraint
  • Android kotlin - get simple string from url
  • F#: integers to pair of integers
  • R outer function Error in persp.default(x, y, z) : invalid 'z' limits
  • Applying enum consist of 3 adapters between 2 activities in Kotlin
  • DynamoDB java filter list - example
  • How to have Facebook Messenger Bot send a message on button click
  • NotSerializableException when pass kotlin function in bundle on saving instance state
  • Calculating the mean using logical condition
  • Take three elements at a time from array
  • Longest Common Substring using Recursion and DP
  • Normalize between-blocks by the maxima of the block corresponding to the columns
  • Sharing an Oracle database connection between simultaneous Celery tasks
  • Kotlin star projection on contravariant types
  • Count of Comma separated values in r
  • Why Copy Constructor Called Twice
  • operation between stat_summary_hex plots made in ggplot2
  • VS2013 std::function with member function [duplicate]
  • Is there a J idiom for adding to a list until a certain condition is met?
  • Tips on wrapping a C library in Objective-C
  • select query to match multiple columns with multiple keywords
  • Code reuse through generics vs polymorphism
  • Python Expected an indented block error
  • google maps js v3 xml is null
  • Align objects to curve with canvas
  • ggplot2: “Unknown parameters: probs” for fun.y = quantile in geom_line()
  • handling exceptions in ML
  • Create an L-shaped border using HTML and CSS, is it possible?
  • assigning sequential ranks to data with multiple ties in R
  • variable length array error when passing array using template deduction
  • Python Regex - checking for a capital letter with a lowercase after
  • How do I create a call-by-need list with increasing size in Standard ML?
  • Webpack not recognizing Node's process module
  • Writing multiple functions in SML - Sequential Composition
  • Invalid template dependent member function template deduction - thinks I'm trying to use std::s
  • use transition on ::-webkit-scrollbar?
  • R: get list and environment of all variables and functions within a given function (for parallel pro
  • creating a new column in a CSV file from a list
  • clearTimeout not working
  • Cannot loop MongoDB Collection Functions
  • How to define a function which accept both Seq[T] and ParSeq[T] as parameter?
  • Passing a function argument to other arguments which are functions themselves
  • Aggregative sum of objects belonging to objects residing inside hierarchy structure
  • count of records within levels of a factor
  • How to do pattern matching on string in SML?
  • Draw min, max function in R
  • Hashing reflect.Type
  • Initialize database using kotlin in AsyncTask
  • How to run a Java Applet on Mac OS 10.6.6
  • Focal function: How do I get the value of the center pixel and use this value within the focal fun a
  • Plot multiple normal curves in same plot
  • efficiency of c++ arrays vs std::vector and std::array
  • Why does Haskell's “do nothing” function, id, consume tons of memory?
  • Array length with pointers
  • How to simply extract many repetitive rows from dataframe [closed]
  • Python Call Function from String [duplicate]
  • cast child class into parent class
  • How to Handle YouTube Fragment OnSaveInstanceState
  • android kotlin -how to add click listener to RecyclerView adapter
  • Way to determine if X and Y are both over 0
  • error in installing RWeka package in R
  • Extract words from text having length more than N characters - RegExp/Java/Android [closed]
  • CsvProvider throws OutOfMemoryException
  • How to use different code lemmas for different modes of inductive predicate?
  • How do I use the extension method Sum on a .NET list in F#?
  • combine multiple rows with same field in R
  • Count of NAs colwise by a group [duplicate]
  • VBA macro that search for file in multiple subfolders
  • espresso ActivityTestRule for activity with generic type parameter
  • Writing a function that is sum of functions
  • Why cannot C# resolve the correct overload in this case?
  • Create an instance of an abstract class in Kotlin
  • VBA Excel How do I Use a Function as a Parameter?
  • How to change a member field with Kotlin reflection?
  • `Failed integrity metadata check.` in JavaFX WebView, ignores SystemProp
  • Invoke function with function name passed as string [duplicate]
  • Template substitution failure with std::function
  • Z3 returns model not available
  • Why am I getting a function error in seemingly similar R code?
  • mzR / Rcpp package anomaly
  • Matlab - 8x8 window and finding mean
  • Ocaml - wrong type
  • Merge inner lists of a list erlang
  • Why copy-constructor is not called but default constructor is invoked in this code? [duplicate]
  • Fill in gaps (e.g. not single cells) of NA values in raster using a neighborhood analysis
  • Catch exception in ctypes based on C-exit code
  • Print without loops [duplicate]
  • Java sort a csv file based on column date
  • Need to find which program called the python script
  • Does Z3 support variable-only patterns in quantified formulas?
  • Android - Overlap two textviews
  • Jquery Image popout on hover
  • Why does apply() return incorrect column types?
  • Python build error while building selenium webdriver project
  • Plot inside a loop using highcharter
  • C++ execute an action for each type in a given list
  • In kotlin, how to make the setter of properties in primary constructor private?
  • How to have swipe to delete and swipe to archive in two colours in Recyclerview Android
  • foreach loop returns only result of first data in the list
  • How can I prove the lemma in Exercise 4.6 in “Programming and Proving in Isabelle/HOL”?
  • Using Rollapply on two columns
  • ESP8266 cannot read flash after programming
  • Determine if Value in Final Column exists in respective rows
  • How to specialize template member functions in template class (already specilzied)?
  • dplyr: mean of a group count
  • Coerce variables in data frame to appropriate format
  • changing y scale when using fun.y ggplot
  • AS3: Copying a Loader from one object to another
  • “Jacobian is required for Newton-CG method” when doing a approximation to a Jacobian not being used
  • Android room database won't export all the data
  • Research data analysis in Excel: Median of x times column value
  • Plot many categories
  • Allow grouping with NA in aggregate function
  • I'm matching a string and want to return the next three lines after the match
  • non-type template parameter whose type depends on another parameter
  • How to display hh:mm:ss in Excel?
  • Is it possible to do applymap using the groupby in pandas?
  • Struggling with functional extensionality
  • XAML Collision detection
  • Get a firestore document id from autocompletetextview onItemClickListener items
  • How to define Hebrew anniversaries to show up in Org agenda?
  • conf.int no longer working in 3.3 using ggplot2, stat_summary
  • ML function currying
  • Kotlin convert TimeStamp to DateTime
  • OCaml error with types
  • Why is DictWriter not Writing all rows in my Dictreader instance?
  • mapply for all arguments' combinations [R]
  • Draw rectangle based on data in matlab
  • How can I insert vertical blank space into an html document?
  • Cumsum excluding current value
  • Can CMake detect if I need to link to libm when using pow in C?
  • Minimize System of Equations with constraints (scipy.optimize.minimize)
  • FLOPS what really is a FLOP
  • html canvas trap left click and allow right click to pass through (pointer-events)
  • Do overridden methods inherit decorators in python?
  • R: How can I make a function with a function input with data.table
  • Updating File Created Date by x number of days Mac OSX
  • Room database migration if only new table is added
  • R Checking for duplicates is painfully slow, even with mclapply
  • RPN Evaluator optimization without losing readability
  • How to debug random cucumber failures?
  • Array.create and jagged array
  • Android alarm manager with multiple pending intents
  • Get index by type in std::variant
  • Wrapping a function with an indeterminate number of parameters in F#
  • How to see source code for functions written in C/C++? [duplicate]
  • Count consecutive elements in a same length vector
  • How can I match a regex at the beginning _or_ end of the line?
  • How to combine mutliple calls to a function?
  • How to use infix operator from a SML module?
  • Nested integral within integral2 in matlab
  • designing class hierarchy for typical characters in role playing game
  • Automate running several vim commands and keystrokes
  • How to see source code for functions written in C/C++? [duplicate]
  • Attending Streak MySQL Query
  • Missing parameter type
  • How to nicely read “alternating” lines?
  • How to groupBy an iterator without converting it to list in scala?
  • XML flat file vs. relational database backend
  • tableGrob: set the height and width of a grid.table
  • using Kotlin with Gradle
  • quadpack.error: Supplied function does not return a valid float in python
  • attaching multiple events to a button issue in IE
  • Simplest way to solve a maze without mutability
  • Share animated GIF to Facebook using Javascript
  • How to collect several interfaces into a Collection in HK2?
  • Quartz.NET and F# - SystemTime and KeyMatcher
  • Reconnect Serial Port on Processing
  • In ExoPlayer, how exactly to use SimpleExoPlayer.setVideoScalingMode to be like in ImageView center-
  • displaying stat_summary accurately on violin plots
  • joining all points inside a grouped point plot using ggplot
  • xcode - your session has expired. please log in
  • R: Applying readRDS to a list object of .Rds file names
  • Retrofit API call: How to make sure that value is not null after making api call?
  • Unable to POST my data using retrofit android using kotlin
  • ACRCloud integration to android app
  • JAVA_HOME cannot be determined error with XLConnect
  • How to include array content in HTML?
  • Semantically correct nested anchors
  • how to make apache run pyc file (python compiled file)
  • Using a static array as datasource for mat-table
  • How do I extract the index or name of the list item within FUN of lapply?
  • Counting vowels in a string using recursion
  • add1 function from scheme to R5RS
  • How to run kotlintest tests using the Gradle Kotlin DSL?
  • PHP - Setting inherited static property will also set it in other classes inheriting it
  • Access Javascript variable in Django Template
  • How to run robotium tests in a specific order?
  • Accidental Complexity in OpenSSL HMAC functions
  • TTTAttributedLabel Delegate didSelectLinkWithURL is not getting called in iPhone
  • Perl script (or anything) to total up CSV column
  • Access Global .resx file in ASP.Net View Page
  • select top N dynamically with N from the same select statement
  • How can unify the signature of this member method and the inline function
  • Order of evaluation for short-circuit operators and let in OCaml
  • How to pass array value from one class to other class
  • MATLAB finding max. of a struct
  • How to use “setTextColor(hexaValue)” on Kotlin for Android,
  • Using outer to produce an array of lists
  • I'd like to select a random YouTube video from MySQL database, and display it on my webpage [cl
  • Why is object not dealloc'ed when using ARC + NSZombieEnabled
  • Unable to generate jar file for Hadoop
  • Why I can not use disposable objects in object members?
  • replacing spaces with just one “_”
  • How to use Google public API access key in android application?
  • Node js & Apache In Parallel?
  • Why won't the bullets fire in the direction the player is facing and stay visible in PyGame?
  • Is it possible to change the Hashing algorithm in django_auth?
  • How to avoid NA columns in dcast() output?
  • Qt binary linked to both Qt 5 and (wrongly) to Qt 4 causing segmentation fault when linked to Qwt
  • Scroll Down [GeckoFx + Javascript]
  • Spanish language chars are not displayed properly?
  • Why are divs behaving like this?
  • Correct functional implementation on Binomial Heap
  • How to establish an ssh connection in a Lua script to execute a command on a remote server?
  • Can I remove just the last added class from an element with jQuery
  • How to loop through an array from the second element in elegant way using Swift
  • beginner-opening explorer to show folder contents
  • Vim: Match whitespace between braces but not on new lines
  • when remove document from capped collection in mongoDB, it through an error?
  • iPhone 5: AVCaptureExposureModeAutoFocus not supported in iOS 7
  • Sending Emails from different accounts with Google App Script
  • Rolling 12 Month sum in PowerPivot
  • How to keep track of a process per browser window and access it at each event in Nitrogen?
  • Save new value to Laravel session array
  • Microsoft Collections for .NET [closed]
  • Python to delete a row in excel spreadsheet
  • Mocktito ArgumentCaptor for Kotlin lambda with arguments
  • Defining a byte in C++
  • Pandas, create columns after groupby
  • Typescript 2.1.5 Function calls are not supported
  • fb-video change url and reload player at runtime (without page refresh)
  • Aptana not saving changes
  • Performance degradation for Django with Gunicorn deployed into Heroku
  • How to write a function using the built-in local variable arguments?
  • Reading value from XML file Throws an error - FAKE F#MAKE
  • FParsec only parses expr between parentheses
  • SQL Keeping count of occurrences
  • Create a class that creates Function objects as instance using es6 class syntax
  • Time Complexity of the given nested loops
  • Is there a way to maintain a 200MB immutable data structure in memory and access it from a script?
  • How can i use a session for both clojure/script
  • Round number to nearest “nth” based on first non zero
  • Parse cloud code ascending / limit won't work in query in promise
  • Internet explorer 8 event fall through transparent parents
  • Density Value for each Return
  • Clustering algorithm with different epsilons on different axes
  • Server control behaving oddly
  • SocketChannel: java.io.IOException: An existing connection was forcibly closed by the remote host
  • How can I join lazy translation in Django?
  • JavaScript execCommand('copy') not working
  • How to put different size vectors in data.table column
  • Drawing a Polygon
  • How to label x-axis with dates?
  • How to get rows with min values in one column, grouped by other column, while keeping other columns?
  • I want to trace logs using a Macro multi parameter always null. problem c++ windows
  • Uploading image using Codeigniter (API)
  • Is there ever a reason to use is versus as? [duplicate]
  • Android - Firebase - Failed to convert value of type java.util.HashMap to String
  • Php Curl live server not working
  • Bind data to Gridview instance inside ListView ItemDataBound
  • Towers of Hanoi with “counter” in python
  • Form Authentication in Ktor
  • Failed to update work status Exception in Python Cloud Dataflow
  • Warning: ldap_start_tls() [function.ldap-start-tls]: Unable to start TLS: Server is unavailable
  • C++ calling the default constructor with parens vs without parens [duplicate]
  • Including data files with setup.py
  • Numpy: How to get rid of the minima along axis=1, given the indices - in an efficient way?
  • Any command in mysql equivalent to Oracle's autotrace for performance turning
  • Get XML response value with GDataXML
  • Converting float[,] to list in f#?
  • Interpolation method that does not add unnecessary extremums
  • Mocking Non-Standard Events in F# Foq
  • @Post method with capturing parenthesis in @Path not matched in Jersey
  • data.table replicate rows after join?
  • JPA CDI Injecting DAO into an Entity
  • SQL Server re-calculate or not?
  • Vigenere cipher not working
  • How to repeat sections of a SQL query across UNIONs? (DRY in SQL)
  • Swift Initialization Rule Confusion
  • Use sed with regex and (
  • I am receiving HibernateException “No Hibernate Session bound to thread, and configuration does not
  • How can Delete be both a DDL and a DML statement
  • jQuery: add elements until a particular height is reached
  • uml Composition relationships to RDF and OWL
  • Azure table store snapshot/backup capability
  • SonarQube: Cannot deactivate rule with missing quality profile
  • How do I include a SWC in an AS2 Flash project?
  • How to add a focus style to an editable ComboBox in WPF
  • pyodbc doesn't report sql server error
  • How do I superscript characters in a UIButton?
  • xtable package: Skipping some rows in the output
  • Swing - Get new component under mouseReleased
  • Swift: Switch statement fallthrough behavior
  • Change JButton Shape while respecting Look And Feel
  • Is my CUDA kernel really runs on device or is being mistekenly executed by host in emulation?
  • Do create extension work in single-user mode in postgres?
  • R: gsub and capture
  • jqPlot EnhancedLegendRenderer plugin does not toggle series for Pie charts
  • Comma separated Values
  • python regex in pyparsing
  • How to load view controller without button in storyboard?