Releases: jinko-core/jinko
v0.3.0-jinx7
What's Changed
- ci: release on crates.io manually instead of using untrusted action by @tanguysegarra in #579
- Prepare release v0.3.0-jinx7 by @tanguysegarra in #580
Full Changelog: v0.3.0-jinx6...v0.3.0-jinx7
v0.3.0-jinx6
What's Changed
- release workflow: checkout before build by @tanguysegarra in #577
- Release v0.3.0-jinx6 by @tanguysegarra in #578
Full Changelog: v0.3.0-jinx5...v0.3.0-jinx6
v0.3.0-jinx5
What's Changed
- Typecheck generic functions properly by @CohenArthur in #482
- misc: Add square logo by @CohenArthur in #483
- Rework ffi calls by @CohenArthur in #490
- stdlib: Add simple bool.not() method by @CohenArthur in #492
- parser: Add base for error location by @CohenArthur in #484
- Add --check by @CohenArthur in #504
- docker: enable repl feature by @tanguysegarra in #507
- typechecker: create proper module and add TypeId by @tanguysegarra in #508
- Funcdec error location by @CohenArthur in #499
- Function Call location by @CohenArthur in #512
- Fix error formatting on multiple errors by @CohenArthur in #511
- Add location() to instruction trait by @CohenArthur in #516
- DecArg location by @CohenArthur in #514
- binary_op: wip: Parse location properly by @CohenArthur in #518
- Parse block location by @CohenArthur in #519
- Add error hints by @CohenArthur in #520
- Add location to assignments by @CohenArthur in #523
- incl: Add location information by @CohenArthur in #524
- Type loc by @CohenArthur in #526
- Add location info on variables by @CohenArthur in #521
- method_call: Add location info by @CohenArthur in #525
- Field access location by @CohenArthur in #527
- Add location to JkReturn and JkInst by @CohenArthur in #529
- jk_constant: wip: Add location to constants by @CohenArthur in #531
- loop: Add location information by @CohenArthur in #530
- Add location info on IfElse by @CohenArthur in #528
- Add errors with location by @CohenArthur in #513
- Parse proper type ids by @CohenArthur in #534
- Better error messages on duplicate function declarations by @CohenArthur in #535
- Cleanup generic implementation by @CohenArthur in #539
- Generic type declarations by @CohenArthur in #540
- install: Add WIP install jinko script by @CohenArthur in #489
- hints: Add source file to error message by @CohenArthur in #543
- Architecture fix by @CohenArthur in #544
- type_id: Refactor implementation by @CohenArthur in #542
- typechecker: Fix statement assignment to variables by @Skallwar in #545
- Cleanup imports in crate by @CohenArthur in #547
- Add proper generic resolution in specialized nodes by @CohenArthur in #546
- Improve error format when emitting by @CohenArthur in #556
- Cleanup logging by @CohenArthur in #560
- Add generic scopes to ScopeMap by @CohenArthur in #563
- Add reader trait by @Skallwar in #569
- Comment
link_with("libc.so.6")
in ffi testsuite by @BastienGermond in #570 - Disable vec include in stdlib by @tanguysegarra in #574
- Enable std feature when building the docker image by @tanguysegarra in #575
- Release v0.3.0-jinx5 by @CohenArthur in #576
Full Changelog: v0.3.0-jinx4...v0.3.0-jinx5
This release concerns the following target(s):
x86_64-unknown-linux
v0.3.0-jinx4
Developer changelog
This is quite a small release as the code inclusion bug was really nasty... and prevented any possible development using jinko
. A bunch of other bugs regarding generics have been fixed.
Multiple instructions such as VarAssign
and FieldAssign
did not expand generics properly. This has been fixed in the PR aiming for generic method calls to resolve correctly.
Previously, non-generic types were getting generically-mapped during the expansion pass. This meant that code like this:
type Something;
func takes_generic_and_some[T](one: T, two: Something) {}
would error out for not mapping the generic type Something
properly.
Typechecking had broken test functions by forbidding the user to declare a test with the same name as an existing function. This is now fixed. Test functions are also now typechecked properly, which wasn't the case before.
You are no longer allowed to perform generic function calls if the function does not contain generics.
func no_gen(a: int, b: string) -> float {
15.4
}
no_gen[int, string, bool](15, true); // Error
fmt_int
has been reimplemented completely in jinko! There is a small performance hit, and the implementation is extremely ugly due to a weird recursion argument mapping bug and the lack of switch cases/pattern matching.
The implementation was benchmarked against a similarly ugly python implementation, and a call to the previous version of fmt_int()
, which is simply a wrapper around rust's Display<i64>
implementation.
~/G/j/jinko (int-to-string|✚2…) $ hyperfine --warmup 10 'python python_impl.py' 'target/release/jinko jinko_impl.jk' 'target/release/jinko native_rust_fmt.jk'
Benchmark #1: python python_impl.py
Time (mean ± σ): 20.5 ms ± 1.4 ms [User: 16.9 ms, System: 3.9 ms]
Range (min … max): 15.7 ms … 23.8 ms 113 runs
Benchmark #2: target/release/jinko jinko_impl.jk
Time (mean ± σ): 6.1 ms ± 0.9 ms [User: 4.7 ms, System: 2.0 ms]
Range (min … max): 2.5 ms … 8.7 ms 258 runs
Warning: Command took less than 5 ms to complete. Results might be inaccurate.
Benchmark #3: target/release/jinko native_rust_fmt.jk
Time (mean ± σ): 2.4 ms ± 1.0 ms [User: 2.7 ms, System: 1.1 ms]
Range (min … max): 0.0 ms … 6.0 ms 543 runs
Warning: Command took less than 5 ms to complete. Results might be inaccurate.
Summary
'target/release/jinko native_rust_fmt.jk' ran
2.51 ± 1.05 times faster than 'target/release/jinko jinko_impl.jk'
8.40 ± 3.32 times faster than 'python python_impl.py'
A side-effect of these fixes is that we also accidentally gained the power to do generic type inference... But this behavior needs to be standardized and tested on its own:
ext func debug[T](instance: T); // builtin function
debug(15);
debug("s");
type Complex(real: int, imaginary: int);
debug(Complex(real: 15, imaginary: 12));
No need to call debug[int](15)
anymore!
Language changelog
Full Changelog: v0.3.0-jinx3...v0.3.0-jinx4
v0.3.0-jinx3
Developer changelog
Thanks to @tanguysegarra, we now have multiple different tags over on dockerhub. If you go over to the tags tab, you'll now find the latest
tag which corresponds to the latest release (or pre-release like this one) and bleeding
which is updated with the most recent version of the interpreter on the default branch.
@SanderJSA worked to improve the string formatting situation and create the needed instructions during the parsing phase instead of the execution phase. Before, each string would get parsed and expanded at runtime: This is no longer the case.
Thanks to this change, we also get all other phases of the context "for free": The nodes to expand are now typechecked like any other, can use generics, andw ill get optimized once that is in.
We can also update formatting delimiters ('{'
and '}'
) if we desire to use them by themselves: For example,
> name = "jinko"
> println("hey {jinko}")
"hey jinko"
> println("hey \{jinko\}")
"hey {jinko}"
We also now have escaped characters such as \t
or \n
! Meaning that we can properly print newlines from the stdlib without necessarily relying on the println
builtin function.
Thanks to his work, the string interpolation feature is now complete enough that I felt confident merging it. This will make tiny scripts easier to write, without relying on multiple calls to concat()
. Thanks!
@n1tram1 started working on an online REPL for the language in order to showcase it. In order to do so, @Skallwar started work on getting the jinko
crate to compile with a WASM target, as well as adding an eval()
function to develop easy REPLs. This meant splitting the code using rust features, to avoid platform dependent interactions such as dynamic library loading or uses of stdin
and stdout
. The eval()
function is also now available for very easy integration of the jinko
language to rust code, as showcased in the simple-repl example.
Work on generics has started in the interpreter. The changes are massive and extremely complex. I decided to focus on generic functions instead of generic types, as they are more complex but easier to test. The implementation still feels extremely fragile, and should not be relied on. The pipeline is as follows:
___________________
| |
| TypeChecking 1 |
|___________________|
|
v
___________________
| |
| Generic expansion |
|___________________|
|
v
___________________
| |
| Generic resolving |
|___________________|
|
v
___________________
| |
| TypeChecking 2 |
|___________________|
Splitting the typechecking pass in two allows for two things:
1/ Resolving generic calls and declarations after the arguments have been typechecked,
in order to generate proper versions of each declarations
2/ Declaring functions after they are being called. This is a feature of many modern
languages, and is still not present in jinko
.
The type is now also cached in every instruction, to not reevaluate unecessary types during the second phase of the typechecking. This adds a lot of mutability, which I am quite sad about, but was necessary.
The generic typechecking works as follows:
If a function declaration contain generic types, it is not typehchecked during the first phase. A typical generic function looks something like this:
func call_method_on_generic[T](animal: T) -> string {
animal.get_name()
}
type Dog;
func get_name(d: Dog) -> string {
"doug"
}
rex = Dog;
call_method_on_generic(rex);
Since the type T
does not exist, there is no point in checking that a get_name()
method exists on it.
However, it makes sense for the interpreter to realize that we'd like to use the call_method_on_generic
function with the Dog
type, and to generate the following function declaration:
// The name comes from mangling the function name and the resolved generics. The user
// cannot directly call these mangled functions, or generate them either as they are not
// valid identifiers. But we are waaaaay paste the parsing phase when generating these, so
// the rules do not apply anymore :)
func call_method_on_generic+Dog(animal: Dog) -> string {
animal.get_name()
}
This function can then get typechecked, and we can make sure that a get_name()
method exists for the type Dog
: This is just a regular function declaration!
The next step is to replace the call to call_method_on_generic(rex)
with its newly generated counterpart: call_method_on_generic+Dog(rex)
The generics pass is a simple "visitor" comprised of two functions. Each instruction runs them on itself, before calling it on its subinstructions (i.e an if_else
block needs to do generic expansion on its condition, its if
block and its else
block).
There are still a lot of issues with generic function calls and declarations, namely:
1/ No type inference. The above example would not work, as we cannot yet infer the correct call from the argument's type. This should not be hard to do, but is still unimplemented. You need to specify the generic types at all times for now, i.e: call_method_on_generic[Dog](rex)
2/ Parsing errors: We cannot call generic methods yet: rex.call_method_on_generic[Dog]()
fails, while it shouldn't.
The issues haves the generic label and should not be too hard to solve. Focus should also be shifted to generic types, as they are the final step required to have a proper generic standard library and interesting types such as Maybe[T]
, Result[T, E]
and so on.
Language changelog
- String formatting for expressions between curly brackets
- Character escaping
- Generic function declarations and calls
Full Changelog: v0.3.0-jinx2...v0.3.0-jinx3
v0.3.0-jinx2
What's Changed
- Allow multi type parsing by @CohenArthur in #349
- Parse list of generic types in function declaration by @CohenArthur in #341
- Type instantiation and Function calls generics by @CohenArthur in #343
- Parse generic type declarations by @CohenArthur in #380
These PRs add the parsing of generic types in function calls, type
instantiations, function declarations and type declarations. The syntax is the
following:
type SomeType[T](member: T);
type OtherType[T, U, V](member: T, member2: U, member3: V);
func takes_generic[T](arg: T) -> T { ... }
instance = SomeType[T](member: some_argument);
takes_generic[T](some_argument);
Thanks to @Skallwar, we now have LTO release builds which are much smaller than
previously. Thanks to you and @tanguysegarra 's efforts, this means we have a
1.9MB large docker image for jinko!
- Parse and instantiate empty types by @CohenArthur in #348
This enables the concept of empty-types or value-types: Types that can be instantiated,
but do not contain any fields. They provide a lot of type safety and can be optimized
and removed completely very easily. The syntax is the following:
type Empty; // declaration
e = Empty; // instantiation
They allow the Maybe
type to be implemented in the following fashion:
type Nothing;
type Maybe[T](inner: T | Nothing);
They also allow the representation of enums once we have multi-types:
type Horse;
type Cat;
type Dog;
type Animal(Horse | Cat | Dog);
-
Add
NoReturn
type by @CohenArthur in #382 -
binop: Allow binary operation as boolean by @CohenArthur in #394
-
Allow function calls as booleans by @CohenArthur in #383
Thanks to @Skallwar, it is now much cleaner to execute expressions and cast
them as booleans for if-else conditions. Since we now have a typechecker, we
can completely avoid checking the type of variables also at execution. This should speed
up the interpreter and improve safety overall.
- docker: use alpine instead of debian by @tanguysegarra in #397
- ci: add docker stage by @tanguysegarra in #398
- ci: add specific dockerhub releases by @tanguysegarra in #411
- ci: remove docker release when push to master by @tanguysegarra in #413
We now have a fantastic Dockerfile and docker image on hub.docker.com thanks to
@tanguysegarra. It is build automatically on each push to master and available as
jinko/jinko:latest
.
- Add --test flag to the interpreter by @CohenArthur in #399
We can now run tests declared in a file with the test
keyword! Once we have a few more
abstractions, we will be able to write testsuites entirely in jinko. What is currently
missing is an assertion
library, as well as a few abstractions.
- Resolve fixed parser issues by @CohenArthur in #393
- Add Args.count() by @CohenArthur in #381
- Fix arg_get builtin by @Skallwar in #391
- Fix empty string parsing by @Skallwar in #405
- Release v0.3.0-jinx2 by @CohenArthur in #412
- Switch to Rust edition 2021 by @Skallwar in #385
- Rename Token::type_tok by @Skallwar in #386
Full Changelog: v0.3.0-jinx1...v0.3.0-jinx2
v0.3.0-jinx1
What's Changed
- Start Implementing new parser by @SanderJSA in #288
- Add builtin parsing by @SanderJSA in #305
- Add return parsing by @SanderJSA in #308
- Parse extern function declarations by @SanderJSA in #317
- Fix variable mutation in block by @CohenArthur in #335
- Add comparison operators by @CohenArthur in #334
- Support block statements by @SanderJSA in #347
- Parse expression between parentheses by @CohenArthur in #337
- Refactor spaced identifiers into own function by @SanderJSA in #353
- Setup BorsNG by @CohenArthur in #355
- Add
--no-std
option by @Yumasi in #357 - Only fail token parsing if alphanum_ is next by @CohenArthur in #363
- stdlib: Remove shell library (moved to oslib) by @CohenArthur in #360
- generics: Update DESIGN and SYNTAX by @CohenArthur in #359
- Split project in core crate and interpreter by @CohenArthur in #356
- Fix functional tests in new parser by @CohenArthur in #352
- docker: add basic Dockerfile to run jinko interpreter by @tanguysegarra in #370
- docker: fix deployed image by @BastienGermond in #373
- Improve parser logic and performance by @CohenArthur in #374
- Release v0.3.0-jinx1 by @CohenArthur in #376
New Contributors
- @Yumasi made their first contribution in #357
- @tanguysegarra made their first contribution in #370
- @BastienGermond made their first contribution in #373
Full Changelog: v0.2.0...v0.3.0-jinx1
v0.2.1
v0.2.0
Major changes:
- Add static typechecker
- Add < and > operators in #321
- Implement correct for loop behavior in #316
- Add FFI
- Add builtin functions
Minor changes:
- Add args handling library in #314
- stdlib/exit: Add exit() function in #318
- Add Iter and Range in #280
- Add install script to package standard library in #309
- Load libraries from path in #310
- ffi: Allow loading libraries without full path in #295
- Add shell library abstraction in #294
- Add link_with() builtin and start of FFI module
This release concerns the following target(s):
x86_64-unknown-linux