Any language that can be compiled for x86 can be transpiled to any language in which an interpreter of x86 opcodes could be written. The question is what level of abstraction can be preserved; if it requires lowering that far, it's not likely to be worth it.
Well, for that matter any Turing complete language can embed an interpreter/compiler for any other Turing complete language. If that's all that is meant by transpiling, it is no different than something like the JVM.
My understanding of 'transpiling' is that it is meant to convert, say, idiomatic Python into idiomatic Java.
The result of the program is "Hello", but the only way a transpiler would be able to reproduce this is by knowing the expression generated by 'gen_expression', and converting the expression to the target language (also assume target language has equivalent of 'eval'). However, then the transpiler needs to know 'gen_expression' will halt, and we have the halting problem.
If the target language has its own eval, why would the transpiler need to run gen_expression at transpile time? It sounds like the transpiler in question is trying to specialize the eval invocation for its input, which is indeed not possible in general. Normal transpilation (as with compilation in general) just converts code that may or may not halt to other code that may or may not halt, without needing to determine AOT what's going to result at runtime. The straightforward way to transpile evalX(langX)->evalY(langY) is to emit evalY(transpileXY(langX)), with the transpiler available at runtime along with the evaluator.
But then aren't you making the target version aware it has been transpiled? Once you go that route, then it becomes a back and forth of hacking around whatever trick used for that situation. I cannot think of a general fix that doesn't result in having to solve the halting problem.
As I said it is logically impossible in general, but you can perhaps restrict the problem to a practical narrower case in which transpilation is always possible.
> But then aren't you making the target version aware it has been transpiled?
I'm not sure what this means.
If you take some code that generates langX at runtime, and compile/transpile that code to langY, you get some langY code that generates the same langX code value. So you need a eval(langX) that can be invoked from langY. Given an X-to-Y transpiler available at runtime, you can create the needed evaluator by composing the transpiler with the langY's eval(langY) function, with ordinary function composition.
I may be explaining this poorly (or misunderstanding you?), but I'm quite sure about the conclusion I'm trying to express. As a concrete example, you can generate some TypeScript at runtime, transpile it, and pass it to the JS eval function. The transpiled-at-compile-time code halts iffi the pre-transpilation version would halt, as does the transpiled-at-runtime code. The transpiler never halts. https://stackoverflow.com/questions/45153848/evaluate-typesc...
Lets say we have a language where each function can return a string expression of itself. E.g. print.str() = "print". gen_exp() uses this function at least for some of its operation. Once we transpile the resulting expression will no longer run in the target language, even with the inner call to transpile. Maybe there is an easy solution to this issue too, but it seems I can keep coming up with new complications the transpiler will need to account for, thus I can't see how transpilation can be guaranteed in general. We would need a general proof that no counter example is ever possible for some given transpilation scheme to guarantee generality.
A transpiler is a compiler. There's nothing that can be compiled but can't be transpiled, because transpiling is just what we call compiling when the target is subjectively deemed a high-level language. So the problem you're describing isn't with transpilation; it sounds like it's with compiling a dynamic language with reflection. That's a tractable problem; you just can't solve it as statically as you would for an AOT-compiler for a more analyzable language. Reflection has to be as late-bound as the rest of the language.