Phase 7b: null literal + x == null (retire ptr_null/ptr_is_null)

`null` is now a real pointer literal and null-tests are comparisons, instead of
`ptr_null()` and `ptr_is_null(x)`:

  ptr_null()          -> null
  ptr_is_null(x)      -> (x == null)
  not ptr_is_null(x)  -> (x != null)

Mechanics: a new E_NULL primary (`null`, like true/false) lowers to the `null`
pointer; emit_bin's comparison path now picks `ptr` vs `i32` from operand type
(via llty), so `==`/`!=` work on any pointer/record/slice. The two intrinsics are
deleted.

Two reseeds: (A) add the literal + ptr comparison keeping the intrinsics; (B)
migrate all 182 call sites (compiler + runtime, via a balanced-paren script that
skips string-literal args and rewrites `not ptr_is_null` to `!= null`) and delete
the intrinsics. Node/Val/Buf/Tok field defaults now read `ptr = null`.

Vocabulary drops the two from LUDIC_INTRINSICS; `null` joins true/false as a
language constant (grammar + ludic_syntax.h). LANGUAGE.md notes the literal.
Reseeded (21664 lines); C-free fixpoint holds; goldens identical; 17/17; vocab +
doc-fences clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-08-28 00:50:21 +03:00
parent ddb1af3008
commit 70ab79a4e9
34 changed files with 5064 additions and 5124 deletions

View file

@ -13,12 +13,12 @@ const IMG_MAX: int = 32
const SPR_MAX: int = 160
const SPR_SZ: int = 16
var img_px: ptr = ptr_null() # IMG_MAX pointers to RGBA buffers
var img_w: ptr = ptr_null()
var img_h: ptr = ptr_null()
var img_px: ptr = null # IMG_MAX pointers to RGBA buffers
var img_w: ptr = null
var img_h: ptr = null
var img_n: int = 0
var spr_px: ptr = ptr_null() # SPR_MAX * 16 * 16 RGBA pixels, one block
var spr_px: ptr = null # SPR_MAX * 16 * 16 RGBA pixels, one block
var spr_n: int = 0
fn rt_image_init() -> void {
@ -44,11 +44,11 @@ fn png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool {
fn rt_read_file(path: str) -> ptr {
let f = file_open(path, "rb")
if ptr_is_null(f) { return ptr_null() }
if (f == null) { return null }
file_seek(f, 0, 2)
let n = file_tell(f)
file_seek(f, 0, 0)
if n <= 0 { file_close(f); return ptr_null() }
if n <= 0 { file_close(f); return null }
let buf = mem_alloc(n + 8)
file_read(f, buf, n)
file_close(f)
@ -60,14 +60,14 @@ var rt_file_len: int = 0
# decoded image is left in these; -1 width means failure
var png_w: int = 0
var png_h: int = 0
var png_px: ptr = ptr_null()
var png_px: ptr = null
fn rt_decode_png(path: str) -> bool {
png_w = 0
png_h = 0
png_px = ptr_null()
png_px = null
let d = rt_read_file(path)
if ptr_is_null(d) { return false }
if (d == null) { return false }
let size = rt_file_len
if size < 8 { mem_free(d); return false }
if peek8(d, 0) != 137 { mem_free(d); return false }
@ -334,7 +334,7 @@ fn rt_png_load(path: str) -> int {
}
}
mem_free(png_px)
png_px = ptr_null()
png_px = null
return id
}
@ -377,7 +377,7 @@ fn rt_hexval(c: int) -> int {
fn rt_sprites_load(path: str) -> void {
let d = rt_read_file(path)
if ptr_is_null(d) { spr_n = 0; return }
if (d == null) { spr_n = 0; return }
let size = rt_file_len
let pal = mem_alloc(128 * 4)
mem_set(pal, 0, 128 * 4)