Giter Club home page Giter Club logo

eve2's People

Contributors

projectmoon avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

eve2's Issues

AOT "Compilation" and caching

The interpreter should serialize Script objects to disk for faster loading later. When a file is executed or imported, the interpreter should check the cache (~/.eve/cache) for a serialized form of the requested file. If the last modified of the executing .eve file is > than the last modified of the serialized form, use the new form and re-serialize. Otherwise just use the serialized form.

As an added bonus from this, we can specify an option to ahead-of-time compile a file via this functionality. In this case, the "compiled" file is placed in the current working directory as a .evec file. If the interpreter receives a .evec file as the script to execute, it should simply copy the file to the cache and then execute as normal.

Calls to non-existent function properties are ignored/silently fail.

When a non-existent function is called, the interpreter should throw an error. However, it apparently just ignores the statement. This might be a case of unassigned expressions being thrown out, but there must be something else going on because assigned functions can be called without assigning the result to anything.

Lists/Array Accessor

Need to implement lists and the array accessor syntax. This is composed of several parts:

  1. Implementation of [] syntax to access indexed properties.
  2. Implementation of List prototype.
  3. Implementation of List built-in type.
  4. Implementation of List literal.
  5. Enable indexed access to string type.

Assignment doesn't work in functions

Assigning a variable or property inside a function doesn't work:

def x = (a) { a = 5; print(a); }
var y = 4; x(y);

The above will print 4 inside the function. This seems to happen in both global and prototype functions.

import should only execute files once

The import function can currently import files. But every time it is called, it will execute that file. This could be bad and/or wasteful if a library is imported many times all over the place. The import call should simply return if a file has already been imported.

Import function enhancements

It would be nice to allow the import function to import more than files. If I come up with a file format for describing a namespace, we could import that and have import execute all files inside it. It would also be lovely to enable Maven repository downloading. Perhaps use Ivy for this task.

Import Paths

The import function should have a paths property of type list. This property will be searched for finding places to import the specified file. It will default to the current working directory and the location of the standard library. The import function should also implicitly add .eve if a file passed to it does not have .eve on the end of it.

Maven Repositories

This could be much more difficult, but it is worth it. Given a URI like mvn://commons-cli/commons-cli/1.2, it should download the dependency and add it to the classpath at runtimme. We can probably use Ivy's Java API for this, although I understand it is difficult to use.

Dict and List literal enhancements

Add the ability to put items into lists and dicts during declaration.

List: var l = [ 1, 2, "3", 4 ];
Dict:

var d = { key1 = "value1", key2 = 5, key3 = true };

protos can access module variables without module::

Prototypes can access module/global variables without using module:: or global::. This only applies to the proto statement itself. Functions defined inside the prototype are fine. An example:

var x = 5;
proto example {
    print(x);
}

This will print the global x variable. It should be `print(module::x);`` instead.

Scope Operator

Need :: to reference specific scopes, since scope is very explicit in Eve.

Event Inheritance Results in Stack Overflow Error

proto Base {
    def doSomething = () {
        print("doing something in super");
    }

    def onClone = (new) {
        new.super = self;
    }
}

var sub = clone Base;
def sub.doSomething = () {
    self.super.doSomething();
    print("doing something in child");
}

sub.doSomething();

This example from the wiki fails with a stack overflow error because of an infinite function invocation loop. Changing the name of the child's doSomething to doSomething2 makes it work. However, sub.doSomething should become different from sub.super.doSomething in this example.

Clone expressions

Currently the clone statement takes an identifier only. It should also allow expressions to be cloned.

Cannot use variables (or other expressions) to access indices

Currently, only numbers can be used to access list indices. This is because the [n] is actually part of the identifier. That is then parsed out and numbers found. It simply does not support anything else. The best solution to this would be to figure out how to work list indices into the ANTLR parsers. Otherwise, the quick ghetto solution would be to add support for at least variables. We will eventually have to implement them into the ANTLR parser though for real world application.

Increment/Decrement operators

The ++ and -- operators should be implemented for int and double types. This would make implementing traditional for loops nicer.

Stack Trace

The interpreter should print a stack trace when it fails.

Event inheritance infinite loop

Because of the change that disallows direct assignment of variables, this has inadvertently broken event-based inheritance. Because the onClone event is fired whenever something is cloned, this will create an infinite loop during event-based inheritance.

First Pass

Problem is that it's left-to-right, so we are flattening the tree and not parsing it right. i.e. first global statement will get added to a the deepest block (function in our test case). That is bad.

Java primitive/object mappings

Eve types boolean, string, and int need to map to both object and primitive versions of their Java counterparts for constructor searching:

  • int -> int, java.lang.Integer
  • string -> java.lang.String, java.lang.Character, char
  • boolean -> java.lang.Boolean, boolean

Return from loops

Verify that loops can be returned from. Don't think this is currently the case.

Variable Assignment needs to do clone

var x = 1;
var y = x;

x.a = 10;
print(y.a);

When assigning a variable to a new variable, it does not clone. The interpreter should either implicitly clone, or require the use of the clone statement. I am a fan of requiring clone, but I would need to make sure I can detect it.

Java interop cannot map to char type

Constructors which require char primitives currently do not work, because nothing maps to the char type. Will have to implement mapping of one-character eve strings to both java.lang.String, java.lang.Character, and char. This will actually be fairly simple, as we just need to catch single-length strings and add three constructor possibilities:

java.create("java.lang.Character", "t") should look for Constructor objects with java.lang.String or char or java.lang.Character as a parameter.

Dot references do not clone properly

The interpreter does not recognize assignment of a new property as a modification to an object. Thus, adding a new property or changing an existing property of one object will also affect its clones.

with statement

Implement a with statement to ensure variable scope. Would be used for closures in loops. This statement is not like JavaScript's with statement for aliasing variables. It is like the let statement that makes sure variables are in a unique scope context. Proposed syntax:

def x = (a, b, c) {
    var funcs = [];
    for (var  c = 0; c < 3; c++) {
        with (a, b, c) {
            def func = () {
                print(a ~ b ~ c);
            }

            funcs[c] = func;
        }
    }

    return funcs;
}

Clone parentheses regression

In the latest development branches, clone is an expression and can clone expressions. It has some issues at times that require it to have parentheses when it would seem like it wouldn't need parentheses. Need to investigate more.

println statement

Should convert print to NOT print newlines, and make a new println statement that prints newlines.

Cannot chain function calls together

If a function returns a function, the interpreter will not recognize something like func()();. You must assign the returned function to a variable and then call that variable.

Dynamic Properties (getters and setters)

Variables/properties should be able to have special get/set functions that act as getters and setters. This would not be that difficult to implement. Just as we check for a toString function in EveObject#toString(), we can also check for get/set functions in getField and putField. The only problem is that we will have to figure out how to do a reference variable, because we do not want to disallow direct assignment in set, but at the same time we do not want to expose pointer logic. Two proposed solutions would be to use a return statement from set, or create a new keyword that only works in the set function.

Use Prototypes as Object Literals

Prototypes are basically object literals already. The only problem is that they can only be defined in global scope and are evaluated as soon as the interpreter comes across a CreateProtoStatement. If we allow prototypes to be defined anywhere, they could be used as object literals. CreateProtoStatement will also need to be modified to place the prototype in the proper scope.

For full effect, we should allow anonymous prototypes that work as expressions. That way, the syntax would be more elegant if returning a prototype from a function.

Disallow shadowing

The interpreter should detect shadowing and then spit out an error. Alternatively, I could fix the interpreter to find shadowed variables properly...

Namespaces/Scope rework

For consideration: change the :: operator to be a namespace operator, and allow the interpreter to resolve scope a little bit more loosely than it does right now. We would lose explicit scope notation though. I suppose we could make a global namespace and implicitly add all global variables to it. That would keep the global:: operator working.

This also raises a problem about closures. If we search up the scope chain to find variables, we no longer need the closure:: operator. How do we detect closures? I suppose we can detect if a function is returned and then trigger closure scope there. But will that have any adverse effects?

Namespaces

Under this proposal, the new use of the :: operator would be for namespacing. Individual eve files could use a namespace statement/function to indicate what namespace they belong to. The file can then be imported and objects from that file referenced via namespace::obj. The internal code would not change much. An EveObject representing the namespace would be pushed on to the stack to find the variable. We may have to do it like closures and do a complete stack switch.

Namespaces would each have to have their own scope stack. The namespace function would be a native call that can only be called once, and it would create a new global.

Array access expression

Currently, [] is part of the identifier, and it is parsed out. This only works with numbers. Index access should be changed to a sort of unary operator that takes an expression inside the braces. This expression must evaluate to an int type. We will also need to allow multi-dimensional access (e.g. x[0][3]). The array expression evaluation should be a tree structure where [0] is evaluated before [3].

Self Regression

Clone an object inside a function, then assign a function as a property to the new clone. Refer to "self" inside the function. Get "self is undefined" error.

Closures

The interpreter has the ability to return functions, but they do not generate closure scope. Any reference to parent:: will be executed in the context of where ever the function gets returned. I would like to do closures, but I have to figure out how to do so. Perhaps a closure statement to go along with the def statement. This will make discovering closures easy.

When a closure statement is found, the interpreter will create a new EveFunction that has a closureScope field attached to it, and the parent:: scope operator will reference that scope.

Cloning Literals

Currently, literals are directly turned into EveObjects via WrappedPrimitiveExpression. This means that hooks and onClone events cannot pick up literal instantiation. Instead, literals should be cloned from prototypes corresponding to their data type. This will require implementation of String, Integer, Double, and Function prototypes and then changing WrappedPrimitiveExpression to clone from the proper prototype.

Cannot do literal.property

Literals are implicit clone statements, so if a property is attached to the proper prototype, the literal should be able to access it. None seem to work. int literals throw a scope error. string literals throw a syntax error.

I think it should be a syntax error to do literal.property simply because of the double data type. Parentheses around a literal should work, however. There are two root problems here:

  1. dots are treated as part of an identifier, not an expression.
  2. the interpreter seems to just throw out expressions that are not assigned to anything.

Dots will have to become an expression somehow. It will require a massive rethinking in ScopeManager. It may make the logic simpler though.

Allow uninitialized variables + push initialization

Variables should be able to be declared via var x; with no additional information. Getters/setters could then be attached to these. As a less obtuse syntax, the push statement should also allow initialization of variables. With a dict literal, it would make a powerful property syntax.

int/Integer mapping

Similar to String/Character/char, Eve int types need to map to int.class and java.lang.Integer.class.

Java Interop: ~ becomes ==

Due to some weird backtracking issue in the AST parser, ~ is being interpreted as == and an EqualsExpression is being created...

Null Pointer on empty file

ASTParser blows up if an empty file is passed:

Exception in thread "main" java.lang.NullPointerException
    at org.antlr.runtime.tree.BaseTreeAdaptor.isNil(BaseTreeAdaptor.java:70)
    at org.antlr.runtime.tree.TreeVisitor.visit(TreeVisitor.java:54)
    at org.antlr.runtime.tree.TreeFilter.downup(TreeFilter.java:115)
    at eve.core.EveCore.run(Unknown Source)
    at eve.core.EveCore.main(Unknown Source)

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.