mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-01-28 08:20:27 +08:00
method bind implemented
- MethodBind type added. - Now methods are first class and can be passed around as arguments store as a variable and return it from a function and they're first class callbales. - Can bind instance to a method bind using .bind() method - Class.methods() method added -> return a list of all methods as method binds - Module.globals() method added -> returns a list of all globals of that module. - Var._class -> attribute added which will return the class of the variable - Class.name, MethodBind.name, Closure.name attribute and Modue._name attribute added - Class._docs, Closure._docs, MethodBind._docs attribute added - MethodBind.instance attribute added
This commit is contained in:
parent
8e6f347009
commit
5bc9dcad6b
@ -1,29 +0,0 @@
|
||||
|
||||
# math
|
||||
|
||||
TODO: this page is incomplete.
|
||||
|
||||
#### math.floor
|
||||
```ruby
|
||||
floor(value:num) -> num
|
||||
```
|
||||
|
||||
#### math.ceil
|
||||
```ruby
|
||||
ceil(value:num) -> num
|
||||
```
|
||||
|
||||
#### math.pow
|
||||
```ruby
|
||||
pow(a:num, b:num) -> num
|
||||
```
|
||||
|
||||
#### math.sqrt
|
||||
```ruby
|
||||
sqrt(value:num) -> num
|
||||
```
|
||||
|
||||
#### math.abs
|
||||
```ruby
|
||||
abs(value:num) -> num
|
||||
```
|
@ -1,23 +0,0 @@
|
||||
# path
|
||||
|
||||
TODO: this page is incomplete.
|
||||
|
||||
#### path.getcwd
|
||||
```ruby
|
||||
getcwd() -> str
|
||||
```
|
||||
|
||||
#### path.abspath
|
||||
```ruby
|
||||
abspath(path:str) -> str
|
||||
```
|
||||
|
||||
#### path.relpath
|
||||
```ruby
|
||||
relpath(path:str) -> str
|
||||
```
|
||||
|
||||
#### path.join
|
||||
```ruby
|
||||
join(...path:str) -> str
|
||||
```
|
99
docs/Reference/io.md
Normal file
99
docs/Reference/io.md
Normal file
@ -0,0 +1,99 @@
|
||||
# io
|
||||
|
||||
### write
|
||||
|
||||
```ruby
|
||||
io.write(stream:Var, bytes:String) -> Null
|
||||
```
|
||||
|
||||
Warning: the function is subjected to be changed anytime soon.
|
||||
Write [bytes] string to the stream. stream should be any of io.stdin, io.stdout, io.stderr.
|
||||
|
||||
### flush
|
||||
|
||||
```ruby
|
||||
io.flush() -> Null
|
||||
```
|
||||
|
||||
Warning: the function is subjected to be changed anytime soon.
|
||||
Flush stdout buffer.
|
||||
|
||||
### getc
|
||||
|
||||
```ruby
|
||||
io.getc() -> String
|
||||
```
|
||||
|
||||
Read a single character from stdin and return it.
|
||||
|
||||
## File
|
||||
A simple file type.
|
||||
|
||||
### open
|
||||
|
||||
```ruby
|
||||
io.File.open(path:String, mode:String) -> Null
|
||||
```
|
||||
|
||||
Opens a file at the [path] with the [mode]. Path should be either absolute or relative to the current working directory. and [mode] can be'r', 'w', 'a' in combination with 'b' (binary) and/or '+' (extended).
|
||||
```
|
||||
mode | If already exists | If does not exist |
|
||||
-----+-------------------+-------------------|
|
||||
'r' | read from start | failure to open |
|
||||
'w' | destroy contents | create new |
|
||||
'a' | write to end | create new |
|
||||
'r+' | read from start | error |
|
||||
'w+' | destroy contents | create new |
|
||||
'a+' | write to end | create new |
|
||||
```
|
||||
|
||||
### read
|
||||
|
||||
```ruby
|
||||
io.File.read(count:Number) -> String
|
||||
```
|
||||
|
||||
Reads [count] number of bytes from the file and return it as String.If the count is -1 it'll read till the end of file and return it.
|
||||
|
||||
### write
|
||||
|
||||
```ruby
|
||||
io.File.write(data:String) -> Null
|
||||
```
|
||||
|
||||
Write the [data] to the file. Since pocketlang string support any validbyte value in it's string, binary data can also be written with strings.
|
||||
|
||||
### getline
|
||||
|
||||
```ruby
|
||||
io.File.getline() -> String
|
||||
```
|
||||
|
||||
Reads a line from the file and return it as string. This function can only be used for files that are opened with text mode.
|
||||
|
||||
### close
|
||||
|
||||
```ruby
|
||||
io.File.close()
|
||||
```
|
||||
|
||||
Closes the opend file.
|
||||
|
||||
### seek
|
||||
|
||||
```ruby
|
||||
io.File.seek(offset:Number, whence:Number) -> Null
|
||||
```
|
||||
|
||||
Move the file read/write offset. where [offset] is the offset from [whence] which should be any of the bellow three.
|
||||
0: Begining of the file.
|
||||
1: Current position.
|
||||
2: End of the file.
|
||||
|
||||
### tell
|
||||
|
||||
```ruby
|
||||
io.File.tell() -> Number
|
||||
```
|
||||
|
||||
Returns the read/write position of the file.
|
17
docs/Reference/json.md
Normal file
17
docs/Reference/json.md
Normal file
@ -0,0 +1,17 @@
|
||||
# json
|
||||
|
||||
### parse
|
||||
|
||||
```ruby
|
||||
json.parse(json_str:String) -> Var
|
||||
```
|
||||
|
||||
Parse a json string into pocket lang object.
|
||||
|
||||
### print
|
||||
|
||||
```ruby
|
||||
json.print(value:Var, pretty:Bool=false)
|
||||
```
|
||||
|
||||
Render a pocketlang value into text. Takes an optional argument pretty, if true it'll pretty print the output.
|
42
docs/Reference/lang.md
Normal file
42
docs/Reference/lang.md
Normal file
@ -0,0 +1,42 @@
|
||||
# lang
|
||||
|
||||
### gc
|
||||
|
||||
```ruby
|
||||
lang.gc() -> Number
|
||||
```
|
||||
|
||||
Trigger garbage collection and return the amount of bytes cleaned.
|
||||
|
||||
### disas
|
||||
|
||||
```ruby
|
||||
lang.disas(fn:Closure) -> String
|
||||
```
|
||||
|
||||
Returns the disassembled opcode of the function [fn].
|
||||
|
||||
### backtrace
|
||||
|
||||
```ruby
|
||||
lang.backtrace() -> String
|
||||
```
|
||||
|
||||
Returns the backtrace as a string, each line is formated as '<function>;<file>;<line>
|
||||
'.
|
||||
|
||||
### modules
|
||||
|
||||
```ruby
|
||||
lang.modules() -> List
|
||||
```
|
||||
|
||||
Returns the list of all registered modules.
|
||||
|
||||
### debug_break
|
||||
|
||||
```ruby
|
||||
lang.debug_break() -> Null
|
||||
```
|
||||
|
||||
A debug function for development (will be removed).
|
145
docs/Reference/math.md
Normal file
145
docs/Reference/math.md
Normal file
@ -0,0 +1,145 @@
|
||||
# math
|
||||
|
||||
### floor
|
||||
|
||||
```ruby
|
||||
math.floor(value:Numberber) -> Numberber
|
||||
```
|
||||
|
||||
Return the floor value.
|
||||
|
||||
### ceil
|
||||
|
||||
```ruby
|
||||
math.ceil(value:Number) -> Number
|
||||
```
|
||||
|
||||
Returns the ceiling value.
|
||||
|
||||
### pow
|
||||
|
||||
```ruby
|
||||
math.pow(a:Number, b:Number) -> Number
|
||||
```
|
||||
|
||||
Returns the power 'b' of 'a' similler to a**b.
|
||||
|
||||
### sqrt
|
||||
|
||||
```ruby
|
||||
math.sqrt(value:Number) -> Number
|
||||
```
|
||||
|
||||
Returns the square root of the value
|
||||
|
||||
### abs
|
||||
|
||||
```ruby
|
||||
math.abs(value:Number) -> Number
|
||||
```
|
||||
|
||||
Returns the absolute value.
|
||||
|
||||
### sign
|
||||
|
||||
```ruby
|
||||
math.sign(value:Number) -> Number
|
||||
```
|
||||
|
||||
return the sign of the which is one of (+1, 0, -1).
|
||||
|
||||
### sin
|
||||
|
||||
```ruby
|
||||
math.sin(rad:Number) -> Number
|
||||
```
|
||||
|
||||
Return the sine value of the argument [rad] which is an angle expressed in radians.
|
||||
|
||||
### cos
|
||||
|
||||
```ruby
|
||||
math.cos(rad:Number) -> Number
|
||||
```
|
||||
|
||||
Return the cosine value of the argument [rad] which is an angle expressed in radians.
|
||||
|
||||
### tan
|
||||
|
||||
```ruby
|
||||
math.tan(rad:Number) -> Number
|
||||
```
|
||||
|
||||
Return the tangent value of the argument [rad] which is an angle expressed in radians.
|
||||
|
||||
### sinh
|
||||
|
||||
```ruby
|
||||
math.sinh(val:Number) -> Number
|
||||
```
|
||||
|
||||
Return the hyperbolic sine value of the argument [val].
|
||||
|
||||
### cosh
|
||||
|
||||
```ruby
|
||||
math.cosh(val:Number) -> Number
|
||||
```
|
||||
|
||||
Return the hyperbolic cosine value of the argument [val].
|
||||
|
||||
### tanh
|
||||
|
||||
```ruby
|
||||
math.tanh(val:Number) -> Number
|
||||
```
|
||||
|
||||
Return the hyperbolic tangent value of the argument [val].
|
||||
|
||||
### asin
|
||||
|
||||
```ruby
|
||||
math.asin(num:Number) -> Number
|
||||
```
|
||||
|
||||
Return the arcsine value of the argument [num] which is an angle expressed in radians.
|
||||
|
||||
### acos
|
||||
|
||||
```ruby
|
||||
math.acos(num:Number) -> Number
|
||||
```
|
||||
|
||||
Return the arc cosine value of the argument [num] which is an angle expressed in radians.
|
||||
|
||||
### atan
|
||||
|
||||
```ruby
|
||||
math.atan(num:Number) -> Number
|
||||
```
|
||||
|
||||
Return the arc tangent value of the argument [num] which is an angle expressed in radians.
|
||||
|
||||
### log10
|
||||
|
||||
```ruby
|
||||
math.log10(value:Number) -> Number
|
||||
```
|
||||
|
||||
Return the logarithm to base 10 of argument [value]
|
||||
|
||||
### round
|
||||
|
||||
```ruby
|
||||
math.round(value:Number) -> Number
|
||||
```
|
||||
|
||||
Round to nearest integer, away from zero and return the number.
|
||||
|
||||
### rand
|
||||
|
||||
```ruby
|
||||
math.rand() -> Number
|
||||
```
|
||||
|
||||
Return a random runber in the range of 0..0x7fff.
|
81
docs/Reference/os.md
Normal file
81
docs/Reference/os.md
Normal file
@ -0,0 +1,81 @@
|
||||
# os
|
||||
|
||||
### getcwd
|
||||
|
||||
```ruby
|
||||
os.getcwd() -> String
|
||||
```
|
||||
|
||||
Returns the current working directory
|
||||
|
||||
### chdir
|
||||
|
||||
```ruby
|
||||
os.chdir(path:String)
|
||||
```
|
||||
|
||||
Change the current working directory
|
||||
|
||||
### mkdir
|
||||
|
||||
```ruby
|
||||
os.mkdir(path:String)
|
||||
```
|
||||
|
||||
Creates a directory at the path. The path should be valid.
|
||||
|
||||
### rmdir
|
||||
|
||||
```ruby
|
||||
os.rmdir(path:String)
|
||||
```
|
||||
|
||||
Removes an empty directory at the path.
|
||||
|
||||
### unlink
|
||||
|
||||
```ruby
|
||||
os.rmdir(path:String)
|
||||
```
|
||||
|
||||
Removes a file at the path.
|
||||
|
||||
### moditime
|
||||
|
||||
```ruby
|
||||
os.moditime(path:String) -> Number
|
||||
```
|
||||
|
||||
Returns the modified timestamp of the file.
|
||||
|
||||
### filesize
|
||||
|
||||
```ruby
|
||||
os.filesize(path:String) -> Number
|
||||
```
|
||||
|
||||
Returns the file size in bytes.
|
||||
|
||||
### system
|
||||
|
||||
```ruby
|
||||
os.system(cmd:String) -> Number
|
||||
```
|
||||
|
||||
Execute the command in a subprocess, Returns the exit code of the child process.
|
||||
|
||||
### getenv
|
||||
|
||||
```ruby
|
||||
os.getenv(name:String) -> String
|
||||
```
|
||||
|
||||
Returns the environment variable as String if it exists otherwise it'll return null.
|
||||
|
||||
### exepath
|
||||
|
||||
```ruby
|
||||
os.exepath() -> String
|
||||
```
|
||||
|
||||
Returns the path of the pocket interpreter executable.
|
105
docs/Reference/path.md
Normal file
105
docs/Reference/path.md
Normal file
@ -0,0 +1,105 @@
|
||||
# path
|
||||
|
||||
### getcwd
|
||||
|
||||
```ruby
|
||||
path.getcwd() -> String
|
||||
```
|
||||
|
||||
Returns the current working directory.
|
||||
|
||||
### abspath
|
||||
|
||||
```ruby
|
||||
path.abspath(path:String) -> String
|
||||
```
|
||||
|
||||
Returns the absolute path of the [path].
|
||||
|
||||
### relpath
|
||||
|
||||
```ruby
|
||||
path.relpath(path:String, from:String) -> String
|
||||
```
|
||||
|
||||
Returns the relative path of the [path] argument from the [from] directory.
|
||||
|
||||
### join
|
||||
|
||||
```ruby
|
||||
path.join(...) -> String
|
||||
```
|
||||
|
||||
Joins path with path seperator and return it. The maximum count of paths which can be joined for a call is MAX_JOIN_PATHS.
|
||||
|
||||
### normpath
|
||||
|
||||
```ruby
|
||||
path.normpath(path:String) -> String
|
||||
```
|
||||
|
||||
Returns the normalized path of the [path].
|
||||
|
||||
### basename
|
||||
|
||||
```ruby
|
||||
path.basename(path:String) -> String
|
||||
```
|
||||
|
||||
Returns the final component for the path
|
||||
|
||||
### dirname
|
||||
|
||||
```ruby
|
||||
path.dirname(path:String) -> String
|
||||
```
|
||||
|
||||
Returns the directory of the path.
|
||||
|
||||
### isabspath
|
||||
|
||||
```ruby
|
||||
path.isabspath(path:String) -> Bool
|
||||
```
|
||||
|
||||
Returns true if the path is absolute otherwise false.
|
||||
|
||||
### getext
|
||||
|
||||
```ruby
|
||||
path.getext(path:String) -> String
|
||||
```
|
||||
|
||||
Returns the file extension of the path.
|
||||
|
||||
### exists
|
||||
|
||||
```ruby
|
||||
path.exists(path:String) -> String
|
||||
```
|
||||
|
||||
Returns true if the file exists.
|
||||
|
||||
### isfile
|
||||
|
||||
```ruby
|
||||
path.isfile(path:String) -> Bool
|
||||
```
|
||||
|
||||
Returns true if the path is a file.
|
||||
|
||||
### isdir
|
||||
|
||||
```ruby
|
||||
path.isdir(path:String) -> Bool
|
||||
```
|
||||
|
||||
Returns true if the path is a directory.
|
||||
|
||||
### listdir
|
||||
|
||||
```ruby
|
||||
path.listdir(path:String='.') -> List
|
||||
```
|
||||
|
||||
Returns all the entries in the directory at the [path].
|
76
docs/Reference/term.md
Normal file
76
docs/Reference/term.md
Normal file
@ -0,0 +1,76 @@
|
||||
# term
|
||||
|
||||
### init
|
||||
|
||||
```ruby
|
||||
term.init(capture_events:Bool) -> Null
|
||||
```
|
||||
|
||||
Initialize terminal with raw mode for tui applications, set [capture_events] true to enable event handling.
|
||||
|
||||
### cleanup
|
||||
|
||||
```ruby
|
||||
term.cleanup() -> Null
|
||||
```
|
||||
|
||||
Cleanup and resotre the last terminal state.
|
||||
|
||||
### isatty
|
||||
|
||||
```ruby
|
||||
term.isatty() -> Bool
|
||||
```
|
||||
|
||||
Returns true if both stdin and stdout are tty.
|
||||
|
||||
### new_screen_buffer
|
||||
|
||||
```ruby
|
||||
term.new_screen_buffer() -> Null
|
||||
```
|
||||
|
||||
Switch to an alternative screen buffer.
|
||||
|
||||
### restore_screen_buffer
|
||||
|
||||
```ruby
|
||||
term.restore_screen_buffer() -> Null
|
||||
```
|
||||
|
||||
Restore the alternative buffer which was created with term.new_screen_buffer()
|
||||
|
||||
### getsize
|
||||
|
||||
```ruby
|
||||
term.getsize() -> types.Vector
|
||||
```
|
||||
|
||||
Returns the screen size.
|
||||
|
||||
### getposition
|
||||
|
||||
```ruby
|
||||
term.getposition() -> types.Vector
|
||||
```
|
||||
|
||||
Returns the cursor position in the screen on a zero based coordinate.
|
||||
|
||||
### read_event
|
||||
|
||||
```ruby
|
||||
term.read_event(event:term.Event) -> Bool
|
||||
```
|
||||
|
||||
Read an event and update the argument [event] and return true.If no event was read it'll return false.
|
||||
|
||||
## Event
|
||||
The terminal event type, that'll be used at term.read_event function to fetch events.
|
||||
|
||||
### binary_mode
|
||||
|
||||
```ruby
|
||||
term.binary_mode() -> Null
|
||||
```
|
||||
|
||||
On windows it'll set stdout to binary mode, on other platforms this function won't make make any difference.
|
25
docs/Reference/time.md
Normal file
25
docs/Reference/time.md
Normal file
@ -0,0 +1,25 @@
|
||||
# time
|
||||
|
||||
### epoch
|
||||
|
||||
```ruby
|
||||
time() -> Number
|
||||
```
|
||||
|
||||
Returns the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
|
||||
|
||||
### sleep
|
||||
|
||||
```ruby
|
||||
sleep(t:num) -> Number
|
||||
```
|
||||
|
||||
Sleep for [t] milliseconds.
|
||||
|
||||
### clock
|
||||
|
||||
```ruby
|
||||
clock() -> Number
|
||||
```
|
||||
|
||||
Returns the number of clocks passed divied by CLOCKS_PER_SEC.
|
95
docs/Reference/types.md
Normal file
95
docs/Reference/types.md
Normal file
@ -0,0 +1,95 @@
|
||||
# types
|
||||
|
||||
### hashable
|
||||
|
||||
```ruby
|
||||
types.hashable(value:Var) -> Bool
|
||||
```
|
||||
|
||||
Returns true if the [value] is hashable.
|
||||
|
||||
### hash
|
||||
|
||||
```ruby
|
||||
types.hash(value:Var) -> Number
|
||||
```
|
||||
|
||||
Returns the hash of the [value]
|
||||
|
||||
## ByteBuffer
|
||||
A simple dynamically allocated byte buffer type. This can be used for constructing larger strings without allocating and adding smaller intermeidate strings.
|
||||
|
||||
### []
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.[](index:Number)
|
||||
```
|
||||
|
||||
|
||||
|
||||
### []=
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.[]=(index:Number, value:Number)
|
||||
```
|
||||
|
||||
|
||||
|
||||
### reserve
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.reserve(count:Number) -> Null
|
||||
```
|
||||
|
||||
Reserve [count] number of bytes internally. This is use full if the final size of the buffer is known beforehand to avoid reduce the number of re-allocations.
|
||||
|
||||
### fill
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.fill(value:Number) -> Null
|
||||
```
|
||||
|
||||
Fill the buffer with the given byte value. Note that the value must be in between 0 and 0xff inclusive.
|
||||
|
||||
### clear
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.clear() -> Null
|
||||
```
|
||||
|
||||
Clear the buffer values.
|
||||
|
||||
### write
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.write(data:Number|String) -> Null
|
||||
```
|
||||
|
||||
Writes the data to the buffer. If the [data] is a number that should be in between 0 and 0xff inclusively. If the [data] is a string all the bytes of the string will be written to the buffer.
|
||||
|
||||
### string
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.string() -> String
|
||||
```
|
||||
|
||||
Returns the buffered values as String.
|
||||
|
||||
### count
|
||||
|
||||
```ruby
|
||||
types.ByteBuffer.count() -> Number
|
||||
```
|
||||
|
||||
Returns the number of bytes that have written to the buffer.
|
||||
|
||||
## Vector
|
||||
A simple vector type contains x, y, and z components.
|
||||
|
||||
### _repr
|
||||
|
||||
```ruby
|
||||
types.Vector._repr()
|
||||
```
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
|
||||
* Getting Started
|
||||
* [Home](/)
|
||||
* [Language Manual](/GettingStarted/LanguageManual.md)
|
||||
|
||||
* Library Reference
|
||||
* [math](/Reference/Math.md)
|
||||
* [path](/Reference/Path.md)
|
||||
* [io](/Reference/io.md)
|
||||
* [json](/Reference/json.md)
|
||||
* [time](/Reference/time.md)
|
||||
* [lang](/Reference/lang.md)
|
||||
* [path](/Reference/path.md)
|
||||
* [os](/Reference/os.md)
|
||||
* [term](/Reference/term.md)
|
||||
* [types](/Reference/types.md)
|
||||
* [math](/Reference/math.md)
|
||||
|
93
scripts/docs_gen.pk
Normal file
93
scripts/docs_gen.pk
Normal file
@ -0,0 +1,93 @@
|
||||
#!pocket
|
||||
## Copyright (c) 2020-2021 Thakee Nathees
|
||||
## Copyright (c) 2021-2022 Pocketlang Contributors
|
||||
## Distributed Under The MIT License
|
||||
|
||||
import lang
|
||||
from path import dirname, join, normpath
|
||||
|
||||
ROOT_PATH = normpath(join(dirname(__file__), '..'))
|
||||
|
||||
REFERENCE_DIR = join(ROOT_PATH, 'docs/Reference/')
|
||||
SIDEBAR_FILE = join(ROOT_PATH, 'docs/_sidebar.md')
|
||||
|
||||
sidebar = "\
|
||||
* Getting Started
|
||||
* [Home](/)
|
||||
* [Language Manual](/GettingStarted/LanguageManual.md)
|
||||
|
||||
* Library Reference
|
||||
"
|
||||
|
||||
def main()
|
||||
for module in lang.modules()
|
||||
## Dummy module is for testing internals and will be
|
||||
##removed soon so skip it.
|
||||
if module._name == 'dummy'
|
||||
continue
|
||||
end
|
||||
f = open(join(REFERENCE_DIR, module._name + '.md'), 'w')
|
||||
gen_module_docs(f, module)
|
||||
f.close()
|
||||
end
|
||||
|
||||
f = open(SIDEBAR_FILE, 'w')
|
||||
f.write(sidebar)
|
||||
f.close()
|
||||
|
||||
end
|
||||
|
||||
## Write the [module]'s documentation content to the file [f].
|
||||
def gen_module_docs(f, module)
|
||||
name = module._name
|
||||
sidebar += ' * [$name](/Reference/$name.md)\n'
|
||||
f.write('# $name\n')
|
||||
for global in module.globals()
|
||||
|
||||
{ ## Map as switch statement alternative.
|
||||
Null: fn end,
|
||||
Number: fn end,
|
||||
String: fn end,
|
||||
|
||||
Closure : fn
|
||||
write_fn_doc(f, global)
|
||||
end,
|
||||
|
||||
Class: fn
|
||||
write_cls_doc(f, global)
|
||||
end,
|
||||
|
||||
} [global._class]()
|
||||
end
|
||||
end
|
||||
|
||||
## Write the function's documentation to the file [f].
|
||||
def write_fn_doc(f, func)
|
||||
f.write('\n')
|
||||
f.write('### ${func.name}\n')
|
||||
f.write('\n')
|
||||
i = func._docs.find('\n\n')
|
||||
symbol = func._docs[0..i-1]
|
||||
desc = func._docs[i+1..-1]
|
||||
f.write("```ruby\n$symbol\n```\n")
|
||||
f.write(desc)
|
||||
f.write('\n')
|
||||
end
|
||||
|
||||
## Write the class's documentation to the file [f].
|
||||
def write_cls_doc(f, cls)
|
||||
f.write('\n')
|
||||
f.write('## ${cls.name}\n')
|
||||
f.write('${cls._docs}\n')
|
||||
for method in cls.methods()
|
||||
if method.name == '_init'
|
||||
continue ## Constructor.
|
||||
end
|
||||
write_fn_doc(f, method)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if _name == "@main"
|
||||
main()
|
||||
end
|
182
src/core/core.c
182
src/core/core.c
@ -145,9 +145,11 @@ void initializeModule(PKVM* vm, Module* module, bool is_main) {
|
||||
String *path = module->path, *name = NULL;
|
||||
|
||||
if (is_main) {
|
||||
// TODO: consider static string "__main__" stored in PKVM. to reduce
|
||||
// TODO: consider static string "@main" stored in PKVM. to reduce
|
||||
// allocations everytime here.
|
||||
name = newString(vm, "__main__");
|
||||
ASSERT(module->name == NULL, OOPS);
|
||||
name = newString(vm, "@main");
|
||||
module->name = name;
|
||||
vmPushTempRef(vm, &name->_super); // _main.
|
||||
} else {
|
||||
ASSERT(module->name != NULL, OOPS);
|
||||
@ -163,7 +165,7 @@ void initializeModule(PKVM* vm, Module* module, bool is_main) {
|
||||
moduleSetGlobal(vm, module, "__file__", 8, VAR_OBJ(path));
|
||||
}
|
||||
|
||||
moduleSetGlobal(vm, module, "__name__", 8, VAR_OBJ(name));
|
||||
moduleSetGlobal(vm, module, "_name", 5, VAR_OBJ(name));
|
||||
|
||||
if (is_main) vmPopTempRef(vm); // _main.
|
||||
}
|
||||
@ -272,7 +274,7 @@ static void _collectMethods(PKVM* vm, List* list, Class* cls) {
|
||||
/*****************************************************************************/
|
||||
|
||||
DEF(coreHelp,
|
||||
"help([value:Closure|Class]) -> Null",
|
||||
"help([value:Closure|MethodBind|Class]) -> Null",
|
||||
"It'll print the docstring the object and return.") {
|
||||
|
||||
int argc = ARGC;
|
||||
@ -305,6 +307,18 @@ DEF(coreHelp,
|
||||
vm->config.stdout_write(vm, closure->fn->name);
|
||||
vm->config.stdout_write(vm, "()' doesn't have a docstring.\n");
|
||||
}
|
||||
} else if (IS_OBJ_TYPE(value, OBJ_METHOD_BIND)) {
|
||||
MethodBind* mb = (MethodBind*) AS_OBJ(value);
|
||||
// If there ins't an io function callback, we're done.
|
||||
|
||||
if (mb->method->fn->docstring != NULL) {
|
||||
vm->config.stdout_write(vm, mb->method->fn->docstring);
|
||||
vm->config.stdout_write(vm, "\n\n");
|
||||
} else {
|
||||
vm->config.stdout_write(vm, "method '");
|
||||
vm->config.stdout_write(vm, mb->method->fn->name);
|
||||
vm->config.stdout_write(vm, "()' doesn't have a docstring.\n");
|
||||
}
|
||||
} else if (IS_OBJ_TYPE(value, OBJ_CLASS)) {
|
||||
Class* cls = (Class*) AS_OBJ(value);
|
||||
if (cls->docstring != NULL) {
|
||||
@ -316,7 +330,8 @@ DEF(coreHelp,
|
||||
vm->config.stdout_write(vm, "' doesn't have a docstring.\n");
|
||||
}
|
||||
} else {
|
||||
RET_ERR(newString(vm, "Expected a closure or class to get help."));
|
||||
RET_ERR(newString(vm, "Expected a Closure, MethodBind or "
|
||||
"Class to get help."));
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,7 +420,7 @@ DEF(coreAssert,
|
||||
String* msg = NULL;
|
||||
|
||||
if (argc == 2) {
|
||||
if (AS_OBJ(ARG(2))->type != OBJ_STRING) {
|
||||
if (!IS_OBJ_TYPE(ARG(2), OBJ_STRING)) {
|
||||
msg = varToString(vm, ARG(2), false);
|
||||
if (msg == NULL) return; //< Error at _to_string override.
|
||||
|
||||
@ -828,7 +843,14 @@ DEF(stdLangModules,
|
||||
vmPushTempRef(vm, &list->_super); // list.
|
||||
for (uint32_t i = 0; i < vm->modules->capacity; i++) {
|
||||
if (!IS_UNDEF(vm->modules->entries[i].key)) {
|
||||
listAppend(vm, list, vm->modules->entries[i].value);
|
||||
Var entry = vm->modules->entries[i].value;
|
||||
ASSERT(IS_OBJ_TYPE(entry, OBJ_MODULE), OOPS);
|
||||
Module* module = (Module*) AS_OBJ(entry);
|
||||
ASSERT(module->name != NULL, OOPS);
|
||||
if (module->name->data[0] == SPECIAL_NAME_CHAR) {
|
||||
continue;
|
||||
}
|
||||
listAppend(vm, list, entry);
|
||||
}
|
||||
}
|
||||
vmPopTempRef(vm); // list.
|
||||
@ -1268,6 +1290,78 @@ DEF(_mapPop,
|
||||
RET(value);
|
||||
}
|
||||
|
||||
DEF(_methodBindBind,
|
||||
"MethodBind.bind(instance:Var) -> MethodBind",
|
||||
"Bind the method to the instance and the method bind will be returned. The "
|
||||
"method should be a valid method of the instance. ie. the instance's "
|
||||
"interitance tree should contain the method.") {
|
||||
|
||||
MethodBind* self = (MethodBind*) AS_OBJ(SELF);
|
||||
|
||||
// We can only bind the method if the instance has that method.
|
||||
String* method_name = newString(vm, self->method->fn->name);
|
||||
vmPushTempRef(vm, &method_name->_super); // method_name.
|
||||
|
||||
Var instance = ARG(1);
|
||||
|
||||
Closure* method;
|
||||
if (!hasMethod(vm, instance, method_name, &method)
|
||||
|| method != self->method) {
|
||||
VM_SET_ERROR(vm, newString(vm, "Cannot bind method, instance and method "
|
||||
"types miss-match."));
|
||||
return;
|
||||
}
|
||||
|
||||
self->instance = instance;
|
||||
vmPopTempRef(vm); // method_name.
|
||||
|
||||
RET(SELF);
|
||||
}
|
||||
|
||||
DEF(_classMethods,
|
||||
"Class.methods() -> List",
|
||||
"Returns a list of unbound MethodBind of the class.") {
|
||||
|
||||
Class* self = (Class*) AS_OBJ(SELF);
|
||||
|
||||
List* list = newList(vm, self->methods.count);
|
||||
vmPushTempRef(vm, &list->_super); // list.
|
||||
for (int i = 0; i < (int) self->methods.count; i++) {
|
||||
Closure* method = self->methods.data[i];
|
||||
ASSERT(method->fn->name, OOPS);
|
||||
if (method->fn->name[0] == SPECIAL_NAME_CHAR) continue;
|
||||
MethodBind* mb = newMethodBind(vm, method);
|
||||
vmPushTempRef(vm, &mb->_super); // mb.
|
||||
listAppend(vm, list, VAR_OBJ(mb));
|
||||
vmPopTempRef(vm); // mb.
|
||||
}
|
||||
vmPopTempRef(vm); // list.
|
||||
|
||||
RET(VAR_OBJ(list));
|
||||
|
||||
}
|
||||
|
||||
DEF(_moduleGlobals,
|
||||
"Module.globals() -> List",
|
||||
"Returns a list of all the globals in the module. Since classes and "
|
||||
"functinos are also globals to a module it'll contain them too.") {
|
||||
|
||||
Module* self = (Module*) AS_OBJ(SELF);
|
||||
|
||||
List* list = newList(vm, self->globals.count);
|
||||
vmPushTempRef(vm, &list->_super); // list.
|
||||
for (int i = 0; i < (int) self->globals.count; i++) {
|
||||
if (moduleGetStringAt(self,
|
||||
self->global_names.data[i])->data[0] == SPECIAL_NAME_CHAR) {
|
||||
continue;
|
||||
}
|
||||
listAppend(vm, list, self->globals.data[i]);
|
||||
}
|
||||
vmPopTempRef(vm); // list.
|
||||
|
||||
RET(VAR_OBJ(list));
|
||||
}
|
||||
|
||||
DEF(_fiberRun,
|
||||
"Fiber.run(...) -> Var",
|
||||
"Runs the fiber's function with the provided arguments and returns it's "
|
||||
@ -1383,6 +1477,12 @@ static void initializePrimitiveClasses(PKVM* vm) {
|
||||
ADD_METHOD(PK_MAP, "has", _mapHas, 1);
|
||||
ADD_METHOD(PK_MAP, "pop", _mapPop, 1);
|
||||
|
||||
ADD_METHOD(PK_METHOD_BIND, "bind", _methodBindBind, 1);
|
||||
|
||||
ADD_METHOD(PK_CLASS, "methods", _classMethods, 0);
|
||||
|
||||
ADD_METHOD(PK_MODULE, "globals", _moduleGlobals, 0);
|
||||
|
||||
ADD_METHOD(PK_FIBER, "run", _fiberRun, -1);
|
||||
ADD_METHOD(PK_FIBER, "resume", _fiberResume, -1);
|
||||
|
||||
@ -1867,6 +1967,10 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
VM_SET_ERROR(vm, stringFormat(vm, "'$' object has no attribute named '$'.", \
|
||||
varTypeName(on), attrib->data))
|
||||
|
||||
if (attrib->hash == CHECK_HASH("_class", 0xa2d93eae)) {
|
||||
return VAR_OBJ(getClass(vm, on));
|
||||
}
|
||||
|
||||
if (!IS_OBJ(on)) {
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
@ -1933,6 +2037,9 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
Closure* closure = (Closure*)obj;
|
||||
switch (attrib->hash) {
|
||||
|
||||
case CHECK_HASH("name", 0x8d39bde6):
|
||||
return VAR_OBJ(newString(vm, closure->fn->name));
|
||||
|
||||
case CHECK_HASH("_docs", 0x8fb536a9):
|
||||
if (closure->fn->docstring) {
|
||||
return VAR_OBJ(newString(vm, closure->fn->docstring));
|
||||
@ -1943,11 +2050,30 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
case CHECK_HASH("arity", 0x3e96bd7a):
|
||||
return VAR_NUM((double)(closure->fn->arity));
|
||||
|
||||
case CHECK_HASH("name", 0x8d39bde6):
|
||||
return VAR_OBJ(newString(vm, closure->fn->name));
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_METHOD_BIND: {
|
||||
MethodBind* mb = (MethodBind*) obj;
|
||||
|
||||
switch (attrib->hash) {
|
||||
case CHECK_HASH("_docs", 0x8fb536a9):
|
||||
if (mb->method->fn->docstring) {
|
||||
return VAR_OBJ(newString(vm, mb->method->fn->docstring));
|
||||
} else {
|
||||
return VAR_OBJ(newString(vm, ""));
|
||||
}
|
||||
|
||||
case CHECK_HASH("name", 0x8d39bde6):
|
||||
return VAR_OBJ(newString(vm, mb->method->fn->name));
|
||||
|
||||
case CHECK_HASH("instance", 0xb86d992):
|
||||
if (IS_UNDEF(mb->instance)) return VAR_NULL;
|
||||
return mb->instance;
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case OBJ_UPVALUE:
|
||||
UNREACHABLE(); // Upvalues aren't first class objects.
|
||||
break;
|
||||
@ -1966,11 +2092,32 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
|
||||
case OBJ_CLASS: {
|
||||
Class* cls = (Class*) obj;
|
||||
if (attrib->hash == CHECK_HASH("_docs", 0x8fb536a9)) {
|
||||
if (cls->docstring) {
|
||||
return VAR_OBJ(newString(vm, cls->docstring));
|
||||
} else {
|
||||
return VAR_OBJ(newString(vm, ""));
|
||||
|
||||
switch (attrib->hash) {
|
||||
case CHECK_HASH("_docs", 0x8fb536a9):
|
||||
if (cls->docstring) {
|
||||
return VAR_OBJ(newString(vm, cls->docstring));
|
||||
} else {
|
||||
return VAR_OBJ(newString(vm, ""));
|
||||
}
|
||||
|
||||
case CHECK_HASH("name", 0x8d39bde6):
|
||||
return VAR_OBJ(newString(vm, cls->name->data));
|
||||
|
||||
case CHECK_HASH("parent", 0xeacdfcfd):
|
||||
if (cls->super_class != NULL) {
|
||||
return VAR_OBJ(cls->super_class);
|
||||
} else {
|
||||
return VAR_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)cls->methods.count; i++) {
|
||||
Closure* method_ = cls->methods.data[i];
|
||||
ASSERT(method_->fn->is_method, OOPS);
|
||||
const char* method_name = method_->fn->name;
|
||||
if (IS_CSTR_EQ(attrib, method_name, strlen(method_name))) {
|
||||
return VAR_OBJ(newMethodBind(vm, method_));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1999,6 +2146,13 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
value = mapGet(inst->attribs, VAR_OBJ(attrib));
|
||||
if (!IS_UNDEF(value)) return value;
|
||||
|
||||
Closure* method;
|
||||
if (hasMethod(vm, on, attrib, &method)) {
|
||||
MethodBind* mb = newMethodBind(vm, method);
|
||||
mb->instance = on;
|
||||
return VAR_OBJ(mb);
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@ -189,6 +189,15 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
|
||||
|
||||
} break;
|
||||
|
||||
case OBJ_METHOD_BIND:
|
||||
{
|
||||
MethodBind* mb = (MethodBind*) obj;
|
||||
markObject(vm, &mb->method->_super);
|
||||
markValue(vm, mb->instance);
|
||||
|
||||
vm->bytes_allocated += sizeof(MethodBind);
|
||||
} break;
|
||||
|
||||
case OBJ_UPVALUE:
|
||||
{
|
||||
Upvalue* upvalue = (Upvalue*)obj;
|
||||
@ -409,6 +418,16 @@ Closure* newClosure(PKVM* vm, Function* fn) {
|
||||
return closure;
|
||||
}
|
||||
|
||||
MethodBind* newMethodBind(PKVM* vm, Closure* method) {
|
||||
MethodBind* mb = ALLOCATE(vm, MethodBind);
|
||||
varInitObject(&mb->_super, vm, OBJ_METHOD_BIND);
|
||||
|
||||
mb->method = method;
|
||||
mb->instance = VAR_UNDEFINED;
|
||||
|
||||
return mb;
|
||||
}
|
||||
|
||||
Upvalue* newUpvalue(PKVM* vm, Var* value) {
|
||||
Upvalue* upvalue = ALLOCATE(vm, Upvalue);
|
||||
varInitObject(&upvalue->_super, vm, OBJ_UPVALUE);
|
||||
@ -920,6 +939,10 @@ static uint32_t _hashObject(Object* obj) {
|
||||
return utilHashNumber(range->from) ^ utilHashNumber(range->to);
|
||||
}
|
||||
|
||||
case OBJ_CLASS: {
|
||||
return utilHashBits( (int64_t) obj);
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
@ -1168,6 +1191,11 @@ void freeObject(PKVM* vm, Object* self) {
|
||||
return;
|
||||
}
|
||||
|
||||
case OBJ_METHOD_BIND: {
|
||||
DEALLOCATE(vm, self, MethodBind);
|
||||
return;
|
||||
}
|
||||
|
||||
case OBJ_UPVALUE: {
|
||||
DEALLOCATE(vm, self, Upvalue);
|
||||
return;
|
||||
@ -1309,6 +1337,7 @@ PkVarType getObjPkVarType(ObjectType type) {
|
||||
case OBJ_MODULE: return PK_MODULE;
|
||||
case OBJ_FUNC: UNREACHABLE();
|
||||
case OBJ_CLOSURE: return PK_CLOSURE;
|
||||
case OBJ_METHOD_BIND: return PK_METHOD_BIND;
|
||||
case OBJ_UPVALUE: UNREACHABLE();
|
||||
case OBJ_FIBER: return PK_FIBER;
|
||||
case OBJ_CLASS: return PK_CLASS;
|
||||
@ -1327,15 +1356,16 @@ ObjectType getPkVarObjType(PkVarType type) {
|
||||
case PK_NUMBER:
|
||||
UNREACHABLE();
|
||||
|
||||
case PK_STRING: return OBJ_STRING;
|
||||
case PK_LIST: return OBJ_LIST;
|
||||
case PK_MAP: return OBJ_MAP;
|
||||
case PK_RANGE: return OBJ_RANGE;
|
||||
case PK_MODULE: return OBJ_MODULE;
|
||||
case PK_CLOSURE: return OBJ_CLOSURE;
|
||||
case PK_FIBER: return OBJ_FIBER;
|
||||
case PK_CLASS: return OBJ_CLASS;
|
||||
case PK_INSTANCE: return OBJ_INST;
|
||||
case PK_STRING: return OBJ_STRING;
|
||||
case PK_LIST: return OBJ_LIST;
|
||||
case PK_MAP: return OBJ_MAP;
|
||||
case PK_RANGE: return OBJ_RANGE;
|
||||
case PK_MODULE: return OBJ_MODULE;
|
||||
case PK_CLOSURE: return OBJ_CLOSURE;
|
||||
case PK_METHOD_BIND: return OBJ_METHOD_BIND;
|
||||
case PK_FIBER: return OBJ_FIBER;
|
||||
case PK_CLASS: return OBJ_CLASS;
|
||||
case PK_INSTANCE: return OBJ_INST;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
@ -1365,6 +1395,7 @@ const char* getObjectTypeName(ObjectType type) {
|
||||
case OBJ_MODULE: return "Module";
|
||||
case OBJ_FUNC: return "Func";
|
||||
case OBJ_CLOSURE: return "Closure";
|
||||
case OBJ_METHOD_BIND: return "MethodBind";
|
||||
case OBJ_UPVALUE: return "Upvalue";
|
||||
case OBJ_FIBER: return "Fiber";
|
||||
case OBJ_CLASS: return "Class";
|
||||
@ -1472,7 +1503,7 @@ bool isValuesEqual(Var v1, Var v2) {
|
||||
|
||||
bool isObjectHashable(ObjectType type) {
|
||||
// Only String and Range are hashable (since they're immutable).
|
||||
return type == OBJ_STRING || type == OBJ_RANGE;
|
||||
return type == OBJ_STRING || type == OBJ_RANGE || type == OBJ_CLASS;
|
||||
}
|
||||
|
||||
// This will prevent recursive list/map from crash when calling to_string, by
|
||||
@ -1681,7 +1712,7 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
||||
}
|
||||
|
||||
case OBJ_FUNC: {
|
||||
const Function* fn = (const Function*)obj;
|
||||
const Function* fn = (const Function*) obj;
|
||||
pkByteBufferAddString(buff, vm, "[Func:", 6);
|
||||
pkByteBufferAddString(buff, vm, fn->name, (uint32_t)strlen(fn->name));
|
||||
pkByteBufferWrite(buff, vm, ']');
|
||||
@ -1689,16 +1720,24 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
||||
}
|
||||
|
||||
case OBJ_CLOSURE: {
|
||||
const Closure* closure = (const Closure*)obj;
|
||||
const Closure* closure = (const Closure*) obj;
|
||||
pkByteBufferAddString(buff, vm, "[Closure:", 9);
|
||||
pkByteBufferAddString(buff, vm, closure->fn->name,
|
||||
(uint32_t)strlen(closure->fn->name));
|
||||
pkByteBufferWrite(buff, vm, ']');
|
||||
return;
|
||||
}
|
||||
case OBJ_METHOD_BIND: {
|
||||
const MethodBind* mb = (const MethodBind*) obj;
|
||||
pkByteBufferAddString(buff, vm, "[MethodBind:", 12);
|
||||
pkByteBufferAddString(buff, vm, mb->method->fn->name,
|
||||
(uint32_t)strlen(mb->method->fn->name));
|
||||
pkByteBufferWrite(buff, vm, ']');
|
||||
return;
|
||||
}
|
||||
|
||||
case OBJ_FIBER: {
|
||||
const Fiber* fb = (const Fiber*)obj;
|
||||
const Fiber* fb = (const Fiber*) obj;
|
||||
pkByteBufferAddString(buff, vm, "[Fiber:", 7);
|
||||
pkByteBufferAddString(buff, vm, fb->closure->fn->name,
|
||||
(uint32_t)strlen(fb->closure->fn->name));
|
||||
@ -1784,6 +1823,7 @@ bool toBool(Var v) {
|
||||
case OBJ_MODULE:
|
||||
case OBJ_FUNC:
|
||||
case OBJ_CLOSURE:
|
||||
case OBJ_METHOD_BIND:
|
||||
case OBJ_UPVALUE:
|
||||
case OBJ_FIBER:
|
||||
case OBJ_CLASS:
|
||||
|
@ -192,6 +192,7 @@ typedef struct Range Range;
|
||||
typedef struct Module Module;
|
||||
typedef struct Function Function;
|
||||
typedef struct Closure Closure;
|
||||
typedef struct MethodBind MethodBind;
|
||||
typedef struct Upvalue Upvalue;
|
||||
typedef struct Fiber Fiber;
|
||||
typedef struct Class Class;
|
||||
@ -223,6 +224,7 @@ typedef enum {
|
||||
OBJ_MODULE,
|
||||
OBJ_FUNC,
|
||||
OBJ_CLOSURE,
|
||||
OBJ_METHOD_BIND,
|
||||
OBJ_UPVALUE,
|
||||
OBJ_FIBER,
|
||||
OBJ_CLASS,
|
||||
@ -402,7 +404,17 @@ struct Closure {
|
||||
|
||||
Function* fn;
|
||||
Upvalue* upvalues[DYNAMIC_TAIL_ARRAY];
|
||||
};
|
||||
|
||||
// Method bounds are first class callable of methods. That are bound to an
|
||||
// instace which will be used as the self when the underlying method invoked.
|
||||
// If the vallue [instance] is VAR_UNDEFINED it's unbound and cannot be
|
||||
// called.
|
||||
struct MethodBind {
|
||||
Object _super;
|
||||
|
||||
Closure* method;
|
||||
Var instance;
|
||||
};
|
||||
|
||||
// In addition to locals (which lives on the stack), a closure has upvalues.
|
||||
@ -594,6 +606,8 @@ Module* newModule(PKVM* vm);
|
||||
|
||||
Closure* newClosure(PKVM* vm, Function* fn);
|
||||
|
||||
MethodBind* newMethodBind(PKVM* vm, Closure* method);
|
||||
|
||||
Upvalue* newUpvalue(PKVM* vm, Var* value);
|
||||
|
||||
Fiber* newFiber(PKVM* vm, Closure* closure);
|
||||
|
@ -1223,6 +1223,15 @@ L_do_call:
|
||||
if (IS_OBJ_TYPE(callable, OBJ_CLOSURE)) {
|
||||
closure = (const Closure*)AS_OBJ(callable);
|
||||
|
||||
} else if (IS_OBJ_TYPE(callable, OBJ_METHOD_BIND)) {
|
||||
const MethodBind* mb = (const MethodBind*) AS_OBJ(callable);
|
||||
if (IS_UNDEF(mb->instance)) {
|
||||
RUNTIME_ERROR(newString(vm, "Cannot call an unbound method."));
|
||||
CHECK_ERROR();
|
||||
}
|
||||
fiber->self = mb->instance;
|
||||
closure = mb->method;
|
||||
|
||||
} else if (IS_OBJ_TYPE(callable, OBJ_CLASS)) {
|
||||
Class* cls = (Class*)AS_OBJ(callable);
|
||||
|
||||
@ -1422,6 +1431,7 @@ L_do_call:
|
||||
case OBJ_MODULE:
|
||||
case OBJ_FUNC:
|
||||
case OBJ_CLOSURE:
|
||||
case OBJ_METHOD_BIND:
|
||||
case OBJ_UPVALUE:
|
||||
case OBJ_FIBER:
|
||||
case OBJ_CLASS:
|
||||
|
@ -180,6 +180,7 @@ enum PkVarType {
|
||||
PK_RANGE,
|
||||
PK_MODULE,
|
||||
PK_CLOSURE,
|
||||
PK_METHOD_BIND,
|
||||
PK_FIBER,
|
||||
PK_CLASS,
|
||||
PK_INSTANCE,
|
||||
|
@ -134,7 +134,7 @@ DEF(_fileOpen,
|
||||
"Opens a file at the [path] with the [mode]. Path should be either "
|
||||
"absolute or relative to the current working directory. and [mode] can be"
|
||||
"'r', 'w', 'a' in combination with 'b' (binary) and/or '+' (extended).\n"
|
||||
"\n"
|
||||
"```\n"
|
||||
" mode | If already exists | If does not exist |\n"
|
||||
" -----+-------------------+-------------------|\n"
|
||||
" 'r' | read from start | failure to open |\n"
|
||||
@ -143,7 +143,7 @@ DEF(_fileOpen,
|
||||
" 'r+' | read from start | error |\n"
|
||||
" 'w+' | destroy contents | create new |\n"
|
||||
" 'a+' | write to end | create new |\n"
|
||||
"") {
|
||||
"```") {
|
||||
|
||||
int argc = pkGetArgc(vm);
|
||||
if (!pkCheckArgcRange(vm, argc, 1, 2)) return;
|
||||
@ -441,7 +441,7 @@ DEF(_open,
|
||||
"Opens a file at the [path] with the [mode]. Path should be either "
|
||||
"absolute or relative to the current working directory. and [mode] can be"
|
||||
"'r', 'w', 'a' in combination with 'b' (binary) and/or '+' (extended).\n"
|
||||
"\n"
|
||||
"```\n"
|
||||
" mode | If already exists | If does not exist |\n"
|
||||
" -----+-------------------+-------------------|\n"
|
||||
" 'r' | read from start | failure to open |\n"
|
||||
@ -450,7 +450,7 @@ DEF(_open,
|
||||
" 'r+' | read from start | error |\n"
|
||||
" 'w+' | destroy contents | create new |\n"
|
||||
" 'a+' | write to end | create new |\n"
|
||||
"") {
|
||||
"```") {
|
||||
pkReserveSlots(vm, 3);
|
||||
|
||||
// slots[1] = path
|
||||
|
@ -182,5 +182,31 @@ def foo(p1, p2, p3) end
|
||||
assert(foo.name == "foo")
|
||||
assert(foo.arity == 3)
|
||||
|
||||
###############################################################################
|
||||
## METHOD BIND
|
||||
###############################################################################
|
||||
|
||||
class Foo
|
||||
def bar()
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
foo = Foo()
|
||||
bar = foo.bar
|
||||
assert(bar() == foo)
|
||||
|
||||
class Bar
|
||||
def baz()
|
||||
"baz doc string"
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
bar = Bar()
|
||||
bz = Bar.baz
|
||||
assert(bz._docs == "baz doc string")
|
||||
bz.bind(bar)()
|
||||
|
||||
## If we got here, that means all test were passed.
|
||||
print('All TESTS PASSED')
|
||||
|
@ -21,6 +21,8 @@ print(a)
|
||||
b = B()
|
||||
assert((b is B) and (b is A))
|
||||
|
||||
assert(B.parent == A)
|
||||
|
||||
class Shape
|
||||
def display()
|
||||
return "${self.name} shape"
|
||||
|
@ -3,7 +3,7 @@
|
||||
## from either mylib.so, or mylib.dll
|
||||
import mylib
|
||||
|
||||
if __name__ == "__main__"
|
||||
if _name == "@main"
|
||||
## Call the registered function.
|
||||
print('mylib.hello() = ${mylib.hello()}')
|
||||
end
|
||||
|
@ -100,6 +100,7 @@ end
|
||||
|
||||
## -------------------------------------------------
|
||||
|
||||
## if __name__ == '__main__' ;)
|
||||
if _name == '@main'
|
||||
main()
|
||||
end
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user