Releases: bitdotgames/BHL
v2.0.0-beta13
- Using '..' prefix instead of '.' for global namespace symbols lookup
- Native class and interface symbols are now explicitely setup lazily to avoid declaration order dependencies
v2.0.0-beta11
Warning: this release breaks BC with previous beta releases
- Passing values stack more explicitly
- Fixed casting to (int) which now internally uses ulong
- Making VM.TryFindFuncAddr(..) public and adding VM.Start(..) variation which accepts FuncAddr
- Adding line number to InitFrame opcode
- Adding better async yield chain calls validation
- Adding more universal binary operator overloads: now they are static methods
var op = new FuncSymbolNative("+", FuncAttrib.Static, ts.T("Color"), 0,
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status)
{
var other = (Color)stack.PopRelease().obj;
var self = (Color)stack.PopRelease().obj;
var v = Val.NewObj(frm.vm, self + other, Types.Color);
stack.Push(v);
return null;
},
new FuncArgSymbol("self", ts.T("Color")),
new FuncArgSymbol("other", ts.T("Color"))
);
cl.Define(op);
v2.0.0-beta1
Warning: this release breaks BC with previous alpha releases
Introducing new async/yield semantics
- Now it's required to mark coroutine functions which may execute longer than one frame with async keyword.
- Any function using yield statements is considered a coroutine.
- Coroutines must be called using yield statement.
- yield calls are not allowed by compiler inside of defer {..} blocks.
- Pointer to async function is considered compatible with pointer with the same signature to non-async function. But not vice versa.
Quick async/yield example:
async func bool GetBool() {
yield while(IsReady())
yield() //yields one tick as before
return yield CalcBool() //CalcBool() must be an async function as well
}
Async pointers compatibility. The following code works just fine since non async functions are a superset over async ones.
async func int () p = func int () { return 10 }
p()
However this is a compile time error: non async pointer can't be assigned an async function:
func int () p = async func int () {
yield()
return 10
}
Unifying function attributes syntax
All function attributes (async, virtual, static, etc) must come before func keyword. For example:
class Bar {
async virtual func int foo() { ..}
}
The following code is now a compile time error:
class Bar {
async func virtual int foo() { ..}
}
Calling functions in a global namespace is now forbidden
The following code is a compile time error:
namespace foo {
Config conf = GetConfig("hey")
}
It rather should be:
namespace foo {
Config _conf
func Config conf() {
if(_conf == null) {
_conf = GetConfig("hey")
}
return _conf;
}
}
Added support for simplified strings concatenation
string foo = "world "
foo += "hello\n"
v2.0.0-alpha78
Implicit variable type declaration with 'var' keyword
func string test() {
var a = "Hello World"
return a
}
Convenient nested namespaces declarations
namespace foo.bar {
…
}
fail() built-in function removed
fail() function removed until we have a better understanding about handling of failures in version 2.0. It was not widely used and didn't allow any recovering in userland code. Once there's a more robust and reliable solution it will be introduced once again.
v2.0.0-alpha67
- Better protection against stack interleaving in paral branches
- Better compile time errors reporting
- Better handling of return keyword parsing ambiguities
v2.0.0-alpha60
Maps foreach and json-alike initialization support
foreach(string k,int v in m) {
…
}
[string]int m = {“Bob” : 42, “Sally” : 69}
Nested classes
class Bar {
class Foo {
int f
func int getF() {
return this.f
}
}
}
Bar.Foo foo = {f: 1}
foo.getF()
Nested class interfaces
class Bar {
interface IFoo {
func int foo()
}
}
class Foo : Bar.IFoo {
func int foo() {
return 1
}
}
Nested class enums
class Bar {
enum E {
E1 = 1
E2 = 2
}
func E getEnum() {
return E.E2
}
}
Bar bar = {}
int what = (int)Bar.E.E1 + (int)bar.getEnum()
Static class fields and methods
class Bar {
static int bar
func static int foo() {
return 42
}
}
Bar.bar = 14
int sum = Bar.bar + Bar.foo()
Variadic function arguments
func int sum(...[]int ns) {
int s = 0
foreach(int n in ns) {
s += n
}
return s
}
sum(1, 2, 3)
sum(...[1, 2, 3])
v2.0.0-alpha39
Basic polymorphic methods support
class Foo {
int a
int b
func virtual int getA() {
return this.a
}
func int getB() {
return this.b
}
}
class Bar : Foo {
int new_a
func override int getA() {
return this.new_a
}
}
Better support for local variables scopes
The following code was impossible before resulting in "already declared symbol i" error:
{
int i = 1
i = i + 1
trace((string)i)
}
{
string i
i = ""foo""
trace((string)i)
}
The following code is now possible as well (variable i is declared twice in each loop condition section):
for(int i=0;i<5;i++) {
…
}
for(int i=0;i<10;i++) {
…
}
Initial implementation of maps
[string]int m = {"wow" : 42}
m["hey"] = 14
if(!m.Contains("bar")) {
m["bar"] = 4
}
bool ok,int v = m.TryGet("bar")
if(ok) {
...
}
foreach(string k, int v in m) {
...
}
m.Remove("hey")
m.Clear()
Arbitrary order of symbols declarations
For example the following code was not valid before resulting in "symbol Bar not found" error:
interface IBar {
func Bar circularDependency()
}
class Bar : IBar {
func Bar circularDependency() {
return this
}
}
Draft std of library implementation
import "std"
func main() {
std.io.WriteLine("Hello World!")
}
v2.0.0-alpha12
- More consistent addressing of enum items: using . instead of ::
enum Items {
BAR = 1
FOO = 2
}
func Items test() {
return Items.BAR
}
- Fixing namespace symbols lookup from inside a lambda
v2.0.0-alpha11
- Adding initial namespaces support which led to major internal type system overhaul
- Namespace symbol aliases not available yet
Conceptually namespaces are quite similar to the implementation found in C#: one is free to declare and nest namespaces anywhere in the code. It's possible to span namespaces across multiple files.
File: std/io.bhl
namespace std {
namespace io {
func int WriteLine(string line) {
…
}
}
}
File: main.bhl
import "std/io"
func main() {
std.io.WriteLine("Hello World!")
}
In case you need to explicitly lookup a symbol in the global namespace you have to prefix it with . (dot), for example:
namespace foo {
func yield() {
…
}
func test() {
yield() // will lookup foo.yield()
.yield() // will lookup built-in global yield()
}
}
v2.0.0-alpha10
- Adding basic support for interfaces
- Adding support for is T expression
- Adding support for as T expression
- Adding support for typeof(T) which returns type as a value of type Type
- Adding built-in func Type type(any o)
- Changing foreach syntax, making it more C# more alike: foreach(arr as a) -> foreach(a in arr)
- Internal clear distinction between Int and Float types for Val: Val.SetNum() -> Val.SetInt(..) and Val.SetFlt(..)
- LSP internal improvements
- VM internal optimisations