Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion bend2/comp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,9 @@ function eff_src(path: string, seen: Set<string>): string {
return "";
}
seen.add(path);
return fs.readFileSync(path, "utf8");
const dir = path.slice(0, path.lastIndexOf("/"));
return fs.readFileSync(path, "utf8").replace(/^\/\/ @src ([a-z0-9_]+\.c)$/gm,
(_: string, name: string) => eff_src(dir + "/" + name, seen));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Include transitive @src files in published packages. pkg_files() in main.ts only collects direct Bend imports, so an effect containing // @src helper.c builds locally but leaves helper.c out of the package. I reproduced this by rebuilding from the files returned by pkg_files(); compilation fails with ENOENT for the helper. The package collector needs to follow these dependencies too.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Protect these helpers from output overwrite. The input set in cli_file() only tracks direct imports, so bend main.bend -o helper.c exits 0 and replaces a helper referenced through // @src helper.c with generated C. I reproduced the overwrite with a working custom effect. Add transitive helpers to the protected input set before emitting any output.

}

// Io
Expand Down
19 changes: 2 additions & 17 deletions bend2/effs/window_close.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Window
// ======

// @src window_host.c

#ifdef __OBJC__

#import <AppKit/AppKit.h>
Expand All @@ -12,23 +14,6 @@ static void window_close(intptr_t at) {

#elif defined(__linux__)

#ifndef BendWin
#define BendWin BendWin
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

typedef struct {
Display* dpy;
Window win;
Atom del;
XImage* img;
u32 n;
u32 cap;
u32* evs;
} BendWin;
#endif

static void window_close(intptr_t at) {
BendWin* win = (BendWin*)at;
XDestroyImage(win->img);
Expand Down
19 changes: 2 additions & 17 deletions bend2/effs/window_frame.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Window
// ======

// @src window_host.c

// An event is five words: kind (0 key, 1 mouse, 2 move, 3 close) and
// its fields; a frame answers the events pumped since the last one.
#if defined(__OBJC__) || defined(__linux__)
Expand Down Expand Up @@ -183,23 +185,6 @@ static Term window_frame(Env e, intptr_t at, Term image) {

#elif defined(__linux__)

#ifndef BendWin
#define BendWin BendWin
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

typedef struct {
Display* dpy;
Window win;
Atom del;
XImage* img;
u32 n;
u32 cap;
u32* evs;
} BendWin;
#endif

// The Mac's key codes: a key's character in lower case, the function
// keys' private-use characters (the arrows at 63232), a modifier's
// 65536 + its key code.
Expand Down
19 changes: 19 additions & 0 deletions bend2/effs/window_host.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Pulled by Window.open/frame/set_title/close (`// @src window_host.c`).
// The X11 window: its own connection (so its queue holds only its
// events), the frame's image and the events pumped since the last
// frame, five words each (kind, a, b, c, d) as on the Mac.
#if defined(__linux__)
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

typedef struct {
Display* dpy;
Window win;
Atom del;
XImage* img;
u32 n;
u32 cap;
u32* evs;
} BendWin;
#endif
23 changes: 2 additions & 21 deletions bend2/effs/window_open.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Window
// ======

// @src window_host.c

#ifdef __OBJC__

#import <AppKit/AppKit.h>
Expand Down Expand Up @@ -178,27 +180,6 @@ static u32 window_make(const char* title, u32 w, u32 h, intptr_t* out,

#elif defined(__linux__)

// The X11 window: its own connection (so its queue holds only its
// events), the frame's image and the events pumped since the last
// frame, five words each (kind, a, b, c, d) as on the Mac. The same
// block sits in window_frame.c and window_close.c under this guard.
#ifndef BendWin
#define BendWin BendWin
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

typedef struct {
Display* dpy;
Window win;
Atom del;
XImage* img;
u32 n;
u32 cap;
u32* evs;
} BendWin;
#endif

static u32 window_make(const char* title, u32 w, u32 h, intptr_t* out,
const char** why) {
if (w < 1 || h < 1 || w > 16384 || h > 16384) {
Expand Down
19 changes: 2 additions & 17 deletions bend2/effs/window_set_title.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Window
// ======

// @src window_host.c

#ifdef __OBJC__

#import <AppKit/AppKit.h>
Expand All @@ -13,23 +15,6 @@ static void window_set_title(intptr_t at, const char* text, u64 n) {

#elif defined(__linux__)

#ifndef BendWin
#define BendWin BendWin
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>

typedef struct {
Display* dpy;
Window win;
Atom del;
XImage* img;
u32 n;
u32 cap;
u32* evs;
} BendWin;
#endif

static void window_set_title(intptr_t at, const char* text, u64 n) {
BendWin* win = (BendWin*)at;
XStoreName(win->dpy, win->win, text);
Expand Down
46 changes: 37 additions & 9 deletions bend2/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,10 @@ async function cli_file(args: string[]): Promise<void> {
process.exitCode = book_run(book, n0, argv);
return;
}
const ins = new Set([...seen.keys(), ...Object.values(book.tlds).flatMap((t) =>
t.$ === "Def" && t.i !== undefined ? t.i.map(path_real) : [])]);
const foreign = Object.values(book.tlds).flatMap((t) =>
t.$ === "Def" && t.i !== undefined ? t.i : []);
const ins = new Set([...seen.keys(), ...foreign.map(path_real),
...src_deps(foreign)]);
for (const out of outs) {
const at = path_real(out);
if (ins.has(at) || (fs.existsSync(at) && fs.statSync(at).isDirectory())) {
Expand Down Expand Up @@ -291,6 +293,27 @@ function path_real(p: string): string {
return fs.existsSync(p) ? fs.realpathSync(p) : path.resolve(p);
}

// Real paths of // @src siblings, a helper's helper included.
function src_deps(files: string[]): string[] {
const out: string[] = [];
const seen = new Set(files.flatMap((f) =>
f.endsWith(".c") && fs.existsSync(f) ? [fs.realpathSync(f)] : []));
for (const q = [...seen]; q.length > 0;) {
const real = q.pop() as string;
const dir = real.slice(0, real.lastIndexOf("/"));
for (const m of fs.readFileSync(real, "utf8")
.matchAll(/^\/\/ @src ([a-z0-9_]+\.c)$/gm)) {
const dep = fs.realpathSync(dir + "/" + m[1]);
if (!seen.has(dep)) {
seen.add(dep);
out.push(dep);
q.push(dep);
}
}
}
return out;
}

function cli_emit(book: Bend.Book, out: string): void {
if (/\.c?js$/.test(out)) {
fs.writeFileSync(out, Comp.js_book(book));
Expand Down Expand Up @@ -449,19 +472,24 @@ async function cli_publish(file: string): Promise<void> {

// pkg_files is the package the loader read for this file, the entry first:
// every .bend file at its namespace (the entry at its name), every foreign
// .c or .js file at its path from the entry's directory; base and the
// store's packages stay out. A path that climbs above the entry's directory
// takes the entry's ancestor directories along, as many as the deepest climb.
// .c or .js file at its path from the entry's directory, and each // @src
// sibling; base and the store's packages stay out. A path that climbs above
// the entry's directory takes the entry's ancestor directories along, as
// many as the deepest climb.
function pkg_files(file: string, book: Bend.Book,
seen: Map<string, string | null>): Record<string, string> {
const dir = file.slice(0, file.lastIndexOf("/") + 1);
const root = fs.realpathSync(dir === "" ? "." : dir.slice(0, -1));
const owned = Object.entries(book.tlds).flatMap(([k, tld]): string[] =>
tld.$ !== "Def" || tld.i === undefined || tld.b === true
|| k.startsWith("0x") ? [] : tld.i);
const raws = [...[...seen].flatMap(([real, ns]): [string, string][] =>
real === BASE || ns === null || ns.startsWith("0x") ? []
: [[ns === "" ? path.basename(file) : ns + ".bend", real]]),
...Object.entries(book.tlds).flatMap(([k, tld]): [string, string][] =>
tld.$ !== "Def" || tld.i === undefined || tld.b === true
|| k.startsWith("0x") ? [] : tld.i.map((f) =>
[f.startsWith(dir) ? f.slice(dir.length) : f, f]))];
...owned.map((f): [string, string] =>
[f.startsWith(dir) ? f.slice(dir.length) : f, f]),
...src_deps(owned).map((real): [string, string] =>
[path.posix.relative(root, real), real])];
const ups = raws.map(([p]) => path.posix.normalize(p).split("/")
.filter((s) => s === "..").length);
const anc = fs.realpathSync(path.dirname(file)).split("/")
Expand Down