Giter Site home page Giter Site logo

cooper / ferret Goto Github PK

View Code? Open in Web Editor NEW
4.0 2.0 0.0 2.99 MB

an evented, objective, hobby programming language with novel features; written in and compiled to Perl

Home Page: https://ferret.mitchellcooper.me

License: BSD 3-Clause "New" or "Revised" License

Perl 86.58% Forth 13.42%
perl interpreted-languages hobby programming-language language compiler interpreter

ferret's People

Contributors

cooper avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ferret's Issues

Delete/weaken do not work on indices

delete $list[0]
delete $hash["blah"]

Not yet implemented. The Indexed interface needs to require .deleteValue(). .weakenValue() should be optional in the interface and raise a runtime error if you attempt to weaken something that cannot be weakened.

Property variables need to refer to a Ferret-accessible variable

Currently certain constructs such as inside and type allow the use of property variables (standalone .prop). However, there is no decent way to access the object itself, besides .*self, which is quite ugly. I'm thinking something like Perl $_. Might even call it that.

Distinguishing between PROPERTY and VAR_PROP

Currently VAR_PROP requires whitespace in front of it. This usually works, but we definitely need something that always works.
Example where it would fail:

doSomething(.blah)

But this would work:

doSomething( .blah)

issues with class inheriting from context

I've always wanted class to inherit from context since you can extend a class with the package keyword just as you can a context, but it causes problems.

I made it so Class inherits from Context now, which is working OK, except that I had to tweak something in Function.pm. I had to use the actual outer scope of the function rather than the nearest context. This is undesirable because it would allow function type checks to be blinded by lexical variables or nested functions having the same name as the type.

Tokenization of interpolated variables needs work

issue 1

"$x"

works literally the same as

$x

instead of forcing string context.

issue 2

"$x is the number we found"

This is the same as

$x + "is the number we found"

but really it needs to be

"$x" + "is the number we found"

to force string context such that the String operator is used rather than the Num one.

*self within event callbacks is very confusing

Problem

The behavior of *self and @instanceVariables is not always clear. We cannot be sure just by looking what they are referring to. By default, *self within on blocks refers to the outer *self from the containing scope. However, this can be overridden by _self and other methods. At that point, there is no certainty.

Example

This is an example where I had to create a second variable to weakly reference the outer *self. I can't just access @commands directly because *self within the on block refers to the IRC::Connection instance. This is because an explicit _self argument is used when calling command handlers.

    $bot = *self
    weaken $bot

    # TODO: need better way to do this
    on $connection.handlers.PRIVMSG, :handleCommand {
        need $msg

        # commands only work in channels right now
        if !$msg.target.*instanceOf(Channel):
            return

        # find the command
        $trim = detail $msg.params[1].word(0).trimPrefix(".")
        if !$trim.trimmed:
            return
        $command = $trim.result

        # call the command
        $bot?.commands.[$command.lowercase]?(
            msg:        $msg,
            channel:    $msg.target
        )
    }

Solution

I think in situations like this, we should not specify an explicit _self. Instead, we should specify _this which would force an override of *this. The problem with this solution is that writing *this over and over is ugly and inconvenient. I know we already have a lot of sigils, but perhaps an additional one to reference properties of *this would provide a more elegant solution.

Example

Here is the above example, adjusted in accordance with this idea.

    on $connection.handlers.PRIVMSG, :handleCommand {
        need $msg

        # commands only work in channels right now
        if !$msg.target.*instanceOf(Channel):
            return

        # find the command
        $trim = detail $msg.params[1].word(0).trimPrefix(".")
        if !$trim.trimmed:
            return
        $command = $trim.result

        # call the command
        # (note that instance variables refer to the outer *self, the Bot instance)
        @commands.[$command.lowercase]?(
            msg:        $msg,
            channel:    $msg.target
        )
    }

And to access properties of *this (assuming we adopt the % sigil):

on $person.haveBirthday {
    %age++
    say("Happy birthday %name!")
}

it's possible to create "fake" events and functions

Event and Function are "fake" classes. Actually, they are real classes, and all events and functions actually do inherit from their prototypes, BUT they're "fake" in the sense that you cannot actually create a function or event with their constructors. Currently it's possible to create empty objects that are instances of these classes. This is bad because it would allow a non-callable object to satisfy a function with a Code argument.

Probably should just raise a runtime error when attempting to initialize a Function or Event this way?

improved operator docs

need to actually look at the signature of operator methods to see whether it's LHS or RHS, or EHS. get rid of the arguments section. show a better example.

Variables not interpolated in regex

The constructor does not attempt to interpolate regex. I did this on purpose because I have not yet implemented regex addition in the runtime.

finish return types

Concept

Return types were added to the compiler. It looks like:

func F {
    return "blah": Str
}

or for named returns

func F {
    A -> "asdf": Str
    B -> 4: Num
}

Purpose

The purpose of this is that type interfaces will soon be able to require methods to have a certain return type:

type Iterable {
    can .iterator -> Iterator
}

or for named returns

type Person {
    can .info -> (name: Str, age: Num, sex: Gender)
}

TODO

  • Add support for this new return type syntax
  • Add Verifier code which checks for return type mismatches within the same function
  • Include the compiler-determined string return types in the compiled code
  • Show return types in function signatures
  • Add support for the return type requirement syntax in type interfaces
  • Use SOIs to determine what the bareword types evaluate to
  • Implement actual checking of return types in type interfaces

Class(instance) still returns instance even if there's a mismatch of generics

$nums = List<Num>()
List($nums)

The above returns $nums. This is expected. It is indeed a list.

$nums = List<Num>()
List<Str>($nums)

The above also returns $nums. This is bad. It is NOT a list of strings.

This is due to the following code in Class.pm:

    # if passed an instance, return the instance.
    if (ref $args eq 'ARRAY' && @$args == 1) {
        return $args->[0] if $args->[0]->instance_of($class);
    }

It needs to consider the generics.

calling events together

Evented::Object allows events on different objects to be called simultaneously. I have wanted to bring this idea to Ferret for some time, but it faces new challenges.

One of the main concerns is that callback names must be unique throughout all events being fired. While this rarely causes an issue in Perl due to Evented::Object automatically generating unique callback names, Ferret would face frequent overlap. The "default function" (the one formally defined by a func or method keyword and whose signature determines the signature of the event) is always called default. This means that virtually any two events will each have a callback named default. When firing the events together, only one of them will be executed.

Generics only work with one-level barewords

Stack<Num>() works, but Stack<Num::Even> fails in the construction phase:

<bottie> Separate bareword generic types by the comma (,).
<bottie>      File    -> (stdin)
<bottie>      Line    -> 1
<bottie>      Near    -> bareword 'Stack'
<bottie>      Parent  -> class name with generics
<bottie> Exception raised by F::TypedClass line 30.

run tests on compile

want to add a -t option to the compiler which automatically runs test files (in the test directory of the source tree)

options for doc generation

there needs to be some way to set options for a class or file to be used in the generation of documentation.

class Complex

$docOptions = [ instanceName: 'z' ]

Need a way to access return objects when explicitly returning another value

func blah {
    a -> "B"
    c -> "D"
    return "E"
}

blah() always yields "E", but what if I want "B" or "D"?

Something like:

$ret = blah().*ret
$ret.a

would be decent (although a prettier syntax would be better). But the idea is there. The problem is that there's no way to know when to dispose of the special ret property. It can't just stick around in random objects forever.

There's an issue with scopes being retained sometimes

<mad> .e activeObjectCount()
<bottie> 2,279
<mad> .e activeObjectCount()
<bottie> 2,377

This will continually increase significantly. I think it has something to do with nested functions. Probably the outer_scope key.

I tried switch to manual garbage disposal with properties. It didn't work too well:

<mad> .e activeObjectCount()
<bottie> 43,097
<mad> .e activeObjectCount()
<bottie> 136,089

the current way to track filenames is bad

A lot of runtime errors say "(unknown file)" but still have a line. The line comes from the $pos. One idea I've had is to make $pos a dualvar and also include the filename.

allow RHS to dictate operator implementation

currently if an operation is unknown the LHS is returned unaltered. we should instead check of the RHS offers an implementation. the LHS implementation will always be preferred if available.

Lists with elements of a certain type

I want to be able to do

$nums = List<Num>()

where

$nums.push("a string")

would fail.

If we had type-specific lists, we might be able to eliminate sets entirely. Which would be good because I don't like them anymore. Too much conversion between lists and sets.

To make this possible, we need the equivalent of class List <T?> in pure Perl. The Perl API does not offer a way to do this yet.

Generic types can stick around with a class unintentionally

I could be wrong; I haven't tested this. But from the code it looks like:

List<Num>
$x = List()

I think $x would have the Num requirement. Because it looks like it sticks to the class until the next call of the initializer. This is undesirable. Need a different way... maybe. I could be thinking wrong.

get rid of constant zero

the constant zero stuff is really bad. also it has bugs such as squaring a negative number. need to fix this. doing it properly would allow for things like changing the sign of an object which cannot be subtracted from zero.

methods in type{}

It would be neat if you could define methods within a type interface. This would require though that the object returned by the type is actually a new object wrapping the original one. Or maybe use the same object but make it an instance of the type interface by pushing the interface's prototype to the object's *isa.

Callback names are unique to the event, not the object the event is attached to

<matthew> .e Socket
<mad> hmm
<bottie> [ Context ](
<bottie>     TCP = [ Class ](
<bottie>         initializer__ = Event 'initializer__' { $address:Str $port:Num ?$readMode:Sym }
<bottie>         name = "TCP"
<bottie>         proto = [ Prototype ](
<bottie>             connected = Event 'connected' [
<bottie>                 default: Function 'default'
<bottie>                 sendRegistration: Function 'sendRegistration'
<bottie>             ]
<bottie>             gotLine = Event 'gotLine' [
<bottie>                 handleLine: Function 'handleLine' { $data }
<bottie>                 default: Function 'default' { $data:Str }
<bottie>             ]
<bottie>             eof = Event 'eof' { $remainder:Str }
<bottie>             println = Event 'println' { $data:Str }
<bottie>             print = Event 'print' { $data:Str }
<bottie>             disconnected = Event 'disconnected' [
<bottie>                 resetState: Function 'resetState'
<bottie>                 default: Function 'default'
<bottie>             ]
<bottie>             connect = Event 'connect'
<bottie>             gotData = Event 'gotData' { $data:Str }
<bottie>         )
<bottie>         Set = (computed)
<bottie>         (init) = Function 'init' { $obj }
<bottie>     )
<bottie>     36 more inherited
<bottie> )
<mad> wow?
<mad> thats not good
<matthew> what isnt
<mad> those callbakcks
<mad> resetState and handleLine 
<mad> are from the irc framework
<mad> and they showed up in the actual Socket?
<mad> that would suggest that callback names have to be unique to AL
<mad> ALL objects of a type
<mad> thats bad
<mad> verybad
<mad> thank you for bringing that to my attention
<matthew> no problem

PropertyOwner

class of expressions which can trace back to a property on an object. to be used for weaken/delete/other property modifiers as well as assignments etc.

Extending classes with generics

class A <T>
class A <T>

These have the same generics, but it ends up requiring two. It needs to detect if they are the same. If not, raise an error. They have to be the same. Even the name has to be the same. One definition can require more than another, but up to that additional one(s), they must be the same.

Get rid of Sets

Now that #11 is finished, we can probably just get rid of sets. I don't like them. They are used internally though in a few places. I can fix that.

problems when two functions have the same arg name but different type

It only happens because $x is the same in both. But that shouldn't matter. It works fine if you use $x and $y instead.

2:54:28 PM <~mad> .e func F { need $x: Num } func F { need $x: Str }
2:54:29 PM <booby> undefined
2:54:29 PM <~mad> .e F(1)
2:54:30 PM <booby> [ No return ]
2:54:30 PM <~mad> .e F(1)
2:54:31 PM <booby> [ Return ](
2:54:31 PM <booby>     error = [NativeCodeError] fuck
2:54:31 PM <booby> )
2:54:31 PM <~mad> .e F(1)
2:54:32 PM <booby> [ No return ]
2:54:32 PM <~mad> .e F(1)
2:54:33 PM <booby> [ No return ]
2:54:33 PM <~mad> .e F(1)
2:54:34 PM <booby> [ No return ]
2:54:35 PM <~mad> .e F(1)
2:54:35 PM <booby> [ Return ](
2:54:35 PM <booby>     error = [NativeCodeError] fuck
2:54:35 PM <booby> )

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.