Following the docs here: https://nim-lang.org/docs/backends.html#backends-the-javascript-target
I have the following code in fib.nim
proc fib(a: cint): cint {.exportc.} =
if a <= 2:
result = 1
else:
result = fib(a - 1) + fib(a - 2)
If I run nim js -o:fib.js fib.nim then it compiles it to JS.
How do I then run fib from nodejs? In the example, its an html file and a browser, but on node, I cant figure out how to import the fib function. It looks like the .js file is missing the exports. How can I build the nim module so that nodejs can import it?
I can't find a built in way of compiling a nim module to a js module. The workaround is to import the module object and export procs.
import jsffi
var module {.importc.}: JsObject
proc fib*(a: cint): cint =
if a <= 2:
result = 1
else:
result = fib(a - 1) + fib(a - 2)
module.exports.fib = fib
The above can be expressed as a macro:
import macros, jsfii
var module {.importc.}: JsObject
macro exportjs(body: typed) =
let bodyName = body.name.strVal
result = newStmtList(
body,
newAssignment(
newDotExpr(newDotExpr(ident"module", ident"exports"), ident(bodyName)),
ident(bodyName)
)
)
proc fib*(a: cint): cint {.exportjs.} =
if a <= 2:
result = 1
else:
result = fib(a - 1) + fib(a - 2)
This repo came up while looking up solutions: https://github.com/nepeckman/jsExport.nim
Related
I am writing a compiler for a programming language I am making in python, I am also using llvmlite to generate ir and object files. For some reason when I use the mod.get_global function it returns the GlobalVariable but it pointerizes it. However it is a string with type i8* and it returns i8** which is making weird results when I try to print it. It also does this with ints, 64 to 64*. I don't know what is going on and I don't know how to fix it. Help would be appreciated.
Here is my shortend code with the same issue:
import llvmlite.ir as llvm
int_type = llvm.IntType(64)
char_type = llvm.IntType(8)
str_type = llvm.PointerType(char_type)
strid = 0
def create_str(mod, str):
global strid
str += "\0"
typ = llvm.ArrayType(char_type, len(str))
var = llvm.GlobalVariable(mod, typ, name=f"str.{strid}")
var.global_constant = True
var.unnamed_addr = True
var.initializer = typ(bytearray(str.encode("utf8")))
strid += 1
return var.gep([int_type(0), int_type(0)])
module = llvm.Module(name="broken")
var = llvm.GlobalVariable(module, str_type, name="brokenvar")
var.global_constant = False
var.unnamed_addr = False
var.initializer = create_str(module, "Hello, World!")
# in my program you can no longer access the var variable after this point
print(module.get_global("brokenvar").type)
After running this program, instead of getting the expected i8*, i get i8**
How can I add a method to the string table and modify self inside it ?
Basically, I'm trying to mimic the behaviour of the io.StringIO.read method in python, which reads n char in the string and returns them, modifying the string by "consuming" it.
I tried this:
function string.read(str, n)
to_return = str:sub(1, n)
str = str:sub(n + 1)
return to_return
end
local foo = "heyfoobarhello"
print(string.read(foo, 3))
print(foo)
Output is:
hey
heyfoobarhello
I expected the second line to be only foobarhello.
How can I achieve this ?
To mimic Python's io.StringIO class, you must make an object that stores both the underlying string and the current position within that string. Reading from an IO stream normally does not modify the underlying data.
local StringIO_mt = {
read = function(self, n)
n = n or #self.buffer - self.position + 1
local result = self.buffer:sub(self.position, self.position + n - 1)
self.position = self.position + n
return result
end,
}
StringIO_mt.__index = StringIO_mt
local function StringIO(buffer)
local o = {buffer = buffer, position = 1}
setmetatable(o, StringIO_mt)
return o
end
local foo = StringIO"heyfoobarhello"
print(foo:read(3))
print(foo:read())
Output:
hey
foobarhello
I don't recommend adding this class or method to Lua's string library, because the object has to be more complex than just a string.
You can add methods to the datatype string independently from the string table.
Short example that shows that the string methods even work if string table gets deleted...
string=nil
return _VERSION:upper():sub(1,3)
-- Returning: LUA
So you can add a method...
-- read.lua
local read = function(self, n1, n2)
return self:sub(n1, n2)
end
getmetatable(_VERSION).__index.read=read
return read
...for all strings.
( Not only _VERSION )
And use it...
do require('read') print(_VERSION:read(1,3):upper()) end
-- Print out: LUA
I am trying to calculate the amount of time an issue spent in a status. But experiencing some errors. The script below goes into the scripted field. Below is my script:
import com.atlassian.jira.component.ComponentAccessor
def changeHistoryManager = ComponentAccessor.changeHistoryManager
def currentStatusName = issue?.status?.name
def rt = [0L]
changeHistoryManager.getChangeItemsForField (issue, "status").reverse().each {item ->
def timeDiff = System.currentTimeMillis() - item.created.getTime()
if (item.fromString == currentStatusName) {
rt = -timeDiff
}
if (item.toString == currentStatusName){
rt = timeDiff
}
}
return (Math.round(rt.sum() / 3600000)) as Double
The error is in the last line of the script(the return statement).
I'm not sure what I'm doing wrong.
The errors I get are:
Static type checking - Cannot find matching java.lang.Object#sum() and Cannot find matching method java.lang.Match#round(java.lang.Object)
You are assigning rt to a Long in your two if blocks. (Just a long, not an array of longs.) Consequently there is no .sum() method available.
You could use
rt << -timeDiff
// or
rt << timeDiff
to add your timeDiffs to the array rather than redefining it.
You also could just initialize rt as 0 and then use rt += timeDiff or rt -= timeDiff if you prefer. It doesn't look like you really need that to exist as an array at all.
Example that may work for you:
import com.atlassian.jira.component.ComponentAccessor
def changeHistoryManager = ComponentAccessor.changeHistoryManager
def currentStatusName = issue?.status?.name
def rt = 0L
changeHistoryManager.getChangeItemsForField (issue, "status").reverse().each {item ->
def timeDiff = System.currentTimeMillis() - item.created.getTime()
if (item.fromString == currentStatusName) {
rt -= timeDiff
}
if (item.toString == currentStatusName){
rt += timeDiff
}
}
return rt / 3600000
// this could still be Math.round(rt/3600000) as Double if you need that; not sure what you're trying to do with the actual result
Below is code to encode an integer value into an ASCII string. It is written in Python, and works fine from my testings.
def encode(value):
code = ''
while value%254 != value:
code = code + chr(value%254)
value = value/254
code = code + chr(value)
return code
def decode(code):
value = 0
length = len(code)
for i in range(0, length):
print code[i]
value = value * 254 + ord(code[length-1-i])
return value
code = encode(123456567)
print code
print decode(code)
However when I try the same implementation in Lua, the values encoded and decoded do not match up. Here is my Lua version:
function encode(value)
code = ''
while value%254 ~= value do
code = code .. string.char(value%254)
value = value/254
end
code = code .. string.char(value)
return code
end
function decode(code)
value = 0
code = string.reverse(code)
for i=1, #code do
local c = code:sub(i,i)
print(c)
value = value*254 + string.byte(c)
end
return value
end
code = encode(2555456)
print(decode(code))
Please note that I am trying to using mod 254 so that I can used 255 as a delimiter.
Use local whenever you are creating variables with similar names (for eg. code and value in your code).
When you use value = value / 254, you need to take only the integer part of the division and not the entire number.
Therefore:
function encode(value)
local code = ''
while value % 254 ~= value do
code = code .. string.char( value % 254 )
value = math.floor( value / 254 )
end
code = code .. string.char( value )
return code
end
function decode(code)
local value = 0
code = code:reverse()
for i = 1, #code do
local c = code:sub( i, i )
value = value * 254 + c:byte()
end
return value
end
I want to read a 32 bit integer binary file provided by another program. The file contains only integer and no other characters (like spaces or commas). The C code to read this file is as follows:
FILE* pf = fopen("C:/rktemp/filename.dat", "r");
int sz = width*height;
int* vals = new int[sz];
int elread = fread((char*)vals, sizeof(int), sz, pf);
for( int j = 0; j < height; j++ )
{
for( int k = 0; k < width; k++ )
{
int i = j*width+k;
labels[i] = vals[i];
}
}
delete [] vals;
fclose(pf);
But I don't know how to read this file into array using Lua.
I've tried to read this file using io.read, but part of the array looks like this:
~~~~~~xxxxxxxxyyyyyyyyyyyyyyzzzzzzzz{{{{{{{{{|||||||||}}}}}}}}}}}~~~~~~~~~xxxxxxxyyyyyyyyyyyyyyzzzzzz{{{{{{{{{{|||||||||}}}}}}}}}}}~~~~~~~~~xxyyyyyyyyyyyyyzzzzz{{{{{{|||}}}yyyyyyyyyyyz{{{yyyyyyyyÞľūơǿȵɶʢ˺̤̼ͽаҩӱľǿجٴȵɶʢܷݸ˺⼼ӱľǿ
Also the Matlab code to read this file is like this:
row = image_size(1);
colomn = image_size(2);
fid = fopen(data_path,'r');
A = fread(fid, row * colomn, 'uint32')';
A = A + 1;
B = reshape(A,[colomn, row]);
B = B';
fclose(fid);
I've tried a function to convert bytes to integer, my code is like this:
function bytes_to_int(b1, b2, b3, b4)
if not b4 then error("need four bytes to convert to int",2) end
local n = b1 + b2*256 + b3*65536 + b4*16777216
n = (n > 2147483647) and (n - 4294967296) or n
return n
end
local sup_filename = '1.dat'
fid = io.open(sup_filename, "r")
st = bytes_to_int(fid:read("*all"):byte(1,4))
print(st)
fid:close()
But it still not read this file properly.
You are only calling bytes_to_int once. You need to call it for every int you want to read. e.g.
fid = io.open(sup_filename, "rb")
while true do
local bytes = fid:read(4)
if bytes == nil then break end -- EOF
local st = bytes_to_int(bytes:byte(1,4))
print(st)
end
fid:close()
Now you can use the new feature of Lua language by calling string.unpack , which has many conversion options for format string. Following options may be useful:
< sets little endian
> sets big endian
= sets native endian
i[n] a signed int with n bytes (default is native size)
I[n] an unsigned int with n bytes (default is native size)
The arch of your PC is unknown, so I assume the data to read is unsigned and native-endian.
Since you are reading binary data from the file, you should use io.open(sup_filename, "rb").
The following code may be useful:
local fid = io.open(sup_filename, "rb")
local contents = fid:read("a")
local now
while not now or now < #contents do
local n, now = string.unpack("=I4", contents, now)
print(n)
end
fid:close()
see also: Lua 5.4 manual