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:
parent
ddb1af3008
commit
70ab79a4e9
34 changed files with 5064 additions and 5124 deletions
|
|
@ -34,7 +34,7 @@ fn strip_ludic(name: ptr) -> ptr {
|
|||
# env var with a fallback when unset
|
||||
fn getenv_or(name: ptr, dflt: ptr) -> ptr {
|
||||
let v = os_getenv(name)
|
||||
if ptr_is_null(v) { return dflt }
|
||||
if (v == null) { return dflt }
|
||||
return v
|
||||
}
|
||||
|
||||
|
|
@ -52,8 +52,8 @@ fn die(msg: ptr) -> void {
|
|||
}
|
||||
|
||||
entry {
|
||||
var path = ptr_null()
|
||||
var out = ptr_null()
|
||||
var path = null
|
||||
var out = null
|
||||
var want = 0 # 0 = auto, 1 = windowed, 2 = headless
|
||||
var emit_ir = false # --emit-llvm: stop after writing IR
|
||||
var fmt = false # --fmt: lex + parse only, then exit (the doc-check gate)
|
||||
|
|
@ -84,11 +84,11 @@ entry {
|
|||
ai = ai + 1
|
||||
}
|
||||
|
||||
if ptr_is_null(path) {
|
||||
if (path == null) {
|
||||
die("usage: ludicc <file.ludic> [-o out] [--windowed|--headless] [--emit-llvm] [--save-temps]\n")
|
||||
}
|
||||
let src = read_file(path)
|
||||
if ptr_is_null(src) { die("ludicc: cannot open input\n") }
|
||||
if (src == null) { die("ludicc: cannot open input\n") }
|
||||
|
||||
cur_dir = dir_of(path)
|
||||
lex(src)
|
||||
|
|
@ -104,7 +104,7 @@ entry {
|
|||
# a game gets a window by default; a plain program stays headless. An explicit
|
||||
# flag always wins. The stdout-IR path (no target) also stays headless, which
|
||||
# is what reseed.sh compiles the compiler itself with.
|
||||
let has_target = run or (not ptr_is_null(out))
|
||||
let has_target = run or ((out != null))
|
||||
if want == 1 { g_windowed = true }
|
||||
else { if want == 2 { g_windowed = false }
|
||||
else { g_windowed = has_target and has_systems() } }
|
||||
|
|
@ -113,10 +113,10 @@ entry {
|
|||
|
||||
# --emit-llvm, or no binary target: emit IR and stop (stdout when out is null).
|
||||
if emit_ir { ir_flush(out); return }
|
||||
if not has_target { ir_flush(ptr_null()); return }
|
||||
if not has_target { ir_flush(null); return }
|
||||
|
||||
# a run with no explicit -o lands in a temp file
|
||||
if run and ptr_is_null(out) {
|
||||
if run and (out == null) {
|
||||
out = sconcat("/tmp/ludic-run-", strip_ludic(base_name(path)))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue