Skip to content

Commit 726559c

Browse files
committed
v2: lots of fixes; macos module to generate objc in V
1 parent c03e038 commit 726559c

65 files changed

Lines changed: 6303 additions & 1207 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/v2/test_all.sh

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
#!/usr/bin/env bash
22
set -euo pipefail
33

4-
cd "$(dirname "$0")"
4+
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
5+
repo_root="$(CDPATH= cd -- "${script_dir}/../.." && pwd)"
6+
7+
cd "${script_dir}"
8+
9+
v1_compiler="${V:-${repo_root}/v}"
10+
if [ ! -x "${v1_compiler}" ]; then
11+
echo "FAIL: v1 compiler not found: ${v1_compiler}"
12+
exit 1
13+
fi
514

615
# V1's formatter may clobber v2 source files during rebuild.
716
# Back up the entire v2 tree and restore after each V1 build.
@@ -21,27 +30,31 @@ KNOWN_FAILURES=0
2130

2231
echo "=== 1/14: ARM64 self-host hello world ==="
2332
backup_v2_src
24-
v -skip-unused -cc cc -o v2 v2.v
33+
"${v1_compiler}" -skip-unused -cc cc -o v2 v2.v
2534
restore_v2_src
26-
./v2 -backend arm64 -nocache -o v3 v2.v && ./v3 -o hello_arm hello.v && ./hello_arm
35+
./v2 -backend arm64 -gc none -nocache -o v3 v2.v
36+
./v3 -backend arm64 -o hello_arm hello.v
37+
./hello_arm
2738

2839
echo ""
29-
echo "=== 2/14: ARM64 self-host chain (v2->v3->v4->v5, parallel) ==="
40+
echo "=== 2/14: ARM64 self-host chain (v2->v3->v4->v5->v6) ==="
3041
echo " Building v3 from v2..."
31-
./v2 -nocache -backend arm64 -o v3_chain v2.v
42+
./v2 -nocache -gc none -backend arm64 -o v3_chain v2.v
3243
echo " Building v4 from v3..."
3344
./v3_chain -nocache -gc none -backend arm64 -o v4_chain v2.v
3445
echo " Building v5 from v4..."
3546
./v4_chain -nocache -gc none -backend arm64 -o v5_chain v2.v
36-
V4_SIZE=$(wc -c < v4_chain)
47+
echo " Building v6 from v5..."
48+
./v5_chain -nocache -gc none -backend arm64 -o v6_chain v2.v
3749
V5_SIZE=$(wc -c < v5_chain)
38-
if [ "$V4_SIZE" -eq "$V5_SIZE" ]; then
39-
echo " v4=v5 ($V4_SIZE bytes) — chain converged"
50+
V6_SIZE=$(wc -c < v6_chain)
51+
if [ "$V5_SIZE" -eq "$V6_SIZE" ]; then
52+
echo " v5=v6 ($V5_SIZE bytes) — chain converged"
4053
else
41-
echo " FAIL: v4 ($V4_SIZE) != v5 ($V5_SIZE)"
54+
echo " FAIL: v5 ($V5_SIZE) != v6 ($V6_SIZE)"
4255
exit 1
4356
fi
44-
rm -f v3_chain v4_chain v5_chain
57+
rm -f v3_chain v4_chain v5_chain v6_chain
4558

4659
echo ""
4760
echo "=== 3/14: Self-host test ==="
@@ -96,23 +109,23 @@ echo "=== 9/14: Sumtype tests (arm64) ==="
96109

97110
echo ""
98111
echo "=== 10/14: SSA backends test (arm64) ==="
99-
v -gc none run test_ssa_backends.v arm64
112+
"${v1_compiler}" -gc none run test_ssa_backends.v arm64
100113

101114
echo ""
102115
echo "=== 11/14: SSA backends test (cleanc) ==="
103-
v -gc none run test_ssa_backends.v cleanc
116+
"${v1_compiler}" -gc none run test_ssa_backends.v cleanc
104117

105118
echo ""
106119
echo "=== 12/14: Transformer unit tests ==="
107-
v ../../vlib/v2/transformer/transformer_test.v
120+
"${v1_compiler}" ../../vlib/v2/transformer/transformer_test.v
108121

109122
echo ""
110123
echo "=== 13/14: Transformer integration test ==="
111-
v ../../vlib/v2/transformer/transformer_v2_darwin_test.v
124+
"${v1_compiler}" ../../vlib/v2/transformer/transformer_v2_darwin_test.v
112125

113126
echo ""
114127
echo "=== 14/14: Cleanc runtime tests ==="
115-
v -gc none run ../../vlib/v2/gen/cleanc/tests/run_tests.v
128+
"${v1_compiler}" -gc none run ../../vlib/v2/gen/cleanc/tests/run_tests.v
116129

117130
echo ""
118131
if [ "$KNOWN_FAILURES" -gt 0 ]; then

vlib/db/pg/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ brew install postgresql
3333
brew services start postgresql
3434
```
3535

36+
On newer Homebrew setups the formula and service name may be versioned
37+
instead, for example `postgresql@18`. Use the exact name reported by
38+
`brew info postgresql`.
39+
3640
### MacOSX (MacPorts)
3741

3842
```
@@ -116,6 +120,10 @@ Read this section to learn how to install and connect to PostgreSQL
116120
[*Linux*](https://www.postgresqltutorial.com/postgresql-getting-started/install-postgresql-linux);
117121
[*macOS*](https://www.postgresqltutorial.com/postgresql-getting-started/install-postgresql-macos).
118122

123+
When you use `pg.connect(pg.Config{ ... })`, empty `Config` fields are omitted from the
124+
generated libpq connection string. That lets libpq defaults, `PGPASSWORD`, and `.pgpass`
125+
apply when you do not set those fields in code.
126+
119127
## Using Parameterized Queries
120128

121129
Parameterized queries (exec_param, etc.) in V require the use of the following syntax: ($n).

vlib/db/pg/pg.c.v

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,57 @@ fn C.PQsocket(conn &C.PGconn) i32
210210

211211
fn C.PQescapeLiteral(conn &C.PGconn, str &char, length usize) &char
212212

213+
fn conninfo_needs_quotes(value string) bool {
214+
for ch in value {
215+
if ch.is_space() || ch == `'` || ch == `\\` {
216+
return true
217+
}
218+
}
219+
return false
220+
}
221+
222+
fn escape_conninfo_value(value string) string {
223+
if !conninfo_needs_quotes(value) {
224+
return value
225+
}
226+
mut escaped := []u8{cap: value.len + 2}
227+
escaped << `'`
228+
for ch in value {
229+
if ch == `\\` || ch == `'` {
230+
escaped << `\\`
231+
}
232+
escaped << ch
233+
}
234+
escaped << `'`
235+
return escaped.bytestr()
236+
}
237+
238+
fn (config Config) conninfo() string {
239+
mut parts := []string{cap: 5}
240+
if config.host != '' {
241+
parts << 'host=${escape_conninfo_value(config.host)}'
242+
}
243+
if config.port > 0 {
244+
parts << 'port=${config.port}'
245+
}
246+
if config.user != '' {
247+
parts << 'user=${escape_conninfo_value(config.user)}'
248+
}
249+
if config.dbname != '' {
250+
parts << 'dbname=${escape_conninfo_value(config.dbname)}'
251+
}
252+
if config.password != '' {
253+
parts << 'password=${escape_conninfo_value(config.password)}'
254+
}
255+
return parts.join(' ')
256+
}
257+
213258
// connect makes a new connection to the database server using
214259
// the parameters from the `Config` structure, returning
215-
// a connection error when something goes wrong
260+
// a connection error when something goes wrong.
261+
// Empty fields are omitted so libpq defaults can still apply.
216262
pub fn connect(config Config) !DB {
217-
conninfo := 'host=${config.host} port=${config.port} user=${config.user} dbname=${config.dbname} password=${config.password}'
218-
219-
return connect_with_conninfo(conninfo)!
263+
return connect_with_conninfo(config.conninfo())!
220264
}
221265

222266
// connect_with_conninfo makes a new connection to the database server using

vlib/goroutines/context_nix.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#ifndef GOROUTINES_CONTEXT_NIX_H
2+
#define GOROUTINES_CONTEXT_NIX_H
3+
4+
#include <ucontext.h>
5+
#include <stdint.h>
6+
#include <stdlib.h>
7+
8+
// Extended context: ucontext_t + entry function info for first-time starts.
9+
typedef struct {
10+
ucontext_t uctx;
11+
void (*entry_fn)(void *);
12+
void *entry_arg;
13+
} goroutine_ctx_t;
14+
15+
// Thread-local pointer to the target goroutine context.
16+
// Set just before swapcontext/setcontext so the trampoline can find its fn/arg.
17+
#if defined(_WIN32) || defined(_WIN64)
18+
static __declspec(thread) goroutine_ctx_t *_goroutine_start_ctx = NULL;
19+
#else
20+
static _Thread_local goroutine_ctx_t *_goroutine_start_ctx = NULL;
21+
#endif
22+
23+
static void *goroutines_context_alloc(void) {
24+
return calloc(1, sizeof(goroutine_ctx_t));
25+
}
26+
27+
// Zero-argument trampoline. Reads fn/arg from the TLS-stored context.
28+
// This avoids passing arguments through makecontext, which is broken on macOS ARM64.
29+
static void goroutines__context_trampoline(void) {
30+
goroutine_ctx_t *gctx = _goroutine_start_ctx;
31+
_goroutine_start_ctx = NULL;
32+
void (*fn)(void *) = gctx->entry_fn;
33+
void *arg = gctx->entry_arg;
34+
// Clear so future context switches to this goroutine don't re-trigger
35+
gctx->entry_fn = NULL;
36+
gctx->entry_arg = NULL;
37+
fn(arg);
38+
}
39+
40+
static void goroutines_context_init(void *ctx_buf, void *stack, int stack_size, void *entry_fn, void *arg) {
41+
goroutine_ctx_t *gctx = (goroutine_ctx_t *)ctx_buf;
42+
gctx->entry_fn = (void (*)(void *))entry_fn;
43+
gctx->entry_arg = arg;
44+
getcontext(&gctx->uctx);
45+
gctx->uctx.uc_stack.ss_sp = stack;
46+
gctx->uctx.uc_stack.ss_size = (size_t)stack_size;
47+
gctx->uctx.uc_link = NULL;
48+
makecontext(&gctx->uctx, (void (*)())goroutines__context_trampoline, 0);
49+
}
50+
51+
static void goroutines_context_switch(void *from_buf, void *to_buf) {
52+
goroutine_ctx_t *from = (goroutine_ctx_t *)from_buf;
53+
goroutine_ctx_t *to = (goroutine_ctx_t *)to_buf;
54+
// If switching to a goroutine that hasn't started yet, set TLS for trampoline
55+
if (to->entry_fn != NULL) {
56+
_goroutine_start_ctx = to;
57+
}
58+
swapcontext(&from->uctx, &to->uctx);
59+
}
60+
61+
static void goroutines_context_set(void *to_buf) {
62+
goroutine_ctx_t *to = (goroutine_ctx_t *)to_buf;
63+
if (to->entry_fn != NULL) {
64+
_goroutine_start_ctx = to;
65+
}
66+
setcontext(&to->uctx);
67+
}
68+
69+
#endif

vlib/io/readerwriter.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ mut:
1717
// read reads up to `buf.len` bytes into `buf`. It returns
1818
// the number of bytes read or any error encountered.
1919
pub fn (mut r ReaderWriterImpl) read(mut buf []u8) !int {
20-
return r.r.read(mut buf)
20+
mut local_buf := unsafe { buf[0..buf.len] }
21+
return r.r.read(mut local_buf)
2122
}
2223

2324
// write writes `buf.len` bytes from `buf` to the underlying

0 commit comments

Comments
 (0)