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
15 changes: 14 additions & 1 deletion bend2/comp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2838,8 +2838,10 @@ function emit_chain(sc: Scope, arms: [string, () => void][]): void {
// namespace, else as is. An effect source is read once, in one namespace.
// effect_src splices a C source's backslash-newlines first, as C does even
// in a comment; JS does not.
// Only #define bodies root IDs on C preprocessor lines.

const ID_WORDS = /\/\/.*|\/\*[^]*?\*\/|"(?:\\[^]|[^"\\\n])*"|'(?:\\[^]|[^'\\\n])*'|`(?:\\[^]|[^`\\])*`|(?<![$\u200c\u200d\p{ID_Continue}])([CF]ID)\(([\w./~-]+)\)/gu;
const C_ID_WORDS = new RegExp(ID_WORDS.source + String.raw`|(?:#|%:)(?:[^\S\n]|/\*[^]*?\*/)*(?![CF]ID\()(\w+)`, "gu");

function c_ids(src: string, m = "", use?: (p: string, k: Name) => void): string {
const replace = (t: string, p: string | undefined, k: string | undefined, at: number): string => {
Expand All @@ -2858,7 +2860,18 @@ function c_ids(src: string, m = "", use?: (p: string, k: Name) => void): string
? js_tag(q) : q) : name_id(p + "_", q);
};
if (use) {
for (const hit of src.matchAll(ID_WORDS)) replace(hit[0], hit[1], hit[2], hit.index);
let end = 0;
let directive = "";
for (const hit of src.matchAll(C_ID_WORDS)) {
for (; end < hit.index; end += 1) {
if (src[end] === "\n") directive = "";
}
end = hit.index + hit[0].length;
if (!directive && hit[3]) directive = hit[3];
if (!directive || directive === "define") {
replace(hit[0], hit[1], hit[2], hit.index);
}
}
return src;
}
return src.replace(ID_WORDS, replace);
Expand Down
19 changes: 19 additions & 0 deletions tests/io/foreign_fid_conditionals.bend
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Presence guards must not root functions; macro-expanded calls must.
import Base

def guard_only(n: U32) -> U32:
U32.inc(n)

def imul(a: U32, b: U32) -> U32:
(a * b : U32)

def answer() -> IO(U32):
import "./foreign_fid_conditionals.c"
import "./foreign_fid_conditionals.js"

def main() -> IO(Unit):
do IO<Unit>:
value : U32 <- answer()
IO.print(U32.show(value))

#|42
35 changes: 35 additions & 0 deletions tests/io/foreign_fid_conditionals.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifdef FID(guard_only)
#error A presence guard kept an unused function alive
#endif
#if defined(\
FID(guard_only))
#error A continued presence guard kept an unused function alive
#endif
#/**/ifdef FID(guard_only)
#error A commented directive kept an unused function alive
#endif
%:if defined(FID(guard_only))
%:error A digraph directive kept an unused function alive
%:endif
#ifndef FID(imul)
#error The macro call target lost its entry
#endif

#define CALL_FID /* A comment's newline does not end the directive.
The call target below still needs an entry. */ \
FID(imul)

static Term answer_run(Env e, Term* f, IoWork* w) {
(void)f;
(void)w;
u64 at = task_node(e, CALL_FID, TERM_HOLE, 0, 0);
e.mem[at] = 6;
e.mem[at + 1] = 7;
Term result = corpus_eval(e.mem, term_tsk(CALL_FID, at));
if (err_seen(e.mem)) err_fail("macro function entry failed");
return result;
}

static void __attribute__((constructor)) answer_use(void) {
io_eff(CID(answer), answer_run);
}
5 changes: 5 additions & 0 deletions tests/io/foreign_fid_conditionals.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function answer() {
const fid = FID(imul);
return Math[fid.slice(fid.lastIndexOf(":") + 1)](6, 7) >>> 0;
}
io_eff(CID(answer), answer);
10 changes: 5 additions & 5 deletions tests/io/foreign_fused_fid.bend
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# The single Bend call must not fuse away an entry also used by FID.
import Base

def hidden(n: U32) -> U32:
U32.inc(n)
def imul(a: U32, b: U32) -> U32:
(a * b : U32)

def caller(n: U32) -> U32:
hidden(n)
def caller(a: U32, b: U32) -> U32:
imul(a, b)

def answer() -> IO(U32):
import "./foreign_fused_fid.c"
import "./foreign_fused_fid.js"

def main() -> IO(Unit):
do IO<Unit>:
IO.print(U32.show(caller(41)))
IO.print(U32.show(caller(6, 7)))
value : U32 <- answer()
IO.print(U32.show(value))

Expand Down
7 changes: 4 additions & 3 deletions tests/io/foreign_fused_fid.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
static Term answer_run(Env e, Term* f, IoWork* w) {
(void)f;
(void)w;
u64 at = task_node(e, FID(hidden), TERM_HOLE, 0, 0);
e.mem[at] = 41;
Term result = corpus_eval(e.mem, term_tsk(FID(hidden), at));
u64 at = task_node(e, FID(imul), TERM_HOLE, 0, 0);
e.mem[at] = 6;
e.mem[at + 1] = 7;
Term result = corpus_eval(e.mem, term_tsk(FID(imul), at));
if (err_seen(e.mem)) err_fail("fused function entry failed");
return result;
}
Expand Down
3 changes: 2 additions & 1 deletion tests/io/foreign_fused_fid.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
function answer() {
return 41 + 1;
const fid = FID(imul);
return Math[fid.slice(fid.lastIndexOf(":") + 1)](6, 7) >>> 0;
}
io_eff(CID(answer), answer);
4 changes: 2 additions & 2 deletions tests/io/foreign_only_fid.bend
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# A C effect calls a function that has no Bend callsite.
import Base

def hidden(n: U32) -> U32:
U32.inc(n)
def imul(a: U32, b: U32) -> U32:
(a * b : U32)

def answer() -> IO(U32):
import "./foreign_only_fid.c"
Expand Down
7 changes: 4 additions & 3 deletions tests/io/foreign_only_fid.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
static Term answer_run(Env e, Term* f, IoWork* w) {
(void)f;
(void)w;
u64 at = task_node(e, FID(hidden), TERM_HOLE, 0, 0);
e.mem[at] = 41;
Term result = corpus_eval(e.mem, term_tsk(FID(hidden), at));
u64 at = task_node(e, FID(imul), TERM_HOLE, 0, 0);
e.mem[at] = 6;
e.mem[at + 1] = 7;
Term result = corpus_eval(e.mem, term_tsk(FID(imul), at));
if (err_seen(e.mem)) err_fail("foreign-only function failed");
return result;
}
Expand Down
3 changes: 2 additions & 1 deletion tests/io/foreign_only_fid.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
function answer() {
return 41 + 1;
const fid = FID(imul);
return Math[fid.slice(fid.lastIndexOf(":") + 1)](6, 7) >>> 0;
}
io_eff(CID(answer), answer);
Loading