sm
This commit is contained in:
45
examples/38-build-config.sx
Normal file
45
examples/38-build-config.sx
Normal file
@@ -0,0 +1,45 @@
|
||||
#import "modules/std.sx";
|
||||
#import "modules/compiler.sx";
|
||||
|
||||
// --- #run build configuration ---
|
||||
// build_options() returns a BuildOptions struct at compile time.
|
||||
// Methods on it (add_link_flag, set_output_path) are compiler builtins
|
||||
// that configure the build without runtime cost.
|
||||
|
||||
configure_build :: () {
|
||||
opts := build_options();
|
||||
// These calls are intercepted by the compiler at compile time.
|
||||
// On a normal (non-wasm) target, inline if gates them off.
|
||||
inline if OS == .wasm {
|
||||
opts.set_output_path("sx-out/wasm/test.html");
|
||||
opts.add_link_flag("-sUSE_SDL=3");
|
||||
}
|
||||
}
|
||||
#run configure_build();
|
||||
|
||||
// --- inline if with compiler constants ---
|
||||
|
||||
main :: () {
|
||||
// Verify #run configure_build() executed without error
|
||||
print("build config: ok\n");
|
||||
|
||||
// Verify compiler constants are available
|
||||
print("pointer size: {}\n", POINTER_SIZE);
|
||||
|
||||
// Verify inline if with OS/ARCH works
|
||||
inline if OS == {
|
||||
case .macos: { print("os: macos\n"); }
|
||||
case .linux: { print("os: linux\n"); }
|
||||
case .windows: { print("os: windows\n"); }
|
||||
case .wasm: { print("os: wasm\n"); }
|
||||
else: { print("os: unknown\n"); }
|
||||
}
|
||||
|
||||
// Verify POINTER_SIZE is usable in inline if
|
||||
inline if POINTER_SIZE == 8 {
|
||||
print("64-bit platform\n");
|
||||
}
|
||||
inline if POINTER_SIZE == 4 {
|
||||
print("32-bit platform\n");
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
// Issue: nested field assignment through pointer
|
||||
// self.inner.field = value should work when self is a pointer
|
||||
|
||||
Inner :: struct {
|
||||
len: s64;
|
||||
cap: s64;
|
||||
}
|
||||
|
||||
Outer :: struct {
|
||||
inner: Inner;
|
||||
count: s64;
|
||||
|
||||
reset :: (self: *Outer) {
|
||||
self.inner.len = 0; // error: field assignment target must be a variable
|
||||
self.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
main :: () {
|
||||
o := Outer.{ inner = Inner.{ len = 5, cap = 10 }, count = 0 };
|
||||
o.reset();
|
||||
print("{}\n", o.inner.len);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Issue: enum literal inference in match expression used as assignment RHS
|
||||
// When a match expression is assigned to a field with a known enum type,
|
||||
// the enum literals in case arms should infer their type from the assignment target.
|
||||
|
||||
Color :: enum {
|
||||
red;
|
||||
green;
|
||||
blue;
|
||||
none;
|
||||
}
|
||||
|
||||
Thing :: struct {
|
||||
color: Color;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
t : Thing = ---;
|
||||
value : u8 = 1;
|
||||
t.color = if value == {
|
||||
case 1: .red; // error: cannot infer enum type for literal
|
||||
case 2: .green;
|
||||
case 3: .blue;
|
||||
else: .none;
|
||||
};
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
Color :: struct {
|
||||
r, g, b, a: u8;
|
||||
}
|
||||
|
||||
COLOR_WHITE :: Color.{ r = 255, g = 255, b = 255, a = 255 };
|
||||
|
||||
// Additional case: struct constant with enum-typed fields
|
||||
HAlign :: enum { leading; center; trailing; }
|
||||
VAlign :: enum { top; center; bottom; }
|
||||
|
||||
Alignment :: struct {
|
||||
h: HAlign;
|
||||
v: VAlign;
|
||||
}
|
||||
|
||||
ALIGN_CENTER :: Alignment.{ h = .center, v = .center };
|
||||
@@ -1,20 +0,0 @@
|
||||
// Issue: top-level constants from imported files are not visible
|
||||
// COLOR_WHITE works after fix, but ALIGN_CENTER (struct with enum fields) does not.
|
||||
// Error: undefined identifier 'ALIGN_CENTER'
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "examples/issue-0004-defs.sx";
|
||||
|
||||
Thing :: struct {
|
||||
color: Color;
|
||||
alignment: Alignment;
|
||||
|
||||
make :: () -> Thing {
|
||||
Thing.{ color = COLOR_WHITE, alignment = ALIGN_CENTER };
|
||||
}
|
||||
}
|
||||
|
||||
main :: () {
|
||||
t := Thing.make();
|
||||
print("{}\n", t.color.r);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// Issue: match on u8 value with enum result assigned to typed field
|
||||
// The switch value is u8 but case constants are s64 (default int literal type).
|
||||
// Compiler should cast case constants to match the switch value type.
|
||||
// LLVM error: Switch constants must all be same type as switch value!
|
||||
|
||||
out :: (str: string) -> void #builtin;
|
||||
|
||||
Button :: enum {
|
||||
none;
|
||||
left;
|
||||
middle;
|
||||
right;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
val : u8 = 2;
|
||||
result : Button = if val == {
|
||||
case 1: .left;
|
||||
case 2: .middle;
|
||||
case 3: .right;
|
||||
else: .none;
|
||||
};
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// Issue: chained method call on struct field operates on a copy
|
||||
// `a.field.method()` where method takes *Self creates a temporary copy of `field`
|
||||
// instead of borrowing `a.field` as a pointer.
|
||||
// The mutation is lost because it modifies the copy, not the original.
|
||||
|
||||
out :: (str: string) -> void #builtin;
|
||||
|
||||
Counter :: struct {
|
||||
value: s64;
|
||||
|
||||
inc :: (self: *Counter) {
|
||||
self.value += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Parent :: struct {
|
||||
counter: Counter;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
p := Parent.{ counter = Counter.{ value = 0 } };
|
||||
|
||||
// This should increment p.counter.value, but the mutation is lost:
|
||||
p.counter.inc();
|
||||
|
||||
if p.counter.value == 0 {
|
||||
out("BUG: p.counter.value is still 0 after inc()\n");
|
||||
} else {
|
||||
out("OK: p.counter.value is 1\n");
|
||||
}
|
||||
|
||||
// Workaround: take explicit pointer
|
||||
cp := @p.counter;
|
||||
cp.inc();
|
||||
|
||||
if p.counter.value == 1 {
|
||||
out("OK: workaround via pointer works\n");
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Issue 0008: Chained ?? (null coalescing) doesn't work
|
||||
//
|
||||
// `a ?? b ?? c` where a: ?f32, b: ?f32, c: f32 fails with:
|
||||
// "narrowing conversion from '?f32' to 'f32' requires explicit 'xx' cast"
|
||||
//
|
||||
// It parses as (a ?? b) ?? c, and the first ?? rejects ?f32 as the rhs.
|
||||
//
|
||||
// Expected: ?? should either be right-associative so it parses as a ?? (b ?? c),
|
||||
// or allow ?T as the rhs (returning ?T when rhs is optional, T when rhs is concrete).
|
||||
//
|
||||
// Workaround: use parentheses — a ?? (b ?? c)
|
||||
|
||||
Foo :: struct {
|
||||
x: ?f32;
|
||||
y: ?f32;
|
||||
}
|
||||
|
||||
main :: () -> void {
|
||||
f := Foo.{ x = 1.0, y = 2.0 };
|
||||
|
||||
// This works:
|
||||
ok := f.x ?? (f.y ?? 0.0);
|
||||
|
||||
// This should also work but fails:
|
||||
bad := f.x ?? f.y ?? 0.0;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Issue 0009: Struct-level constant declarations
|
||||
//
|
||||
// Constants declared inside a struct body with `NAME :Type: value;` syntax
|
||||
// fail with "expected field name in struct".
|
||||
//
|
||||
// Expected: structs should support constant declarations alongside fields and methods.
|
||||
|
||||
Foo :: struct {
|
||||
x: f32;
|
||||
|
||||
// This method works:
|
||||
get_x :: (self: *Foo) -> f32 { self.x; }
|
||||
|
||||
// This constant should work but fails:
|
||||
DEFAULT_X :f32: 42.0;
|
||||
}
|
||||
|
||||
main :: () -> void {
|
||||
f := Foo.{ x = Foo.DEFAULT_X };
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Issue 0010: inline if-else in struct literal field produces type error
|
||||
// The `null` branch is typed as `*void` instead of being coerced to `?f32`
|
||||
//
|
||||
// Error: narrowing conversion from '*void' to 'f32' requires explicit 'xx' cast
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Foo :: struct {
|
||||
width: ?f32;
|
||||
}
|
||||
|
||||
main :: () -> void {
|
||||
x :f32: 10.0;
|
||||
|
||||
// null in then branch, value in else
|
||||
f1 := Foo.{ width = if true then null else x };
|
||||
print("{}\n", f1.width ?? 99.0);
|
||||
|
||||
// value in then branch, null in else
|
||||
f2 := Foo.{ width = if true then x else null };
|
||||
print("{}\n", f2.width ?? 99.0);
|
||||
|
||||
// both branches are values
|
||||
f3 := Foo.{ width = if false then 5.0 else x };
|
||||
print("{}\n", f3.width ?? 99.0);
|
||||
|
||||
// standalone variable, not just struct fields
|
||||
val: ?f32 = if true then null else 42.0;
|
||||
print("{}\n", val ?? 0.0);
|
||||
|
||||
val2: ?f32 = if false then null else 42.0;
|
||||
print("{}\n", val2 ?? 0.0);
|
||||
|
||||
// negation in condition
|
||||
cond := false;
|
||||
val3: ?f32 = if !cond then null else 42.0;
|
||||
print("{}\n", val3 ?? 0.0);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
// Forward references: types, struct fields, methods, and free functions
|
||||
// can reference types declared later in the file.
|
||||
|
||||
// Free function referencing types declared later
|
||||
make_frame :: (e: EdgeInsets) -> Frame {
|
||||
Frame.{ x = e.left, y = e.top,
|
||||
w = 100.0 - e.left - e.right,
|
||||
h = 100.0 - e.top - e.bottom };
|
||||
}
|
||||
|
||||
// Struct with a field whose type is declared later
|
||||
Container :: struct {
|
||||
frame: Frame;
|
||||
insets: EdgeInsets;
|
||||
}
|
||||
|
||||
Frame :: struct {
|
||||
x, y, w, h: f32;
|
||||
|
||||
inset :: (self: Frame, insets: EdgeInsets) -> Frame {
|
||||
Frame.{ x = self.x + insets.left, y = self.y + insets.top,
|
||||
w = self.w - insets.left - insets.right,
|
||||
h = self.h - insets.top - insets.bottom };
|
||||
}
|
||||
}
|
||||
|
||||
EdgeInsets :: struct {
|
||||
top, left, bottom, right: f32;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
e := EdgeInsets.{ top = 10.0, left = 10.0, bottom = 10.0, right = 10.0 };
|
||||
f := make_frame(e);
|
||||
r := f.inset(e);
|
||||
c := Container.{ frame = f, insets = e };
|
||||
print("{}", r.x);
|
||||
print(" {}", r.w);
|
||||
print(" {}", c.frame.x);
|
||||
}
|
||||
@@ -1,6 +1,19 @@
|
||||
OperatingSystem :: enum { macos; linux; windows; wasm; unknown; }
|
||||
Architecture :: enum { aarch64; x86_64; wasm32; unknown; }
|
||||
Architecture :: enum { aarch64; x86_64; wasm32; wasm64; unknown; }
|
||||
|
||||
OS : OperatingSystem = .unknown;
|
||||
ARCH : Architecture = .unknown;
|
||||
POINTER_SIZE : s64 = 8;
|
||||
|
||||
BuildOptions :: struct {
|
||||
add_link_flag :: (self: BuildOptions, flag: [:0]u8) {
|
||||
// Compiler builtin — intercepted at compile time
|
||||
}
|
||||
set_output_path :: (self: BuildOptions, path: [:0]u8) {
|
||||
// Compiler builtin — intercepted at compile time
|
||||
}
|
||||
}
|
||||
|
||||
build_options :: () -> BuildOptions {
|
||||
return BuildOptions.{};
|
||||
}
|
||||
|
||||
1611
examples/smoke_a.sx
1611
examples/smoke_a.sx
File diff suppressed because it is too large
Load Diff
1931
examples/smoke_b.sx
1931
examples/smoke_b.sx
File diff suppressed because it is too large
Load Diff
2667
examples/smoke_c.sx
2667
examples/smoke_c.sx
File diff suppressed because it is too large
Load Diff
2343
examples/smoke_d.sx
2343
examples/smoke_d.sx
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
Phys :: struct {
|
||||
x, y: f32;
|
||||
GRAVITY :f32: 9.81;
|
||||
MAX_SPEED :: 100;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
print("gravity: {}\n", Phys.GRAVITY);
|
||||
print("max speed: {}\n", Phys.MAX_SPEED);
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () {
|
||||
n1 : s32 = 1;
|
||||
n2 : s32 = 2;
|
||||
n3 : s32 = 3;
|
||||
|
||||
f1 := closure((x: s32) -> s32 => x + n1);
|
||||
f2 := closure((x: s32) -> s32 => x + n2);
|
||||
f3 := closure((x: s32) -> s32 => x + n3);
|
||||
|
||||
print("f1: {}\n", f1(10));
|
||||
print("f2: {}\n", f2(10));
|
||||
print("f3: {}\n", f3(10));
|
||||
|
||||
// closure struct field
|
||||
Button :: struct {
|
||||
label: string;
|
||||
on_press: Closure(s32) -> void;
|
||||
}
|
||||
btn_val := 99;
|
||||
btn_cb := closure((id: s32) {
|
||||
print("btn: {} {}\n", id, btn_val);
|
||||
});
|
||||
btn := Button.{ label = "OK", on_press = btn_cb };
|
||||
btn.on_press(1);
|
||||
|
||||
// optional closure
|
||||
f_none : ?Closure(s64) -> s64 = null;
|
||||
if f_none != null { print("should not print\n"); }
|
||||
else { print("opt-closure: none\n"); }
|
||||
|
||||
// closure factory
|
||||
make_adder :: (n: s32) -> Closure(s32) -> s32 {
|
||||
closure((x: s32) -> s32 => x + n);
|
||||
}
|
||||
add5 := make_adder(5);
|
||||
add10 := make_adder(10);
|
||||
print("factory: {} {}\n", add5(100), add10(100));
|
||||
|
||||
// HOF compose
|
||||
compose :: (f: Closure(s32) -> s32, g: Closure(s32) -> s32) -> Closure(s32) -> s32 {
|
||||
closure((x: s32) -> s32 => f(g(x)));
|
||||
}
|
||||
double :: (x: s32) -> s32 { return x * 2; }
|
||||
cf := compose(add5, double);
|
||||
print("compose: {}\n", cf(10));
|
||||
|
||||
// closure with array
|
||||
sort_bubble :: (arr: [*]s32, cnt: s64, less: Closure(s32, s32) -> bool) {
|
||||
i : s64 = 0;
|
||||
while i < cnt {
|
||||
j : s64 = 0;
|
||||
while j < cnt - 1 {
|
||||
if less(arr[j + 1], arr[j]) {
|
||||
tmp := arr[j];
|
||||
arr[j] = arr[j + 1];
|
||||
arr[j + 1] = tmp;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
sort_arr : [5]s32 = .[5, 3, 1, 4, 2];
|
||||
sort_bubble(xx @sort_arr, 5, closure((a: s32, b: s32) -> bool {
|
||||
return a < b;
|
||||
}));
|
||||
print("sort: {} {} {} {} {}\n", sort_arr[0], sort_arr[1], sort_arr[2], sort_arr[3], sort_arr[4]);
|
||||
|
||||
// Many closures with string captures
|
||||
tag1 := "hello";
|
||||
tag2 := "world";
|
||||
sf1 := closure((x: s32) { print("sf1: {} {}\n", tag1, x); });
|
||||
sf2 := closure((x: s32) { print("sf2: {} {}\n", tag2, x); });
|
||||
sf1(1);
|
||||
sf2(2);
|
||||
|
||||
print("=== DONE ===\n");
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
main :: () {
|
||||
n := 42;
|
||||
f := closure((x: s64) -> s64 { x + n; });
|
||||
r := f(10);
|
||||
print("r: {}\n", r);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
greet :: () -> string { format("hello"); }
|
||||
main :: () {
|
||||
print("{}\n", greet());
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
main :: () -> s32 {
|
||||
v := Vector(3,f32).[1,2,3];
|
||||
print("{}
|
||||
", v);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
Point :: struct { x: s32; y: s32; }
|
||||
|
||||
Eq :: protocol {
|
||||
eq :: (other: Self) -> bool;
|
||||
}
|
||||
|
||||
impl Eq for Point {
|
||||
eq :: (self: *Point, other: Point) -> bool {
|
||||
self.x == other.x and self.y == other.y;
|
||||
}
|
||||
}
|
||||
|
||||
are_equal :: ($T: Type/Eq, a: T, b: T) -> bool {
|
||||
a.eq(b);
|
||||
}
|
||||
|
||||
main :: () {
|
||||
p1 := Point.{ x = 1, y = 2 };
|
||||
p2 := Point.{ x = 1, y = 2 };
|
||||
p3 := Point.{ x = 3, y = 4 };
|
||||
print("P6.1: {} {}\n", are_equal(p1, p2), are_equal(p1, p3));
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
main :: () {
|
||||
s := "";
|
||||
print("{}\n", s);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#import "modules/std.sx";
|
||||
|
||||
Vec2 :: union {
|
||||
data: [2]f32;
|
||||
struct { x, y: f32; };
|
||||
}
|
||||
|
||||
main :: () {
|
||||
uv : Vec2 = ---;
|
||||
uv.x = 1.0;
|
||||
uv.y = 2.0;
|
||||
print("promoted-x: {}\n", uv.x);
|
||||
print("promoted-data0: {}\n", uv.data[0]);
|
||||
}
|
||||
Reference in New Issue
Block a user