Reflection/Get source: Difference between revisions

m
m (→‎{{header|Wren}}: Minor tidy)
 
(34 intermediate revisions by 19 users not shown)
Line 1:
{{task|Reflection}}
{{omit from|C}}
{{omit from|C++}}
{{omit from|Modula-2}}
{{omit from|Rust}}
 
;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.
<br><br>
=={{header|6502 Assembly}}==
A printing routine that can convert hex digits to ASCII characters can point to the address of a subroutine and start printing from there.
Such a printing routine would work best if it substituted the null terminator for $60 (the <code>RTS</code> instruction.) This would only print the bytecode for the routine. Conversion to assembly language would need to be done separately.
 
<syntaxhighlight lang="6502asm">LDA #<foo
sta $00
LDA #>foo
sta $01
jsr PrintBytecode
 
foo:
;do stuff
rts
 
PrintBytecode:
ldy #0
 
lda $01 ;high byte of starting address of the source
jsr PrintHex
;unimplemented routine that separates the "nibbles" of the accumulator,
; adds $30 or $37 to each depending on if it's 0-9 or A-F respectively, which converts hex to ASCII,
; then prints the high nibble then the low.
 
lda $00 ;low byte of the starting address of the source
jsr PrintHex
jsr NewLine ;unimplemented new line routine
 
loop:
lda ($00),y
cmp #$60
beq Terminated
jsr PrintHex
 
jmp loop
Terminated:
jsr PrintHex ;print the last instruction of the routine.
rts</syntaxhighlight>
 
There is no way to get the file name that the routine is stored in. Whether you use a linker or <code>include</code> statements, this information is lost by the time the code is assembled into an executable form.
 
=={{header|Clojure}}==
 
<syntaxhighlight lang="clojure">
; Use source function for source code.
(source println)
 
; Use meta function for filenames and line numbers (and other metadata)
(meta #'println)</syntaxhighlight>
 
=={{header|Factor}}==
Printing definitions:
<syntaxhighlight lang="factor">USE: see
\ integer see ! class
nl
\ dip see ! word</syntaxhighlight>
{{out}}
<pre>
IN: math
UNION: integer fixnum bignum ;
 
IN: kernel
: dip ( x quot -- x ) swap [ call ] dip ;
</pre>
Obtaining the code that makes up a word as a quotation (an anonymous function/collection that stores code):
<syntaxhighlight lang="factor">USE: accessors
\ partition def>> .</syntaxhighlight>
{{out}}
<pre>
[ over [ 2selector [ each ] 2dip ] dip [ like ] curry bi@ ]
</pre>
Obtaining the vocabulary name a word belongs to:
<syntaxhighlight lang="factor">USE: accessors
\ dip vocabulary>> print</syntaxhighlight>
{{out}}
<pre>
kernel
</pre>
Obtaining file paths for a particular vocabulary:
<syntaxhighlight lang="factor">USE: vocabs.files
"sequences" vocab-files .</syntaxhighlight>
{{out}}
<pre>
{
"resource:core/sequences/sequences.factor"
"resource:core/sequences/sequences-docs.factor"
"resource:core/sequences/sequences-tests.factor"
}
</pre>
Obtaining the path and line number where a word is defined:
<syntaxhighlight lang="factor">"loc" \ dip props>> at</syntaxhighlight>
{{out}}
<pre>
{ "resource:core/kernel/kernel.factor" 111 }
</pre>
 
=={{header|FreeBASIC}}==
Line 10 ⟶ 109:
This is mainly useful for debugging purposes. Here's a simple example :
 
<langsyntaxhighlight lang="freebasic">' FB 1.05.0 Win64 (getsource.bas)
 
Sub Proc()
Line 17 ⟶ 116:
 
Proc()
Sleep</langsyntaxhighlight>
 
{{out}}
<pre>
PROC is defined in c:\FreeBasic\getsource.bas at line 3
</pre>
 
=={{header|Go}}==
It is possible to get the file name/path and line number of a given function in Go as follows.
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"path"
"reflect"
"runtime"
)
 
func someFunc() {
fmt.Println("someFunc called")
}
 
func main() {
pc := reflect.ValueOf(someFunc).Pointer()
f := runtime.FuncForPC(pc)
name := f.Name()
file, line := f.FileLine(pc)
fmt.Println("Name of function :", name)
fmt.Println("Name of file :", path.Base(file))
fmt.Println("Line number :", line)
}</syntaxhighlight>
 
{{out}}
<pre>
Name of function : main.someFunc
Name of file : reflection_get_source.go
Line number : 10
</pre>
 
Line 32 ⟶ 163:
Examples:
 
<langsyntaxhighlight Jlang="j"> mean=:+/ %#
5!:5 <'mean'
+/ % #
Line 44 ⟶ 175:
┌────────────────────────────────────────────┐
│/Applications/j64-804/system/main/stdlib.ijs│
└────────────────────────────────────────────┘</langsyntaxhighlight>
 
We could also provide convenience functions for these mechanisms:
 
<langsyntaxhighlight Jlang="j"> linrep=: 5!:5@<
srcfile=: (4!:4@<) { a:,~ 4!:3 bind ''</langsyntaxhighlight>
 
Example use:
 
<langsyntaxhighlight Jlang="j"> linrep 'names'
list_z_@nl
srcfile 'names'
Line 62 ⟶ 193:
┌┐
││
└┘</langsyntaxhighlight>
 
Note that these mechanisms can be disabled (using [http://www.jsoftware.com/help/dictionary/dx003.htm 3!:6]).
 
=={{header|Java}}==
 
A java exception will contain a list of <code>StackTraceElement</code>'s. Each element is one method call in the call stack. The element contains information on the location of the code. Samples are shown below.
 
Note that the file name is not the absolute path on the file system, but is relative to the java CLASSPATH.
 
<syntaxhighlight lang="java">
 
public class ReflectionGetSource {
 
public static void main(String[] args) {
new ReflectionGetSource().method1();
 
}
public ReflectionGetSource() {}
public void method1() {
method2();
}
public void method2() {
method3();
}
public void method3() {
Throwable t = new Throwable();
for ( StackTraceElement ste : t.getStackTrace() ) {
System.out.printf("File Name = %s%n", ste.getFileName());
System.out.printf("Class Name = %s%n", ste.getClassName());
System.out.printf("Method Name = %s%n", ste.getMethodName());
System.out.printf("Line number = %s%n%n", ste.getLineNumber());
}
}
 
}
</syntaxhighlight>
{{out}}
<pre>
File Name = ReflectionGetSource.java
Class Name = ReflectionGetSource
Method Name = method3
Line number = 20
 
File Name = ReflectionGetSource.java
Class Name = ReflectionGetSource
Method Name = method2
Line number = 16
 
File Name = ReflectionGetSource.java
Class Name = ReflectionGetSource
Method Name = method1
Line number = 12
 
File Name = ReflectionGetSource.java
Class Name = ReflectionGetSource
Method Name = main
Line number = 5
</pre>
 
=={{header|JavaScript}}==
<code>Function.toString()</code> will return the source code for user-defined functions.
 
<langsyntaxhighlight lang="javascript">function foo() {...}
foo.toString();
// "function foo() {...}"
</syntaxhighlight>
</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.
<langsyntaxhighlight lang="javascript">Math.sqrt.toString();
// "function sqrt() { [native code] }"
</syntaxhighlight>
</lang>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
 
<syntaxhighlight lang="julia"># Definition
function foo() end
 
@which foo() # where foo is defined
@less foo() # first file where foo is defined</syntaxhighlight>
 
=={{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.
<syntaxhighlight lang="scala">// Kotlin JS Version 1.2.31
 
fun hello() {
println("Hello")
}
 
fun main(args: Array<String>) {
val code = js("_.hello.toString()")
println(code)
}
</syntaxhighlight>
 
{{out}}
<pre>
function hello() {
println('Hello');
}
</pre>
 
=={{header|Lingo}}==
Line 86 ⟶ 312:
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).
<langsyntaxhighlight lang="lingo">----------------------------------------
-- Returns source code either for a class (parent script) or a class instance (object)
-- @param {script|instance} class
Line 110 ⟶ 336:
end repeat
end repeat
end</langsyntaxhighlight>
Usage:
<langsyntaxhighlight lang="lingo">obj = script("MyClass").new()
put getClassCode(obj)
-- script text is printed...
Line 118 ⟶ 344:
func = #startMovie
put getGlobalFunctionCode(func)
-- script text is printed...</langsyntaxhighlight>
 
=={{header|Perl 6Lua}}==
Introspective capabilities are provided by the debug library..
<syntaxhighlight lang="lua">debug = require("debug")
function foo(bar)
info = debug.getinfo(1)
for k,v in pairs(info) do print(k,v) end
end
foo()</syntaxhighlight>
{{out}}
<pre>linedefined 2
func function: 0000000000d8d670
currentline 3
source @reflection.lua
lastlinedefined 5
short_src reflection.lua
what Lua
namewhat global
nparams 0
isvararg false
name foo
istailcall false
nups 1</pre>
 
=={{header|Nanoquery}}==
Filename of a subroutine:
If a program is run from the command line, the absolute path of the source file will be stored in __file__ as a string.
<lang perl6>say &sum.file;</lang>
<syntaxhighlight lang="nanoquery">import Nanoquery.IO
println new(File, __file__).readAll()</syntaxhighlight>
 
=={{header|Nim}}==
Filename of a method:
<syntaxhighlight lang="nim">import macros, strformat
<lang perl6>say Date.^find_method("day-of-week").file;</lang>
proc f(arg: int): int = arg+1
 
macro getSource(source: static[string]) =
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 <code>gen/moar/m-CORE.setting</code> (rather than a full path) for built-ins.
let module = parseStmt(source)
for node in module.children:
if node.kind == nnkProcDef:
echo(&"source of procedure {node.name} is:\n{toStrLit(node).strVal}")
 
proc g(arg: float): float = arg*arg
 
getSource(staticRead(currentSourcePath()))</syntaxhighlight>
{{out}}
<pre>source of procedure f is:
proc f(arg: int): int =
arg + 1
 
source of procedure g is:
proc g(arg: float): float =
arg * arg
 
</pre>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl"># 20211213 Perl programming solution
 
use strict;
use warnings;
 
use Class::Inspector;
 
print Class::Inspector->resolved_filename( 'IO::Socket::INET' ), "\n";
</syntaxhighlight>
{{out}}
<pre>/home/hkdtam/perl5/perlbrew/perls/perl-5.30.0/lib/5.30.0/x86_64-linux/IO/Socket/INET.pm
</pre>
 
=={{header|Phix}}==
There are at least two separate methods for achieving this.
===From Edita===
When using the Edita editor as shipped with Phix, pressing F1 on a call shows a pop-up with the definition and an option to jump to that file/source.
However that only works for routines, not variables/constants/etc. That (older) method is powered by a background scan which periodically saves the required information in edita.edb - and you can investigate the contents of that via Tools/Database Viewer.
 
Holding down the Ctrl key and hovering the mouse over an identifier changes it to a link; left clicking will jump straight to the definition, and right-clicking will show a pop-up with a basic summary, and an option to jump directly to that file/source.
 
The latter is achieved (see demo\edita\src\eaisense.ew) by invoking "pw.exe -isense file line col partial_key mode main_file" which plants the requested information from a partial compilation into %TMP%\isense.txt (don't worry, it's near-instant) and sends back a message once it is ready.
Edita handles the messy details of all that for you automatically, but of course you are free to copy and modify those techniques however you like.
 
I should warn you that Edita is windows-only, however Edix is well under way and if ever finished will offer the same functionality cross-platform.
 
===Programmatically===
The autoinclude file builtins\pincpathN.e defines the include_paths() builtin, which returns something like:
<pre>
{"C:\\Program Files (x86)\\Phix\\builtins\\",
"C:\\Program Files (x86)\\Phix\\builtins\\VM\\",
"C:\\Program Files (x86)\\Phix\\"}
</pre>
or the directories where your project is located. There is also a matching include_files() function that retrieves a set of {idx,name} where idx are indexes into the result from above, should that be of interest to you. Note that if it is a pre-compiled executable installed on an end users machine, those sources might not be available, but the internal routines still provide the same names since they are generally quite useful for diagnostic purposes.
 
A caught exception (see the documentation for throw) contains the line number, file, and path (with the same caveat as above when installed elsewhere).
 
The file pincpathN.e also shows you how to get your grubby little mitts on the symbol table, and you may also want to look at builtins/VM/prtnidN.e for some ideas on scanning that. Throwing and catching an exception is one way to ensure the symbol table is populated with proper names rather than obscure integer ternary tree indexes. See pglobals.e for detailed notes about the contents of the symbol table. Some caution is advised here; the compiler may plant some otherwise illegal raw values in the symbol table, and play fast and loose with reference counts, etc, and of course messing it up may make life (/subsequent debugging) rather troublesome.
 
Of course the source files are just files that you can read like any other text files, and for all its detail, the symbol table contains very little in the way of context, which may make mapping of non-unique identifiers rather difficult.
 
=={{header|Python}}==
Modules loaded from files have a <code>__file__</code> attribute.
<langsyntaxhighlight lang="python">import os
os.__file__
# "/usr/local/lib/python3.5/os.pyc"
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
{{Works with|rakudo|2016.11}}
 
 
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.
 
<syntaxhighlight lang="raku" line>say &sum.file;
say Date.^find_method("day-of-week").file;</syntaxhighlight>
 
{{out}}
<pre>
SETTING::src/core/Any.pm
SETTING::src/core/Dateish.pm
</pre>
 
=={{header|REXX}}==
This REXX version was modeled after the &nbsp; '''zkl''' &nbsp; example, but in addition, it also displays the source.
<syntaxhighlight 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.*/</syntaxhighlight>
{{out|output|:}}
<pre>
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
</pre>
 
=={{header|Ring}}==
<syntaxhighlight lang="ring">
# Project : Reflection/Get source
 
fp = fopen("C:\Ring\applications\fifteenpuzzle\CalmoSoftFifteenPuzzleGame.ring","r")
r = ""
str = ""
flag = 0
numline = 0
see "give the function: "
give funct
funct = "func " + funct
while isstring(r)
r = fgetc(fp)
if r = char(10)
flag = 1
numline = numline + 1
else
flag = 0
str = str + r
ok
if flag = 1
if left(str,len(funct)) = funct
see '"' + funct + '"' +" is in the line: " + numline + nl
ok
str = ""
ok
end
fclose(fp)
</syntaxhighlight>
Output:
<pre>
give the function: rotateleft
"func rotateleft" is in the line: 328
</pre>
 
=={{header|Ruby}}==
<code>[http://ruby-doc.org/core/Method.html#method-i-source_location Method#source_location]</code> will return the file and line number of a Ruby method. If a method wasn't defined in Ruby, <code>Method#source_location</code> returns nil.
<langsyntaxhighlight lang="ruby">require 'mathn'
Math.method(:sqrt).source_location
# ["/usr/local/lib/ruby2.3/2.3.0/mathn.rb", 119]
Line 145 ⟶ 541:
Class.method(:nesting).source_location
# nil, since Class#nesting is native
</syntaxhighlight>
</lang>
 
=={{header|Smalltalk}}==
You can ask a class for a method:
<syntaxhighlight lang="smalltalk">mthd := someClass compiledMethodAt:#nameOfMethod</syntaxhighlight>
and a method for its source:
<syntaxhighlight lang="smalltalk">mthd source</syntaxhighlight>
 
or better yet, you can ask any active stack frame for its method, source and line number (what is the line number of the "current PC" if you like):
<syntaxhighlight lang="smalltalk">thisContext method source
thisContext lineNumber</syntaxhighlight>
so, a Logger could (actually: does) print a log-message with:
Stderr print: e'{msg} generated in {thisContext sender selector} line: {thisContext sender lineNumber}'.
Stderr print: e'generated by the following source line: {thisContext sender method source asStringCollection at:thisContext sender lineNumber}'.
 
=={{header|Tcl}}==
Tcl's <tt>info</tt> command makes it possible to access the source of nearly anything. This example can show the source code of any proc. The popular <b>tkcon</b> includes a <tt>dump</tt> command which is capable of showing aliases, arrays and more .. and a <tt>edit</tt> command which lets you edit them in an interactive window!
 
<syntaxhighlight 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]</syntaxhighlight>
 
{{out}}
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.
 
<syntaxhighlight 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
}</syntaxhighlight>
 
=={{header|Wren}}==
{{libheader|Wren-pattern}}
Wren doesn't have reflection as such but the command line version (Wren CLI) does have an easy way to obtain a script's own source code which can then be searched for where an object is defined
<syntaxhighlight lang="wren">import "os" for Platform, Process
import "io" for File
import "/.pattern" for Pattern
 
var getSourceLines = Fn.new {
var fileName = Process.allArguments[1]
var text = File.read(fileName)
var sep = Platform.isWindows ? "\r\n" : "\n"
return [fileName, text.split(sep)]
}
 
var res = getSourceLines.call()
var fileName = res[0]
var lines = res[1]
// look for getSourceLines function
var funcName = "getSourceLines"
var p = Pattern.new("+1/s")
var i = 1
var found = 0
for (line in lines) {
var t = p.splitAll(line.trim())
if (t[0] == "var" && t[1] == funcName && t[2] == "=" && t[3] == "Fn.new") {
found = i
break
}
i = i + 1
}
 
System.print("File name : %(fileName)")
System.print("Function name : %(funcName)")
System.print("Line number : %(found > 0 ? found : "Function not found")")</syntaxhighlight>
 
{{out}}
<pre>
File name : Reflection_get_source.wren
Function name : getSourceLines
Line number : 5
</pre>
 
=={{header|zkl}}==
Reads the source file and counts the lines.
<langsyntaxhighlight lang="zkl">src:=File(__FILE__).read();
println("Src file is \"%s\" and has %d lines".fmt(__FILE__,src.len(1)));</langsyntaxhighlight>
{{out}}
<pre>
9,476

edits