-
Notifications
You must be signed in to change notification settings - Fork 169
Adding Classes to scarpet. #306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Ghoulboy78
wants to merge
26
commits into
master
Choose a base branch
from
classes
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 19 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
c0997d7
Added classes.scl
Ghoulboy78 f5fce43
Added max heap example
Ghoulboy78 0d7eb44
renamed heap.sc to min_heap.sc
Ghoulboy78 9ecdf1c
Renaming max_heap.sc to max_heap.scl
Ghoulboy78 2e1c112
Adding docs
Ghoulboy78 010ff89
Making a copy of the class map
Ghoulboy78 28b87bf
Adding inheritance
Ghoulboy78 1c7cdc8
Checking for own class when doing instanceof
Ghoulboy78 90b839a
Updating instance_of to account for inputting non-class values
Ghoulboy78 aaf504b
Adding .bak files to gitignore
Ghoulboy78 b063328
Adding object class
Ghoulboy78 2e56d8f
Adding interface and iterator class
Ghoulboy78 893e686
Removing unfinished sentence
Ghoulboy78 26a7c63
Adding anonymous classes
Ghoulboy78 02cb871
Adding limit to while loop
Ghoulboy78 6e2cde1
Checking for a null next() function to break out of loop
Ghoulboy78 b8f29f6
Added detailed Readme.md
Ghoulboy78 d6e60ce
Adding headings
Ghoulboy78 7c3ff11
Adding interface docs
Ghoulboy78 35103f0
Updating documentation in max_heap.scl
Ghoulboy78 0849558
Updating docs in Readme.md
Ghoulboy78 5730ed7
Merge branch 'classes' of https://github.com/gnembon/scarpet into cla…
Ghoulboy78 f4cf11e
Update classes.scl
Ghoulboy78 3f52786
Making docs more verbose
Ghoulboy78 921dfec
Update max_heap.scl
Ghoulboy78 38ce6ba
Update README.md
Ghoulboy78 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,4 +19,8 @@ | |
bin/ | ||
.classpath | ||
.project | ||
*.code-workspace | ||
*.code-workspace | ||
|
||
|
||
# npp | ||
*.bak |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,92 @@ | ||
Programs for calculating math operations, and examples for min/max interation, heaps and hashes | ||
# Fundamentals | ||
Programs for calculating math and other programming operations. | ||
|
||
## `hashmap.sc` | ||
#### By: LucunJi(禄存) | ||
An implementation of hash maps, which predates native scarpet maps and sets. Contains functions to create and | ||
modify maps, which are stored as lists. This implementation onlny works for numbers, however you can add your | ||
own `_hash` function to make it work for all types. | ||
|
||
## `hashset.sc` | ||
#### By: LucunJi(禄存) | ||
Same deal as with `hashmap.sc`, except for hash sets. You can currently use native scarpet implementation, but | ||
these also give a good insight into how hash sets and hash maps work. | ||
|
||
## `math.scl` | ||
#### By: gnembom | ||
A bunch of useful maths functions, such as `sum()`, `bin()` and `hex()`, as well as the distance functions | ||
from the math.scl built into carpet mod. | ||
|
||
## `min_heap.sc` | ||
#### By: LucunJi(禄存) | ||
An implementation of min heaps in scarpet. This approach shows very well how min heaps work. Heaps are stored | ||
as lists, and the functions in the library can be used to manipulate them as if they were hash set objects. | ||
|
||
## `max_heap.scl` | ||
#### By: Ghoulboy | ||
An implementation of max heaps using `classes.scl`. This implementation works very differently to | ||
`min_heap.scl`, as here the heap is stored as a map, which represents the object. To use it, you need to | ||
import the `max_heap()` function from here as well as (at the very least `call_function` from `classes.scl`. | ||
You can use it by calling the `'insert'` and `'remove'` methods on the object. | ||
For more information on how these work, see below for `classes.scl`. | ||
|
||
## `classes.scl` | ||
#### By: Ghoulboy | ||
This is a library which allows the user to add classes into the game. Much like with Python, it works by | ||
making maps (or dicts) act as classes. Fields are regular map entries, and methods are entries with a string | ||
key and an anonymous function value. The important part is that the function always has at least 1 argument, | ||
which is going to be the object itself, so that the function can handle it (see `self` in Python). | ||
|
||
### Declaring a class | ||
To register a new class, use `new_class()`. The first argument is the name of the class, which will later be | ||
stored in the `__name__` field automatically by `classes.scl`. The second argument is the map representing the | ||
class, its fields and its methods. The last argument is a vararg list of the parent classes of this class. If | ||
a parent specifies a field or a method then this class will imherit that unless it specifies that same field | ||
or method. Note, the last argument takes in the parent classes, not their names, because classes.scl does not | ||
store classes, it just allows to manipulate them. | ||
|
||
To initialize an object, use the `new_object()` function. The first argument is the class variable (returned from | ||
the `new_class()` function). The next few arguments are the constructor of the class. This must be declared as an | ||
`__init__` method (see below) with any args you wish, except `classes.scl` will throw an error if it is not | ||
present. A class can also inherit an `__init__` method from its parent class. The `__init__` method will be | ||
called when running the `new_object()` function. | ||
|
||
If a class is not meant to be initialised, then you can initialise it as an interface. To do this, import | ||
`global_interface_class` from `classes.scl` and put it as a parent class, and don't specify a constructor. If a | ||
class chooses to implement your interface and doesn't implement a method, it will give an error message | ||
describing which method they didn't override and where it came from. | ||
|
||
### Declaring a method | ||
When creating a method, as mentioned previously it must take in at least one argument which is the object | ||
(here referred to as `self`). The method can then do whatever it wants with its arguments. It must then return | ||
either the `self` object, or a list with `self` as the first argument and a return value as the second. This | ||
allows a programmer to do `return_value = call_function(object, method, args)` and get a value. Returning the | ||
object (along with any modifications you have made to it) is important because that way the object will remain | ||
modified after you're done with it. | ||
|
||
To access a class' fields, you just do the same as with a normal map (`object:'field_name'`). This doesn't | ||
really allow for private fields, however methods will be considered private if they have a `_` prefix. This | ||
will make `call_function` throw an error if the programmer tries to call them. If you need to call a private | ||
method within a class, use `call(object:'private_method_name', object, args)`. Note that unlike with | ||
`call_function`, this will not give neat return values, instead it will either return the object or a list of the object and return value. | ||
|
||
### `Object` class | ||
Classes also have some built-in methods. Much like with Java, they all inherit from the `Object` class. This | ||
gives them the following methods: | ||
- `str` : Returns a string representation of the object | ||
- `hash` : Returns a hash of the object (calculated by default using native scarpet `hash()` function) | ||
- `number` : Returns a numeric representation of the object (by default length of `str` representation) | ||
- `class` : Returns the name of this class (also available as `object:'__name__'` field) | ||
- `equals` : Compares two objects to check if they are equal (by default using scarpet `==` operator) | ||
- `clone` : Returns an identical copy of this object which is it's own separate object (using underused scarpet | ||
`copy()` function) | ||
- `bool` : Returns a boolean representation of hte object (by default checking whether object's `number` | ||
representation is not 0) | ||
- `compare` : Takes in another object and returns a positive number if this one is greater, negative if it's | ||
less and 0 if they are equal (by default by subtracting this object's `number` representation with the other | ||
object's `number` representation) | ||
- `length` : Returns the length of this object (by default the length of its `str` representation) | ||
- `nbt` : Returns a nbt representation of this object (by default an nbt of `str` representation) | ||
- `json` : Returns a json representation of this object (by default a json of `str` representation) | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
//Library functions which add classes to scarpet | ||
// | ||
//This implementation makes maps as classes, and each map has to have a __init__ function. | ||
//All functions must take at least one parameter (like in Python 'self'), and then any additional parameters. | ||
//If the function should return nothing, then return just the object itself (with any modifications that the function adds) | ||
//If the function should return something, return a list with the object as the first element, and return value as the second | ||
//For fields, just access and set them like you would access and set values in a normal map | ||
// | ||
//When declaring methods in the class, you can optionally add a _ infront of them to make them private. | ||
//This means that they cannot be called using call_function(), telling the programmer that they're potentially dangerous. | ||
//When calling functions within the class methods, just use call(self:function_name, self, args). | ||
//This allows you to access private functions within the object. | ||
// | ||
//When calling a function, use call_function(), with the object as the first parameter, function name as the second | ||
//and then any arguments at the end. If the function has a return value, then call_function() will return it, otherwise | ||
//it will return null. | ||
// | ||
// | ||
//For an example of all this, see max_heap.scl | ||
//By: Ghoulboy | ||
|
||
//Initializes a class with its parent classes, which are passed in as their classes, not their names | ||
//We need the classes to complete the declaration of the class by essentially filling in all the missing methods | ||
new_class(name, declarer, ...parents)->( | ||
//Also means a class called Anonymous won't work | ||
declarer:'__name__' = if(name=='', 'Anonymous', name); | ||
declarer:'__parents__' = {}; //Using a set to avoid duplicate parentage | ||
declarer:'__member_data__' = {}; //Used to improve error messages | ||
for(parents, | ||
class=_; | ||
if(class:'__name__'=='Anonymous', throw('Cannot inherit from an anonymous class')); | ||
declarer:'__parents__'+=class:'__name__'; | ||
for(class, | ||
member = _; | ||
if(member=='__parents__',//Pushing parents' parents into child's parents | ||
declarer:'__parents__' = declarer:'__parents__' + class:'__parents__', | ||
!has(declarer, member), //stuff which the declarer doesn't override | ||
declarer:member = class:member; | ||
declarer:'__member_data__':member = class:'__name__' | ||
); | ||
) | ||
); | ||
if(name!='Object', | ||
object = global_object_class; | ||
for(object, | ||
member = _; | ||
if(!has(declarer, member), | ||
declarer:member = object:member; | ||
declarer:'__member_data__':member = 'Object' | ||
) | ||
) | ||
); | ||
//Checking for initializer here cos it could have been stolen from a parent class | ||
if(!has(declarer, '__init__') || type(declarer:'__init__')!='function', throw('missing_constructor', 'value_exception', declarer)); | ||
declarer | ||
); | ||
|
||
|
||
//Checks that a given input is a class. | ||
//NB: this only checks that it has a valid constructor and has a __name__ property | ||
is_class(class)-> | ||
type(class)=='map' && has(class, '__init__') && type(class:'__init__')=='function' && has(class, '__name__') && has(class, '__parents__'); | ||
|
||
//This throws an exception if a given input is not a valid class | ||
check_class(class)-> | ||
if(!is_class(class), throw('invalid_class', 'value_exception', class)); | ||
|
||
//the object is literally the same as class, except we have called initializer | ||
new_object(class, ...args)->( | ||
check_class(class); | ||
object = copy(class); //this is to avoid modifying the original map | ||
call(object:'__init__', object, ...args); | ||
); | ||
|
||
//Basically java instanceof operator | ||
instance_of(object, class_name)->is_class(object)&&(object:'__name__'==class_name || has(object:'__parents__', class_name)); | ||
|
||
//This is for calling public functions (which don't begin with _) | ||
//You can use call() directly, but this gives return value of functions neatly and blocks you from using private methods | ||
call_function(object, function, ...args)->( | ||
check_class(object); | ||
if(!has(object, function), throw('unknown_method', 'value_exception', function)); | ||
if(split(function):0 == '_', throw('hidden_method', 'value_exception', function)); | ||
cb = call(object:function, object, ...args); | ||
if(type(cb)=='map', | ||
object = cb; null, | ||
type(cb)=='list', | ||
object=cb:0; cb:1, | ||
// must either return modified object, or a list pair of the object and the return value of the function | ||
// Just checking here if we forgot to implement an abstract method from an interface | ||
instance_of(object, 'Interface'), | ||
//Copying Java's error message for unimplemented interface functions | ||
throw(str('Class \'%s\' must implement abstract method \'%s\' inherited from class \'%s\'', | ||
object:'__name__', | ||
function, | ||
object:'__member_data__':function | ||
)), | ||
throw('invalid_function_return', 'value_exception', cb) | ||
) | ||
); | ||
|
||
|
||
//This is a fundamental base class which all classes inherit from. | ||
//It contains base methods which we can guarantee will be in all classes | ||
//A bit of the code is copied from Value.java, and some from Object.java | ||
global_object_class = new_class('Object', { | ||
'__init__'->_(self)->throw('Cannot initialize class of Object'), | ||
'str'->_(self)->[self, self:'__name__' + '@' + call_function(self, 'hash')], | ||
'hash'->_(self)->[self, hash(self)], | ||
'number'->_(self)->[self, length(call_function(self, 'str'))], | ||
'class'->_(self)->[self, self:'__name__'], | ||
'equals'->_(self, obj)->[self, self==obj], | ||
'clone'->_(self)->[self, copy(self)], | ||
'bool'->_(self)->[self, bool(call_function(self, 'number'))], | ||
'compare'->_(self, other)->[self, call_function(self, 'number') - call_function(other, 'number')], | ||
'length'->_(self)->[self, length(call_function(self, 'str'))], | ||
'nbt'->_(self)->[self, nbt(call_function(self, 'str'))], | ||
'json'->_(self)->[self, encode_json(call_function(self, 'str'))], | ||
}); | ||
|
||
//This will be used to simulate interfaces, essentially. | ||
//Classes which want to be interfaces can inherit from this and not specify a constructor | ||
global_interface_class = new_class('Interface', { | ||
'__init__'->_(self)->throw('Cannot initialize an interface class'), | ||
}); | ||
|
||
//Some template classes. These may in time be moved to a separate file | ||
global_iterator_class = new_class('Iterator', { | ||
'has_next'->_(self)->null, | ||
'next'->_(self)->null, | ||
'for_each'->_(self, function)->( | ||
while(call_function(self, 'has_next'), 0x7FFFFFFFFFFFFFFF, | ||
next = call(self:'next', self); | ||
if(next==null, break()); | ||
call(function, next:1); | ||
); | ||
self | ||
), | ||
}, global_interface_class); | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
//A library script which contains the class of max heaps, implemented using classes.scl | ||
//If you want to know how a max heap works, see documentation of min_heaps.sc (which works very differently) | ||
// | ||
//To use this, import it into your script, and then import 'call_function' from classes.scl, so you can use the methods | ||
//At the bottom, commented out, is an example script showing how it works and how to use it. | ||
// | ||
//By: Ghoulboy | ||
|
||
import('classes', 'new_class', 'new_object', 'call_function'); | ||
|
||
max_heap_class = new_class('MaxHeap', { | ||
'__init__'->_(self, max_size)->( | ||
self:'max_size' = max_size; | ||
self:'size' = 0; | ||
_Heap = []; | ||
loop(max_size, _Heap+=0); | ||
self:'_Heap' = _Heap; | ||
self:'_FRONT' = 0; | ||
self | ||
), | ||
'_parent'->_(self, pos)->[self, bitwise_shift_right(pos, 1)], | ||
'_leftChild'->_(self, pos)->[self, bitwise_shift_left(pos, 1)], | ||
'_rightChild'->_(self, pos)->[self, bitwise_shift_left(pos, 1) + 1], | ||
'_isLeaf'->_(self, pos)->[self, pos*2 > self:'size'], | ||
'_swap'->_(self, fpos, spos)->( | ||
temp = self:'_Heap':fpos; | ||
self:'_Heap':fpos = self:'_Heap':spos; | ||
self:'_Heap':spos = temp; | ||
self | ||
), | ||
'_maxHeapify'->_(self, pos) -> ( | ||
//Getting all this stuff here cos it doesn't change and clutters up the code like crazy | ||
left = call(self:'_leftChild', self, pos):1; | ||
right = call(self:'_rightChild', self, pos):1; | ||
selfpos = self:'_Heap':pos; | ||
leftchild = self:'_Heap':left; | ||
rightchild = self:'_Heap':right; | ||
if(!call(self:'_isLeaf', self, pos):1 && (selfpos < leftchild || selfpos < rightchild), | ||
heapifypos = if(leftchild>rightchild, left, right); | ||
call(self:'_swap', self, pos, heapifypos); | ||
call(self:'_maxHeapify', self, heapifypos) | ||
); | ||
self | ||
), | ||
'insert'->_(self, element) -> ( | ||
if(self:'size' < self:'max_size', | ||
self:'size' += 1; | ||
self:'_Heap':(self:'size') = element; | ||
current = self:'size'; | ||
while(self:'_Heap':current > self:'_Heap':(call(self:'_parent', self, current):1), self:'max_size', | ||
call(self:'_swap', self, current, call(self:'_parent', self, current):1); | ||
current = call(self:'_parent', self, current):1 | ||
); | ||
); | ||
self | ||
), | ||
'remove'->_(self)->( | ||
popped = self:'_Heap':(self:'_FRONT'); | ||
self:'_Heap':(self:'_FRONT') = self:'_Heap':(self:'size'); | ||
self:'size' += -1; | ||
call(self:'_maxHeapify', self, self:'_FRONT'); | ||
[self, popped] | ||
), | ||
}); | ||
|
||
max_heap(outer(max_heap_class), maxsize) -> new_object(max_heap_class, maxsize); | ||
|
||
//This is an example of using a MaxHeap | ||
//heap = new_object(max_heap, 5); | ||
//print(heap:'_Heap'); => [0, 0, 0, 0, 0] | ||
//call_function(heap, 'insert', 1); | ||
//print(heap:'_Heap'); => [1, 0, 0, 0, 0] | ||
//call_function(heap, 'insert', 3); | ||
//print(heap:'_Heap'); => [3, 1, 0, 0, 0] | ||
//call_function(heap, 'insert', 3); | ||
//print(heap:'_Heap'); => [3, 3, 0, 1, 0] | ||
//print(call_function(heap, 'remove')); => 3 | ||
//print(heap:'_Heap'); => [3, 1, 0, 1, 0] //The extra 1 here is becase we don't remove it from the list, rather overwrite it later | ||
//call_function(heap, 'insert', 5); | ||
//print(heap:'_Heap'); => [5, 3, 0, 1, 0] //The first 1 from before has overwritten the trailing 1 | ||
//call_function(heap, 'insert', 6); | ||
//print(heap:'_Heap'); => [6, 5, 3, 1, 0] | ||
//print(call_function(heap, 'remove')); | ||
//print(heap:'_Heap'); => [5, 3, 0, 1, 0] | ||
// | ||
//print(heap); => {remove: _, __name__: MaxHeap, _Heap: [5, 3, 0, 1, 0], _leftChild: _, _isLeaf: _, _rightChild: _, _maxHeapify: _, __init__: _, _swap: _, insert: _, _parent: _, _FRONT: 0, size: 3, max_size: 5} |
File renamed without changes.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.