In FunC (and in Tolk before) throwing an exception is just
calling a built-in function:
> throw 123; // actually, __throw(123)
Since it's a regular function, the compiler was not aware
that execution will stop, and all following code is unreachable.
For instance, `throw` in the end on function needed to be
followed by `return` statement.
Now, `throw` interrupts control flow, all statements after
it are considered unreachable. At IR level, code Ops are
also not produced.
This works because a built-in __throw() now has `never` type.
It can also be applied to custom functions:
> fun alwaysThrow(): never { throw 123; }
The code after alwaysThrow() call will also be unreachable.
With the introduction of nullable types, we want the
compiler to be smart in cases like
> if (x == null) return;
> // x is int now
or
> if (x == null) x = 0;
> // x is int now
These are called smart casts: when the type of variable
at particular usage might differ from its declaration.
Implementing smart casts is very challenging. They are based
on building control-flow graph and handling every AST vertex
with care. Actually, I represent cfg not a as a "graph with
edges". Instead, it's a "structured DFS" for the AST:
1) at every point of inferring, we have "current flow facts"
2) when we see an `if (...)`, we create two derived contexts
3) after `if`, finalize them at the end and unify
4) if we detect unreachable code, we mark that context
In other words, we get the effect of a CFG but in a more direct
approach. That's enough for AST-level data-flow.
Smart casts work for local variables and tensor/tuple indices.
Compilation errors have been reworked and now are more friendly.
There are also compilation warnings for always true/false
conditions inside if, assert, etc.
This commit introduces nullable types `T?` that are
distinct from non-nullable `T`.
Example: `int?` (int or null) and `int` are different now.
Previously, `null` could be assigned to any primitive type.
Now, it can be assigned only to `T?`.
A non-null assertion operator `!` was also introduced,
similar to `!` in TypeScript and `!!` in Kotlin.
If `int?` still occupies 1 stack slot, `(int,int)?` and
other nullable tensors occupy N+1 slots, the last for
"null precedence". `v == null` actually compares that slot.
Assigning `(int,int)` to `(int,int)?` implicitly creates
a null presence slot. Assigning `null` to `(int,int)?` widens
this null value to 3 slots. This is called "type transitioning".
All stdlib functions prototypes have been updated to reflect
whether they return/accept a nullable or a strict value.
This commit also contains refactoring from `const FunctionData*`
to `FunctionPtr` and similar.
In FunC (and in Tolk before), the assignment
> lhs = rhs
evaluation order (at IR level) was "rhs first, lhs second".
In practice, this did not matter, because lhs could only
be a primitive:
> (v1, v2) = getValue()
Left side of assignment actually has no "evaluation".
Since Tolk implemented indexed access, there could be
> getTensor().0 = getValue()
or (in the future)
> getObject().field = getValue()
where evaluation order becomes significant.
Now evaluation order will be to "lhs first, rhs second"
(more expected from user's point of view), which will become
significant when building control flow graph.
* add folders smartcont and lib only to release for having a small download link
* allow usage of patter in file name
* upgrade upload-release-action@v2 to v3
* Revert "upgrade upload-release-action@v2 to v3"
This reverts commit 516126084a.
* use gh cli for upload smartcont_lib
* use gh cli for upload smartcont_lib
* gh requires gh_token
* clean up
In C++20, macro 'ATOMIC_FLAG_INIT' has been marked as deprecated.
We need still to use it to be able to compile for C++17.
For now, just suppress this warning.
They are not keywords anymore.
> var cell = ...;
> var cell: cell = ...;
Motivation: in the future, when structures are implemented, this obviously should be valid:
> struct a { ... }
> var a = ...;
Struct fields will also be allowed to have names int/slice/cell.
It works both for reading and writing:
> var t = (1, 2);
> t.0; // 1
> t.0 = 5;
> t; // (5, 2)
It also works for typed/untyped tuples, producing INDEX and SETINDEX.
Global tensors and tuples works. Nesting `t.0.1.2` works. `mutate` works.
Even mixing tuples inside tensors inside a global for writing works.
In FunC (and in Tolk before), tensor vars (actually occupying
several stack slots) were represented as a single var in terms
or IR vars (Ops):
> var a = (1, 2);
> LET (_i) = (_1, _2)
Now, every tensor of N stack slots is represented as N IR vars.
> LET (_i, _j) = (_1, _2)
This will give an ability to control access to parts of a tensor
when implementing `tensorVar.0` syntax.
Currently, tolk-tester can test various "output" of the compiler:
pass input and check output, validate fif codegen, etc.
But it can not test compiler internals and AST representation.
I've added an ability to have special functions to check/expose
internal compiler state. The first (and the only now) is:
> __expect_type(some_expr, "<type>");
Such a call has special treatment in a compilation process.
Compilation fails if this expression doesn't have requested type.
It's intended to be used in tests only. Not present in stdlib.
* improve windows builds
* install nasm for openssl compilation on win
* install nasm for openssl compilation on win for github
* add create-state, proxy-liteserver, rldp-http-proxy, http-proxy, adnl-proxy, dht-server, libtonlibjson.so and libemulator.so to docker image
* build new artifacts inside Docker
* add files smartcont/auto/* to docker image
* build arm64 in docker branch build
* improve secp256k1 build
* adding natively portable binaries (all statically linked with libc++, without nixpkgs help) for x86-64 linux
* install missing headers on ubuntu 20.04
* use clang-16 on ubuntu 20.04
* remove gsl for portable artifacts; add -f key to generate-random-id in order to read addr_list from file;
* typo
* decode json
* decode json
* add github workflow for appimages creation
* add missing dependencies
* use libc++ for appimages artifacts
* typo
* appimages wihtout libc++
* appimages with libc++ and some checks
* add appimages to release (for testing)
* add appimages to release (for testing)
* add appimages to release (for testing)
* add appimages to release (for testing) 2
* add appimages to release (for testing) 3
* appimages only on ubuntu 22 with ssl-3 for now
* appimages only on ubuntu 20 with ssl-3 for now
* appimages only on ubuntu 20 with ssl-3 for now
* add export LD_LIBRARY_PATH="${APPDIR}/usr/lib:${LD_LIBRARY_PATH}" to appimage AppRun
* create release
* appimages without jemalloc
* bind specific libraries to appimages
* add libreadline
* add plain portable libs
* add proper /lib/x86_64-linux-gnu/libreadline.so.8
* app images build with libc
* try to ensure ABI compatibility with older glibc
* try to ensure ABI compatibility with older glibc for shared libraries
* shared lib without libc but with D_GLIBCXX_USE_CXX11_ABI and -static-libgcc -static-libstdc++
* add -fPIC -fcommon
* add /lib/x86_64-linux-gnu/libstdc++.so.6 to static binaries
* add -static-libgcc -static-libstdc++ to libtonlibjson and emulator when PORTABLE=1
* add -static-libgcc -static-libstdc++ to libtonlibjson and emulator when PORTABLE=1
* update emulator portable
* Update CMakeLists.txt
* test portable macos binaries
* do not use -static-libgcc -static-libstdc++ on mac for shared libs
* do not use -static-libgcc -static-libstdc++ on mac for shared libs
* adjust create-release.yml
* minor fixes, typos
* minor fixes
* linux apps double check
* avoid infinite loop when place in system bin dir
* avoid infinite loop when place in system bin dir 2
* test compilation on linux arm64
* test appimages on arm64 linux
* test appimages on arm64 linux 2
* add portable linux arm64 to release
* clean up
* update README.md