Skip to content
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

Standard library entries to match Getting Started guide #57

Closed
33 tasks done
faultyserver opened this issue Dec 1, 2017 · 2 comments
Closed
33 tasks done

Standard library entries to match Getting Started guide #57

faultyserver opened this issue Dec 1, 2017 · 2 comments
Labels
good first issue An issue that provides a good intro to working with the Myst codebase. Be helpful! nativelib Any issue relating to the native library (Crystal code) of Myst. stdlib Any issue relating to the standard library (Myst code) of Myst.
Milestone

Comments

@faultyserver
Copy link
Member

faultyserver commented Dec 1, 2017

This issue has been marked as a "Good First Issue"! If you'd like to tackle this issue as your first contribution to the project, be sure to read the Get Involved section of the README for some help with how to get started.

This is also a very large issue with many parts. It is meant to be tackled piece-by-piece. A contribution that implements even one of these methods will gladly be accepted.

For the past few weeks, I've been working on a Getting Started guide for Myst. In that guide, I make some references to standard library functions that don't actually exist yet. The goal of this issue is to list all of the functions that are referenced that do not yet have an implementation so that they can be added one by one. Since the guide is not finished, entries may be added to this issue in the future.

Additionally, there are some other functions that I think would be good additions for the next release.

Some of these functions will be part of the native library (written in Crystal), while others will be part of the standard library (written in Myst). Each entry here has a small description of what it should do. For the most part, these follow the versions from Ruby, so feel free to look there for inspiration.

Native library

  • Map#+(other : Map)

    Add two Maps together into a new Map. If a key exists in both Maps, the value from the second map should be used.

  • List#-(other : List)

    Return a new List with only the entries from the first List that do not exist in the second.

  • Integer#<(other)

    Return true if the integer is numerically less than other. Return false otherwise.

  • Integer#<=(other)

    Return true if the integer is numerically less than or equal to other. Return false otherwise.

  • Integer#>=(other)

    Return true if the integer is numerically greater than or equal to other. Return false otherwise.

  • Integer#>(other)

    Return true if the integer is numerically greater than other. Return false otherwise.

  • Float#<(other)

    See Integer#<.

  • Float#<=(other)

    See Integer#<=.

  • Float#>=(other)

    See Integer#>=.

  • Float#>(other)

    See Integer#>.

  • List#<(other : List)

    Return true if the List is a proper subset of other. That is, if every element of the List appears in other, but other also contains at least one more value. Return false otherwise.

  • List#<=(other : List)

    Same as List#<(other), but also return true if there are no extra elements in other.

  • Map#<(other : Map)

    Return true if the Map is a proper subset of other. That is, if every key of the Map appears in other, but other also contains at least one more key. Return false otherwise.

    The values of the Map are not important. Only the keys determine the subset.

  • Map#<=(other: Map)

    Same as Map#<(other), but also return true if there are no extra elements in other.

  • IO.print(string : String)

    Print the given string to the output of the Interpreter, with no formatting or conversions done. The argument should be expected to already be a String.

  • List#size

    Return the number of elements in the List as an Integer.

  • Map#size

    Return the number of elements in the Map as an Integer.

Standard library

  • String#size

    Return the number of characters in the String as an Integer.

  • String#empty?

    Return true if the String contains 0 characters. Return false otherwise.

  • List#empty?

    Return true if the List contains 0 elements. Return false otherwise.

  • Map#empty?

    Return true if the Map contains 0 elements. Return false otherwise.

  • Enumerable#all?(&block)

    Pass each element of the enumerable to block, returning true if all elements in the enumerable causes block to return a truthy value.

  • Enumerable#any?(&block)

    Pass each element of the enumerable to block, returning true if any element in the enumerable causes block to return a truthy value.

  • Enumerable#find(default=nil, &block)

    Iterate the enumerable, passing each element to block. The return value should be the first element for which the block is truthy. If no elements cause a truthy return value, return the default value instead (which itself should default to nil).

  • Enumerable#min

    Iterate the enumerable, finding the element with the lowest value as determined by <.

  • Enumerable#max

    Iterate the enumerable, finding the element with the highest value as determined by >.

  • Enumerable#select(&block)

    Returns an array containing all the elements of the enumerable that cause block to return a truthy value.

  • Enumerable#sort

    Sort the elements of the enumerable with the ordering determined by the <= method for each element. To start with, the sort can be something simple like insertion sort, eventually replaced by a proper hybrid quick sort.

  • Enumerable#size

    Return the number of elements in the enumerable, determined by incrementing a counter for each element yielded by #each.

  • Enumerable#to_list

    Return a List containing all the elements of the enumerable.

  • Enumerable#reduce(&block(acc, elem))

    For every element in the enumerable, call block with the result of the previous call and the current element as arguments. The first element is used as the initial value of the accumulator; it does not get a separate call to the block.

  • Enumerable#reduce(initial, &block(acc, elem))

    Same as Enumerable#reduce(&block(acc, elem)), but also specifying an initial value to use for the accumulator. In this version, the first element will get its own call to the block.

  • Int#times(&block)

    Call block as many times as the value of this integer. For example, 3.times(...) would call block 3 times.

Implementation

Obviously, there are a lot of things to add. I don't expect that all of these would be added in a single PR. Tackling them one at a time is fine by me.

Adding functions to the native library can be done in the src/myst/interpreter/native_lib folder. All of the types listed above should already exist there. Use NativeLib.method to write the implementation for a function, then call NativeLib.def_instance_method or NativeLib.def_method to add it to the appropriate module. There are plenty of examples in the code already that should help you out.

The standard library exists in the stdlib folder at the top level. Look at the existing entries (specifically, Enumerable) to see how new functions can be added.

Also, please try to add a descriptive comment to each method describing the arguments that it accepts, the values that might be returned and a description of what the method does. The Enumerable module) has some good examples of these comments.

If you'd like to pick up one or more of these functions, please comment below saying which function you would like to implement so that others know they are taken.

As always, if you have any other questions, feel free to ask them here or let me know directly so I can help out :) Good luck!

@faultyserver faultyserver added good first issue An issue that provides a good intro to working with the Myst codebase. Be helpful! nativelib Any issue relating to the native library (Crystal code) of Myst. stdlib Any issue relating to the standard library (Myst code) of Myst. labels Dec 1, 2017
@faultyserver faultyserver added this to the Next milestone Dec 1, 2017
minirop added a commit to minirop/myst that referenced this issue Dec 5, 2017
@faultyserver
Copy link
Member Author

To expand a bit on how native library methods can be added:

The interpreter provides a few helper macros under the NativeLib module, namely method, def_method, and def_instance_method. These end up getting used by files in the native_lib folder to create and register methods on types in the Kernel.

Adding a new method to the native library is a two-step process:

  1. use NativeLib.method to define the method implementation. For example, the String#size implementation looks like this:

    NativeLib.method :string_size, TString do
    TInteger.new(this.value.size.to_i64)
    end

    The first argument to this function is the name of the implementation. This is often made up of the name of the type the method is being defined on, followed by the name of the method being implemented. The second argument is the type to use for the self object (available as the variable this) while inside the method.
     
    Any further arguments are parameters for the method, and require a type restriction (normally just Value). The other methods in native_lib/string.cr show this usage.

  2. In the init_* method for the type (e.g., init_string in native_lib/string.cr), use NativeLib.def_instance_method to register the implementation with the type it belongs to. For example, the String#size method shown above is registered with a line like this:

NativeLib.def_instance_method(string_type, :size,   :string_size)

Here, string_type is the Type that represents String in Myst (see it's instantiation at the beginning of init_string). :size is the name of the method as it should appear in Myst, and string_size is the name of the implementation method.

def_instance_method is used to define instance methods for Types. It will register the method in the instance_scope of the given TType. def_method is used to define static methods, or methods for Modules (e.g., IO.puts). The arguments for the two use the same structure.

Hopefully that helps clear up how the Native Library is built up. Feel free to ask any more questions in the #help channel in the discord, or on here.

minirop added a commit to minirop/myst that referenced this issue Dec 6, 2017
faultyserver added a commit that referenced this issue Dec 6, 2017
faultyserver added a commit that referenced this issue Dec 7, 2017
faultyserver added a commit that referenced this issue Dec 7, 2017
faultyserver added a commit that referenced this issue Dec 8, 2017
Implement empty? for Map and List (see #57)
faultyserver added a commit that referenced this issue Dec 9, 2017
faultyserver added a commit that referenced this issue Dec 9, 2017
…?`, `Enumerable#find`, `List#==`.

Thanks to @atuley and @zkayser for help with these implementations.
faultyserver added a commit that referenced this issue Dec 9, 2017
Implement `Enumerable#size`, `Enumerable#all?`, `Enumerable#find`, `List#==` (See #57)
@faultyserver
Copy link
Member Author

faultyserver commented Dec 26, 2017

I've removed the Dir.[pattern : String] method from this issue because it doesn't really fit any of the other things here. Without more methods on Dir and File, it's pretty useless anyway.

For reference, here is the original text:

  • Dir.[pattern : String]

    Return a List containing the file names that match the given pattern, which can be given as a grep pattern like in Bash. Crystal provides this same functionality, so this function can act as a direct passthrough to that method.

With that, this issue is complete! Thank you to everyone who helped implement these methods! This has been a long-lived issue, but 0.3.0 will be a great release because of it :) Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue An issue that provides a good intro to working with the Myst codebase. Be helpful! nativelib Any issue relating to the native library (Crystal code) of Myst. stdlib Any issue relating to the standard library (Myst code) of Myst.
Projects
None yet
Development

No branches or pull requests

1 participant