Macro to evaluate expression and create import - import

This may seem odd and is perhaps impossible but I was wondering if there's a way to create a macro that evaluates the expression passed and performs an import.
I can get it to work easily enough if a string literal is the expression:
import macros
macro createImport(ex: expr): stmt =
result = newNimNode(nnkImportStmt)
result.add(ex)
createImport("strutils")
let a = ["foo", "bar", "baz"]
echo a.join("---") # using `join()` from the `strutils` module
But if a variable is passed, this of course will fail.
var s = "strutils"
createImport(s)
(Note that the import could be a string path do a module.)
I've attempted many adjustments to the macro and scoured the docs and source but I just can't find a way to get the actual value of the ex: expr to be useful in the import.
I can get the macro to create an echo call that reveals the string passed but any attempt to use it with the import ends up using the variable name itself.
I guess it makes since since it would seem that the value may not be available when the macro itself is evaluated. Is it possible to do this and if so, how?

I'm not quite sure why you need such a helper macro and whether it's a good idea, but the simplest way to achieve what you need is the following:
template my_import(x: static[string]) = import x
const x = "strutils"
my_import x

Related

How to evaluate an expression in nim?

I'm trying to perform the equivalent of the eval method from Python in nim.
I was under the impression that parseStmt from the macros package should help me with this, but I'm facing a compilation issue that I don't understand.
import macros
echo parseStmt("1 + 2")
I would have expected this to print 3 when executed, but instead the compilation complains that
Error: request to generate code for .compileTime proc: $
I found this thread, and the examples there work, and following this, I was able to make the following program that works as I would expect:
import macros
import strformat
macro eval(value: string): untyped =
result = parseStmt fmt"{value}"
echo eval("1+2")
But I don't undertand why it needs to be written in this way at all. If I inline the statement, let value = "1 + 2"; echo parseStmt fmt"{value}", I get the same compile error as above.
Also, why is parseStmt value different from parseStmt fmt"{value}", in the context of the eval macro above?
What am I missing here?
Thank you in advance for any clarifications!
Unlike Python which is an interpreted language, Nim is compiled. This means that all code is parsed and turned into machine code on compile-time and the program that you end up with doesn't really know anything about Nim at all (at least as long as you don't import the Nim compiler as a module, which is possible). So parseStmt and all macro/template expansion stuff in Nim is done completely during compilation. The error, although maybe a bit hard to read, is trying to tell you that what was passed to $ (which is the convert-to-string operator in Nim, and called by echo on all its arguments) is a compile-time thing that can't be used on runtime. In this case it's because parseStmt doesn't return "3", it returns something like NimNode(kind: nnkIntLit, intVal: 3), and the NimNode type is only available during compile-time. Nim however allows you to run code on compile-time to return other code, this is what a macro does. The eval macro you wrote there takes value which is any statement that resolves to a string during runtime, passed as a NimNode. This is also why result = parseStmt value won't work in your case, because value is not yet a string, but could be something like reading a string from standard input which would result in a string during runtime. However the use of strformat here is a bit confusing and overkill. If you change your code to:
import macros
macro eval(value: static[string]): untyped =
result = parseStmt value
echo eval("1+2")
It will work just fine. This is because we have now told Nim that value needs to be a static i.e. known during compile-time. In this case the string literal "1+2" is obviously known at compile-time, but this could also be a call to a compile-time procedure, or even the output of staticRead which reads a file during compilation.
As you can see Nim is very powerful, but the barrier between compile-time and run-time can sometimes be a bit confusing. Note also that your eval procedure doesn't actually evaluate anything at compile-time, it simply returns the Nim code 1 + 2 so your code ends up being echo 1 + 2. If you want to actually run the code at compile-time you might want to look into compile-time procedures.
Hope this helps shed some light on your issue.
Note: while this answer outlines why this happens, keep in mind that what you're trying to do probably won't result in what you want (which I assumed to be runtime evaluation of expressions).
You're trying to pass a NimNode to parseStmt which expects a string. The fmt macro automatically stringifies anything in the {}, you can omit the fmt by doing $value to turn the node into a string.
As I already noted, this will not work as it does in Python: Nim does not have runtime evaluation. The expression in the string is going to be evaluated at compile time, so a simple example like this will not do what you want:
import std/rdstdin
let x = readLineFromStdin(">")
echo eval(x)
Why?
First of all, because you're stringifying the AST you pass to the eval, it's not the string behind the x variable that's going to get passed to the macro - it's going to be the symbol that denotes the x variable. If you stringify a symbol, you get the underlying identifier, which means that parseStmt will receive "x" as its parameter. This will effect in the string stored in x being printed out, which is wrong.
What you want instead is the following:
import std/rdstdin
import std/macros
macro eval(value: static string): untyped =
result = parseStmt(value)
echo eval("1 + 2")
This prevents runtime-known values from being passed to the macro. You can only pass consts and literals to it now, which is the correct behavior.

How to get the fully-qualified name of the currently executing function?

Suppose I have:
+MyPackage/+MySubPackage2/some_function.m
How can I generate the string 'MyPackage.MySubPackage2.some_function' from within this some_function.m when it's executing?
mfilename(), dbstack(), what(), etc. all just give 'some_function'
meta.package.fromName requires the string we're after as its input
parsing the full path (mfilename('fullpath')) or meta.package.getAllPackages() etc. seems to be the only way...
Seems that calling mfilename('class') in a class inside a package gives the right answer, but there's no equivalent for plain functions...
...or is there? Feels like I'm missing something obvious...
If it is possible to import the containing package (say p1/p2), then:
function outputArg1 = some_function()
import p1.p2.*
t = #some_function;
func2str(t)
%ans = 'p1.p2.some_function'
outputArg1 = ...;
end
The method in this answer may also be used (with some changes possibly) to automate the import process.

Using LuaJ with Scala

I am attempting to use LuaJ with Scala. Most things work (actually all things work if you do them correctly!) but the simple task of setting object values has become incredibly complicated thanks to Scala's setter implementation.
Scala:
class TestObject {
var x: Int = 0
}
Lua:
function myTestFunction(testObject)
testObject.x = 3
end
If I execute the script or line containing this Lua function and pass a coerced instance of TestObject to myTestFunction this causes an error in LuaJ. LuaJ is trying to direct-write the value, and Scala requires you to go through the implicitly-defined setter (with the horrible name x_=, which is not valid Lua so even attempting to call that as a function makes your Lua not parse).
As I said, there are workarounds for this, such as defining your own setter or using the #BeanProperty markup. They just make code that should be easy to write much more complicated:
Lua:
function myTestFunction(testObject)
testObject.setX(testObject, 3)
end
Does anybody know of a way to get luaj to implicitly call the setter for such assignments? Or where I might look in the luaj source code to perhaps implement such a thing?
Thanks!
I must admit that I'm not too familiar with LuaJ, but the first thing that comes to my mind regarding your issue is to wrap the objects within proxy tables to ease interaction with the API. Depending upon what sort of needs you have, this solution may or may not be the best, but it could be a good temporary fix.
local mt = {}
function mt:__index(k)
return self.o[k] -- Define how your getters work here.
end
function mt:__newindex(k, v)
return self.o[k .. '_='](v) -- "object.k_=(v)"
end
local function proxy(o)
return setmetatable({o = o}, mt)
end
-- ...
function myTestFunction(testObject)
testObject = proxy(testObject)
testObject.x = 3
end
I believe this may be the least invasive way to solve your problem. As for modifying LuaJ's source code to better suit your needs, I had a quick look through the documentation and source code and found this, this, and this. My best guess says that line 71 of JavaInstance.java is where you'll find what you need to change, if Scala requires a different way of setting values.
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
Perhaps you should use the method syntax:
testObject:setX(3)
Note the colon ':' instead of the dot '.' which can be hard to distinguish in some editors.
This has the same effect as the function call:
testObject.setX(testObject, 3)
but is more readable.
It can also be used to call static methods on classes:
luajava.bindClass("java.net.InetAddress"):getLocalHost():getHostName()
The part to the left of the ':' is evaluated once, so a statement such as
x = abc[d+e+f]:foo()
will be evaluated as if it were
local tmp = abc[d+e+f]
x = tmp.foo(tmp)

Embedding XML (and other languages?) in Scala

I'm wondering how the scala.xml library is implemented, to get an Elem-instance out of XML.
So I can write:
val xml = {
<myxml>
Some wired text withoud "'s or code like
import x
x.func()
It's like a normal sting in triple-quotes.
</myxml>
}
xml.text
String =
"
Some text wired withoud "'s or code like
import x
x.func()
It's like a normal sting in triple-quotes.
"
A look at the source code doesn't gave me the insight, how this is achieved.
Is the "XML-detection" a (hard) scala language feature or is it an internal DSL? Because I would like to build my own things like this:
var x = LatexCode {
\sqrt{\frac{a}{b}}
}
x.toString
"\sqrt{\frac{a}{b}}"
or
var y = PythonCode {
>>> import something
>>> something.func()
}
y.toString
"""import something ..."""
y.execute // e.g. passed to python as python-script
or
object o extends PythonCode {
import x
x.y()
}
o.toString
"""import x...."""
I would like to avoid using such things like PythonCode { """import ...""" } as "DSL". And in scala, XML is magically transported to a scala.xml-Class; same with Symbol which I can get with val a = 'symoblname, but in the source code there's no clue how this is implemented.
How can I do something like that on myself, preferably as internal DSL?
XML is a scala language feature (*) - see the SLS, section 1.5.
I think that string interpolation is coming in 2.10, however, which would at least allow you to define your own DSL:
val someLatex = latex"""\sqrt{\frac{a}{b}}}"""
It's an experimental feature explained more fully in the SIP but has been additionally blogged about by the prolific Daniel Sobral. The point of this is (of course) that the correctness of the code in the String can be checked at compile time (well, to the extent possible in an untyped language :-) and your IDE can even help you write it (well, to the extent possible in an untyped language :-( )
(*) - We might expect this to change in the future given the many shortcomings of the implementation. My understanding is that a combination of string interpolation and anti-xml may yet be the one true way.
It's an XML literal, just like "foo" is a string literal, 42 is an integer literal, 12.34 is a floating point literal, 'foo is a symbol literal, (foo) => foo + 1 is a function literal and so on.
Scala has fewer literals than other languages (for example, it doesn't have array literals or regexp literals), but it does have XML literals.
Note that in Scala 2.10 string literals become vastly more powerful by allowing you to intercept and re-interpret them using StringContexts. These more powerful string literals would allow you to implement all of your snippets, including XML without separate language support. It is likely that XML literals will be removed in a future version of the language.

Is there a way to let arguments be var instead of val?

When debugging command line argument handling in Java I'm used to doing
args = new String[] { "some", "new", "arguments" };
(especially useful if have a filename as argument which you frequently change, but don't want to go through some dialog windows in the IDE). This has the benefit that I can simply comment out the line when building a release.
So when I tried this in Scala I discovered that arguments are vals. (And I can't write var in front of the parameter).
Q1: What's the rationale for this?
Q2: So is there any obvious work-around except for doing
val newArgs = if (...) args else Array("some", "new", "arguments")
and stick to newArgs in the remaining main method?
Q1: Mutating the input parameters is often seen as bad style and makes it harder to reason about code.
Q2: You could assign the args to a var before doing anything with it.
Arrays are mutable, so if you insist:
Seq("some", "new", "arguments").copyToArray(args, 0, 3)
That does, of course, only work if there is enough space in the passed array.
Remember that you can use default parameters in Scala to solve your original probem in a much cleaner way.
If you only want to modify the args inside of the function, then your approach in the description is enough.
However, if you need to treat it as a true "reference" type and keep the modifications valid outside the function, you can wrap the arguments in a case class, e.g.:
case class Ref[A](var value: A)
And use it like:
def modify(refInt: Ref[Int]) = refInt.value = 3
Then, when you use refInt.value outside the function, it would still be 3.