Reflection/Get source: Difference between revisions

m
m (→‎{{header|Wren}}: Minor tidy)
 
(9 intermediate revisions by 6 users not shown)
Line 8:
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}}==
 
<langsyntaxhighlight lang="clojure">
; Use source function for source code.
(source println)
 
; Use meta function for filenames and line numbers (and other metadata)
(meta #'println)</langsyntaxhighlight>
 
=={{header|Factor}}==
Printing definitions:
<langsyntaxhighlight lang="factor">USE: see
\ integer see ! class
nl
\ dip see ! word</langsyntaxhighlight>
{{out}}
<pre>
Line 33 ⟶ 72:
</pre>
Obtaining the code that makes up a word as a quotation (an anonymous function/collection that stores code):
<langsyntaxhighlight lang="factor">USE: accessors
\ partition def>> .</langsyntaxhighlight>
{{out}}
<pre>
Line 40 ⟶ 79:
</pre>
Obtaining the vocabulary name a word belongs to:
<langsyntaxhighlight lang="factor">USE: accessors
\ dip vocabulary>> print</langsyntaxhighlight>
{{out}}
<pre>
Line 47 ⟶ 86:
</pre>
Obtaining file paths for a particular vocabulary:
<langsyntaxhighlight lang="factor">USE: vocabs.files
"sequences" vocab-files .</langsyntaxhighlight>
{{out}}
<pre>
Line 58 ⟶ 97:
</pre>
Obtaining the path and line number where a word is defined:
<langsyntaxhighlight lang="factor">"loc" \ dip props>> at</langsyntaxhighlight>
{{out}}
<pre>
Line 70 ⟶ 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 77 ⟶ 116:
 
Proc()
Sleep</langsyntaxhighlight>
 
{{out}}
Line 86 ⟶ 125:
=={{header|Go}}==
It is possible to get the file name/path and line number of a given function in Go as follows.
<langsyntaxhighlight lang="go">package main
 
import (
Line 107 ⟶ 146:
fmt.Println("Name of file :", path.Base(file))
fmt.Println("Line number :", line)
}</langsyntaxhighlight>
 
{{out}}
Line 124 ⟶ 163:
Examples:
 
<langsyntaxhighlight Jlang="j"> mean=:+/ %#
5!:5 <'mean'
+/ % #
Line 136 ⟶ 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 154 ⟶ 193:
┌┐
││
└┘</langsyntaxhighlight>
 
Note that these mechanisms can be disabled (using [http://www.jsoftware.com/help/dictionary/dx003.htm 3!:6]).
Line 164 ⟶ 203:
Note that the file name is not the absolute path on the file system, but is relative to the java CLASSPATH.
 
<syntaxhighlight lang="java">
<lang Java>
 
public class ReflectionGetSource {
Line 194 ⟶ 233:
 
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 221 ⟶ 260:
<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}}
 
<langsyntaxhighlight lang="julia"># Definition
function foo() end
 
@which foo() # where foo is defined
@less foo() # first file where foo is defined</langsyntaxhighlight>
 
=={{header|Kotlin}}==
Line 247 ⟶ 286:
2. In the example below the ''hello'' function will actually be referred to as ''_.hello'' in the generated JavaScript from within the main() function.
<langsyntaxhighlight lang="scala">// Kotlin JS Version 1.2.31
 
fun hello() {
Line 257 ⟶ 296:
println(code)
}
</syntaxhighlight>
</lang>
 
{{out}}
Line 273 ⟶ 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 297 ⟶ 336:
end repeat
end repeat
end</langsyntaxhighlight>
Usage:
<langsyntaxhighlight lang="lingo">obj = script("MyClass").new()
put getClassCode(obj)
-- script text is printed...
Line 305 ⟶ 344:
func = #startMovie
put getGlobalFunctionCode(func)
-- script text is printed...</langsyntaxhighlight>
 
=={{header|Lua}}==
Introspective capabilities are provided by the debug library..
<langsyntaxhighlight 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()</langsyntaxhighlight>
{{out}}
<pre>linedefined 2
Line 332 ⟶ 371:
=={{header|Nanoquery}}==
If a program is run from the command line, the absolute path of the source file will be stored in __file__ as a string.
<langsyntaxhighlight lang="nanoquery">import Nanoquery.IO
println new(File, __file__).readAll()</langsyntaxhighlight>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import macros, strformat
proc f(arg: int): int = arg+1
 
macro getSource(source: static[string]) =
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}}==
Line 365 ⟶ 443:
=={{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}}==
Line 377 ⟶ 455:
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" perl6line>say &sum.file;
say Date.^find_method("day-of-week").file;</langsyntaxhighlight>
 
{{out}}
Line 388 ⟶ 466:
=={{header|REXX}}==
This REXX version was modeled after the &nbsp; '''zkl''' &nbsp; example, but in addition, it also displays the source.
<langsyntaxhighlight lang="rexx">/*REXX program gets the source function (source code) and */
/*───────────────────────── displays the number of lines. */
#=sourceline()
Line 399 ⟶ 477:
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.*/</langsyntaxhighlight>
{{out|output|:}}
<pre>
Line 420 ⟶ 498:
 
=={{header|Ring}}==
<langsyntaxhighlight lang="ring">
# Project : Reflection/Get source
 
Line 448 ⟶ 526:
end
fclose(fp)
</syntaxhighlight>
</lang>
Output:
<pre>
Line 457 ⟶ 535:
=={{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 463 ⟶ 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!
 
<langsyntaxhighlight Tcllang="tcl">proc getproc {name} {
set name [uplevel 1 [list namespace which -command $name]]
set args [info args $name]
Line 482 ⟶ 573:
}
 
puts [getproc getproc]</langsyntaxhighlight>
 
{{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.
 
<langsyntaxhighlight Tcllang="tcl">proc ::getproc name {
set name [uplevel 1 [list namespace which -command $name]]
set args [info args $name]
Line 499 ⟶ 590:
set body [info body $name]
list proc $name $args $body
}</langsyntaxhighlight>
 
=={{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
<langsyntaxhighlight ecmascriptlang="wren">import "os" for Platform, Process
import "io" for File
import "/.pattern" for Pattern
 
var getSourceLines = Fn.new {
Line 534 ⟶ 625:
System.print("File name : %(fileName)")
System.print("Function name : %(funcName)")
System.print("Line number : %(found > 0 ? found : "Function not found")")</langsyntaxhighlight>
 
{{out}}
<pre>
File name : reflection_get_sourceReflection_get_source.wren
Function name : getSourceLines
Line number : 5
Line 545 ⟶ 636:
=={{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