1. 10 Jun, 2018 1 commit
  2. 07 Jun, 2018 1 commit
  3. 01 Jun, 2018 3 commits
  4. 31 May, 2018 1 commit
  5. 16 Mar, 2018 1 commit
    • Yorick Peterse's avatar
      Added support for method type requirements · f8a176e8
      Yorick Peterse authored
      An example use case would be Array.==: this method should only be
      available if all values in the Array implement the Equal trait.
      Requiring the Equal trait to be implemented up front (along with any
      other traits some methods may require) means potentially having to
      implement a lot of unused traits _just_ so you can store a value in the
      Using method type requirements we can set method specific requirements,
      ensuring the method is only available when all requirements are method.
      For Array.== this means we'd define it as follows:
          impl Equal for Array!(T) {
            def ==(other: Self) -> Boolean where T: Equal {
      The code necessary to make this work is a total hack, like most of the
      compiler. Chances are it's buggy and might be changed a lot in the
      future, but for now it should be good enough.
  6. 28 Feb, 2018 1 commit
    • Yorick Peterse's avatar
      Support converting optional types to non optionals · b4a26ef4
      Yorick Peterse authored
      This adds support for converting optional types (e.g. ?T) to their
      non-optional equivalents (T in this case). This is useful for cases
      where you can guarantee the value is never Nil. For example,
      std::os.platform uses this because the VM never returns a platform index
      greater than the number of known platform names.
      Converting optional types does not generate any runtime checks and as
      such should be used with extreme care. In the future I hope to extend
      the compiler so it can do this automatically when using "if_true" or "if
  7. 22 Feb, 2018 1 commit
    • Yorick Peterse's avatar
      Turn Boolean back into a trait and rework AND/OR · 99a57b22
      Yorick Peterse authored
      A few months ago I turned Boolean from a trait into an object. Back then
      the trait setup for Boolean was rather horrible and I thought using a
      regular object would be better. Unfortunately the use of an object
      brought various issues with it. For example, every method defined on
      True or False would also have to be defined (as a dummy method) on
      Boolean itself. It was also impossible to support code such as this:
          def example(other: do -> Boolean) -> Boolean {
            if true: {
            }, false: {
      This wouldn't work because "Boolean" is not guaranteed to implement the
      same methods as "True".
      One solution to this problem would be to introduce union types and
      define "Boolean" as a union like so:
          type Boolean = True | False
      While tempting I feel that union types are the wrong approach. Every
      union type can be replaced by a trait and traits in general are much
      more pleasant to work with. For example, consider the following union
          type Number = Integer | Float
      Now let's say this type is defined somewhere in the standard library or
      some other piece of code we can't easily modify, and we use it in a
      whole bunch of places. If we at some point want to also support a
      Complex or Rational we'd have to either define our own type, or somehow
      ask the author of the "Number" type to extend it. Both cases are a pain.
      With traits on the other hand this would not be an issue as we can
      simply implement it where necessary and we're good to go.
      Because of the above issues we now define "Boolean" as a trait. To
      support this one can now define a trait and later redefine it, but
      _only_ if the trait is empty. This allows us to define "Boolean" in the
      "std::bootstrap" module and later refine it in "std::boolean". Without
      this we would not be able to bootstrap the runtime as various modules
      depend on "Boolean" being present from the very beginning.
      With these changes we also no longer need the GetBooleanPrototype
      instruction and thus it has been removed. We also removed && and || in
      favour of "and" and "or". Both these methods take a block that is only
      evaluated when necessary. This means that instead of this:
          foo && bar
      You would write:
          foo.and { bar }
      This has the added benefit of automatically grouping expressions, making
      it easier to chain message sends. For example, instead of this:
          (foo && bar).if_true {
      You can now write this:
          foo.and { bar }.if_true {
      To make all of this work I also had to make some changes to the type
      system. In particular we need to support downcasting of blocks in
      certain cases. Take the following piece of code for example:
          def or(other: do -> Boolean) -> Boolean {
            if true: {
            }, false: {
      Here the block passed to `true:` would be inferred as `do -> True` while
      the block passed to `false:` would be inferred as `do -> Boolean`. This
      would then produce a type erro because `do -> Boolean` is not compatible
      with `do -> True`.
      To support this we now check if in such cases we can downcast the
      expected type (`do -> True` in this example) to the given type.
      Currently we only downcast the return type of a block, but we may
      add support for other cases in the future.
  8. 18 Feb, 2018 1 commit
  9. 26 Nov, 2017 1 commit
  10. 17 Nov, 2017 2 commits
  11. 13 Nov, 2017 1 commit
  12. 21 Oct, 2017 1 commit
  13. 14 Oct, 2017 1 commit
  14. 11 Oct, 2017 2 commits
  15. 10 Oct, 2017 1 commit
  16. 08 Oct, 2017 1 commit
  17. 03 Oct, 2017 1 commit
    • Yorick Peterse's avatar
      Merge Type::TypeParameter into Type::Trait · 9f6d9a54
      Yorick Peterse authored
      Type parameters are now internally called "generated traits". By merging
      the two we remove the need for duplicating a lot of logic that for the
      most part already exists in Type::Trait.
  18. 01 Oct, 2017 1 commit
    • Yorick Peterse's avatar
      Rework how traits are handled · 8e96a774
      Yorick Peterse authored
      This is still a bit of a WIP but trait implementations are now separate
      and the compiler performs trait validations. Having trait
      implementations separate allows for modules to refine existing objects
      by implementing new traits for them, without having to somehow reopen or
      redefine the entire object.
  19. 29 Sep, 2017 1 commit
  20. 23 Sep, 2017 1 commit
  21. 12 Sep, 2017 2 commits
  22. 30 Aug, 2017 1 commit
  23. 07 Aug, 2017 1 commit
  24. 06 Aug, 2017 1 commit
  25. 04 Aug, 2017 1 commit
  26. 28 Jul, 2017 1 commit
    • Yorick Peterse's avatar
      Start moving the compiler to Ruby · cdcecbe6
      Yorick Peterse authored
      While Rust is a great language overall, I wasn't making as much progress
      writing a compiler in it as I hoped for. In particular I found myself
      fighting Rust more often than should be necessary. Perhaps I am to
      blame, perhaps Rust was too strict.
      Either way, since the goal is to make the compiler self hosting there's
      no point in spending months trying to implement a Rust based compiler.
      As such I decided to write the compiler in Ruby. Ruby has many flaws,
      but it makes it much easier to quickly write a compiler without having
      to fight the language all the time, at the cost of the occasional
      runtime error during development. For example, porting over most of the
      Rust code _and_ using a linear IR (instead of the tree IR used in the
      Rust compiler) only took a few days.