Giter VIP home page Giter VIP logo

zeolite's People

Contributors

ta0kira avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

zeolite's Issues

Allow "private" inheritance.

For example, SimpleOutput was implemented by hand (in C++) to inherit BufferedWriter<Formatted>, but it does not use refines BufferedWriter<Formatted> in the .0rp.

This is mostly useful for factory/singleton functions that return a parent interface rather than a concrete value, i.e., when the caller doesn't really need to know the inheritance relationship.

This can probably be done by:

  1. Updating the define syntax to allow refines and defines at the top.
  2. Adding a helper to merge in new refines and defines in ValueConcrete.
  3. When including new types when compiling the .0rx, "undo" the addition of the types from the .0rp and re-add them after merging with the new refines and defines from the definitions.

Overriding of inheritance (e.g., Writer<String> in the concrete and Writer<Formatted> in the define) might be a bit complicated to implement, so it might be better to skip that.

Make `String` concatenation more efficient.

For example:

  • Just chain them together, since String is immutable.
  • Implement a special BufferedWriter<Formatted> that executes concatenation efficiently when flush() is called.

Figure out how to mitigate future C++ source incompatibilities.

This will be important for modules that have hand-written C++ sources.

Detecting errors using version metadata would be helpful, but there also needs to be a more active approach to preventing errors.

For example, having a base module foo that gets configured to have a public dependency on foo/0.1.1, and putting the C++ sources in the latter instead of the former. (This would require the module author to have some sort of setup script or instructions.)

Make `TypeInstance` usage shared.

The main reason to do this is to remove types from the cache when they're no longer needed.

The cache can probably be handled by storing weak_ptr, having the type instance store an iterator to its cache entry, and removing itself in its destructor.

An alternative to this is to just disallow unbounded type recursion, e.g., prohibit this:

concrete Type<#x> {
  @type recursive (Int) -> ()
}

define Type {
  recursive (x) {
    if (x > 0) {
      \ Type<Type<#x>>$recursive(x-1)
    }
  }
}

That's probably not feasible for mutual recursion, however. Maybe the problem is using Type<#x> in param substitution.

Command to be executed prints in two separate parts when compiling binaries.

For example, when compilation of example/regex gets to RegexDemo, the clang++ command prints up until /tmp/zmain_??????.cpp, stops for a few seconds, and then prints the rest of the .o files. I can't tell if this is because gathering the .o deps takes a while or because the output is buffered. Flushing and strict evaluation in executeProcess didn't fix it.

Fix C++ code gen for tail calls.

A tail call in Zeolite should remain a tail call in C++ so that the C++ compiler has the option to optimize it.

Currently, the result is assigned to returns and then returns is returned. Just return the result directly if the return doesn't need to be constructed, i.e., any return other than return { ... } or return _.

Streamline C++ extensions.

I'm leaning toward generating most of the .cpp file so that the user's .cpp file looks something like this:

// Category_MyExtension.cpp

// Initially generated with --templates, then hand-edited by the user.

#include "Category_MyExtension.hpp"

INCLUDE_BASE(
  "CategoryBase_MyExtension.cpp",    // Generated. Contains Value_MyExtension, etc.
  ,                                  // Extra members for the category. (None.)
  int counter; S<TypeValue> parent;  // Extra members for values.
)

ReturnTuple Value_MyExtension::Call_myFunc(const S<TypeValue>& Var_self, 
                                           const ParamTuple& params, 
                                           const ValueTuple& args) {
  TRACE_FUNCTION("MyExtension.myFunc")
  // Hand-written function definition.
}

This approach will make maintenance easier (especially adding/removing functions), but it has a few complications that need to be worked out:

  • Unclear how to streamline initialization of extra members in the category/value constructors while still hiding implementation details.
  • Unclear how to remind the user to implement newly-added functions after initial template generation, other than having them write a no-op test so that they get a linker error.
  • Unclear how to allow helper functions, other than making all data members public.

Add syntax for grouping statements for use with `scoped`.

For example, something like this should be possible:

scoped {
  RawFileReader reader <- RawFileReader$open("file")
} cleanup {
  reader.freeResource()
} in {
  // some procedure using reader
}

At the moment, the closest alternative (semantically) is something like:

scoped {
  RawFileReader reader <- RawFileReader$open("file")
  // some procedure using reader
} cleanup {
  reader.freeResource()
} in scoped {
  // some procedure using reader
} in ~ empty

scoped was originally meant to act like {} scoping in C++, while also encouraging the user to separate scoped variables from the sub-procedure that uses them. We therefore don't want to generally allow {} scoping outside of scoped/cleanup.

Get rid of redundant return in C++ code gen.

Get rid of the unreachable return returns; at the end of functions that use explicit returns. This should be easy because ProcedureContext keeps track of unreachable points in the procedure.

Prevent cross-module definitions.

It might currently be possible to define a public concrete category from another module or from a testcase. This is because there isn't a separate map of categories from the current module when matching definitions to declarations.

Get rid of `{}` in mutiple return/assign syntax.

It makes parsing more complex because { ... } <- ... is similar to { ... }. (The latter is only available with scoped/cleanup at the moment.) The main consequence is misleading parser errors when something inside { ... } is invalid.

It should be fine to just remove {} from the parser and update all of the source files. The , and <- should be sufficient to avoid ambiguity.

This is also a major syntax change, so it might need a separate branch so that the readme isn't misleading to someone who has an older compiler version.

Add a "fast" mode to CLI.

There should be a mode to just compile a single .0rx into a binary without creating a cache or module config in the file's path.

Find a cleaner way to deal with builtin types internally.

Specifically, adding a new builtin type requires updating quite a few Haskell and C++ files. It's possible that the Haskell code only needs to directly refer to Bool (for conditionals) and the types used in literals, and the supporting code can (should?) be treated like any other module that has hand-written C++ code.

Add tests for compiling outside of `$ZEOLITE_PATH`.

All of the tests at the moment rely on that path, which is what allowed the issue fixed by a550db2 to happen.

tl;dr: Path resolution seemed fine because system modules (e.g., lib/util) happened to already be in the -p directory. It was the addition of --fast that revealed the problem, but only after installing the compiler.

Add flags to control compilation verbosity.

Now that zeolite has a proper installation process, many of the clang++ commands fill up the entire terminal view, or more. This output will not be helpful to people unless they need to report an issue, or they're curious about how the compiler works.

Look into the feasibility of anonymous structures, as a generalization of lambdas.

Possible syntax:

  • As a value type:

    @value map<#y> ([(#x) -> (#y)]) -> (List<#y>)
    
  • Creating a lambda value:

    List<Bool> bools <- intList.map(
      [(#x) -> (#y)] (x) { 
        return x.toBool() 
      })
    
  • Reference to a named function:

    List<Bool> bools <- intList.map([(#x) -> (#y)] Int$toBool)
    

The syntax will be easy; designing closure semantics will be the difficult part.

Allow contravariant params to have `defines` and `requires` filters?

Such param filters were originally allowed, but later I decided that there should be a "contains" relationship between filters before/after variance conversions. For example, if #x requires Y (#x→Y), then converting #x from A to B implies that A requires Y (A→Y) should contain B requires Y (B→Y), i.e., A→B→Y, implying A→B. The latter means that requires implies either covariance or invariance of #x.

The intuitive reasoning is that defines and requires imply reading something from the parameter, e.g., #x$equals(x,y) reads the equals function from #x. This results in using a contravariant type for reading when only writing should be allowed.

On the other hand, the parameter substitution is an immutable part of the object or function call, in the sense that any code using parameter #x uses #x as originally assigned; not as whatever it might be converted to. For example, any call to #x$equals(x,y) will use the "real" #x; not whatever #x might become via variance conversions.

So, I think the entire argument for allowing these filters hinges on those filters never being externally accessible after parameter substitution. In other words, if they are allowed, then at no future point can there be a language feature that allows retrieving a parameter from a value or type. (For example, something like using pattern-matching in C++ to extract a template parameter.)

Add better checks for definitions of `concrete` categories from `.0rp` files.

  • There is a quasi-test in tests/multiple-defs, which tests the compiler check for multiple definitions in separate .0rx files. The compiler should also check .0rx+.0rt combinations.
  • Should the compiler just disallow defining a category from a .0rp in a testcase?
  • It would help to be able to check for declarations that don't have definitions; however, that complicates defining those categories in .cpp files.

Make atomic operations in the language thread-safe in the C++ output.

  • Creation of type instances, e.g., the Type in both Type$create() and call<Type>().
  • Copying value references, e.g., arg passing, variable assignment.

As long as the only object state is data members and static parameters, and (future) lambdas don't use C++ references in closures, everything else should be fine.

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.