Skip to content
Snippets Groups Projects
  1. Nov 07, 2019
  2. Oct 13, 2019
    • Yorick Peterse's avatar
      Remove async finalisation of objects · c6407a0a
      Yorick Peterse authored
      Finalising objects was handled in one of two ways:
      
      1. When reclaiming blocks we would schedule blocks that needed
         finalisation. These blocks were processed in a separate thread.
      2. When allocating into a block that needed finalisation, all objects in
         this block in need of finalisation would be finalised.
      
      The idea of this approach was to move the expensive finalising of
      objects out of the garbage collection phase, at the cost of delaying
      finalisation a bit.
      
      Unfortunately, this approach was anything but simple. This finalisation
      approach also required various data structures taking up memory.
      Finally, as part of the finalisation process we would have to scan over
      all objects; instead of just lines.
      
      In this commit we change the approach to a much simpler one. All async
      related code and data structures are removed. When allocating an Immix
      block, we zero out the block.
      
      When allocating a new object into a previously used slot that needs
      finalising, we finalise the object. This delays the finalising of
      objects until their memory is reused. In the usual program this should
      not pose a problem, as memory will be reused frequently. Indeed, this is
      something we have observed with Inko's own test suite and a few other
      test programs: memory usage actually goes down due to fewer data
      structures needed, instead of going on.
      Unverified
      c6407a0a
    • Yorick Peterse's avatar
      Make ArcWithoutWeak NonNull · bde4250c
      Yorick Peterse authored
      This reduces the size of an Option<ArcWithoutWeak<T>> from 16 bytes to
      just 8 bytes. This in turn can save a decent amount of memory when
      allocating many closures.
      Unverified
      bde4250c
  3. Oct 03, 2019
    • Yorick Peterse's avatar
      Clean up extending of types in the runtime · 60d86364
      Yorick Peterse authored
      Instead of various modules extending a built-in type, all this logic is
      moved to separate extension modules. This makes it easier to figure out
      what module defined something, keeps the code more consistend, and gives
      greater control over the order in which types are refined.
      Unverified
      60d86364
    • Yorick Peterse's avatar
      Add Pathname.join, .absolute?, and .relative? · 3634ceee
      Yorick Peterse authored
      Pathname.join can be used to join a Path and a Path/String toether.
      Pathname.absolute? and Pathname.relative? can be used to check if a Path
      is absolute or relative respectively.
      Unverified
      3634ceee
    • Yorick Peterse's avatar
      Add String.byte · 7b7165ef
      Yorick Peterse authored
      This method can be used to obtain a single byte at a byte position. This
      in turn is useful when performing byte comparisons of strings, as it
      removes the need for creating byte arrays.
      Unverified
      7b7165ef
  4. Sep 29, 2019
  5. Sep 26, 2019
    • Yorick Peterse's avatar
      Add Iterator.any? · d22e281e
      Yorick Peterse authored
      This method can be used to check if an Iterator includes a certain
      value.
      
      This method does not reuse Iterator.find as the current Ruby compiler
      does not know that type parameters are instances of Object, making it
      impossible to use not_nil? on a ?T type.
      Unverified
      d22e281e
    • Yorick Peterse's avatar
      Add Object.not_nil? · b0ccdba1
      Yorick Peterse authored
      This method is used to check if an object is _not_ nil, making it the
      opposite of Object.nil?. This removes the need for writing
      `something.nil?.not`, which reads a bit awkwardly.
      Unverified
      b0ccdba1
  6. Sep 25, 2019
    • Yorick Peterse's avatar
      Do not expose Trait and Module by default · 60c47568
      Yorick Peterse authored
      This allows custom modules to define types with the name Trait or
      Module. To use Trait and Module you just import them from std::trait and
      std::module respectively. The module std::module does not define
      anything useful at this time, but more useful code will be added to it
      in the future.
      Unverified
      60c47568
  7. Sep 21, 2019
    • Yorick Peterse's avatar
      Clean up Object, Conditional, and Boolean · d87be76d
      Yorick Peterse authored
      This makes it easier to implement Conditional and Equal, and makes
      Object a little bit less of a mess. These changes uncovered two bugs:
      
      1. The compiler did not support looking up default methods on a trait
         when they were defined on Object.
      
      2. Map.iter was not implemented correctly. If the last bucket in a Map
         was Nil, Map.iter would produce a Nil value. This has been fixed by
         the Iterator not producing values at all in this case.
      
      Originally I started working on these changes in hopes of getting rid of
      Object entirely. This will not be possible, as it makes Inko a bit
      annoying to work with. For example, Conditional and Equal would have to
      be implemented manually for every object, leading to a lot of
      boilerplate. Instead, we'll keep Object for the time being.
      Unverified
      d87be76d
  8. Sep 16, 2019
  9. Sep 15, 2019
    • Yorick Peterse's avatar
      Implement Inko's parser in Inko · bffdb0c1
      Yorick Peterse authored
      The parser is an LL(1) recursive descent parser. While the Ruby parser
      was used as a reference, it is not a 1:1 port.
      
      As part of porting the parser to Inko, several syntax changes were made:
      
      1. "where" on methods is not supported by the Inko parser. When we start
         using the parser we will move "where" to traits.
      
      2. The comments "#!" and "##" are replaced with just "#". This makes the
         lexer and parser internals easier, and removes the need for having to
         remember three different comment types.
      
      3. Mutable rest arguments are supported in the Inko parser using
         "mut *NAME", instead of "* mut NAME".
      
      Using the parser is straightforward:
      
          import std::compiler::parser::Parser
      
          let parser = Parser.new(input: '10 + 2', file: 'test.inko')
      
          try! parser.parse
      
      The AST nodes are located in modules under `std::compiler::ast`. For
      example, integer literals are in `std::compiler::ast::literals`. For now
      there is some minor duplication across some of the AST nodes. For
      example, the types of methods (MethodDefinition) and required methods
      (RequiredMethodDefinition) are similar. When we start implementing the
      compiler we may change this around a bit, or perhaps split the AST nodes
      into more separate types.
      
      Fixes https://gitlab.com/inko-lang/inko/issues/172
      Unverified
      bffdb0c1
  10. Sep 02, 2019
  11. Aug 27, 2019
  12. Aug 26, 2019
    • Yorick Peterse's avatar
      Improve output of failed tests · 6f06114b
      Yorick Peterse authored
      Test group and test names are now displayed separately, an additional
      line is added to show the location on which the test is defined, and all
      output is now left aligned with the corresponding labels. This makes it
      easier to read the output whenever there are test failures.
      Unverified
      6f06114b
  13. Aug 24, 2019
  14. Aug 23, 2019
  15. Aug 20, 2019
  16. Aug 19, 2019
  17. Aug 18, 2019
    • Yorick Peterse's avatar
      Remove support for binary newline sends · c5d3b303
      Yorick Peterse authored
      This removes syntax support for sending messages to the result of a
      binary expression without using parentheses. In other words, this:
      
          foo == bar
            .something
      
      Is no longer parsed as `(foo == bar).something`, instead it is not
      parsed as `foo == bar.something`. To send a message to the result you
      need to use parentheses:
      
          (foo == bar).something
      
      This might be a bit more verbose, but it makes the syntax easier to
      parse for both humans and computers. It also makes it possible to spread
      the right-hand side over multiple lines when necessary. For example,
      prior to this MR this would not work as expected:
      
          foo ==
            bar
              .baz
              .quix
      
      This would be parsed as `(foo == bar).baz.quix`, and not `(foo ==
      bar.baz.quix)`.
      Unverified
      c5d3b303
  18. Aug 13, 2019
    • Yorick Peterse's avatar
      Remove support for Array literals · c94fb713
      Yorick Peterse authored
      Similar to the removal of Map literal support, this is aimed at
      simplifying the syntax and making it more consistent. Arrays are now
      created using `Array.new`, which takes every value as a separate
      argument:
      
          Array.new(10, 20, 30, ...)
      
      To make this more pleasant to work with, the methods `StringBuffer.new`
      and `ByteArray.new` now take a rest argument. This means you don't have
      to write `ByteArray.new(Array.new(...))`, and instead can write
      `ByteArray.new(...)`. For the `StringBuffer` type this requires that we
      manually create an instance of it. To remove the need for using VM
      instructions directly, we introduce `Object.allocate` as a wrapper
      around this. This allows one to manually create instances like so:
      
          static def some_method {
            let instance = allocate
      
            instance.init(...)
      
            instance
          }
      Unverified
      c94fb713
  19. Aug 12, 2019
  20. Aug 11, 2019
    • Yorick Peterse's avatar
      Remove hash map literals · 94ac7d14
      Yorick Peterse authored
      In order to simplify the syntax, hash map literals have been removed.
      Instead, one now creates a hash map using `Map.new`. To make it easier
      to create a map with a bunch of pairs in one expression, we introduce
      the `Map.set` method. This method behaves similar to `Map.[]=`, but
      returns the Map itself instead of the value written:
      
          Map
            .new
            .set('foo', 'bar')
            .set('baz', 'quix')
      
      So why were map literals removed? Well, first of all their syntax was
      not intuitive: `%[key: value]`. This syntax was taken from Elixir, but
      is not used in other languages that we are aware of. Many languages use
      curly braces (e.g. `{key => value}`), but these are already used for
      closures. Some languages reuse square brackets (e.g. `[key: value]`),
      but this makes the meaning of `[]` unclear. We considered using a syntax
      similar to Scala:
      
          Map.new(key -> value)
      
      Here `->` would be a method that returns some sort of tuple, and
      `Map.new` would take this list of tuples and use them to fill the map.
      The method `->` would have to be available for every object, since
      it's perfectly valid to use outside of constructing maps. This means
      `->` would have to be defined on `Object`, or in a trait that is
      implemented for it. Manually implementing the method/trait would be too
      cumbersome. The hypothetical code for this might look as follows:
      
          impl Object {
            def ->!(V)(other: V) -> Tuple!(Self, V) {
              Tuple.new(self, other)
            }
          }
      
      Unfortunately, the Ruby compiler does not support the use of self types
      in generic types well enough to make this work. This is a long standing
      issue [1], but it would require an extensive rewrite of the type system
      to support. Since we want to rewrite the Ruby compiler in Inko, adding
      support for this in the Ruby compiler would be a waste of time.
      
      There are a variety of other approaches, such as passing a closure to
      `Map.new` that can be used to fill up the map. All of these suffer from
      similar problems: the Ruby compiler's type system is a bit buggy.
      
      To work around all of this, we added the `Map.set` method. While the
      resulting code is a bit more verbose, it does not require any compiler
      changes. The API should also feel familiar to those used to immutable
      programming languages, which typically use a similar approach for
      constructing hash maps.
      
      The removal of map literals also allows us to remove various compiler
      optimisations of these literals, simplifying the compiler and making the
      language more predictable.
      
      [1]: https://gitlab.com/inko-lang/inko/issues/107
      Unverified
      94ac7d14
  21. Aug 07, 2019
  22. Aug 05, 2019
  23. Aug 02, 2019
Loading