Skip to content

Commit fa28c44

Browse files
authored
Merge pull request #60 from helixlang/compliance/current-to-new-standard
**Extended Description:** This merge brings the `compiler-v0.0.1` branch into alignment with the evolving Helix language standard. The goal of this update is to unify syntax conventions, improve clarity of declarations, and expand the core runtime library with essential functionality for both developers and end-users. The updates span parser refactors, runtime improvements, and new standard library APIs, making this one of the most substantial shifts since the compiler’s initial release. While most changes are backward-compatible, operator declarations introduce a breaking change that requires migration. ### Why These Changes? * **Consistency:** Operator and interface syntax were updated to follow a single, predictable pattern (`impl` replaces `has`, operator functions now use `fn op`). This simplifies parsing and improves readability. * **Ergonomics:** The shorthand `impl` and `derives` syntax reduces boilerplate, making generic constraints and trait usage more concise without sacrificing clarity. * **Capability Expansion:** New corelib APIs (`std::process`, `std::system`, `std::Stacktrace`, `std::ABI`) provide critical runtime utilities for process management, debugging, and ABI-level symbol handling. * **Error Handling Improvements:** Panics now default to throwing at the panic site, removing the need for explicit `?` returns while still surfacing clear diagnostics. ### Key Additions * Operator declarations migrated to new form. * Shorthand syntax for `impl` and `derives` added. * New runtime APIs in `std`: * Process spawning (`Subprocess`, `ProcessOutput`). * Command execution (`system`). * Symbol mangling/demangling (`ABI`). * Runtime stacktraces. * Updated test suite and build system to reflect new standards. * Improved parsing for generics, `where` bounds, and declaration handling. ### Breaking Changes * **Operator Declarations:** * **Old:** `op <symbol> fn <name>(...) -> <ret> {}` * **New:** `fn op <symbol>(...)[<alias>] -> <ret> {}` * Requires clause update is **not** breaking — old syntax remains supported. ### Migration Notes * All operator functions must be rewritten to the new `fn op` form. * No changes required for `requires` clauses, but adopting the new form is recommended. * Code relying on `has` must be updated to `impl`. ### Impact This merge provides a cleaner, more consistent foundation for Helix going forward, while introducing key runtime and tooling capabilities necessary for real-world application development. Contributors should expect minor refactoring in existing codebases (mostly operator declarations), but otherwise migration is smooth.
2 parents b77aadc + 994a46b commit fa28c44

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+3208
-888
lines changed

.vscode/launch.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
"name": "Launch",
88
"target": "helix",
99
"args": [
10-
"/Volumes/Development/Projects/Helix/helix-lang/tests/main.hlx",
11-
"--emit-ast"
10+
"tests/test.hlx"
1211
],
13-
"cwd": "${cwd}/helix-lang/",
12+
"cwd": "${cwd}",
1413
"stopAtEntry": true
1514
}
1615
]

assets/code/arc/async-example.hlx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ async fn fetch_data() -> string {
66
}
77

88
fn main() {
9-
let future: Future = spawn fetch_data(); // start a os-manged child process
10-
let data = await future;
9+
var future: Future = spawn fetch_data(); // start a os-manged child process
10+
var data = await future;
1111

1212
for i in data:
1313
print(f"{i=}", end=", ");

assets/code/arc/control-flow-example.hlx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
let x: int = 10;
1+
var x: int = 10;
22

33
if x > 5 {
44
print("x is greater than 5");
@@ -12,6 +12,6 @@ unless x < 5 { // unless is the same as if not
1212
print("x is 5 or less");
1313
}
1414

15-
for let i: int = 0; i < 10; i += 1{
15+
for var i: int = 0; i < 10; i += 1{
1616
print(i);
1717
}

assets/code/arc/ffi-example.hlx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ ffi "python" import sympy as sp;
22
ffi "c++" import "circle.hh";
33

44
fn main() {
5-
let eq1: sp::Eq = sp::Eq(x + y, 10)
6-
let eq2: sp::Eq = sp::Eq(x - y, 4)
7-
let solutions = sp.solve((eq1, eq2), (x, y)); // type inferd by the compiler
5+
var eq1: sp::Eq = sp::Eq(x + y, 10)
6+
var eq2: sp::Eq = sp::Eq(x - y, 4)
7+
var solutions = sp.solve((eq1, eq2), (x, y)); // type inferd by the compiler
88

99
print(solutions);
1010

11-
let circle = circle::Circle{10, 20};
11+
var circle = circle::Circle{10, 20};
1212

1313
print(circle->to_string());
1414
}

assets/code/arc/showcase.hlx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class Point {
2-
let x: int;
3-
let y: int;
2+
var x: int;
3+
var y: int;
44

55
eval fn Point(self, x: int, y: int) {
66
self.x = x;
@@ -18,14 +18,14 @@ class Point {
1818
}
1919

2020
fn main() {
21-
let p = Point(0, 0);
21+
var p = Point(0, 0);
2222

2323
for i in 1..4 {
2424
p.move(i, i);
2525
p.display();
2626
}
2727

28-
let value: u32 = p.x as u32;
28+
var value: u32 = p.x as u32;
2929

3030
match value {
3131
0 -> print("The point is at the origin"),

assets/code/arc/type-bounds-example.hlx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ interface Drawable {
44
}
55

66
class Circle derives Drawable {
7-
let radius: float;
7+
var radius: float;
88

99
fn Circle(self, radius: float) {
1010
self.radius = radius;
@@ -20,7 +20,7 @@ class Circle derives Drawable {
2020
}
2121

2222
class Square derives Drawable {
23-
let side: float;
23+
var side: float;
2424

2525
fn Square(self, side: float) {
2626
self.side = side;
@@ -35,15 +35,15 @@ class Square derives Drawable {
3535
}
3636
}
3737

38-
fn draw_all(...objects: T)
39-
requires <T> if T is Drawable {
38+
fn <T> draw_all(...objects: T)
39+
requires T impl Drawable {
4040
for obj in objects {
4141
obj.draw();
4242
}
4343
}
4444

4545
fn main() {
46-
let shapes = (Circle(1.0), Square(1.0), Circle(2.0)); // type of tuple
46+
var shapes = (Circle(1.0), Square(1.0), Circle(2.0)); // type of tuple
4747

4848
draw_all(shapes...);
4949
}

assets/code/language/types.hlx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ fn main() -> i32 {
1414
delete int_holder
1515
}
1616

17-
// Helix has type inference, so theres no need to specify the type of value. But any modifiers
17+
// Helix impl type inference, so theres no need to specify the type of value. But any modifiers
1818
// like pointers, questionable, etc. must be specified. (enforced for readability and safety)
1919
var *value? = int_holder.get(1)
2020

2121
if !(value?) { // if value is null or panicked
2222
value = Heap::construct<int>(21) // Equivalent to new int(21) in C++
2323
}
2424

25-
// Helix has support for named parameters/default values
25+
// Helix impl support for named parameters/default values
2626
var *invalid_value? = int_holder.get(index=100) // Attempt to fetch an out-of-bounds value
2727

2828
if invalid_value?:
@@ -40,14 +40,14 @@ fn main() -> i32 {
4040
// Structs in Helix are data containers with no methods.
4141
// They can include: operator overloads, nested structs, destructors, enums, and fields.
4242
// All fields are public by default.
43-
struct Data {
43+
struct <T> Data {
4444
// Regular pointers: non-nullable, no arithmetic, and auto-dereferenced (like references in other languages).
4545
var value: *T?
4646
}
4747

4848
// Classes in Helix support methods, fields, and constructors.
4949
// Fields are private by default, while methods and constructors are public by default.
50-
class Holder requires <T> {
50+
class <T> Holder {
5151
// Unsafe pointers: nullable, allow pointer arithmetic, and require manual dereferencing.
5252
var num_values: usize
5353
var many_values: unsafe *Data
@@ -67,7 +67,7 @@ class Holder requires <T> {
6767
}
6868
}
6969

70-
op delete fn (self) {
70+
fn op delete (self) {
7171
for i in 0..self.num_values {
7272
if self.many_values[i].value? {
7373
Heap::drop(self.many_values[i].value)
@@ -77,8 +77,7 @@ class Holder requires <T> {
7777
Heap::drop(self.many_values)
7878
}
7979

80-
fn get(self, index: usize) -> *T?
81-
requires <T> {
80+
fn <T> get(self, index: usize) -> *T? {
8281
if index < self.num_values {
8382
return self.many_values[index].value
8483
} else {

build.hlx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Everything in the api:
3+
fn set_target(name: string)
4+
fn end_target(name: string? = null)
5+
fn set_builddir(path: string)
6+
fn set_project(name: string)
7+
fn set_version(version: string)
8+
fn set_description(description: string)
9+
fn add_links(links: vec::<string>)
10+
fn add_link(link: string)
11+
fn add_include(include: string)
12+
fn add_includes(includes: vec::<string>)
13+
fn add_source(source: string)
14+
fn set_linkage(linkage: Linkage)
15+
fn after_build(callback: fn (*Target) -> void)
16+
fn before_build(callback: fn (*Target) -> void)
17+
fn set_cxxflags(flags: vec::<string>)
18+
fn add_define(name: string, value: string)
19+
20+
*/
21+
import vial::rt::api::*;
22+
23+
fn build() -> i32 {
24+
25+
set_target("vial_runtime");
26+
add_source("vial/rt/api.hlx");
27+
add_source("vial/rt/logger.hlx");
28+
add_source("vial/rt/fs.hlx");
29+
30+
add_include("vial/");
31+
set_cxxflags(["-std=c++20", "-Wall", "-Wextra", "-Werror"]);
32+
add_define("USING_MSVC", "true");
33+
add_define("USING_CLANG", "true");
34+
end_target();
35+
36+
set_target("vial_build");
37+
add_source("vial/vial.hlx");
38+
add_include("vial/");
39+
40+
set_cxxflags(["-std=c++20", "-Wall", "-Wextra", "-Werror"]);
41+
42+
add_define("USING_MSVC", "true" );
43+
add_define("USING_CLANG", "true" );
44+
end_target();
45+
46+
return 0;
47+
}

lang/arc/.hlx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55

66
class Point {
7-
pub let x: f32
8-
pub let y: f32
7+
pub var x: f32
8+
pub var y: f32
99
}
1010

1111

@@ -15,7 +15,7 @@ class Shape {
1515

1616
class Circle derives Shape {
1717
pub fn area() -> f32 { return 3.14 * radius * radius }
18-
pub let radius: f32
18+
pub var radius: f32
1919
}
2020

2121
class Base {
@@ -53,12 +53,12 @@ fn make_noise(a: Box<Animal>) {
5353
print(a.speak()) // Uses v-table lookup
5454
}
5555

56-
fn make_noise(a: T) requires <T> if T has Animal {
56+
fn <T> make_noise(a: T) requires T impl Animal {
5757
print(a.speak()) // No v-table lookup, method is inlined
5858
}
5959

6060
class SecureData {
61-
priv let key: str
61+
priv var key: str
6262

6363
pub fn get_key() -> str { return key }
6464
}

0 commit comments

Comments
 (0)