ta0kira / zeolite Goto Github PK
View Code? Open in Web Editor NEWZeolite is a statically-typed, general-purpose programming language.
License: Apache License 2.0
Zeolite is a statically-typed, general-purpose programming language.
License: Apache License 2.0
For example, sin
, exp
, etc.
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:
define
syntax to allow refines
and defines
at the top.refines
and defines
in ValueConcrete
..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.
There is too much duplication and argument-passing.
Most things should be set up via .zeolite-module
, with CLI-based setup limited to very simple cases.
For example:
String
is immutable.BufferedWriter<Formatted>
that executes concatenation efficiently when flush()
is called.This likely isn't a new issue, but I just started noticing because now the file format is readable.
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.)
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.
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.
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 _
.
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:
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
.
Hand-written C++ sources currently can't depend on headers outside of the same module and its deps. This prevents adding Zeolite bindings for existing libraries that support C or C++ linkage.
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.
This requires the code to actually have access to the version number.
compileExecutableProcedure
is a good place to start, as well as many of the helpers in runCompiler
and runSingleTest
.
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.
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.
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.
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.
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.
Not really a big deal; just an aesthetic thing I've been wanting to do for a long time.
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.
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.
This will be necessary in order for libraries to be distributed separately from the compiler.
It could be some combination of an .rc
file, a global config, and environment variables.
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.)
All categories in .0rp
source files are visible outside of the module. There should be a way to mark certain categories as private to the module, probably in .zeolite-module
.
Maybe something like Haskell uses, e.g.
a `#x$lessThan` b
tests/multiple-defs
, which tests the compiler check for multiple definitions in separate .0rx
files. The compiler should also check .0rx
+.0rt
combinations..0rp
in a testcase
?.cpp
files.This is most noticeable when compiling the examples. This leads to the awkward situation where zeolite -r
is going to write the binary to whatever $PWD
was at the time the user compiled it the first time.
Type
in both Type$create()
and call<Type>()
.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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.