ScriptControl.AddCode without executing the code? - javascript

I'm working on a project in C# that get scripts (VBScript, Jscript and JavaScript) from the EA database and executes certain functions at specific moments.
To be able to do this I use the Microsoft ScriptControl.
First I add all script code to the ScriptControl using ScriptControl.AddCode and then I functions with a specific name.
The code that adds the code to the script control looks like this:
//create new scriptcontroller
this.scriptController = new ScriptControl();
this.scriptController.Language = this.language.name;
this.scriptController.AddObject("Repository", model.getWrappedModel());
//Add the actual code. This must be done in a try/catch because a syntax error in the script will result in an exception from AddCode
try
{
//first add the included code
string includedCode = this.IncludeScripts(this._code);
//then remove any statements that execute a function or procedure because scriptControl.AddCode actually executes those statements
string cleanedCode = this.language.removeExecutingStatements(includedCode);
//then add the cleaned code to the scriptcontroller
this.scriptController.AddCode(cleanedCode);
The problem is that apparently AddCode also executes the script code in some way, which is not what I want.
Say I have following VBScript:
sub main
MsgBox("main executed")
end sub
main
As soon as I add the code of this script to the ScriptControl using AddCode the main sub is executed and I see the messagebox appear.
Does anyone know an easy way to avoid executing the main sub in cases like this?
My current workaround (currently only implemented for VBScript) involves parsing the script code and stripping the line that calls functions or procedures, but that is pretty tedious and error prone.
/// <summary>
/// removes the statements that execute a function/procedure from the code
/// </summary>
/// <param name="code">the code with executing statements</param>
/// <returns>the code without executing statements</returns>
public override string removeExecutingStatements(string code)
{
StringReader reader = new StringReader(code);
string cleanedCode = code;
string line;
bool functionStarted = false;
bool subStarted = false;
while (null != (line = reader.ReadLine()))
{
if (line != string.Empty)
{
if (line.StartsWith(this.functionStart))
{
functionStarted = true;
}else if (line.StartsWith(this.subStart))
{
subStarted = true;
}else if (functionStarted && line.StartsWith(this.functionEnd))
{
functionStarted = false;
}
else if (subStarted && line.StartsWith(this.subEnd))
{
subStarted = false;
}else if (!functionStarted && !subStarted)
{
//code outside of a function or sub, figure out if this code calls another sub or function
foreach (string linepart in line.Split(new char[] {' ' , '(' },StringSplitOptions.RemoveEmptyEntries))
{
if (cleanedCode.Contains(this.functionStart + linepart)
||cleanedCode.Contains(this.subStart + linepart))
{
//found a line that calls an existing function or sub, replace it by an empty string.
cleanedCode = cleanedCode.Replace(Environment.NewLine +line + Environment.NewLine,
Environment.NewLine + string.Empty + Environment.NewLine);
}
}
}
}
}
return cleanedCode;
}
Any better idea is welcome.

If you want the script code modules to act as code libraries without any static initializers then you can enforce it by declaring it in coding conventions
If you want the static initializers and other side-effects not to appear until the run-time then you can postpone the script activation through delay loading the script when it is required for the first time
If you want to have more fine-grained control over the scripting environment than you can implement a scripting host and interact with the script engines more directly (e.g. using the IActiveScriptParse interface will not probably trigger any unexpected side-effects).
MSDN: Windows Script Interfaces
...To make implementation of the host as flexible as possible, an OLE Automation wrapper for Windows Script is provided. However, a host that uses this wrapper object to instantiate the scripting engine does not have the degree of control over the run-time name space, the persistence model, and so on, that it would if it used Windows Script directly.
The Windows Script design isolates the interface elements required only in an authoring environment so that nonauthoring hosts (such as browsers and viewers) and script engines (for example, VBScript) can be kept lightweight...

Main executes because you call it from a top level command. Anything not in sub/functions is executed.

Related

Unity - communicating with clientside Javascript and ajax. How to pass data back to the webpage from unity?

What I am really asking is this; if there are dependencies which are impossible to compile into the unity build, is there a way of still calling them from within the unity and simply using the scripts loaded into the browser from the website and communicating with them?
Relevant documentation does not address this deeply:
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
I am creating a website wrapper for a unity application. The buttons for the experience are located within the website, as the buttons affect the rest of the site, not just the unity application.
When certain content is loaded in the unity game play however, the app needs to be able to affect the website. Is there a way to pass the data back to the website in a creative way? Currently, I am including all my javascript code for the website in the unity compile, and it is erroring out on:
gameInstance = UnityLoader.instantiate("gameContainer", "/Build/DomumProto16_Web.json", {
onProgress: UnityProgress
});
Sending data to the gameplay from the website:
gameInstance.SendMessage('Manager','Filter', JSON.stringify(filterActive));
Need to call this function from the unity gameplay. However, ajax.ajax_url is undefined due to it being localized using wp_localize_script() on the backend.
function showStudentWork(studentIndex){
//make sure to remove all the
var x = document.getElementById("studentWork");
var studentID = studentWork[studentIndex];
console.log(studentID);
$.ajax({
url: ajax.ajax_url,
type: "POST",
data: {
action: 'getStudentPost',
currentStudent: studentID
},
success: function (data) {
x.innerHTML = "";
x.innerHTML = data;
x.style.display = "grid";
},
error: function (error) {
console.log(`Error ${error}`);
}
});
return false;
}
What I am really asking is this; if there are dependencies which are impossible to compile into the unity build, is there a way of still calling them from within the unity and simply using the scripts loaded into the browser from the website and communicating with them?
Here are two methods. One is, in my opinion, easier, but it is deprecated and you should ~not~ use it. Options two is the 'corrrect' way, but it is kinda ugly imo.
Option 1: Application.ExternalCall
Documentation
This option allows you to call browser javascript directly, but Unity has deprecated support for it and is probably a bad idea for anything long term.
In a given browser with a Unity web player working, consider the following:
In browser source, define a javascript function
<other html>
<script>
function foo(msg) {
alert(msg);
}
</script>
In Unity, whenever it is nessecary:
Application.ExternalCall( "foo", "The game says hello!" );
This allows Javascript to be called from Unity.
There is similar functionality for communication in the opposite direction.
Option 2: jslibs
Documentation
This is the unity-endorsed way of doing things. It involved packaging javascript libraries into your games.
First, create a javascript file that will be packaged with your game. Here is an example file:
// Unity syntactic sugar
mergeInto(LibraryManager.library, {
// Declare all your functions that can be called from c# here
alert_user: function (msg) {
window.alert(msg);
},
other_func: function () {
// does something else
// etc.
// put as many functions as you'd like in here
}
}
Place that file, with extension .jslib in your Plugins folder on your project.
Then, in your c# files, you need to:
// Declare a monobehavior, whatever
using UnityEngine;
using System.Runtime.InteropServices;
public class NewBehaviourScript : MonoBehaviour {
// IMPORTANT
// You have to declare the javascript functions you'll be calling
// as private external function in your c# file. Additionally,
// They need a special function decorator [DllImport("__Internal")]
// Example:
[DllImport("__Internal")]
private static extern void alert_user(string msg);
// With that unpleasantness over with, you can now call the function
void Start() {
alert_user("Hello, I am a bad person and I deserve to write c#");
}
}
Et viola. You can call other javascript from your c# javascript, and interact with the dom, but I will leave all those decisions up to you.
The other direction
In both cases, communication in the opposite direction (browser saying something to Unity) is the same format.
In javascript, create a UnityInstance (the way of this is a little two long-winded to put into this answer, check either docs). Then, just .sendMessage.
e.g.:
c#
...
void DoSomething (string msg) {
// this is a c# function that does something in the game
// use your imagination
}
...
javascript:
let game = UnityLoader // Actually load the game here
game.SendMessage('TheNameOfMyGameObject', 'DoSomething', 'This is my message');
If I understand it can be done using WWW call function
This is not a proper code okay . This will be just an idea for you.
Send a variable to the PHP function like this
string url = "" // add your URL here;
WWWForm form = new WWWForm ();
form.AddField("YourFunctionName", "SampleFunction");
WWW www = new WWW(url, form);
yield return www;
Now in your PHP do it something like this
function YourFunctionName()
{
// your function code here
}
and now on
$YourFunctionName = $_POST["functionName"];
switch ($functionName){
case "SampleFunction":
SampleFunction();
break;
}
So the idea here is still you will need a PHP and from that PHP call your ajax :)

Is it required to grab v8::Locker before making v8::Function::Call?

I'm using V8 to execute some custom javascript code, exposing OnUpdate function to JS world. Overall code works fine but currently I'm concerned about performance of below code - is it required to grab v8::Locker for executing any user defined function? Instruments.app shows code here spends way too much time in v8::Locker constructor and destructor -
90 ms (in actual code execution) vs ~4000ms (by Locker & ~Locker) - this is absurd and I feel I might be doing something wrong.
So my basic question is it really necessary to grab v8::Locker to execute a v8::Function::Call? In current state if I comment out v8::LockerI get below error message:
# Fatal error in HandleScope::HandleScope
# Entering the V8 API without proper locking in place
Code snippet:
int Bucket::send_doc_update_bucket(const char *msg) {
Locker locker(GetIsolate());
Isolate::Scope isolate_scope(GetIsolate());
HandleScope handle_scope(GetIsolate());
Local<Context> context = Local<Context>::New(GetIsolate(), context_);
Context::Scope context_scope(context);
TryCatch try_catch;
Local<Value> args[1];
args[0] = String::NewFromUtf8(GetIsolate(), msg);
assert(!try_catch.HasCaught());
Handle<Value> val;
if(!context->Global()->Get(context,
createUtf8String(GetIsolate(),
"OnUpdate")).ToLocal(&val) ||
!val->IsFunction()) {
return 3;
}
Handle<Function> on_doc_update = Handle<Function>::Cast(val);
on_doc_update->Call(context, context->Global(), 1, args);
if (try_catch.HasCaught()) {
//w->last_exception = ExceptionString(GetIsolate(), &try_catch);
return 2;
}
return 0;
}
If you're not doing any multithreading, you never need to touch v8::Locker. As soon as you do, though, then you have to have it pretty much everywhere.
A v8::Locker is to stop multiple v8::Context's from the same v8::Isolate from running at the same time.
If you want multiple simultaneous threads of execution, each context must be created in a different isolate.

How to run V8 evaluation multiple times?

Maybe it is stupid question (I am newbie to C++, just wanted to use it as library for android), but I am not able to run evaluation of some JS multiple times.
I have started with "hello world" tutorial. But then I have wanted simple thing, re-run main (just wrap content of tutorial code into function and run it twice in newly empty main.
This is what I got:
#
# Fatal error in ../src/isolate.cc, line 1868
# Check failed: thread_data_table_.
#
==== C stack trace ===============================
1: 0xa890b9
2: 0x6a22fc
3: 0x42694f
4: 0x405f66
5: 0x405ec7
6: __libc_start_main
7: 0x405dc9
Illegal instruction (core dumped)
This cames after creating new isolate
Isolate* isolate = Isolate::New(create_params);
Well, what I should do? Am I using wrong construct or so? Should I close/delete/clear something more?
In bigger view I just want to do evaluate function, that can be triggered multiple times, and beside that also run multiple js snipets in same context (how to split this function?).
Any idea?
UPDATE:
Ok, lets say that the main can be split into three logical parts:
init
int main(int argc, char* argv[]) {
// Initialize V8.
V8::InitializeICU();
V8::InitializeExternalStartupData(argv[0]);
Platform* platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(platform);
V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
evaluation
Isolate* isolate = Isolate::New(create_params);
{
Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(isolate);
// Create a new context.
Local<Context> context = Context::New(isolate);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(context);
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(isolate, "'Hello' + ', World!'",
NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
// Run the script to get the result.
Local<Value> result = script->Run(context).ToLocalChecked();
// Convert the result to an UTF8 string and print it.
String::Utf8Value utf8(result);
printf("%s\n", *utf8);
}
isolate->Dispose();
and clean
// Dispose and tear down V8.
V8::Dispose();
V8::ShutdownPlatform();
delete platform;
return 0;
Now as I said before if I run main consists of init->evaluation->clean twice, that mean init->evaluation->clean->init->evaluation->clean, then the error occurs. I have figured out, that if I extract evaluation part into separate function I can run it multiple times e.g. as init->(evaluation){2}->clean
Is that how should it work? Next step is to divide this main into tree separate function that mean I have to have static member with platform? Could it cause leak somehow?
NOTE: that I want to run it from android, that mean e.g. click in UI, propagate js source to C via JNI and then call c++ V8, which is already initialized or not. hm?
Prefered way is to have "blackbox", but if I have to hold platform, so be it. It maybe could be also faster without re-initialization of V8, right?
UPDATE 2:
Well, still have problems with splitting evaluation part to achieve multiple runs in same isolate/context.
I have splitted it after creating context with stored isolate and context, but with no luck. When in second part try to create source string it fails, probably because of using stored isolate (something with isolate scope I guess).
:(
My assumption as I introduced in UPDATE1 was correct. That part works well.
According to UPDATE2 I have splitted evaluation part into two.
First for initialize isolate and context:
mIsolate = Isolate::New(mCreate_params);
Isolate::Scope isolate_scope(mIsolate);
{
// Create a stack-allocated handle scope.
HandleScope handle_scope(mIsolate);
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(mIsolate);
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::NewFromUtf8(mIsolate, "print"), v8::FunctionTemplate::New(mIsolate, Print));
// Create a new context.
mContext = Context::New(mIsolate, NULL, global);
Persistent<Context, CopyablePersistentTraits<Context>> persistent(mIsolate, mContext);
mContext_persistent = persistent;
}
and second that will run js in same context:
Isolate::Scope isolate_scope(mIsolate);
{
HandleScope handle_scope(mIsolate);
mContext = Local<Context>::New(mIsolate, mContext_persistent);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(mContext);
{
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(mIsolate, js_source, NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(mContext, source).ToLocalChecked();
TryCatch trycatch(mIsolate);
// Run the script to get the result.
v8::Local<v8::Value> result;
if(!script->Run(mContext).ToLocal(&result)){
v8::String::Utf8Value exception_str(trycatch.Exception());
dprint(*exception_str);
}else{
if(!result->IsUndefined()){
String::Utf8Value utf8(result);
dprint(*utf8);
}
}
}
}
Well the code works very well on linux, but I still have some issues when I try to run first part for the second time (create new context) on android:
A/art: art/runtime/thread.cc:986] pthread_getschedparam failed for DumpState: No such process
A/art: art/runtime/base/mutex.cc:485] Unexpected state_ 0 in unlock for logging lock
But that's another question I guess. Peace.
Did you initialize v8 more than once?
v8::V8::Initialize() this method should be called once per process.
deep into project source file "v8/src/v8.cc", you will find the prove
bool V8::Initialize() {
InitializeOncePerProcess();
return true;
}

addons.mozilla.org validation shows compile-time error in the JavaScript

Note:addons works correctly but getting error in firefox validation addon website https://addons.mozilla.org/en-us/developers/addon/validate
my code
panel.port.on("changing_now_speed_val", function (speed) {
var com = 'document.getElementsByTagName("video")[0].playbackRate='+speed + ';';
tabs.activeTab.attach({
contentScript: com
});
});
Error
while testing on it says
https://addons.mozilla.org/en-us/developers/addon/validate
Extension Tests
JavaScript Compile-Time Error
Warning: A compile-time error in the JavaScript halted validation of that file.
Message: expected expression, got ';
resources/html5_youtube_video_speed_controller/lib/main.js
But addons works correctly
https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/Loading_Content_Scripts
"Unless your content script is extremely simple and consists only of a static string, don't use contentScript: if you do, you may have problems getting your add-on approved on AMO.
Instead, keep the script in a separate file and load it using contentScriptFile. This makes your code easier to maintain, secure, debug and review"
There is more info there:
https://bugzilla.mozilla.org/show_bug.cgi?id=1185355
Maybe try:
panel.port.on("changing_now_speed_val", function (speed) {
speed = speed || 1;
if (speed.trim() === "") {
speed = 1;
}
....
This is just some sanity check, which ensures that the value of speed is never empty or null. This should pass the edge cases in testing/validation.
speed = speed || 1;
prevents the code from breaking if nothing is passed on speed
and the if condition checks that empty string should not be passed.
To make this even non-breakable, you can check if you can convert speed to a valid integer or not. That would be a great fix.
Also, referring to the comments in bugzilla, you could use an external file:
That could probably be done by something like this:
var data = self.data;
panel.port.on("changing_now_speed_val", function (speed) {
var workers = tabs.activeTab.attach({
contentScriptFile:[data.url('externalFile.js')]
});
workers.emit('speedChanged', speed)
}
and on your data/ folder in your addon, create a file externalFile.js which should contain something like this:
self.port.on('speedChanged', function(speed){
speed = speed || 1;
speed = speed.trim() === "" ? 1 : speed; //little ternary trick
document.getElementsByTagName("video")[0].playbackRate='+speed + ';';
}
I think this explains something. Please comment me back if you have any questions! Happy addon-ing!

Haxe for javascript without global namespace pollution?

This question only applies to Haxe version < 2.10
I've known about haxe for a while, but never really played with it until yesterday. Being curious, I decided to port showdown.js, a javascript port of markdown.pl, to haxe. This was pretty straightforward, and the javascript it generates seems to run fine (edit: If you want to see it in action, check it out here).
However, I noticed that the generated code dumps a ton of stuff in the global namespace... and what's worse, it does it by assigning values to undeclared identifiers without using the var keyword, so they're global even if you wrap the whole thing with a closure.
For example...
if(typeof js=='undefined') js = {}
...
Hash = function(p) { if( p === $_ ) return; {
...
EReg = function(r,opt) { if( r === $_ ) return; {
...
I managed to clean most of that up with sed, but I'm also bothered by stuff like this:
{
String.prototype.__class__ = String;
String.__name__ = ["String"];
Array.prototype.__class__ = Array;
Array.__name__ = ["Array"];
Int = { __name__ : ["Int"]}
Dynamic = { __name__ : ["Dynamic"]}
Float = Number;
Float.__name__ = ["Float"];
Bool = { __ename__ : ["Bool"]}
Class = { __name__ : ["Class"]}
Enum = { }
Void = { __ename__ : ["Void"]}
}
{
Math.__name__ = ["Math"];
Math.NaN = Number["NaN"];
Math.NEGATIVE_INFINITY = Number["NEGATIVE_INFINITY"];
Math.POSITIVE_INFINITY = Number["POSITIVE_INFINITY"];
Math.isFinite = function(i) {
return isFinite(i);
}
Math.isNaN = function(i) {
return isNaN(i);
}
}
This is some pretty unsavory javascript.
Questions
Is there a fork or clone of haxe somewhere that doesn't pollute globals? Is it worth it to modify the haxe source to get what I want, or has someone already solved this? Googling hasn't turned up much. I'm open to any suggestions. Meanwhile, I'm dying to see what kind of PHP code this thing's going to produce... :D
Answers?
Here are some of the ideas I've tried:
postprocessing
Here's my humble build script; it does a pretty good job of stripping stuff out, but it doesn't catch everything. I'm hesitant to remove the modifications to the built-in constructor prototypes; I'm sure that would break things. Fixing everything might be a bit of a task, and I don't want to start on it if someone's already done the work...
haxe -cp ~/Projects/wmd-new -main Markdown -js markdown.js
echo "this.Markdown=(function(){ var \$closure, Float;" > markdown.clean.js;
sed "s/^if(typeof js=='undefined') js = {}$/if(typeof js=='undefined') var js = {};/g ;
s/^\([ \x09]*\)\([\$_a-zA-Z0-9]* = \({\|function\)\)/\1var \2/g ;
/^[ \x09]*\(else \)\?null;$/d ;
" markdown.js >> markdown.clean.js
echo "return Markdown}());" >> markdown.clean.js;
java -jar closure/compiler.jar --js markdown.clean.js \
--compilation_level SIMPLE_OPTIMIZATIONS \
> markdown.cc.js
--js-namespace switch saves the day
Thanks to Dean Burge for pointing out the namespace switch. This pretty much solved my problem, with a minor bit of help. Here's my current build script. I think this catches all the global variables...
NS=N\$
haxe -cp ~/Projects/wmd-new -main Markdown --js-namespace $NS -js markdown.js
# export our function and declare some vars
echo "this.markdown=(function(){var \$_,\$Main,\$closure,\$estr,js,"$NS"" > markdown.clean.js;
# strip silly lines containing "null;" or "else null;"
sed "/^[ \x09]*\(else \)\?null;$/d ;" markdown.js >> markdown.clean.js
# finish the closure
echo "return "$NS".Markdown.makeHtml}());" >> markdown.clean.js;
I use the namespace switch on the compiler to clean those global root types up.
Haxe is not meant to be used for writing an isolated reusable component in a javascript web application. This is evidenced by the fact that the compiler emits standard library for every goddamn compilation. Most optimal use of javascript target is to write an application entirely in haxe and call external stuff using untyped blocks hoping it won't break anything. You should treat haxe output like a flash clip, oblivious to the environment it runs in, assumes it is the only thing running.
Or you might try wrapping the code with a with() block.
there's a namespaced (experimental) haxe compiler here http://github.com/webr3/haxe
The JSTM JavaScript generator macro optimizes haxe output in a number of ways:
the javascript output is split into seperate files per type
these files are optimized
a loader script loads the required types asynchronously
only one global variable is used: jstm
only code that is actually required to run your app is downloaded
new types can be loaded at runtime which makes possible highly scalable apps
check out http://code.google.com/p/jstm/ for more info.

Categories