duktape how to parse argument of type String Object (similarly Number object) in duktape c function - duktape

How to type check the String object/Number object argument types in duktape c function and parse the value from String object/Number object. There is generic api like duk_is_object() but I need the correct object type to parse the value .
ex:
ecmascript code
var str1 = new String("duktape");
var version = new Number(2.2);
dukFunPrintArgs(str1,str2);
duktape c function :
dukFunPrintArgs(ctx)
{
// code to know whether the args is of type String Object / Number Object
}

Where did you find the information how to register a C function in duktape? That place certainly also has details on how to access the parameters passed to it. Already on the homepage of duktape.org you can find a Getting Started example:
3 Add C function bindings
To call a C function from Ecmascript code, first declare your C functions:
/* Being an embeddable engine, Duktape doesn't provide I/O
* bindings by default. Here's a simple one argument print()
* function.
*/
static duk_ret_t native_print(duk_context *ctx) {
printf("%s\n", duk_to_string(ctx, 0));
return 0; /* no return value (= undefined) */
}
/* Adder: add argument values. */
static duk_ret_t native_adder(duk_context *ctx) {
int i;
int n = duk_get_top(ctx); /* #args */
double res = 0.0;
for (i = 0; i < n; i++) {
res += duk_to_number(ctx, i);
}
duk_push_number(ctx, res);
return 1; /* one return value */
}
Register your functions e.g. into the global object:
duk_push_c_function(ctx, native_print, 1 /*nargs*/);
duk_put_global_string(ctx, "print");
duk_push_c_function(ctx, native_adder, DUK_VARARGS);
duk_put_global_string(ctx, "adder");
You can then call your function from Ecmascript code:
duk_eval_string_noresult(ctx, "print('2+3=' + adder(2, 3));");
One of the core concepts in duktape are stacks. The value stack is where parameters are stored. Read more on the Getting Started page.

Related

Rust Wasm Bindgen returns object but gets a number

today while doing some rust wasm vs js speed benchmarking with wasm-bindgen, I ran into a problem.
I had made a simple struct as you can see here:
I used this struct in a simple function called gimmeDirections
as shown here:
After compiling this into browser javascript, I looked into the .d.ts file that was compiled into it and noticed that the gimmeDirections function returned a number.
even though in the js, it states in the JSDOC that it returned the class of XY which was defined earlier in the compiled code.
here is the class:
export class XY {
static __wrap(ptr) {
const obj = Object.create(XY.prototype);
obj.ptr = ptr;
return obj;
}
free() {
const ptr = this.ptr;
this.ptr = 0;
wasm.__wbg_xy_free(ptr);
}
/**
* #returns {number}
*/
get x() {
var ret = wasm.__wbg_get_xy_x(this.ptr);
return ret;
}
/**
* #param {number} arg0
*/
set x(arg0) {
wasm.__wbg_set_xy_x(this.ptr, arg0);
}
/**
* #returns {number}
*/
get y() {
var ret = wasm.__wbg_get_xy_y(this.ptr);
return ret;
}
/**
* #param {number} arg0
*/
set y(arg0) {
wasm.__wbg_set_xy_y(this.ptr, arg0);
}
}
after being very confused, due to the fact of how the typescript said it would return a number but the js said it would return a class, I decided to run it... and got a number back.
The object below is my javascript function running identical code for the benchmark, as you can see, I got an object, not a number.
Here is my JS code:
import * as funcs from './wasm/wildz.js';
// compiled wasm js file
function directionsJS(x, y) {
let xX = x;
let yY = y;
if (Math.abs(xX) === Math.abs(yY)) {
xX /= Math.SQRT2;
yY /= Math.SQRT2;
}
return {
x: x,
y: yY
};
}
(async() => {
const game = await funcs.default();
console.time('Rust Result'); console.log(game.gimmeDirections(10, 10));
console.timeEnd('Rust Result'); console.time('JS Result');
console.log(directionsJS(10, 10)); console.timeEnd('JS Result');
})();
I'm still very confused on why it's returning a number when clearly I'm returning a object. Help is much needed, and appreciated
Much of this and more is explained in Exporting a struct to JS in the wasm-bindgen guide, but I'll summarize.
Rust structs are "returned" by allocating space for them dynamically and returning a pointer to it. What you're seeing, in regards to the function returning number, is the "raw" ffi function that binds the JS runtime and wasm module. It just returns that pointer value.
The generated XY Javascript class is a wrapper around that pointer value and provides functions for interacting with it. The generated gimmeDirections function is a wrapper around that wasm module call that creates that class.

How to get the name of the current and calling function in dart?

C# has:
System.Reflection.MethodBase.GetCurrentMethod().Name
Does Dart have something similar but returns results for both the function that is currently being run as well as the name of the function that called the currently run function.
I wrote a simple class that gives the current function and the caller function, but also, the file name, line number and column line from the StackTrace.current property.
Heres the code:
class CustomTrace {
final StackTrace _trace;
String fileName;
String functionName;
String callerFunctionName;
int lineNumber;
int columnNumber;
CustomTrace(this._trace) {
_parseTrace();
}
String _getFunctionNameFromFrame(String frame) {
/* Just giving another nickname to the frame */
var currentTrace = frame;
/* To get rid off the #number thing, get the index of the first whitespace */
var indexOfWhiteSpace = currentTrace.indexOf(' ');
/* Create a substring from the first whitespace index till the end of the string */
var subStr = currentTrace.substring(indexOfWhiteSpace);
/* Grab the function name using reg expr */
var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9]'));
/* Create a new substring from the function name index till the end of string */
subStr = subStr.substring(indexOfFunction);
indexOfWhiteSpace = subStr.indexOf(' ');
/* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */
subStr = subStr.substring(0, indexOfWhiteSpace);
return subStr;
}
void _parseTrace() {
/* The trace comes with multiple lines of strings, (each line is also known as a frame), so split the trace's string by lines to get all the frames */
var frames = this._trace.toString().split("\n");
/* The first frame is the current function */
this.functionName = _getFunctionNameFromFrame(frames[0]);
/* The second frame is the caller function */
this.callerFunctionName = _getFunctionNameFromFrame(frames[1]);
/* The first frame has all the information we need */
var traceString = frames[0];
/* Search through the string and find the index of the file name by looking for the '.dart' regex */
var indexOfFileName = traceString.indexOf(RegExp(r'[A-Za-z]+.dart'));
var fileInfo = traceString.substring(indexOfFileName);
var listOfInfos = fileInfo.split(":");
/* Splitting fileInfo by the character ":" separates the file name, the line number and the column counter nicely.
Example: main.dart:5:12
To get the file name, we split with ":" and get the first index
To get the line number, we would have to get the second index
To get the column number, we would have to get the third index
*/
this.fileName = listOfInfos[0];
this.lineNumber = int.parse(listOfInfos[1]);
var columnStr = listOfInfos[2];
columnStr = columnStr.replaceFirst(")", "");
this.columnNumber = int.parse(columnStr);
}
}
This class takes in a StackTrace object and reads its string and parse it.
How to use it (get the info):
void main() {
CustomTrace programInfo = CustomTrace(StackTrace.current);
print("Source file: ${programInfo.fileName}, function: ${programInfo.functionName}, caller function: ${programInfo.callerFunctionName}, current line of code since the instanciation/creation of the custom trace object: ${programInfo.lineNumber}, even the column(yay!): ${programInfo.columnNumber}");
}
The variable programInfo now has the function name, the caller function name, line number, column number and even the file name of the current program's execution.
You can print to the console the following:
print(StackTrace.current.toString());
And you will see how the string looks and be able to understand how i parse the string in order to get the information.
The simple benefit of this is that you dont have to install any library. I made this because i was doing a project just using Dart and i didnt want to add/install any third party library into my simple project. And you will end up with an object having all of the information by just calling the constructor. The downside of this is that it if Dart, for some reason, changes the string format of the stack trace somewhere in the future, this will no longer work BUT if this somehow happens, you can easily change how this class parses the frames*/
NOTE: This code by no means is the most optimize code, but it works :D. I would like to see some better implementations and abstractions.
There is no way to directly access the call stack in the Dart reflection library.
You can get a string representation of the stack trace, and then try to parse that:
var stack = StackTrace.current;
var stackString = "$stack"; // because the only method on StackTrace is toString.
The stack_trace package tries to do this for you for a number of known stack trace formats, so maybe:
import "package:stack_trace";
main() {
print(Trace.current().frames[0].member); // prints "main" unless minified.
}
Tidied up #LuisDev99's answer a bit, optimizing for yourself:
class LoggerStackTrace {
const LoggerStackTrace._({
required this.functionName,
required this.callerFunctionName,
required this.fileName,
required this.lineNumber,
required this.columnNumber,
});
factory LoggerStackTrace.from(StackTrace trace) {
final frames = trace.toString().split('\n');
final functionName = _getFunctionNameFromFrame(frames[0]);
final callerFunctionName = _getFunctionNameFromFrame(frames[1]);
final fileInfo = _getFileInfoFromFrame(frames[0]);
return LoggerStackTrace._(
functionName: functionName,
callerFunctionName: callerFunctionName,
fileName: fileInfo[0],
lineNumber: int.parse(fileInfo[1]),
columnNumber: int.parse(fileInfo[2].replaceFirst(')', '')),
);
}
final String functionName;
final String callerFunctionName;
final String fileName;
final int lineNumber;
final int columnNumber;
static List<String> _getFileInfoFromFrame(String trace) {
final indexOfFileName = trace.indexOf(RegExp('[A-Za-z]+.dart'));
final fileInfo = trace.substring(indexOfFileName);
return fileInfo.split(':');
}
static String _getFunctionNameFromFrame(String trace) {
final indexOfWhiteSpace = trace.indexOf(' ');
final subStr = trace.substring(indexOfWhiteSpace);
final indexOfFunction = subStr.indexOf(RegExp('[A-Za-z0-9]'));
return subStr
.substring(indexOfFunction)
.substring(0, subStr.substring(indexOfFunction).indexOf(' '));
}
#override
String toString() {
return 'LoggerStackTrace('
'functionName: $functionName, '
'callerFunctionName: $callerFunctionName, '
'fileName: $fileName, '
'lineNumber: $lineNumber, '
'columnNumber: $columnNumber)';
}
}
print(LoggerStackTrace.from(StackTrace.current).toString());
import 'dart:mirrors';
...
MethodMirror methodMirror = reflect(functionOne).function;
See also https://github.com/dart-lang/sdk/issues/11916#issuecomment-108381556
This will only work in the Dart command line VM, but not in the browser or Flutter because there reflection is not supported.
Code generation solutions like https://pub.dartlang.org/packages/reflectable might work instead where reflection is not available.
https://github.com/dart-lang/sdk/issues/28372 seems related.
LuisDev99's answer doesn't cope well with inner methods and anonymous lambda blocks, so I used a more complex regex approach.
My solution:
/*
Define regex for each entry in the stack
group 0: full line
group 1: stack index
group 2: function name
group 3: package
group 4: file name
group 5: line number
group 6: column number
*/
RegExp regExp = new RegExp(r'^#(\d+) +(.+) +\(package:([^/]+)/(.+\.\w):(\d+):(\d+)\)$');
/* Get the stack as an array of strings */
var frames = StackTrace.current.toString().split("\n");
/* The second entry in the stack is the caller function */
var matches = regExp.allMatches(frames[1])
/* The regex matches each line of the stack only once so only one match */
var match = matches.elementAt(0);
/* Print all groups. Note that "groupCount" doesn't include group 0 (the whole line) */
for (int i = 0; i <= match.groupCount; i++) {
print("group $i: " + match.group(i));
}

how many vectors can be added in DataFrame::create( vec1, vec2 ... )?

I am creating a DataFrame to hold a parsed haproxy http log files which has quite a few fields (25+).
If I add more than 20 vectors (one for each field), I get the compilation error:
no matching function call to 'create'
The create method:
return DataFrame::create(
_["clientIp"] = clientIp,
_["clientPort"] = clientPort,
_["acceptDate"] = acceptDate,
_["frontendName"] = frontendName,
_["backendName"] = backendName,
_["serverName"] = serverName,
_["tq"] = tq,
_["tw"] = tw,
_["tc"] = tc,
_["tr"] = tr,
_["tt"] = tt,
_["status_code"] = statusCode,
_["bytes_read"] = bytesRead,
#if CAPTURED_REQUEST_COOKIE_FIELD == 1
_["capturedRequestCookie"] = capturedRequestCookie,
#endif
#if CAPTURED_REQUEST_COOKIE_FIELD == 1
_["capturedResponseCookie"] = capturedResponseCookie,
#endif
_["terminationState"] = terminationState,
_["actconn"] = actconn,
_["feconn"] = feconn,
_["beconn"] = beconn,
_["srv_conn"] = srvConn,
_["retries"] = retries,
_["serverQueue"] = serverQueue,
_["backendQueue"] = backendQueue
);
Questions:
Have I hit a hard limit?
Is there a workaround to allow me to add more than 20 vectors to a data frame?
Yes, you have hit a hard limit -- Rcpp is limited by the C++98 standard, which requires explicit code bloat to support 'variadic' arguments. Essentially, a new overload must be generated for each create function used, and to avoid choking the compiler Rcpp just provides up to 20.
A workaround would be to use a 'builder' class, where you successively add elements, and then convert to DataFrame at the end. A simple example of such a class -- we create a ListBuilder object, for which we successively add new columns. Try running Rcpp::sourceCpp() with this file to see the output.
#include <Rcpp.h>
using namespace Rcpp;
class ListBuilder {
public:
ListBuilder() {};
~ListBuilder() {};
inline ListBuilder& add(std::string const& name, SEXP x) {
names.push_back(name);
// NOTE: we need to protect the SEXPs we pass in; there is
// probably a nicer way to handle this but ...
elements.push_back(PROTECT(x));
return *this;
}
inline operator List() const {
List result(elements.size());
for (size_t i = 0; i < elements.size(); ++i) {
result[i] = elements[i];
}
result.attr("names") = wrap(names);
UNPROTECT(elements.size());
return result;
}
inline operator DataFrame() const {
List result = static_cast<List>(*this);
result.attr("class") = "data.frame";
result.attr("row.names") = IntegerVector::create(NA_INTEGER, XLENGTH(elements[0]));
return result;
}
private:
std::vector<std::string> names;
std::vector<SEXP> elements;
ListBuilder(ListBuilder const&) {}; // not safe to copy
};
// [[Rcpp::export]]
DataFrame test_builder(SEXP x, SEXP y, SEXP z) {
return ListBuilder()
.add("foo", x)
.add("bar", y)
.add("baz", z);
}
/*** R
test_builder(1:5, letters[1:5], rnorm(5))
*/
PS: With Rcpp11, we have variadic functions and hence the limitations are removed.
The other common approach with Rcpp is to just use an outer list containing as many DataFrame objects (with each limited by the number of elements provided via the old-school macro expansion / repetition) in the corresponding header) as you need.
In (untested) code:
Rcpp::DataFrame a = Rcpp::DateFrame::create(/* ... */);
Rcpp::DataFrame b = Rcpp::DateFrame::create(/* ... */);
Rcpp::DataFrame c = Rcpp::DateFrame::create(/* ... */);
return Rcpp::List::create(Rcpp::Named("a") = a,
Rcpp::Named("b") = b,
Rcpp::Named("c") = c);

Calling Method Wrapped for JS on v8 ObjectWrap from C++

I'm using a node module and would like to call some of its methods on subclasses of ObjectWrap from C++. It's not entirely clear to me how to correctly construct the Arguments object in the function definitions.
For instance, I'd like to call the following method (Context2d extends ObjectWrap):
Handle<Value>
Context2d::LineTo(const Arguments &args) {
HandleScope scope;
if (!args[0]->IsNumber())
return ThrowException(Exception::TypeError(String::New("lineTo() x must be a number")));
if (!args[1]->IsNumber())
return ThrowException(Exception::TypeError(String::New("lineTo() y must be a number")));
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
cairo_line_to(context->context(), args[0]->NumberValue(), args[1]->NumberValue());
return Undefined();
}
So, concisely: having an unwrapped Context2D, how do I call the static LineTo such that the same instance is returned from the args.This call? I realize of course that I can figure this out by digging through v8, but I was hoping someone knowledgable on the topic could point me in the right direction.
You should be able to call it with something like this. I'm assuming that the function is toLine on the object. You haven't shown your object prototype construction so you'll have to adjust this to match.
int x = 10;
int y = 20;
Context2D *context = ...;
// Get a reference to the function from the object.
Local<Value> toLineVal = context->handle_->Get(String::NewSymbol("toLine"));
if (!toLineVal->IsFunction()) return; // Error, toLine was replaced somehow.
// Cast the generic reference to a function.
Local<Function> toLine = Local<Function>::Cast(toLineVal);
// Call the function with two integer arguments.
Local<Value> args[2] = {
Integer::New(x),
Integer::New(y)
};
toLine->Call(context->handle_, 2, args);
This should be equivalent to this JS:
var toLineVal = context.toLine;
if (typeof toLineVal !== 'function') return; // Error
toLineVal(10, 20);

Using an array as a parameter in Haxe

I have a function that takes an array as a parameter, and it keeps returning the following error message:
Test.hx:34: characters 23-24 : Array<Int> should be { length : Void -> Int }
Test.hx:34: characters 23-24 : Invalid type for field length :
Test.hx:34: characters 23-24 : Int should be Void -> Int
Test.hx:34: characters 23-24 : For function argument 'array'
This is the code that produced the error message:
class Test{
static function main() {
var a = new Array();
a = [1,2,3,4];
enlarge1DArray(a); //why won't it work when I try to invoke this function?
}
static function enlarge1DArray(array){
var i = 0;
while(i < array.length()){
i++;
trace("i is " + i);
}
}
}
The length you are trying to access is a property, not a method. See the Array API Documentation.
Change the while line from this:
while(i < array.length())
to this:
while(i < array.length)
Detailed Answer:
The error you're getting is due to Haxe getting confused as it's guessing at the types. Basically, because you had were treating length as a method, it was assuming that the array parameter in the enlarge1DArray had to be some kind of object that had a method called length, with the type signature "Void->Int".
In short, because you were asking for a method, it was expecting the parameter "array" to have:
{ length : Void -> Int }
when an Array actually has:
{ length : Int }
So the compiler got confused and said you had your typing wrong. You can read more about this on the Haxe wiki page for Type Inference. In future you can explicitly state what the types of each function parameter are, and then Haxe will give you more useful error messages.

Resources