ww source: align UTF-8 BOM placement

This commit is contained in:
2026-08-21 20:34:10 +09:00
parent ee4573bf55
commit 9381f8fb8e
11 changed files with 764 additions and 5 deletions

View File

@@ -7,6 +7,15 @@
#include <string.h>
#include <errno.h>
static int
bomat(const char *src, u64 len, u64 pos)
{
return pos <= len && len - pos >= 3
&& (unsigned char)src[pos] == 0xef
&& (unsigned char)src[pos + 1] == 0xbb
&& (unsigned char)src[pos + 2] == 0xbf;
}
void
lexinit(Lex *l, Arena *a, const char *file, const char *src, u64 len)
{
@@ -17,6 +26,12 @@ lexinit(Lex *l, Arena *a, const char *file, const char *src, u64 len)
l->line = 1;
l->col = 1;
l->a = a;
/* Go 1.26.5 syntax.source.nextch ignores U+FEFF only at the first
* source position but counts its three bytes for the next column. */
if (bomat(src, len, 0)) {
l->pos = 3;
l->col = 4;
}
}
static int
@@ -25,6 +40,8 @@ lpeek(Lex *l, u64 ahead)
u64 p = l->pos + ahead;
if (p >= l->srclen)
return -1;
if (bomat(l->src, l->srclen, p))
return 0xfeff;
return (unsigned char)l->src[p];
}
@@ -33,6 +50,14 @@ lget(Lex *l)
{
if (l->pos >= l->srclen)
return -1;
if (bomat(l->src, l->srclen, l->pos)) {
Pos p = { l->file, l->line, l->col };
l->pos += 3;
l->col += 3;
errorf(p, "invalid BOM in the middle of the file");
l->errs++;
return 0xfeff;
}
int c = (unsigned char)l->src[l->pos++];
if (c == '\n') {
l->line++;
@@ -529,6 +554,11 @@ lexnext(Lex *l)
return t;
}
int c = lpeek(l, 0);
if (c == 0xfeff) {
lget(l);
Tok t = (Tok){ TK_ERR, start, "", 0, {0}, TK_NONE };
return t;
}
if (isidstart(c))
return lexident(l, start);

View File

@@ -4740,7 +4740,18 @@ sep_emit_body(FILE *out, const char *path, const char *modpath)
} else if (fputs("//ww:module-reset\n", out) == EOF) {
bad = 1;
}
if (fwrite(buf, 1, (size_t)len, out) != (size_t)len
/* Each physical source owns its own first-codepoint position. The
* compiler sees one synthetic aggregate, so replace the optional UTF-8
* BOM with position-preserving whitespace rather than turning a later
* source's marker into a mid-unit BOM. */
u64 off = len >= 3
&& (unsigned char)buf[0] == 0xef
&& (unsigned char)buf[1] == 0xbb
&& (unsigned char)buf[2] == 0xbf ? 3 : 0;
if (off != 0 && fwrite(" ", 1, 3, out) != 3)
bad = 1;
if (fwrite(buf + off, 1, (size_t)(len - off), out)
!= (size_t)(len - off)
|| fputc('\n', out) == EOF)
bad = 1;
free(buf);