Reflection/Get source
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.
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>
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>
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|VOID}
on getClassCode (class)
if ilk(class)=#instance then class=class.script -- 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] -- check if it's a script member if m.type<>#script then next repeat if m.script=class then return m.scriptText end repeat end repeat
end
-- Returns the source code of the 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] -- check if it's a script member if m.type<>#script then next repeat -- check if it's a movie script if m.scriptType=#movie then -- check if func is contained in its function list (handlers) if m.script.handlers().getPos(func) then return m.scriptText end if 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
Filename of a subroutine: <lang perl6>say &sum.file;</lang>
Filename of a method: <lang perl6>say Date.^find_method("day-of-week").file;</lang>
Unfortunately, as of Rakudo 6.c on MoarVM, it prints a precompilation hash (rather than a proper file path) for routines exported by pre-compiled modules, and just gen/moar/m-CORE.setting
(rather than a full path) for built-ins.
Python
Modules loaded from files have a __file__
attribute.
<lang python>import os
os.__file__
- "/usr/local/lib/python3.5/os.pyc"
</lang>
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>
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