Reflection/Get source: Difference between revisions
(Added Julia language) |
(Added Kotlin) |
||
Line 97: | Line 97: | ||
@which foo() # where foo is defined |
@which foo() # where foo is defined |
||
@less foo() # first file where foo is defined</lang> |
@less foo() # first file where foo is defined</lang> |
||
=={{header|Kotlin}}== |
|||
It's possible to do this (in a fashion) in Kotlin JS by using inline JavaScript and applying toString() to the function name to get its source code in a similar way to the JavaScript entry above. However, there are a couple of things to note: |
|||
1. Kotlin JS transpiles to JavaScript and it will therefore be the JS code for the function which will be printed. To my knowledge, there is no way to recover the original Kotlin code. |
|||
2. In the example below the ''hello'' function will actually be referred to as ''_.hello'' in the generated JavaScript from within the main() function. |
|||
<lang scala>// Kotlin JS Version 1.2.31 |
|||
fun hello() { |
|||
println("Hello") |
|||
} |
|||
fun main(args: Array<String>) { |
|||
val code = js("_.hello.toString()") |
|||
println(code) |
|||
} |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
function hello() { |
|||
println('Hello'); |
|||
} |
|||
</pre> |
|||
=={{header|Lingo}}== |
=={{header|Lingo}}== |
Revision as of 15:18, 18 April 2018
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
The goal is to get the source code or file path and line number where a programming object (e.g. module, class, function, method) is defined.
Clojure
<lang clojure>
- Use source function for source code.
(source println)
- Use meta function for filenames and line numbers (and other metadata)
(meta #'println)</lang>
FreeBASIC
FreeBASIC is a fully compiled language which does not support reflection as such.
Nevertheless, the language does have a number of built-in macros which can be used to map certain entities back to the source code file. This is mainly useful for debugging purposes. Here's a simple example :
<lang freebasic>' FB 1.05.0 Win64 (getsource.bas)
Sub Proc()
Print __Function__ & " is defined in " & __Path__ & "\" & __File__ & " at line " & ( __line__ - 1)
End Sub
Proc() Sleep</lang>
- Output:
PROC is defined in c:\FreeBasic\getsource.bas at line 3
J
Source code which when executed will recreate the definition can be obtained using 5!:5 <'name'
where name is the name of the thing you want source code for. Or, you can use 5!:6 which will provide a "fully parenthesized" variant for the tacit part of any definition.
You can also use 4!:4 and 4!:3 to find the file containing the name's definition (if there is one). Line number is not tracked.
Examples:
<lang J> mean=:+/ %#
5!:5 <'mean'
+/ % #
5!:6 <'mean'
(+/) % #
4!:4 <'mean'
_1
4!:4 <'names'
2
2 { 4!:3
┌────────────────────────────────────────────┐ │/Applications/j64-804/system/main/stdlib.ijs│ └────────────────────────────────────────────┘</lang>
We could also provide convenience functions for these mechanisms:
<lang J> linrep=: 5!:5@<
srcfile=: (4!:4@<) { a:,~ 4!:3 bind </lang>
Example use:
<lang J> linrep 'names' list_z_@nl
srcfile 'names'
┌────────────────────────────────────────────┐ │/Applications/j64-804/system/main/stdlib.ijs│ └────────────────────────────────────────────┘
srcfile 'mean'
┌┐ ││ └┘</lang>
Note that these mechanisms can be disabled (using 3!:6).
JavaScript
Function.toString()
will return the source code for user-defined functions.
<lang javascript>function foo() {...} foo.toString(); // "function foo() {...}" </lang>
For native functions, the function body typically will be a syntactically invalid string indicating the function is native. This behavior isn't part of any ECMAScript standard, but is common practice. <lang javascript>Math.sqrt.toString(); // "function sqrt() { [native code] }" </lang>
Julia
<lang julia># Definition function foo() end
@which foo() # where foo is defined @less foo() # first file where foo is defined</lang>
Kotlin
It's possible to do this (in a fashion) in Kotlin JS by using inline JavaScript and applying toString() to the function name to get its source code in a similar way to the JavaScript entry above. However, there are a couple of things to note:
1. Kotlin JS transpiles to JavaScript and it will therefore be the JS code for the function which will be printed. To my knowledge, there is no way to recover the original Kotlin code.
2. In the example below the hello function will actually be referred to as _.hello in the generated JavaScript from within the main() function.
<lang scala>// Kotlin JS Version 1.2.31
fun hello() {
println("Hello")
}
fun main(args: Array<String>) {
val code = js("_.hello.toString()") println(code)
} </lang>
- Output:
function hello() { println('Hello'); }
Lingo
Lingo does not allow to identify specific line numbers (automatically), but you can get the full source code of the script which defines either a class or a global function. Class scripts (called "parent scripts") only define a single class, so no additional parsing needed. Global functions are defined in movie scripts, there can be any number of such movie scripts, but in each movie script all function names must be unique. So it's not too hard to manually find the line number for a specific function in the returned code (e.g. using a RegExp). <lang lingo>---------------------------------------- -- Returns source code either for a class (parent script) or a class instance (object) -- @param {script|instance} class -- @return {string}
on getClassCode (class)
if ilk(class)=#instance then class=class.script return class.text
end
-- Returns the source code of the movie script that defines the specified global function -- @param {symbol} func - function specified as symbol -- @return {string|VOID}
on getGlobalFunctionCode (func)
-- iterate over all members in all castlibs repeat with i = 1 to _movie.castlib.count repeat with j = 1 to _movie.castlib[i].member.count m = _movie.castlib[i].member[j] if m.type<>#script then next repeat if m.scriptType=#movie and m.script.handler(func) then return m.script.text end repeat end repeat
end</lang> Usage: <lang lingo>obj = script("MyClass").new() put getClassCode(obj) -- script text is printed...
func = #startMovie put getGlobalFunctionCode(func) -- script text is printed...</lang>
Perl 6
A full path is provided for built-in routines/methods. However for routines exported by pre-compiled modules a precompilation hash is returned, not a proper file path.
<lang perl6>say &sum.file; say Date.^find_method("day-of-week").file;</lang>
- Output:
SETTING::src/core/Any.pm SETTING::src/core/Dateish.pm
Python
Modules loaded from files have a __file__
attribute.
<lang python>import os
os.__file__
- "/usr/local/lib/python3.5/os.pyc"
</lang>
REXX
This REXX version was modeled after the zkl example, but in addition, it also displays the source. <lang rexx>/*REXX program gets the source function (source code) and */ /*───────────────────────── displays the number of lines. */
- =sourceline()
do j=1 for sourceline() say 'line' right(j, length(#) ) '──►' , strip( sourceline(j), 'T') end /*j*/
say parse source x y sID say 'The name of the source file (program) is: ' sID say 'The number of lines in the source program: ' #
/*stick a fork in it, we're all done.*/</lang>
- output:
line 1 ──► /*REXX program gets the source function (source code) and */ line 2 ──► /*───────────────────────── displays the number of lines. */ line 3 ──► #=sourceline() line 4 ──► do j=1 for sourceline() line 5 ──► say 'line' right(j, length(#) ) '──►' , line 6 ──► strip( sourceline(j), 'T') line 7 ──► end /*j*/ line 8 ──► say line 9 ──► parse source x y sID line 10 ──► say 'The name of the source file (program) is: ' sID line 11 ──► say 'The number of lines in the source program: ' # line 12 ──► /*stick a fork in it, we're all done.*/ The name of the source file (program) is: c:\reflecti.rex The number of lines in the source program: 12
Ruby
Method#source_location
will return the file and line number of a Ruby method. If a method wasn't defined in Ruby, Method#source_location
returns nil.
<lang ruby>require 'mathn'
Math.method(:sqrt).source_location
- ["/usr/local/lib/ruby2.3/2.3.0/mathn.rb", 119]
Class.method(:nesting).source_location
- nil, since Class#nesting is native
</lang>
Tcl
Tcl's info command makes it possible to access the source of nearly anything. This example can show the source code of any proc. The popular tkcon includes a dump command which is capable of showing aliases, arrays and more .. and a edit command which lets you edit them in an interactive window!
<lang Tcl>proc getproc {name} {
set name [uplevel 1 [list namespace which -command $name]] set args [info args $name] set args [lmap arg $args { ;# handle default arguments, if it has them! if {[info default $name $arg default]} { list $name $default } else { return -level 0 $arg } }] set body [info body $name] list proc $name $args $body
}
puts [getproc getproc]</lang>
- Output:
Note the output differs very slightly from the original source: the procedure's name is fully namespace-qualified, and the arguments are in "canonical list form", which does not include braces in this simple case.
<lang Tcl>proc ::getproc name {
set name [uplevel 1 [list namespace which -command $name]] set args [info args $name] set args [lmap arg $args { ;# handle default arguments, if it has them! if {[info default $name $arg default]} { list $name $default } else { return -level 0 $arg } }] set body [info body $name] list proc $name $args $body
}</lang>
zkl
Reads the source file and counts the lines. <lang zkl>src:=File(__FILE__).read(); println("Src file is \"%s\" and has %d lines".fmt(__FILE__,src.len(1)));</lang>
- Output:
$ zkl foo Src file is "foo.zkl" and has 2 lines