Release 1.0.0-beta.6 networking foundation
This commit is contained in:
parent
9956b1d874
commit
2726ec4915
66
.llm/BETA_6_NETWORKING_FOUNDATION.md
Normal file
66
.llm/BETA_6_NETWORKING_FOUNDATION.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# 1.0.0-beta.6 Networking Foundation Target
|
||||||
|
|
||||||
|
Status: released as `1.0.0-beta.6` on 2026-05-22.
|
||||||
|
|
||||||
|
`1.0.0-beta.6` targets a deliberately narrow networking foundation after the
|
||||||
|
resource-handle and host-error policy introduced in `1.0.0-beta.2`. The goal
|
||||||
|
is blocking loopback TCP only, enough for local client/server fixtures and
|
||||||
|
small request/response examples without committing to a full networking stack.
|
||||||
|
|
||||||
|
## Slovo Source Surface
|
||||||
|
|
||||||
|
The staged source facade is `lib/std/net.slo`, importable explicitly as
|
||||||
|
`std.net`.
|
||||||
|
|
||||||
|
Exported helpers:
|
||||||
|
|
||||||
|
- `tcp_connect_loopback_result : (i32) -> (result i32 i32)`
|
||||||
|
- `tcp_listen_loopback_result : (i32) -> (result i32 i32)`
|
||||||
|
- `tcp_bound_port_result : (i32) -> (result i32 i32)`
|
||||||
|
- `tcp_accept_result : (i32) -> (result i32 i32)`
|
||||||
|
- `tcp_read_all_result : (i32) -> (result string i32)`
|
||||||
|
- `tcp_write_text_result : (i32, string) -> (result i32 i32)`
|
||||||
|
- `tcp_close_result : (i32) -> (result i32 i32)`
|
||||||
|
- `tcp_write_text_ok : (i32, string) -> bool`
|
||||||
|
- `tcp_close_ok : (i32) -> bool`
|
||||||
|
|
||||||
|
The `i32` values returned by successful connect/listen/accept operations are
|
||||||
|
opaque process-local handles. They are not host file descriptors, stable ABI
|
||||||
|
values, transferable capabilities, or ownership-checked affine resources.
|
||||||
|
|
||||||
|
## Runtime Calls
|
||||||
|
|
||||||
|
The facade wraps these compiler-known runtime calls:
|
||||||
|
|
||||||
|
- `std.net.tcp_connect_loopback_result(port i32) -> (result i32 i32)`
|
||||||
|
- `std.net.tcp_listen_loopback_result(port i32) -> (result i32 i32)`
|
||||||
|
- `std.net.tcp_bound_port_result(handle i32) -> (result i32 i32)`
|
||||||
|
- `std.net.tcp_accept_result(listener i32) -> (result i32 i32)`
|
||||||
|
- `std.net.tcp_read_all_result(handle i32) -> (result string i32)`
|
||||||
|
- `std.net.tcp_write_text_result(handle i32, text string) -> (result i32 i32)`
|
||||||
|
- `std.net.tcp_close_result(handle i32) -> (result i32 i32)`
|
||||||
|
|
||||||
|
Ordinary host failures return `err 1`. Successful status-returning operations
|
||||||
|
return `ok 0`. Successful handle-returning operations return `ok handle`.
|
||||||
|
Successful `tcp_bound_port_result` returns the bound loopback TCP port.
|
||||||
|
|
||||||
|
## Fixtures
|
||||||
|
|
||||||
|
- `examples/projects/std-import-net/` exercises explicit `std.net` source
|
||||||
|
import.
|
||||||
|
- `examples/projects/std-layout-local-net/` mirrors the facade as a local
|
||||||
|
module fixture and keeps the source-search contract explicit.
|
||||||
|
|
||||||
|
The source-side fixtures use invalid ports and handles for deterministic
|
||||||
|
result-shape checks. Positive loopback client/server behavior is covered by
|
||||||
|
the matching compiler/runtime tests when the local sandbox allows loopback
|
||||||
|
sockets.
|
||||||
|
|
||||||
|
## Deferrals
|
||||||
|
|
||||||
|
This scope does not add DNS, TLS, UDP, Unix-domain sockets, non-loopback
|
||||||
|
binding, async IO, event loops, readiness polling, timeouts, buffering policy,
|
||||||
|
HTTP frameworks, socket options beyond the implementation minimum,
|
||||||
|
platform-specific error codes, rich host-error ADTs, stable runtime helper
|
||||||
|
symbols, stable ABI/layout/ownership guarantees, automatic cleanup, or a
|
||||||
|
stable standard-library API freeze.
|
||||||
28
README.md
28
README.md
@ -6,7 +6,7 @@ This repository is the canonical public monorepo for the language design,
|
|||||||
standard library source, compiler, runtime, examples, benchmarks, and technical
|
standard library source, compiler, runtime, examples, benchmarks, and technical
|
||||||
documents.
|
documents.
|
||||||
|
|
||||||
Current release: `1.0.0-beta.5`.
|
Current release: `1.0.0-beta.6`.
|
||||||
|
|
||||||
## Repository Layout
|
## Repository Layout
|
||||||
|
|
||||||
@ -24,13 +24,13 @@ scripts/ local release and document tooling
|
|||||||
|
|
||||||
## Beta Scope
|
## Beta Scope
|
||||||
|
|
||||||
`1.0.0-beta.5` keeps the `1.0.0-beta` language baseline, includes the
|
`1.0.0-beta.6` keeps the `1.0.0-beta` language baseline, includes the
|
||||||
`1.0.0-beta.1` tooling/install hardening slice, the `1.0.0-beta.2`
|
`1.0.0-beta.1` tooling/install hardening slice, the `1.0.0-beta.2`
|
||||||
runtime/resource foundation bundle, the `1.0.0-beta.3` standard-library
|
runtime/resource foundation bundle, the `1.0.0-beta.3` standard-library
|
||||||
stabilization bundle, the `1.0.0-beta.4` language-usability diagnostics
|
stabilization bundle, the `1.0.0-beta.4` language-usability diagnostics
|
||||||
bundle, and the `1.0.0-beta.5` local package/workspace discipline bundle. The
|
bundle, the `1.0.0-beta.5` local package/workspace discipline bundle, and the
|
||||||
language baseline supports practical local command-line programs and libraries
|
`1.0.0-beta.6` loopback networking foundation. The language baseline supports
|
||||||
with:
|
practical local command-line programs and libraries with:
|
||||||
|
|
||||||
- modules, explicit imports, packages, and local workspaces
|
- modules, explicit imports, packages, and local workspaces
|
||||||
- `new`, `check`, `fmt`, `test`, `doc`, and `build`
|
- `new`, `check`, `fmt`, `test`, `doc`, and `build`
|
||||||
@ -39,11 +39,12 @@ with:
|
|||||||
current `match`
|
current `match`
|
||||||
- explicit `std/*.slo` imports from `lib/std`, installed `share/slovo/std`, or
|
- explicit `std/*.slo` imports from `lib/std`, installed `share/slovo/std`, or
|
||||||
`SLOVO_STD_PATH`
|
`SLOVO_STD_PATH`
|
||||||
|
- beta-scoped loopback TCP handles through `std.net`
|
||||||
- hosted native builds through LLVM IR, Clang, and `runtime/runtime.c`
|
- hosted native builds through LLVM IR, Clang, and `runtime/runtime.c`
|
||||||
|
|
||||||
Still deferred before stable: generics, maps/sets, broad package registry
|
Still deferred before stable: generics, maps/sets, broad package registry
|
||||||
semantics, networking/async, LSP/watch/debug-adapter guarantees, stable ABI and
|
semantics, DNS/TLS/async networking, LSP/watch/debug-adapter guarantees,
|
||||||
layout, and a stable standard-library compatibility freeze.
|
stable ABI and layout, and a stable standard-library compatibility freeze.
|
||||||
|
|
||||||
## Build And Test
|
## Build And Test
|
||||||
|
|
||||||
@ -163,6 +164,19 @@ package/dependency summary, new workspace templates declare
|
|||||||
local-package rules. Remote registries, lockfiles, semantic-version solving,
|
local-package rules. Remote registries, lockfiles, semantic-version solving,
|
||||||
package publishing, and stable package ABI/layout remain deferred.
|
package publishing, and stable package ABI/layout remain deferred.
|
||||||
|
|
||||||
|
## 1.0.0-beta.6 Networking Foundation
|
||||||
|
|
||||||
|
The `1.0.0-beta.6` release adds a narrow blocking loopback TCP foundation:
|
||||||
|
|
||||||
|
- compiler-known `std.net.tcp_*_result` calls for connect, listen,
|
||||||
|
bound-port lookup, accept, read-all, write-text, and close
|
||||||
|
- `lib/std/net.slo` source facades and explicit std/local example projects
|
||||||
|
- opaque beta-scoped `i32` socket handles with concrete `result` values
|
||||||
|
|
||||||
|
This is not a general networking stack. DNS, TLS, UDP, non-loopback binding,
|
||||||
|
async IO, HTTP frameworks, rich host-error ADTs, stable socket ABI/layout, and
|
||||||
|
automatic resource ownership remain deferred.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
- [Language Manifest](docs/language/MANIFEST.md)
|
- [Language Manifest](docs/language/MANIFEST.md)
|
||||||
|
|||||||
2
compiler/Cargo.lock
generated
2
compiler/Cargo.lock
generated
@ -4,4 +4,4 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glagol"
|
name = "glagol"
|
||||||
version = "1.0.0-beta.5"
|
version = "1.0.0-beta.6"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "glagol"
|
name = "glagol"
|
||||||
version = "1.0.0-beta.5"
|
version = "1.0.0-beta.6"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Glagol, the first compiler for the Slovo language"
|
description = "Glagol, the first compiler for the Slovo language"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|||||||
@ -57,6 +57,13 @@ pub fn emit(_file: &str, program: &CheckedProgram) -> Result<String, Vec<Diagnos
|
|||||||
out.push_str("declare i64 @__glagol_fs_open_text_read_result(ptr)\n\n");
|
out.push_str("declare i64 @__glagol_fs_open_text_read_result(ptr)\n\n");
|
||||||
out.push_str("declare ptr @__glagol_fs_read_open_text_result(i32)\n\n");
|
out.push_str("declare ptr @__glagol_fs_read_open_text_result(i32)\n\n");
|
||||||
out.push_str("declare i32 @__glagol_fs_close_result(i32)\n\n");
|
out.push_str("declare i32 @__glagol_fs_close_result(i32)\n\n");
|
||||||
|
out.push_str("declare i64 @__glagol_net_tcp_connect_loopback_result(i32)\n\n");
|
||||||
|
out.push_str("declare i64 @__glagol_net_tcp_listen_loopback_result(i32)\n\n");
|
||||||
|
out.push_str("declare i64 @__glagol_net_tcp_bound_port_result(i32)\n\n");
|
||||||
|
out.push_str("declare i64 @__glagol_net_tcp_accept_result(i32)\n\n");
|
||||||
|
out.push_str("declare ptr @__glagol_net_tcp_read_all_result(i32)\n\n");
|
||||||
|
out.push_str("declare i32 @__glagol_net_tcp_write_text_result(i32, ptr)\n\n");
|
||||||
|
out.push_str("declare i32 @__glagol_net_tcp_close_result(i32)\n\n");
|
||||||
out.push_str("declare i1 @__glagol_string_eq(ptr, ptr)\n\n");
|
out.push_str("declare i1 @__glagol_string_eq(ptr, ptr)\n\n");
|
||||||
out.push_str("declare ptr @__glagol_vec_i32_empty()\n\n");
|
out.push_str("declare ptr @__glagol_vec_i32_empty()\n\n");
|
||||||
out.push_str("declare ptr @__glagol_vec_i32_append(ptr, i32)\n\n");
|
out.push_str("declare ptr @__glagol_vec_i32_append(ptr, i32)\n\n");
|
||||||
@ -1661,6 +1668,7 @@ impl FunctionGen<'_> {
|
|||||||
| "__glagol_env_get_result"
|
| "__glagol_env_get_result"
|
||||||
| "__glagol_fs_read_text_result"
|
| "__glagol_fs_read_text_result"
|
||||||
| "__glagol_fs_read_open_text_result"
|
| "__glagol_fs_read_open_text_result"
|
||||||
|
| "__glagol_net_tcp_read_all_result"
|
||||||
| "__glagol_io_read_stdin_result"
|
| "__glagol_io_read_stdin_result"
|
||||||
) {
|
) {
|
||||||
return self.emit_string_result_host_call(expr, callee, &arg_values);
|
return self.emit_string_result_host_call(expr, callee, &arg_values);
|
||||||
@ -1670,11 +1678,17 @@ impl FunctionGen<'_> {
|
|||||||
|| callee == "__glagol_fs_remove_file_result"
|
|| callee == "__glagol_fs_remove_file_result"
|
||||||
|| callee == "__glagol_fs_create_dir_result"
|
|| callee == "__glagol_fs_create_dir_result"
|
||||||
|| callee == "__glagol_fs_close_result"
|
|| callee == "__glagol_fs_close_result"
|
||||||
|
|| callee == "__glagol_net_tcp_write_text_result"
|
||||||
|
|| callee == "__glagol_net_tcp_close_result"
|
||||||
{
|
{
|
||||||
return self.emit_i32_result_status_call(expr, callee, &arg_values);
|
return self.emit_i32_result_status_call(expr, callee, &arg_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
if callee == "__glagol_fs_open_text_read_result"
|
if callee == "__glagol_fs_open_text_read_result"
|
||||||
|
|| callee == "__glagol_net_tcp_connect_loopback_result"
|
||||||
|
|| callee == "__glagol_net_tcp_listen_loopback_result"
|
||||||
|
|| callee == "__glagol_net_tcp_bound_port_result"
|
||||||
|
|| callee == "__glagol_net_tcp_accept_result"
|
||||||
|| callee == "__glagol_string_parse_i32_result"
|
|| callee == "__glagol_string_parse_i32_result"
|
||||||
{
|
{
|
||||||
return self.emit_i32_result_encoded_i64_call(expr, callee, &arg_values);
|
return self.emit_i32_result_encoded_i64_call(expr, callee, &arg_values);
|
||||||
|
|||||||
@ -68,6 +68,7 @@ const F64_PARAM: &[RuntimeType] = &[RuntimeType::F64];
|
|||||||
const BOOL_PARAM: &[RuntimeType] = &[RuntimeType::Bool];
|
const BOOL_PARAM: &[RuntimeType] = &[RuntimeType::Bool];
|
||||||
const STRING_PARAM: &[RuntimeType] = &[RuntimeType::String];
|
const STRING_PARAM: &[RuntimeType] = &[RuntimeType::String];
|
||||||
const STRING_STRING_PARAMS: &[RuntimeType] = &[RuntimeType::String, RuntimeType::String];
|
const STRING_STRING_PARAMS: &[RuntimeType] = &[RuntimeType::String, RuntimeType::String];
|
||||||
|
const I32_STRING_PARAMS: &[RuntimeType] = &[RuntimeType::I32, RuntimeType::String];
|
||||||
const VEC_I32_PARAM: &[RuntimeType] = &[RuntimeType::VecI32];
|
const VEC_I32_PARAM: &[RuntimeType] = &[RuntimeType::VecI32];
|
||||||
const VEC_I32_I32_PARAMS: &[RuntimeType] = &[RuntimeType::VecI32, RuntimeType::I32];
|
const VEC_I32_I32_PARAMS: &[RuntimeType] = &[RuntimeType::VecI32, RuntimeType::I32];
|
||||||
const VEC_I64_PARAM: &[RuntimeType] = &[RuntimeType::VecI64];
|
const VEC_I64_PARAM: &[RuntimeType] = &[RuntimeType::VecI64];
|
||||||
@ -350,6 +351,55 @@ pub const FUNCTIONS: &[RuntimeFunction] = &[
|
|||||||
return_type: RuntimeType::ResultI32I32,
|
return_type: RuntimeType::ResultI32I32,
|
||||||
promoted: true,
|
promoted: true,
|
||||||
},
|
},
|
||||||
|
RuntimeFunction {
|
||||||
|
source_name: "std.net.tcp_connect_loopback_result",
|
||||||
|
runtime_symbol: "__glagol_net_tcp_connect_loopback_result",
|
||||||
|
params: I32_PARAM,
|
||||||
|
return_type: RuntimeType::ResultI32I32,
|
||||||
|
promoted: true,
|
||||||
|
},
|
||||||
|
RuntimeFunction {
|
||||||
|
source_name: "std.net.tcp_listen_loopback_result",
|
||||||
|
runtime_symbol: "__glagol_net_tcp_listen_loopback_result",
|
||||||
|
params: I32_PARAM,
|
||||||
|
return_type: RuntimeType::ResultI32I32,
|
||||||
|
promoted: true,
|
||||||
|
},
|
||||||
|
RuntimeFunction {
|
||||||
|
source_name: "std.net.tcp_bound_port_result",
|
||||||
|
runtime_symbol: "__glagol_net_tcp_bound_port_result",
|
||||||
|
params: I32_PARAM,
|
||||||
|
return_type: RuntimeType::ResultI32I32,
|
||||||
|
promoted: true,
|
||||||
|
},
|
||||||
|
RuntimeFunction {
|
||||||
|
source_name: "std.net.tcp_accept_result",
|
||||||
|
runtime_symbol: "__glagol_net_tcp_accept_result",
|
||||||
|
params: I32_PARAM,
|
||||||
|
return_type: RuntimeType::ResultI32I32,
|
||||||
|
promoted: true,
|
||||||
|
},
|
||||||
|
RuntimeFunction {
|
||||||
|
source_name: "std.net.tcp_read_all_result",
|
||||||
|
runtime_symbol: "__glagol_net_tcp_read_all_result",
|
||||||
|
params: I32_PARAM,
|
||||||
|
return_type: RuntimeType::ResultStringI32,
|
||||||
|
promoted: true,
|
||||||
|
},
|
||||||
|
RuntimeFunction {
|
||||||
|
source_name: "std.net.tcp_write_text_result",
|
||||||
|
runtime_symbol: "__glagol_net_tcp_write_text_result",
|
||||||
|
params: I32_STRING_PARAMS,
|
||||||
|
return_type: RuntimeType::ResultI32I32,
|
||||||
|
promoted: true,
|
||||||
|
},
|
||||||
|
RuntimeFunction {
|
||||||
|
source_name: "std.net.tcp_close_result",
|
||||||
|
runtime_symbol: "__glagol_net_tcp_close_result",
|
||||||
|
params: I32_PARAM,
|
||||||
|
return_type: RuntimeType::ResultI32I32,
|
||||||
|
promoted: true,
|
||||||
|
},
|
||||||
RuntimeFunction {
|
RuntimeFunction {
|
||||||
source_name: "std.vec.i32.empty",
|
source_name: "std.vec.i32.empty",
|
||||||
runtime_symbol: "__glagol_vec_i32_empty",
|
runtime_symbol: "__glagol_vec_i32_empty",
|
||||||
@ -665,6 +715,13 @@ const RESERVED_HELPER_SYMBOLS: &[&str] = &[
|
|||||||
"__glagol_fs_open_text_read_result",
|
"__glagol_fs_open_text_read_result",
|
||||||
"__glagol_fs_read_open_text_result",
|
"__glagol_fs_read_open_text_result",
|
||||||
"__glagol_fs_close_result",
|
"__glagol_fs_close_result",
|
||||||
|
"__glagol_net_tcp_connect_loopback_result",
|
||||||
|
"__glagol_net_tcp_listen_loopback_result",
|
||||||
|
"__glagol_net_tcp_bound_port_result",
|
||||||
|
"__glagol_net_tcp_accept_result",
|
||||||
|
"__glagol_net_tcp_read_all_result",
|
||||||
|
"__glagol_net_tcp_write_text_result",
|
||||||
|
"__glagol_net_tcp_close_result",
|
||||||
"__glagol_vec_i32_eq",
|
"__glagol_vec_i32_eq",
|
||||||
"__glagol_vec_i32_allocation_trap",
|
"__glagol_vec_i32_allocation_trap",
|
||||||
"__glagol_vec_i32_index_trap",
|
"__glagol_vec_i32_index_trap",
|
||||||
|
|||||||
@ -2672,6 +2672,170 @@ fn eval_expr(
|
|||||||
payload: if was_open { 0 } else { 1 },
|
payload: if was_open { 0 } else { 1 },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if runtime_symbol == "__glagol_net_tcp_connect_loopback_result" {
|
||||||
|
let Some(port) = args.first() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_connect_loopback_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let port = eval_expr(file, port, locals, functions, foreign_imports, depth)?;
|
||||||
|
let Some(_) = port.as_i32() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_connect_loopback_result` port on non-i32 values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
return Ok(Value::ResultI32 {
|
||||||
|
is_ok: false,
|
||||||
|
payload: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if runtime_symbol == "__glagol_net_tcp_listen_loopback_result" {
|
||||||
|
let Some(port) = args.first() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_listen_loopback_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let port = eval_expr(file, port, locals, functions, foreign_imports, depth)?;
|
||||||
|
let Some(_) = port.as_i32() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_listen_loopback_result` port on non-i32 values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
return Ok(Value::ResultI32 {
|
||||||
|
is_ok: false,
|
||||||
|
payload: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if runtime_symbol == "__glagol_net_tcp_bound_port_result" {
|
||||||
|
let Some(handle) = args.first() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_bound_port_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let handle = eval_expr(file, handle, locals, functions, foreign_imports, depth)?;
|
||||||
|
let Some(_) = handle.as_i32() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_bound_port_result` handle on non-i32 values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
return Ok(Value::ResultI32 {
|
||||||
|
is_ok: false,
|
||||||
|
payload: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if runtime_symbol == "__glagol_net_tcp_accept_result" {
|
||||||
|
let Some(listener) = args.first() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_accept_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let listener =
|
||||||
|
eval_expr(file, listener, locals, functions, foreign_imports, depth)?;
|
||||||
|
let Some(_) = listener.as_i32() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_accept_result` listener on non-i32 values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
return Ok(Value::ResultI32 {
|
||||||
|
is_ok: false,
|
||||||
|
payload: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if runtime_symbol == "__glagol_net_tcp_read_all_result" {
|
||||||
|
let Some(handle) = args.first() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_read_all_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let handle = eval_expr(file, handle, locals, functions, foreign_imports, depth)?;
|
||||||
|
let Some(_) = handle.as_i32() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_read_all_result` handle on non-i32 values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
return Ok(Value::ResultStringI32 {
|
||||||
|
is_ok: false,
|
||||||
|
ok_payload: String::new(),
|
||||||
|
err_payload: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if runtime_symbol == "__glagol_net_tcp_write_text_result" {
|
||||||
|
let Some(handle) = args.first() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_write_text_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Some(text) = args.get(1) else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_write_text_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let handle = eval_expr(file, handle, locals, functions, foreign_imports, depth)?;
|
||||||
|
let text = eval_expr(file, text, locals, functions, foreign_imports, depth)?;
|
||||||
|
let Some(_) = handle.as_i32() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_write_text_result` handle on non-i32 values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let Some(_) = text.as_string() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_write_text_result` text on non-string values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
return Ok(Value::ResultI32 {
|
||||||
|
is_ok: false,
|
||||||
|
payload: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if runtime_symbol == "__glagol_net_tcp_close_result" {
|
||||||
|
let Some(handle) = args.first() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"malformed `std.net.tcp_close_result` calls",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let handle = eval_expr(file, handle, locals, functions, foreign_imports, depth)?;
|
||||||
|
let Some(_) = handle.as_i32() else {
|
||||||
|
return Err(unsupported_test_expr(
|
||||||
|
file,
|
||||||
|
expr,
|
||||||
|
"`std.net.tcp_close_result` handle on non-i32 values",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
return Ok(Value::ResultI32 {
|
||||||
|
is_ok: false,
|
||||||
|
payload: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
if runtime_symbol == "__glagol_vec_i32_empty" {
|
if runtime_symbol == "__glagol_vec_i32_empty" {
|
||||||
return Ok(Value::VecI32(Vec::new()));
|
return Ok(Value::VecI32(Vec::new()));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1141,6 +1141,28 @@ const STANDARD_FS_SOURCE_FACADE_ALPHA: &[&str] = &[
|
|||||||
"read_bool_or",
|
"read_bool_or",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const STANDARD_NET_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
|
"tcp_connect_loopback_result",
|
||||||
|
"tcp_listen_loopback_result",
|
||||||
|
"tcp_bound_port_result",
|
||||||
|
"tcp_accept_result",
|
||||||
|
"tcp_read_all_result",
|
||||||
|
"tcp_write_text_result",
|
||||||
|
"tcp_close_result",
|
||||||
|
"tcp_write_text_ok",
|
||||||
|
"tcp_close_ok",
|
||||||
|
];
|
||||||
|
|
||||||
|
const STANDARD_NET_RUNTIME_NAMES: &[&str] = &[
|
||||||
|
"std.net.tcp_connect_loopback_result",
|
||||||
|
"std.net.tcp_listen_loopback_result",
|
||||||
|
"std.net.tcp_bound_port_result",
|
||||||
|
"std.net.tcp_accept_result",
|
||||||
|
"std.net.tcp_read_all_result",
|
||||||
|
"std.net.tcp_write_text_result",
|
||||||
|
"std.net.tcp_close_result",
|
||||||
|
];
|
||||||
|
|
||||||
const STANDARD_PROCESS_SOURCE_FACADE_ALPHA: &[&str] = &[
|
const STANDARD_PROCESS_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
"argc",
|
"argc",
|
||||||
"arg",
|
"arg",
|
||||||
@ -1715,6 +1737,7 @@ fn promotion_gate_artifacts_are_aligned() {
|
|||||||
repo.join("examples/projects/std-layout-local-random");
|
repo.join("examples/projects/std-layout-local-random");
|
||||||
let glagol_project_std_layout_local_env = repo.join("examples/projects/std-layout-local-env");
|
let glagol_project_std_layout_local_env = repo.join("examples/projects/std-layout-local-env");
|
||||||
let glagol_project_std_layout_local_fs = repo.join("examples/projects/std-layout-local-fs");
|
let glagol_project_std_layout_local_fs = repo.join("examples/projects/std-layout-local-fs");
|
||||||
|
let glagol_project_std_layout_local_net = repo.join("examples/projects/std-layout-local-net");
|
||||||
let glagol_project_std_layout_local_io = repo.join("examples/projects/std-layout-local-io");
|
let glagol_project_std_layout_local_io = repo.join("examples/projects/std-layout-local-io");
|
||||||
let glagol_project_std_layout_local_cli = repo.join("examples/projects/std-layout-local-cli");
|
let glagol_project_std_layout_local_cli = repo.join("examples/projects/std-layout-local-cli");
|
||||||
let glagol_project_std_layout_local_vec_i32 =
|
let glagol_project_std_layout_local_vec_i32 =
|
||||||
@ -1734,6 +1757,7 @@ fn promotion_gate_artifacts_are_aligned() {
|
|||||||
let glagol_project_std_import_random = repo.join("examples/projects/std-import-random");
|
let glagol_project_std_import_random = repo.join("examples/projects/std-import-random");
|
||||||
let glagol_project_std_import_env = repo.join("examples/projects/std-import-env");
|
let glagol_project_std_import_env = repo.join("examples/projects/std-import-env");
|
||||||
let glagol_project_std_import_fs = repo.join("examples/projects/std-import-fs");
|
let glagol_project_std_import_fs = repo.join("examples/projects/std-import-fs");
|
||||||
|
let glagol_project_std_import_net = repo.join("examples/projects/std-import-net");
|
||||||
let glagol_project_std_import_process = repo.join("examples/projects/std-import-process");
|
let glagol_project_std_import_process = repo.join("examples/projects/std-import-process");
|
||||||
let glagol_project_std_import_string = repo.join("examples/projects/std-import-string");
|
let glagol_project_std_import_string = repo.join("examples/projects/std-import-string");
|
||||||
let glagol_project_std_import_num = repo.join("examples/projects/std-import-num");
|
let glagol_project_std_import_num = repo.join("examples/projects/std-import-num");
|
||||||
@ -2085,6 +2109,7 @@ fn promotion_gate_artifacts_are_aligned() {
|
|||||||
assert_project_std_import_random_tooling_matches_fixture(&glagol_project_std_import_random);
|
assert_project_std_import_random_tooling_matches_fixture(&glagol_project_std_import_random);
|
||||||
assert_project_std_import_env_tooling_matches_fixture(&glagol_project_std_import_env);
|
assert_project_std_import_env_tooling_matches_fixture(&glagol_project_std_import_env);
|
||||||
assert_project_std_import_fs_tooling_matches_fixture(&glagol_project_std_import_fs);
|
assert_project_std_import_fs_tooling_matches_fixture(&glagol_project_std_import_fs);
|
||||||
|
assert_project_std_import_net_tooling_matches_fixture(&glagol_project_std_import_net);
|
||||||
assert_project_std_import_process_tooling_matches_fixture(&glagol_project_std_import_process);
|
assert_project_std_import_process_tooling_matches_fixture(&glagol_project_std_import_process);
|
||||||
assert_project_std_import_string_tooling_matches_fixture(&glagol_project_std_import_string);
|
assert_project_std_import_string_tooling_matches_fixture(&glagol_project_std_import_string);
|
||||||
assert_project_std_import_num_tooling_matches_fixture(&glagol_project_std_import_num);
|
assert_project_std_import_num_tooling_matches_fixture(&glagol_project_std_import_num);
|
||||||
@ -2123,6 +2148,9 @@ fn promotion_gate_artifacts_are_aligned() {
|
|||||||
&glagol_project_std_layout_local_env,
|
&glagol_project_std_layout_local_env,
|
||||||
);
|
);
|
||||||
assert_project_std_layout_local_fs_tooling_matches_fixture(&glagol_project_std_layout_local_fs);
|
assert_project_std_layout_local_fs_tooling_matches_fixture(&glagol_project_std_layout_local_fs);
|
||||||
|
assert_project_std_layout_local_net_tooling_matches_fixture(
|
||||||
|
&glagol_project_std_layout_local_net,
|
||||||
|
);
|
||||||
assert_project_std_layout_local_io_tooling_matches_fixture(&glagol_project_std_layout_local_io);
|
assert_project_std_layout_local_io_tooling_matches_fixture(&glagol_project_std_layout_local_io);
|
||||||
assert_project_std_layout_local_cli_tooling_matches_fixture(
|
assert_project_std_layout_local_cli_tooling_matches_fixture(
|
||||||
&glagol_project_std_layout_local_cli,
|
&glagol_project_std_layout_local_cli,
|
||||||
@ -3310,6 +3338,7 @@ fn assert_slovo_std_source_layout_alpha(repo: &Path, std_dir: &Path) {
|
|||||||
std_dir.join("fs.slo"),
|
std_dir.join("fs.slo"),
|
||||||
std_dir.join("io.slo"),
|
std_dir.join("io.slo"),
|
||||||
std_dir.join("math.slo"),
|
std_dir.join("math.slo"),
|
||||||
|
std_dir.join("net.slo"),
|
||||||
std_dir.join("num.slo"),
|
std_dir.join("num.slo"),
|
||||||
std_dir.join("option.slo"),
|
std_dir.join("option.slo"),
|
||||||
std_dir.join("process.slo"),
|
std_dir.join("process.slo"),
|
||||||
@ -3338,6 +3367,7 @@ fn assert_slovo_std_source_layout_alpha(repo: &Path, std_dir: &Path) {
|
|||||||
"env.slo",
|
"env.slo",
|
||||||
"fs.slo",
|
"fs.slo",
|
||||||
"math.slo",
|
"math.slo",
|
||||||
|
"net.slo",
|
||||||
"num.slo",
|
"num.slo",
|
||||||
"option.slo",
|
"option.slo",
|
||||||
"process.slo",
|
"process.slo",
|
||||||
@ -4194,6 +4224,56 @@ fn assert_slovo_std_source_layout_alpha(repo: &Path, std_dir: &Path) {
|
|||||||
helper
|
helper
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let local_net = repo.join("examples/projects/std-layout-local-net/src/net.slo");
|
||||||
|
let slovo_net = read(&std_dir.join("net.slo"));
|
||||||
|
let glagol_net = read(&local_net);
|
||||||
|
assert!(
|
||||||
|
slovo_net.contains("(module net") && glagol_net.contains("(module net"),
|
||||||
|
"both Slovo std/net.slo and the Glagol local fixture should use explicit `net` module source shape"
|
||||||
|
);
|
||||||
|
for runtime_name in STANDARD_NET_RUNTIME_NAMES {
|
||||||
|
assert!(
|
||||||
|
slovo_net.contains(runtime_name) && glagol_net.contains(runtime_name),
|
||||||
|
"standard net facade must stay backed by `{}`",
|
||||||
|
runtime_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert_std_only_contains(
|
||||||
|
&slovo_net,
|
||||||
|
STANDARD_NET_RUNTIME_NAMES,
|
||||||
|
"Slovo std/net.slo must not introduce other compiler-known std names",
|
||||||
|
);
|
||||||
|
assert_std_only_contains(
|
||||||
|
&glagol_net,
|
||||||
|
STANDARD_NET_RUNTIME_NAMES,
|
||||||
|
"Glagol local net fixture must not introduce other compiler-known std names",
|
||||||
|
);
|
||||||
|
for source in [&slovo_net, &glagol_net] {
|
||||||
|
assert!(
|
||||||
|
!source.contains("dns")
|
||||||
|
&& !source.contains("tls")
|
||||||
|
&& !source.contains("udp")
|
||||||
|
&& !source.contains("async")
|
||||||
|
&& !source.contains("http")
|
||||||
|
&& !source.contains("timeout")
|
||||||
|
&& !source.contains("non_loopback")
|
||||||
|
&& !source.contains("host_error"),
|
||||||
|
"standard net facade must not claim deferred networking policies"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for helper in STANDARD_NET_SOURCE_FACADE_ALPHA {
|
||||||
|
assert!(
|
||||||
|
slovo_net.contains(&format!("(fn {} ", helper)),
|
||||||
|
"Slovo std/net.slo is missing beta6 facade `{}`",
|
||||||
|
helper
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
glagol_net.contains(&format!("(fn {} ", helper)),
|
||||||
|
"Glagol local net fixture is missing beta6 facade `{}`",
|
||||||
|
helper
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_source_shaped_file(path: &Path) {
|
fn assert_source_shaped_file(path: &Path) {
|
||||||
@ -7007,6 +7087,26 @@ fn assert_project_std_import_fs_tooling_matches_fixture(project: &Path) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assert_project_std_import_net_tooling_matches_fixture(project: &Path) {
|
||||||
|
assert_project_std_import_host_facade_tooling_matches_fixture(
|
||||||
|
project,
|
||||||
|
"net",
|
||||||
|
STANDARD_NET_SOURCE_FACADE_ALPHA,
|
||||||
|
concat!(
|
||||||
|
"test \"explicit std net invalid connect facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid listen facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid bound port facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid accept facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid read facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid write facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid close facade\" ... ok\n",
|
||||||
|
"test \"explicit std net helper invalids facade\" ... ok\n",
|
||||||
|
"test \"explicit std net facade all\" ... ok\n",
|
||||||
|
"9 test(s) passed\n",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn assert_project_std_import_process_tooling_matches_fixture(project: &Path) {
|
fn assert_project_std_import_process_tooling_matches_fixture(project: &Path) {
|
||||||
assert_project_std_import_host_facade_shape(
|
assert_project_std_import_host_facade_shape(
|
||||||
project,
|
project,
|
||||||
@ -9089,6 +9189,88 @@ fn assert_standard_fs_source_facade_alpha(project: &Path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn assert_project_std_layout_local_net_tooling_matches_fixture(project: &Path) {
|
||||||
|
assert!(project.join("slovo.toml").is_file());
|
||||||
|
assert!(project.join("src/net.slo").is_file());
|
||||||
|
assert!(project.join("src/main.slo").is_file());
|
||||||
|
assert_standard_net_source_facade_alpha(project);
|
||||||
|
|
||||||
|
let check = run_glagol([OsStr::new("check"), project.as_os_str()]);
|
||||||
|
assert_success_stdout(check, "", "std layout local net project check");
|
||||||
|
|
||||||
|
let test = run_glagol([OsStr::new("test"), project.as_os_str()]);
|
||||||
|
assert_success_stdout(
|
||||||
|
test,
|
||||||
|
concat!(
|
||||||
|
"test \"explicit local net invalid connect facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid listen facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid bound port facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid accept facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid read facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid write facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid close facade\" ... ok\n",
|
||||||
|
"test \"explicit local net helper invalids facade\" ... ok\n",
|
||||||
|
"test \"explicit local net facade all\" ... ok\n",
|
||||||
|
"9 test(s) passed\n",
|
||||||
|
),
|
||||||
|
"std layout local net project test",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_standard_net_source_facade_alpha(project: &Path) {
|
||||||
|
let net_source = read(&project.join("src/net.slo"));
|
||||||
|
let main = read(&project.join("src/main.slo"));
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
net_source.starts_with("(module net (export "),
|
||||||
|
"local net fixture must stay an explicitly exported local module"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
main.starts_with("(module main)\n\n(import net ("),
|
||||||
|
"local net fixture must stay an explicit local import"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!main.contains("(import std") && !main.contains("(import slovo.std"),
|
||||||
|
"standard net source facade fixture must not use automatic std imports"
|
||||||
|
);
|
||||||
|
for runtime_name in STANDARD_NET_RUNTIME_NAMES {
|
||||||
|
assert!(
|
||||||
|
net_source.contains(runtime_name),
|
||||||
|
"standard net source facade fixture must wrap `{}`",
|
||||||
|
runtime_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert_std_only_contains(
|
||||||
|
&net_source,
|
||||||
|
STANDARD_NET_RUNTIME_NAMES,
|
||||||
|
"standard net source facade fixture must use only existing std.net runtime names directly",
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!main.contains("std.")
|
||||||
|
&& !net_source.contains("dns")
|
||||||
|
&& !net_source.contains("tls")
|
||||||
|
&& !net_source.contains("udp")
|
||||||
|
&& !net_source.contains("async")
|
||||||
|
&& !net_source.contains("http")
|
||||||
|
&& !net_source.contains("timeout")
|
||||||
|
&& !net_source.contains("non_loopback")
|
||||||
|
&& !net_source.contains("host_error"),
|
||||||
|
"standard net source facade fixture must remain local and must not claim deferred networking policies"
|
||||||
|
);
|
||||||
|
for helper in STANDARD_NET_SOURCE_FACADE_ALPHA {
|
||||||
|
assert!(
|
||||||
|
net_source.contains(&format!("(fn {} ", helper)),
|
||||||
|
"local net fixture is missing facade `{}`",
|
||||||
|
helper
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
main.contains(helper),
|
||||||
|
"main fixture import/use is missing facade `{}`",
|
||||||
|
helper
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn assert_project_std_layout_local_io_tooling_matches_fixture(project: &Path) {
|
fn assert_project_std_layout_local_io_tooling_matches_fixture(project: &Path) {
|
||||||
assert!(project.join("slovo.toml").is_file());
|
assert!(project.join("slovo.toml").is_file());
|
||||||
assert!(project.join("src/io.slo").is_file());
|
assert!(project.join("src/io.slo").is_file());
|
||||||
|
|||||||
496
compiler/tests/standard_net.rs
Normal file
496
compiler/tests/standard_net.rs
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
ffi::OsStr,
|
||||||
|
fs,
|
||||||
|
io::{ErrorKind, Read, Write},
|
||||||
|
net::{Shutdown, TcpListener, TcpStream},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::{Child, Command, Output, Stdio},
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
thread,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn standard_net_lowers_to_private_runtime_helpers() {
|
||||||
|
let fixture = write_fixture(
|
||||||
|
"lowering",
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(match (std.net.tcp_connect_loopback_result 1)
|
||||||
|
((ok client)
|
||||||
|
(std.net.tcp_write_text_result client "ping")
|
||||||
|
(std.net.tcp_read_all_result client)
|
||||||
|
(std.net.tcp_close_result client)
|
||||||
|
0)
|
||||||
|
((err code)
|
||||||
|
(match (std.net.tcp_listen_loopback_result 0)
|
||||||
|
((ok listener)
|
||||||
|
(std.net.tcp_bound_port_result listener)
|
||||||
|
(std.net.tcp_accept_result listener)
|
||||||
|
(std.net.tcp_close_result listener)
|
||||||
|
0)
|
||||||
|
((err listen_code)
|
||||||
|
listen_code)))))
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let output = run_glagol([fixture.as_os_str()]);
|
||||||
|
assert_success("compile standard net lowering", &output);
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
stdout.contains("declare i64 @__glagol_net_tcp_connect_loopback_result(i32)")
|
||||||
|
&& stdout.contains("declare i64 @__glagol_net_tcp_listen_loopback_result(i32)")
|
||||||
|
&& stdout.contains("declare i64 @__glagol_net_tcp_bound_port_result(i32)")
|
||||||
|
&& stdout.contains("declare i64 @__glagol_net_tcp_accept_result(i32)")
|
||||||
|
&& stdout.contains("declare ptr @__glagol_net_tcp_read_all_result(i32)")
|
||||||
|
&& stdout.contains("declare i32 @__glagol_net_tcp_write_text_result(i32, ptr)")
|
||||||
|
&& stdout.contains("declare i32 @__glagol_net_tcp_close_result(i32)")
|
||||||
|
&& stdout.contains("call i64 @__glagol_net_tcp_connect_loopback_result(i32 1)")
|
||||||
|
&& stdout.contains("call i32 @__glagol_net_tcp_write_text_result(")
|
||||||
|
&& stdout.contains("call ptr @__glagol_net_tcp_read_all_result(")
|
||||||
|
&& stdout.contains("call i64 @__glagol_net_tcp_listen_loopback_result(i32 0)")
|
||||||
|
&& stdout.contains("call i64 @__glagol_net_tcp_bound_port_result(")
|
||||||
|
&& stdout.contains("call i64 @__glagol_net_tcp_accept_result(")
|
||||||
|
&& stdout.contains("call i32 @__glagol_net_tcp_close_result(")
|
||||||
|
&& !stdout.contains("@std.net."),
|
||||||
|
"standard net LLVM shape drifted\nstdout:\n{}",
|
||||||
|
stdout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_runner_reports_deterministic_net_result_errors() {
|
||||||
|
let fixture = write_fixture(
|
||||||
|
"test-runner",
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(test "connect invalid port returns err"
|
||||||
|
(= (unwrap_err (std.net.tcp_connect_loopback_result 0)) 1))
|
||||||
|
|
||||||
|
(test "listen invalid port returns err"
|
||||||
|
(= (unwrap_err (std.net.tcp_listen_loopback_result -1)) 1))
|
||||||
|
|
||||||
|
(test "bound port invalid handle returns err"
|
||||||
|
(= (unwrap_err (std.net.tcp_bound_port_result -1)) 1))
|
||||||
|
|
||||||
|
(test "accept invalid listener returns err"
|
||||||
|
(= (unwrap_err (std.net.tcp_accept_result -1)) 1))
|
||||||
|
|
||||||
|
(test "read invalid handle returns err"
|
||||||
|
(= (unwrap_err (std.net.tcp_read_all_result -1)) 1))
|
||||||
|
|
||||||
|
(test "write invalid handle returns err"
|
||||||
|
(= (unwrap_err (std.net.tcp_write_text_result -1 "ping")) 1))
|
||||||
|
|
||||||
|
(test "close invalid handle returns err"
|
||||||
|
(= (unwrap_err (std.net.tcp_close_result -1)) 1))
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let output = run_glagol([OsStr::new("test"), fixture.as_os_str()]);
|
||||||
|
assert_success("run standard net tests", &output);
|
||||||
|
assert_eq!(
|
||||||
|
String::from_utf8_lossy(&output.stdout),
|
||||||
|
concat!(
|
||||||
|
"test \"connect invalid port returns err\" ... ok\n",
|
||||||
|
"test \"listen invalid port returns err\" ... ok\n",
|
||||||
|
"test \"bound port invalid handle returns err\" ... ok\n",
|
||||||
|
"test \"accept invalid listener returns err\" ... ok\n",
|
||||||
|
"test \"read invalid handle returns err\" ... ok\n",
|
||||||
|
"test \"write invalid handle returns err\" ... ok\n",
|
||||||
|
"test \"close invalid handle returns err\" ... ok\n",
|
||||||
|
"7 test(s) passed\n",
|
||||||
|
),
|
||||||
|
"standard net test runner stdout drifted"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn standard_net_diagnostics_cover_promoted_and_unpromoted_names() {
|
||||||
|
let cases = [
|
||||||
|
(
|
||||||
|
"connect-arity",
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(std.net.tcp_connect_loopback_result))
|
||||||
|
"#,
|
||||||
|
"ArityMismatch",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"write-type",
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(std.net.tcp_write_text_result "handle" "ping")
|
||||||
|
0)
|
||||||
|
"#,
|
||||||
|
"TypeMismatch",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"unknown-net",
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(std.net.udp_bind_loopback_result 0))
|
||||||
|
"#,
|
||||||
|
"UnsupportedStandardLibraryCall",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"promoted-shadow",
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(fn std.net.tcp_close_result ((handle i32)) -> (result i32 i32)
|
||||||
|
(ok i32 i32 0))
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(unwrap_ok (std.net.tcp_close_result 1)))
|
||||||
|
"#,
|
||||||
|
"DuplicateFunction",
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (name, source, diagnostic) in cases {
|
||||||
|
let fixture = write_fixture(name, source);
|
||||||
|
let output = run_glagol([fixture.as_os_str()]);
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!output.status.success(),
|
||||||
|
"compiler unexpectedly accepted `{}`\nstdout:\n{}\nstderr:\n{}",
|
||||||
|
name,
|
||||||
|
stdout,
|
||||||
|
stderr
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
stdout.is_empty(),
|
||||||
|
"rejected compile wrote stdout:\n{}",
|
||||||
|
stdout
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
stderr.contains(diagnostic),
|
||||||
|
"diagnostic `{}` was not reported for `{}`\nstderr:\n{}",
|
||||||
|
diagnostic,
|
||||||
|
name,
|
||||||
|
stderr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hosted_loopback_client_and_server_smoke_when_clang_is_available() {
|
||||||
|
let Some(clang) = find_clang() else {
|
||||||
|
eprintln!("skipping standard net runtime smoke: set GLAGOL_CLANG or install clang");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(port) = try_reserve_loopback_port() else {
|
||||||
|
eprintln!("skipping standard net server smoke: loopback bind is not permitted");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let server_source = format!(
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(match (std.net.tcp_listen_loopback_result {port})
|
||||||
|
((ok listener)
|
||||||
|
(match (std.net.tcp_accept_result listener)
|
||||||
|
((ok stream)
|
||||||
|
(match (std.net.tcp_read_all_result stream)
|
||||||
|
((ok text)
|
||||||
|
(std.net.tcp_write_text_result stream "pong")
|
||||||
|
(std.net.tcp_close_result stream)
|
||||||
|
(std.net.tcp_close_result listener)
|
||||||
|
(if (= text "ping") 0 2))
|
||||||
|
((err read_code)
|
||||||
|
(std.net.tcp_close_result stream)
|
||||||
|
(std.net.tcp_close_result listener)
|
||||||
|
3)))
|
||||||
|
((err accept_code)
|
||||||
|
(std.net.tcp_close_result listener)
|
||||||
|
4)))
|
||||||
|
((err listen_code)
|
||||||
|
5)))
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
let server_fixture = write_fixture("runtime-server", &server_source);
|
||||||
|
let compile = run_glagol([server_fixture.as_os_str()]);
|
||||||
|
assert_success("compile standard net server smoke", &compile);
|
||||||
|
let server_exe = compile_with_runtime(&clang, "standard-net-server", &compile.stdout);
|
||||||
|
|
||||||
|
let mut child = Command::new(&server_exe)
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap_or_else(|err| panic!("spawn `{}`: {}", server_exe.display(), err));
|
||||||
|
|
||||||
|
let mut stream = connect_with_retry(port, &mut child);
|
||||||
|
stream
|
||||||
|
.write_all(b"ping")
|
||||||
|
.unwrap_or_else(|err| panic!("write ping to loopback server: {}", err));
|
||||||
|
stream
|
||||||
|
.shutdown(Shutdown::Write)
|
||||||
|
.expect("shutdown loopback client write half");
|
||||||
|
|
||||||
|
let mut response = String::new();
|
||||||
|
stream
|
||||||
|
.read_to_string(&mut response)
|
||||||
|
.unwrap_or_else(|err| panic!("read loopback server response: {}", err));
|
||||||
|
assert_eq!(response, "pong", "loopback response drifted");
|
||||||
|
|
||||||
|
let output = wait_child_with_timeout(child, Duration::from_secs(5));
|
||||||
|
assert_success("run standard net server smoke", &output);
|
||||||
|
assert!(
|
||||||
|
output.stdout.is_empty(),
|
||||||
|
"standard net server smoke wrote stdout:\n{}",
|
||||||
|
String::from_utf8_lossy(&output.stdout)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn hosted_loopback_client_smoke_when_clang_is_available() {
|
||||||
|
let Some(clang) = find_clang() else {
|
||||||
|
eprintln!("skipping standard net client smoke: set GLAGOL_CLANG or install clang");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let listener = match TcpListener::bind(("127.0.0.1", 0)) {
|
||||||
|
Ok(listener) => listener,
|
||||||
|
Err(err) if err.kind() == ErrorKind::PermissionDenied => {
|
||||||
|
eprintln!("skipping standard net client smoke: loopback bind is not permitted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(err) => panic!("bind loopback smoke listener: {}", err),
|
||||||
|
};
|
||||||
|
let port = listener
|
||||||
|
.local_addr()
|
||||||
|
.expect("loopback smoke listener addr")
|
||||||
|
.port();
|
||||||
|
let server = thread::spawn(move || {
|
||||||
|
let (mut stream, _) = listener.accept().expect("accept loopback client");
|
||||||
|
let mut request = [0u8; 4];
|
||||||
|
stream
|
||||||
|
.read_exact(&mut request)
|
||||||
|
.expect("read loopback client request");
|
||||||
|
assert_eq!(&request, b"ping");
|
||||||
|
stream
|
||||||
|
.write_all(b"pong")
|
||||||
|
.expect("write loopback client response");
|
||||||
|
});
|
||||||
|
|
||||||
|
let client_source = format!(
|
||||||
|
r#"
|
||||||
|
(module main)
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(match (std.net.tcp_connect_loopback_result {port})
|
||||||
|
((ok client)
|
||||||
|
(std.net.tcp_write_text_result client "ping")
|
||||||
|
(match (std.net.tcp_read_all_result client)
|
||||||
|
((ok text)
|
||||||
|
(std.net.tcp_close_result client)
|
||||||
|
(if (= text "pong") 0 2))
|
||||||
|
((err read_code)
|
||||||
|
(std.net.tcp_close_result client)
|
||||||
|
3)))
|
||||||
|
((err connect_code)
|
||||||
|
4)))
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
let client_fixture = write_fixture("runtime-client", &client_source);
|
||||||
|
let compile = run_glagol([client_fixture.as_os_str()]);
|
||||||
|
assert_success("compile standard net client smoke", &compile);
|
||||||
|
let run = compile_and_run_with_runtime(&clang, "standard-net-client", &compile.stdout);
|
||||||
|
assert_success("run standard net client smoke", &run);
|
||||||
|
assert!(
|
||||||
|
run.stdout.is_empty(),
|
||||||
|
"standard net client smoke wrote stdout:\n{}",
|
||||||
|
String::from_utf8_lossy(&run.stdout)
|
||||||
|
);
|
||||||
|
server.join().expect("loopback smoke server thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_glagol<I, S>(args: I) -> Output
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
||||||
|
.args(args)
|
||||||
|
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
||||||
|
.output()
|
||||||
|
.expect("run glagol")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
||||||
|
let mut path = env::temp_dir();
|
||||||
|
path.push(format!(
|
||||||
|
"glagol-standard-net-{}-{}-{}.slo",
|
||||||
|
name,
|
||||||
|
std::process::id(),
|
||||||
|
NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed)
|
||||||
|
));
|
||||||
|
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_reserve_loopback_port() -> Option<u16> {
|
||||||
|
let listener = match TcpListener::bind(("127.0.0.1", 0)) {
|
||||||
|
Ok(listener) => listener,
|
||||||
|
Err(err) if err.kind() == ErrorKind::PermissionDenied => return None,
|
||||||
|
Err(err) => panic!("reserve loopback port: {}", err),
|
||||||
|
};
|
||||||
|
Some(
|
||||||
|
listener
|
||||||
|
.local_addr()
|
||||||
|
.expect("reserved loopback addr")
|
||||||
|
.port(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn connect_with_retry(port: u16, child: &mut Child) -> TcpStream {
|
||||||
|
let deadline = Instant::now() + Duration::from_secs(5);
|
||||||
|
loop {
|
||||||
|
match TcpStream::connect(("127.0.0.1", port)) {
|
||||||
|
Ok(stream) => return stream,
|
||||||
|
Err(connect_err) => {
|
||||||
|
if let Some(status) = child.try_wait().expect("poll loopback server child") {
|
||||||
|
let mut stdout = String::new();
|
||||||
|
let mut stderr = String::new();
|
||||||
|
if let Some(mut out) = child.stdout.take() {
|
||||||
|
let _ = out.read_to_string(&mut stdout);
|
||||||
|
}
|
||||||
|
if let Some(mut err) = child.stderr.take() {
|
||||||
|
let _ = err.read_to_string(&mut stderr);
|
||||||
|
}
|
||||||
|
panic!(
|
||||||
|
"loopback server exited before connect: {}\nstdout:\n{}\nstderr:\n{}",
|
||||||
|
status, stdout, stderr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if Instant::now() >= deadline {
|
||||||
|
panic!("timed out connecting to loopback server: {}", connect_err);
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_millis(20));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_child_with_timeout(mut child: Child, timeout: Duration) -> Output {
|
||||||
|
let deadline = Instant::now() + timeout;
|
||||||
|
while Instant::now() < deadline {
|
||||||
|
if child.try_wait().expect("poll child").is_some() {
|
||||||
|
return child.wait_with_output().expect("collect child output");
|
||||||
|
}
|
||||||
|
thread::sleep(Duration::from_millis(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = child.kill();
|
||||||
|
let output = child
|
||||||
|
.wait_with_output()
|
||||||
|
.expect("collect killed child output");
|
||||||
|
panic!(
|
||||||
|
"child timed out\nstdout:\n{}\nstderr:\n{}",
|
||||||
|
String::from_utf8_lossy(&output.stdout),
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_success(context: &str, output: &Output) {
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
||||||
|
context,
|
||||||
|
stdout,
|
||||||
|
stderr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_and_run_with_runtime(clang: &Path, name: &str, ir: &[u8]) -> Output {
|
||||||
|
let exe_path = compile_with_runtime(clang, name, ir);
|
||||||
|
Command::new(&exe_path)
|
||||||
|
.output()
|
||||||
|
.unwrap_or_else(|err| panic!("run `{}`: {}", exe_path.display(), err))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_with_runtime(clang: &Path, name: &str, ir: &[u8]) -> PathBuf {
|
||||||
|
let manifest = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
let temp_dir = env::temp_dir().join(format!(
|
||||||
|
"glagol-standard-net-{}-{}",
|
||||||
|
std::process::id(),
|
||||||
|
NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed)
|
||||||
|
));
|
||||||
|
fs::create_dir_all(&temp_dir)
|
||||||
|
.unwrap_or_else(|err| panic!("create `{}`: {}", temp_dir.display(), err));
|
||||||
|
|
||||||
|
let ir_path = temp_dir.join(format!("{}.ll", name));
|
||||||
|
let exe_path = temp_dir.join(name);
|
||||||
|
fs::write(&ir_path, ir).unwrap_or_else(|err| panic!("write `{}`: {}", ir_path.display(), err));
|
||||||
|
|
||||||
|
let runtime = manifest.join("../runtime/runtime.c");
|
||||||
|
let mut clang_command = Command::new(clang);
|
||||||
|
clang_command
|
||||||
|
.arg(&runtime)
|
||||||
|
.arg(&ir_path)
|
||||||
|
.arg("-o")
|
||||||
|
.arg(&exe_path)
|
||||||
|
.current_dir(manifest);
|
||||||
|
configure_clang_runtime_env(&mut clang_command, clang);
|
||||||
|
let clang_output = clang_command
|
||||||
|
.output()
|
||||||
|
.unwrap_or_else(|err| panic!("run `{}`: {}", clang.display(), err));
|
||||||
|
assert_success("clang standard net runtime smoke", &clang_output);
|
||||||
|
exe_path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_clang() -> Option<PathBuf> {
|
||||||
|
if let Some(path) = env::var_os("GLAGOL_CLANG").filter(|value| !value.is_empty()) {
|
||||||
|
return Some(PathBuf::from(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
let hermetic_clang = PathBuf::from("/tmp/glagol-clang-root/usr/bin/clang");
|
||||||
|
if hermetic_clang.is_file() {
|
||||||
|
return Some(hermetic_clang);
|
||||||
|
}
|
||||||
|
|
||||||
|
find_on_path("clang")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_on_path(program: &str) -> Option<PathBuf> {
|
||||||
|
let path = env::var_os("PATH")?;
|
||||||
|
env::split_paths(&path)
|
||||||
|
.map(|dir| dir.join(program))
|
||||||
|
.find(|candidate| candidate.is_file())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_clang_runtime_env(command: &mut Command, clang: &Path) {
|
||||||
|
if !clang.starts_with("/tmp/glagol-clang-root") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = Path::new("/tmp/glagol-clang-root");
|
||||||
|
let lib64 = root.join("usr/lib64");
|
||||||
|
let lib = root.join("usr/lib");
|
||||||
|
let mut paths = vec![lib64, lib];
|
||||||
|
|
||||||
|
if let Some(existing) = env::var_os("LD_LIBRARY_PATH") {
|
||||||
|
paths.extend(env::split_paths(&existing));
|
||||||
|
}
|
||||||
|
|
||||||
|
let joined = env::join_paths(paths).expect("join LD_LIBRARY_PATH");
|
||||||
|
command.env("LD_LIBRARY_PATH", joined);
|
||||||
|
}
|
||||||
245
compiler/tests/standard_net_source_facade_alpha.rs
Normal file
245
compiler/tests/standard_net_source_facade_alpha.rs
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
use std::{
|
||||||
|
ffi::OsStr,
|
||||||
|
fs,
|
||||||
|
path::Path,
|
||||||
|
process::{Command, Output},
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPECTED_LOCAL_TEST_OUTPUT: &str = concat!(
|
||||||
|
"test \"explicit local net invalid connect facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid listen facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid bound port facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid accept facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid read facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid write facade\" ... ok\n",
|
||||||
|
"test \"explicit local net invalid close facade\" ... ok\n",
|
||||||
|
"test \"explicit local net helper invalids facade\" ... ok\n",
|
||||||
|
"test \"explicit local net facade all\" ... ok\n",
|
||||||
|
"9 test(s) passed\n",
|
||||||
|
);
|
||||||
|
|
||||||
|
const EXPECTED_STD_IMPORT_TEST_OUTPUT: &str = concat!(
|
||||||
|
"test \"explicit std net invalid connect facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid listen facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid bound port facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid accept facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid read facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid write facade\" ... ok\n",
|
||||||
|
"test \"explicit std net invalid close facade\" ... ok\n",
|
||||||
|
"test \"explicit std net helper invalids facade\" ... ok\n",
|
||||||
|
"test \"explicit std net facade all\" ... ok\n",
|
||||||
|
"9 test(s) passed\n",
|
||||||
|
);
|
||||||
|
|
||||||
|
const STANDARD_NET_SOURCE_FACADE_ALPHA: &[&str] = &[
|
||||||
|
"tcp_connect_loopback_result",
|
||||||
|
"tcp_listen_loopback_result",
|
||||||
|
"tcp_bound_port_result",
|
||||||
|
"tcp_accept_result",
|
||||||
|
"tcp_read_all_result",
|
||||||
|
"tcp_write_text_result",
|
||||||
|
"tcp_close_result",
|
||||||
|
"tcp_write_text_ok",
|
||||||
|
"tcp_close_ok",
|
||||||
|
];
|
||||||
|
|
||||||
|
const STANDARD_NET_RUNTIME_NAMES: &[&str] = &[
|
||||||
|
"std.net.tcp_connect_loopback_result",
|
||||||
|
"std.net.tcp_listen_loopback_result",
|
||||||
|
"std.net.tcp_bound_port_result",
|
||||||
|
"std.net.tcp_accept_result",
|
||||||
|
"std.net.tcp_read_all_result",
|
||||||
|
"std.net.tcp_write_text_result",
|
||||||
|
"std.net.tcp_close_result",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn standard_net_source_facade_project_checks_formats_and_tests() {
|
||||||
|
let project =
|
||||||
|
Path::new(env!("CARGO_MANIFEST_DIR")).join("../examples/projects/std-layout-local-net");
|
||||||
|
|
||||||
|
assert_local_net_fixture_is_source_authored(&project);
|
||||||
|
|
||||||
|
let fmt = run_glagol([
|
||||||
|
OsStr::new("fmt"),
|
||||||
|
OsStr::new("--check"),
|
||||||
|
project.as_os_str(),
|
||||||
|
]);
|
||||||
|
assert_success("std layout local net fmt --check", &fmt);
|
||||||
|
|
||||||
|
let check = run_glagol([OsStr::new("check"), project.as_os_str()]);
|
||||||
|
assert_success_stdout(check, "", "std layout local net check");
|
||||||
|
|
||||||
|
let test = run_glagol([OsStr::new("test"), project.as_os_str()]);
|
||||||
|
assert_success_stdout(
|
||||||
|
test,
|
||||||
|
EXPECTED_LOCAL_TEST_OUTPUT,
|
||||||
|
"std layout local net test output",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn standard_net_std_import_project_checks_formats_and_tests() {
|
||||||
|
let project = Path::new(env!("CARGO_MANIFEST_DIR")).join("../examples/projects/std-import-net");
|
||||||
|
|
||||||
|
assert_std_import_net_fixture_uses_repo_std(&project);
|
||||||
|
|
||||||
|
let fmt = run_glagol([
|
||||||
|
OsStr::new("fmt"),
|
||||||
|
OsStr::new("--check"),
|
||||||
|
project.as_os_str(),
|
||||||
|
]);
|
||||||
|
assert_success("std import net fmt --check", &fmt);
|
||||||
|
|
||||||
|
let check = run_glagol([OsStr::new("check"), project.as_os_str()]);
|
||||||
|
assert_success_stdout(check, "", "std import net check");
|
||||||
|
|
||||||
|
let test = run_glagol([OsStr::new("test"), project.as_os_str()]);
|
||||||
|
assert_success_stdout(
|
||||||
|
test,
|
||||||
|
EXPECTED_STD_IMPORT_TEST_OUTPUT,
|
||||||
|
"std import net test output",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_local_net_fixture_is_source_authored(project: &Path) {
|
||||||
|
let net = read(&project.join("src/net.slo"));
|
||||||
|
let main = read(&project.join("src/main.slo"));
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
net.starts_with("(module net (export "),
|
||||||
|
"net.slo must stay an explicit local module export"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
main.starts_with("(module main)\n\n(import net ("),
|
||||||
|
"main.slo must stay an explicit local net import"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!main.contains("(import std") && !main.contains("(import slovo.std"),
|
||||||
|
"net fixture must not depend on automatic or package std imports"
|
||||||
|
);
|
||||||
|
assert_net_source_shape(&net, &main, "local net fixture");
|
||||||
|
assert!(
|
||||||
|
!main.contains("std."),
|
||||||
|
"local net main fixture must use only local imports"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_std_import_net_fixture_uses_repo_std(project: &Path) {
|
||||||
|
let std_net = read(&Path::new(env!("CARGO_MANIFEST_DIR")).join("../lib/std/net.slo"));
|
||||||
|
let main = read(&project.join("src/main.slo"));
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!project.join("src/net.slo").exists(),
|
||||||
|
"std import net fixture must use repo-root std/net.slo, not a local copy"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
main.starts_with("(module main)\n\n(import std.net ("),
|
||||||
|
"std import net fixture must use explicit `std.net` import syntax"
|
||||||
|
);
|
||||||
|
assert_net_source_shape(&std_net, &main, "repo std.net fixture");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_net_source_shape(net: &str, main: &str, context: &str) {
|
||||||
|
for runtime_name in STANDARD_NET_RUNTIME_NAMES {
|
||||||
|
assert!(
|
||||||
|
net.contains(runtime_name),
|
||||||
|
"{} must wrap `{}`",
|
||||||
|
context,
|
||||||
|
runtime_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert_std_only_contains(net, STANDARD_NET_RUNTIME_NAMES, context);
|
||||||
|
assert!(
|
||||||
|
!net.contains("dns")
|
||||||
|
&& !net.contains("tls")
|
||||||
|
&& !net.contains("udp")
|
||||||
|
&& !net.contains("async")
|
||||||
|
&& !net.contains("http")
|
||||||
|
&& !net.contains("timeout")
|
||||||
|
&& !net.contains("non_loopback")
|
||||||
|
&& !net.contains("host_error")
|
||||||
|
&& !main.contains("dns")
|
||||||
|
&& !main.contains("tls")
|
||||||
|
&& !main.contains("udp")
|
||||||
|
&& !main.contains("async")
|
||||||
|
&& !main.contains("http")
|
||||||
|
&& !main.contains("timeout")
|
||||||
|
&& !main.contains("non_loopback")
|
||||||
|
&& !main.contains("host_error"),
|
||||||
|
"{} must not claim deferred networking policies",
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
for helper in STANDARD_NET_SOURCE_FACADE_ALPHA {
|
||||||
|
assert!(
|
||||||
|
net.contains(&format!("(fn {} ", helper)),
|
||||||
|
"{} is missing source facade `{}`",
|
||||||
|
context,
|
||||||
|
helper
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
main.contains(helper),
|
||||||
|
"{} main fixture import/use is missing `{}`",
|
||||||
|
context,
|
||||||
|
helper
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_std_only_contains(source: &str, allowed: &[&str], context: &str) {
|
||||||
|
let mut remaining = source.to_string();
|
||||||
|
for name in allowed {
|
||||||
|
remaining = remaining.replace(name, "");
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
!remaining.contains("std."),
|
||||||
|
"{} introduced unexpected compiler-known std names",
|
||||||
|
context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_glagol<I, S>(args: I) -> Output
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<std::ffi::OsStr>,
|
||||||
|
{
|
||||||
|
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
||||||
|
.args(args)
|
||||||
|
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
||||||
|
.output()
|
||||||
|
.expect("run glagol")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(path: &Path) -> String {
|
||||||
|
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_success(context: &str, output: &Output) {
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
||||||
|
context,
|
||||||
|
stdout,
|
||||||
|
stderr
|
||||||
|
);
|
||||||
|
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_success_stdout(output: Output, expected: &str, context: &str) {
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
output.status.success(),
|
||||||
|
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
||||||
|
context,
|
||||||
|
stdout,
|
||||||
|
stderr
|
||||||
|
);
|
||||||
|
assert_eq!(stdout, expected, "{} stdout drifted", context);
|
||||||
|
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
||||||
|
}
|
||||||
@ -157,6 +157,14 @@ Work:
|
|||||||
- keep TLS, async, DNS policy, HTTP server frameworks, and event loops deferred
|
- keep TLS, async, DNS policy, HTTP server frameworks, and event loops deferred
|
||||||
- add small examples such as echo client/server or local request/response
|
- add small examples such as echo client/server or local request/response
|
||||||
|
|
||||||
|
Released in `1.0.0-beta.6`: `lib/std/net.slo` now provides explicit wrappers
|
||||||
|
for loopback TCP connect, listen, bound-port lookup, accept, read-all,
|
||||||
|
write-text, and close result calls. The source fixtures use invalid port/handle
|
||||||
|
checks for deterministic result-shape coverage, and the compiler/runtime tests
|
||||||
|
cover lowering plus hosted loopback client/server smoke when the local sandbox
|
||||||
|
allows loopback sockets. DNS, TLS, UDP, async IO, non-loopback binding, HTTP
|
||||||
|
frameworks, rich host-error ADTs, and stable socket ABI/layout remain deferred.
|
||||||
|
|
||||||
Why sixth: networking is useful, but doing it before resources and host errors
|
Why sixth: networking is useful, but doing it before resources and host errors
|
||||||
would create unstable API debt.
|
would create unstable API debt.
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,37 @@ integration/readiness release, not the first real beta.
|
|||||||
|
|
||||||
No unreleased changes yet.
|
No unreleased changes yet.
|
||||||
|
|
||||||
|
## 1.0.0-beta.6
|
||||||
|
|
||||||
|
Release label: `1.0.0-beta.6`
|
||||||
|
|
||||||
|
Release date: 2026-05-22
|
||||||
|
|
||||||
|
Release state: networking foundation beta update
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Glagol `1.0.0-beta.6` keeps the `1.0.0-beta` compiler support baseline and
|
||||||
|
adds the first narrow networking foundation:
|
||||||
|
|
||||||
|
- compiler-known `std.net.tcp_connect_loopback_result`,
|
||||||
|
`std.net.tcp_listen_loopback_result`, `std.net.tcp_bound_port_result`,
|
||||||
|
`std.net.tcp_accept_result`, `std.net.tcp_read_all_result`,
|
||||||
|
`std.net.tcp_write_text_result`, and `std.net.tcp_close_result`
|
||||||
|
- POSIX loopback TCP runtime helpers using opaque process-local `i32` handles
|
||||||
|
and concrete `result` values
|
||||||
|
- deterministic interpreter/test-runner error behavior for `std.net` invalid
|
||||||
|
handles and ports
|
||||||
|
- focused lowering, diagnostics, source-facade, promotion, and hosted loopback
|
||||||
|
smoke tests, with hosted socket smokes skipped only when the local sandbox
|
||||||
|
denies loopback sockets
|
||||||
|
|
||||||
|
### Explicit Deferrals
|
||||||
|
|
||||||
|
This release does not add DNS, TLS, UDP, non-loopback binding, async IO, event
|
||||||
|
loops, HTTP frameworks, rich host-error ADTs, stable socket ABI/layout,
|
||||||
|
automatic resource ownership, or a stable standard-library API freeze.
|
||||||
|
|
||||||
## 1.0.0-beta.5
|
## 1.0.0-beta.5
|
||||||
|
|
||||||
Release label: `1.0.0-beta.5`
|
Release label: `1.0.0-beta.5`
|
||||||
|
|||||||
@ -22,15 +22,15 @@ general-purpose beta release.
|
|||||||
|
|
||||||
A Glagol feature is done only when it has parser/lowerer support, checker behavior, diagnostics for invalid forms, backend behavior or explicit unsupported diagnostics, and tests.
|
A Glagol feature is done only when it has parser/lowerer support, checker behavior, diagnostics for invalid forms, backend behavior or explicit unsupported diagnostics, and tests.
|
||||||
|
|
||||||
Current stage: `1.0.0-beta.5`, released on 2026-05-22 as the first post-beta
|
Current stage: `1.0.0-beta.6`, released on 2026-05-22 as the first post-beta
|
||||||
package/workspace discipline update. It keeps the `1.0.0-beta`
|
networking foundation update. It keeps the `1.0.0-beta` language/compiler
|
||||||
language/compiler support baseline and includes the `1.0.0-beta.1` tooling
|
support baseline and includes the `1.0.0-beta.1` tooling hardening release, the
|
||||||
hardening release, the `1.0.0-beta.2` runtime/resource foundation release, the
|
`1.0.0-beta.2` runtime/resource foundation release, the `1.0.0-beta.3`
|
||||||
`1.0.0-beta.3` standard-library stabilization release, the `1.0.0-beta.4`
|
standard-library stabilization release, the `1.0.0-beta.4`
|
||||||
language-usability diagnostics release, `[workspace] default_package = "name"`
|
language-usability diagnostics release, the `1.0.0-beta.5` package/workspace
|
||||||
for deterministic build/run entry selection, tighter workspace-member/default
|
discipline release, and the `1.0.0-beta.6` compiler-known `std.net` loopback
|
||||||
package diagnostics, workspace package/dependency docs, and
|
TCP runtime family with focused lowering, interpreter, diagnostics,
|
||||||
`docs/language/PACKAGES.md` for beta local-package rules.
|
source-facade, promotion, and hosted smoke coverage.
|
||||||
|
|
||||||
The final experimental precursor scope is `exp-125`. Its unsigned direct-value
|
The final experimental precursor scope is `exp-125`. Its unsigned direct-value
|
||||||
flow, parse/format runtime lanes, and matching staged stdlib helper breadth
|
flow, parse/format runtime lanes, and matching staged stdlib helper breadth
|
||||||
|
|||||||
@ -8,18 +8,47 @@ Historical `exp-*` releases listed here are experimental maturity milestones.
|
|||||||
The pushed tag `v2.0.0-beta.1` is historical. It is now documented as an
|
The pushed tag `v2.0.0-beta.1` is historical. It is now documented as an
|
||||||
experimental integration/readiness release, not as a beta maturity claim.
|
experimental integration/readiness release, not as a beta maturity claim.
|
||||||
|
|
||||||
The current release is `1.0.0-beta.5`, published on 2026-05-22. It keeps the
|
The current release is `1.0.0-beta.6`, published on 2026-05-22. It keeps the
|
||||||
`1.0.0-beta` language surface, includes the first post-beta tooling/install
|
`1.0.0-beta` language surface, includes the first post-beta tooling/install
|
||||||
hardening bundle from `1.0.0-beta.1`, and adds the first runtime/resource
|
hardening bundle from `1.0.0-beta.1`, and adds the first runtime/resource
|
||||||
foundation bundle from `1.0.0-beta.2` plus the first standard-library
|
foundation bundle from `1.0.0-beta.2` plus the first standard-library
|
||||||
stabilization bundle from `1.0.0-beta.3`, the first language-usability
|
stabilization bundle from `1.0.0-beta.3`, the first language-usability
|
||||||
diagnostics bundle from `1.0.0-beta.4`, and the first local
|
diagnostics bundle from `1.0.0-beta.4`, and the first local
|
||||||
package/workspace discipline bundle.
|
package/workspace discipline bundle from `1.0.0-beta.5`, plus the first
|
||||||
|
loopback networking foundation bundle from `1.0.0-beta.6`.
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
No unreleased changes yet.
|
No unreleased changes yet.
|
||||||
|
|
||||||
|
## 1.0.0-beta.6
|
||||||
|
|
||||||
|
Release label: `1.0.0-beta.6`
|
||||||
|
|
||||||
|
Release name: Networking Foundation Bundle
|
||||||
|
|
||||||
|
Release date: 2026-05-22
|
||||||
|
|
||||||
|
Status: released beta networking foundation update on the `1.0.0-beta`
|
||||||
|
language baseline.
|
||||||
|
|
||||||
|
- `lib/std/net.slo` stages an explicit `std.net` source facade for blocking
|
||||||
|
loopback TCP only.
|
||||||
|
- The facade wraps the targeted compiler-known calls
|
||||||
|
`std.net.tcp_connect_loopback_result`,
|
||||||
|
`std.net.tcp_listen_loopback_result`, `std.net.tcp_bound_port_result`,
|
||||||
|
`std.net.tcp_accept_result`, `std.net.tcp_read_all_result`,
|
||||||
|
`std.net.tcp_write_text_result`, and `std.net.tcp_close_result`.
|
||||||
|
- `examples/projects/std-import-net/` and
|
||||||
|
`examples/projects/std-layout-local-net/` document the explicit import and
|
||||||
|
local source facade shapes using deterministic invalid port/handle result
|
||||||
|
checks.
|
||||||
|
|
||||||
|
This release does not add DNS, TLS, async IO, UDP, non-loopback binding, HTTP
|
||||||
|
frameworks, stable socket ABI/layout, platform-specific error codes, rich
|
||||||
|
host-error ADTs, automatic ownership/finalization, or a stable standard-library
|
||||||
|
API freeze.
|
||||||
|
|
||||||
## 1.0.0-beta.5
|
## 1.0.0-beta.5
|
||||||
|
|
||||||
Release label: `1.0.0-beta.5`
|
Release label: `1.0.0-beta.5`
|
||||||
|
|||||||
@ -10,15 +10,16 @@ Long-horizon planning lives in
|
|||||||
release train from the historical `v2.0.0-beta.1` tag toward and beyond the
|
release train from the historical `v2.0.0-beta.1` tag toward and beyond the
|
||||||
first real general-purpose beta Slovo contract.
|
first real general-purpose beta Slovo contract.
|
||||||
|
|
||||||
Current stage: `1.0.0-beta.5`, released on 2026-05-22 as the first post-beta
|
Current stage: `1.0.0-beta.6`, released on 2026-05-22 as the first post-beta
|
||||||
package/workspace discipline update. It keeps the `1.0.0-beta` language
|
networking foundation update. It keeps the `1.0.0-beta` language contract and
|
||||||
contract and includes the `1.0.0-beta.1` tooling hardening release, the
|
includes the `1.0.0-beta.1` tooling hardening release, the `1.0.0-beta.2`
|
||||||
`1.0.0-beta.2` runtime/resource foundation release, the `1.0.0-beta.3`
|
runtime/resource foundation release, the `1.0.0-beta.3` standard-library
|
||||||
standard-library stabilization release, the `1.0.0-beta.4`
|
stabilization release, the `1.0.0-beta.4` language-usability diagnostics
|
||||||
language-usability diagnostics release, `[workspace] default_package = "name"`
|
release, the `1.0.0-beta.5` package/workspace discipline release, and a narrow
|
||||||
for deterministic build/run entry selection, tighter duplicate-member/default
|
`std.net` source facade for blocking loopback TCP client/server primitives over
|
||||||
package diagnostics, workspace package/dependency docs, and
|
opaque `i32` handles and concrete `result` families. DNS, TLS, UDP, async IO,
|
||||||
`docs/language/PACKAGES.md` for beta local-package rules.
|
non-loopback binding, HTTP frameworks, rich host-error ADTs, stable socket
|
||||||
|
ABI/layout, and a stable standard-library API freeze remain deferred.
|
||||||
|
|
||||||
The final experimental precursor scope is `exp-125`, defined in
|
The final experimental precursor scope is `exp-125`, defined in
|
||||||
`.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its
|
`.llm/EXP_125_UNSIGNED_U32_U64_NUMERIC_AND_STDLIB_BREADTH_ALPHA.md`. Its
|
||||||
|
|||||||
@ -1042,6 +1042,40 @@ solving, package publishing, archive formats, optional/dev/target
|
|||||||
dependencies, feature flags, package build scripts, or stable package
|
dependencies, feature flags, package build scripts, or stable package
|
||||||
ABI/layout promises.
|
ABI/layout promises.
|
||||||
|
|
||||||
|
### 4.4.4 Post-Beta Networking Foundation
|
||||||
|
|
||||||
|
Status: released in `1.0.0-beta.6`.
|
||||||
|
|
||||||
|
The `1.0.0-beta.6` networking foundation stages blocking loopback TCP only. It
|
||||||
|
does not change source syntax.
|
||||||
|
|
||||||
|
The source facade is `lib/std/net.slo`, imported explicitly as `std.net`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
std.net.tcp_connect_loopback_result: (i32) -> (result i32 i32)
|
||||||
|
std.net.tcp_listen_loopback_result: (i32) -> (result i32 i32)
|
||||||
|
std.net.tcp_bound_port_result: (i32) -> (result i32 i32)
|
||||||
|
std.net.tcp_accept_result: (i32) -> (result i32 i32)
|
||||||
|
std.net.tcp_read_all_result: (i32) -> (result string i32)
|
||||||
|
std.net.tcp_write_text_result: (i32 string) -> (result i32 i32)
|
||||||
|
std.net.tcp_close_result: (i32) -> (result i32 i32)
|
||||||
|
```
|
||||||
|
|
||||||
|
Successful connect/listen/accept operations return `ok handle`, where
|
||||||
|
`handle` is a positive opaque process-local `i32`. Successful
|
||||||
|
`tcp_bound_port_result` returns the bound loopback TCP port. Successful
|
||||||
|
`tcp_write_text_result` and `tcp_close_result` return `ok 0`. Ordinary host
|
||||||
|
failures return `err 1`.
|
||||||
|
|
||||||
|
The source facade also provides `tcp_write_text_ok` and `tcp_close_ok`, both
|
||||||
|
ordinary source helpers over the result-returning operations.
|
||||||
|
|
||||||
|
This release is not a general networking contract. DNS, TLS, UDP, Unix-domain
|
||||||
|
sockets, non-loopback binding, async IO, event loops, readiness polling,
|
||||||
|
timeouts, buffering policy, HTTP frameworks, platform-specific error codes,
|
||||||
|
rich host-error ADTs, stable runtime helper symbols, stable socket ABI/layout,
|
||||||
|
automatic cleanup, and affine ownership guarantees remain deferred.
|
||||||
|
|
||||||
## 4.5 v2.0.0-beta.1 Experimental Integration Readiness
|
## 4.5 v2.0.0-beta.1 Experimental Integration Readiness
|
||||||
|
|
||||||
Status: current experimental Slovo-side release contract, released 2026-05-17.
|
Status: current experimental Slovo-side release contract, released 2026-05-17.
|
||||||
|
|||||||
@ -21,6 +21,12 @@ use the existing concrete `result` families where host failures need to be
|
|||||||
observable. Handles are positive opaque `i32` process-local tokens, not stable
|
observable. Handles are positive opaque `i32` process-local tokens, not stable
|
||||||
file descriptors or ABI values.
|
file descriptors or ABI values.
|
||||||
|
|
||||||
|
The `1.0.0-beta.6` networking foundation release adds a narrow loopback TCP
|
||||||
|
runtime family behind the `std.net` source facade. These names are blocking,
|
||||||
|
result-returning, and loopback-only; they do not define DNS, TLS, UDP, async
|
||||||
|
IO, non-loopback binding, HTTP frameworks, stable socket ABI/layout, or rich
|
||||||
|
platform error values.
|
||||||
|
|
||||||
The exp-era catalog is closed to names promoted through exp-101. exp-29,
|
The exp-era catalog is closed to names promoted through exp-101. exp-29,
|
||||||
exp-30, exp-32, exp-33, and exp-35 through exp-93 add no new standard-runtime
|
exp-30, exp-32, exp-33, and exp-35 through exp-93 add no new standard-runtime
|
||||||
operation names. exp-32/exp-39/exp-56/exp-57 `std/math.slo` helpers,
|
operation names. exp-32/exp-39/exp-56/exp-57 `std/math.slo` helpers,
|
||||||
@ -97,6 +103,13 @@ source-level result helper names are the `std.result.*` names cataloged below.
|
|||||||
| `std.fs.open_text_read_result` | `(string) -> (result i32 i32)` | `1.0.0-beta.2` | `examples/projects/std-layout-local-fs` | Opens a text file for read-only resource-handle flow; success returns `ok handle` where `handle` is a positive opaque process-local `i32`, and ordinary open or handle-table failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Writable handles, binary IO, directory handles, process handles, sockets, async IO, platform-specific error codes, stable handle ABI/layout. |
|
| `std.fs.open_text_read_result` | `(string) -> (result i32 i32)` | `1.0.0-beta.2` | `examples/projects/std-layout-local-fs` | Opens a text file for read-only resource-handle flow; success returns `ok handle` where `handle` is a positive opaque process-local `i32`, and ordinary open or handle-table failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Writable handles, binary IO, directory handles, process handles, sockets, async IO, platform-specific error codes, stable handle ABI/layout. |
|
||||||
| `std.fs.read_open_text_result` | `(i32) -> (result string i32)` | `1.0.0-beta.2` | `examples/projects/std-layout-local-fs` | Reads remaining text from an open read handle; success returns `ok text`, while invalid, closed, or failed reads return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Chunked reads, seek, buffering controls, binary IO, async IO, platform-specific error codes, stable handle ABI/layout. |
|
| `std.fs.read_open_text_result` | `(i32) -> (result string i32)` | `1.0.0-beta.2` | `examples/projects/std-layout-local-fs` | Reads remaining text from an open read handle; success returns `ok text`, while invalid, closed, or failed reads return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Chunked reads, seek, buffering controls, binary IO, async IO, platform-specific error codes, stable handle ABI/layout. |
|
||||||
| `std.fs.close_result` | `(i32) -> (result i32 i32)` | `1.0.0-beta.2` | `examples/projects/std-layout-local-fs` | Closes an open resource handle; success returns `ok 0`, while invalid, closed, or failed close operations return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Finalizers, destructors, affine ownership, automatic cleanup, stable handle ABI/layout. |
|
| `std.fs.close_result` | `(i32) -> (result i32 i32)` | `1.0.0-beta.2` | `examples/projects/std-layout-local-fs` | Closes an open resource handle; success returns `ok 0`, while invalid, closed, or failed close operations return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Finalizers, destructors, affine ownership, automatic cleanup, stable handle ABI/layout. |
|
||||||
|
| `std.net.tcp_connect_loopback_result` | `(i32) -> (result i32 i32)` | `1.0.0-beta.6` | `examples/projects/std-layout-local-net` | Connects to a loopback TCP port; success returns `ok handle` where `handle` is a positive opaque process-local `i32`, and ordinary host failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | DNS, TLS, UDP, non-loopback connect policy, async IO, timeouts, rich host errors, stable socket ABI/layout. |
|
||||||
|
| `std.net.tcp_listen_loopback_result` | `(i32) -> (result i32 i32)` | `1.0.0-beta.6` | `examples/projects/std-layout-local-net` | Opens a blocking loopback TCP listener; success returns `ok handle`, and ordinary bind/listen or handle-table failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Non-loopback binding, socket options, backlog policy beyond the implementation minimum, async IO, rich host errors, stable socket ABI/layout. |
|
||||||
|
| `std.net.tcp_bound_port_result` | `(i32) -> (result i32 i32)` | `1.0.0-beta.6` | `examples/projects/std-layout-local-net` | Returns the bound loopback TCP port for a listener handle as `ok port`; invalid handles or host lookup failure return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Stable handle ABI/layout, address inspection, IPv6 policy, rich host errors. |
|
||||||
|
| `std.net.tcp_accept_result` | `(i32) -> (result i32 i32)` | `1.0.0-beta.6` | `examples/projects/std-layout-local-net` | Accepts one blocking connection from a listener handle; success returns `ok handle`, and invalid handles or host accept failure return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Async accept, cancellation, readiness polling, peer address APIs, rich host errors, stable socket ABI/layout. |
|
||||||
|
| `std.net.tcp_read_all_result` | `(i32) -> (result string i32)` | `1.0.0-beta.6` | `examples/projects/std-layout-local-net` | Reads remaining text from a stream handle until EOF; success returns `ok text`, and invalid handles or host read failure return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Chunked reads, binary IO, buffering policy, encodings, async IO, rich host errors, stable socket ABI/layout. |
|
||||||
|
| `std.net.tcp_write_text_result` | `(i32, string) -> (result i32 i32)` | `1.0.0-beta.6` | `examples/projects/std-layout-local-net` | Writes the complete text to a stream handle; success returns `ok 0`, and invalid handles or host write failure return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Partial-write APIs, binary IO, buffering policy, async IO, rich host errors, stable socket ABI/layout. |
|
||||||
|
| `std.net.tcp_close_result` | `(i32) -> (result i32 i32)` | `1.0.0-beta.6` | `examples/projects/std-layout-local-net` | Closes a TCP stream or listener handle; success returns `ok 0`, while invalid, already closed, or failed close operations return `err 1`. | Uses existing standard-runtime usage recording if present; no schema change. | Finalizers, destructors, affine ownership, automatic cleanup, stable socket ABI/layout. |
|
||||||
| `std.random.i32` | `() -> i32` | exp-11 | `examples/supported/random.slo` | Returns a non-negative implementation-owned random `i32`; unavailable randomness traps as `slovo runtime error: random i32 unavailable`. | Uses existing standard-runtime usage recording if present; no randomness-specific schema field. | Seed APIs, crypto/security promises, ranges, bytes, floats, UUIDs, stable RNG ABI/layout. |
|
| `std.random.i32` | `() -> i32` | exp-11 | `examples/supported/random.slo` | Returns a non-negative implementation-owned random `i32`; unavailable randomness traps as `slovo runtime error: random i32 unavailable`. | Uses existing standard-runtime usage recording if present; no randomness-specific schema field. | Seed APIs, crypto/security promises, ranges, bytes, floats, UUIDs, stable RNG ABI/layout. |
|
||||||
| `std.io.read_stdin_result` | `() -> (result string i32)` | exp-12 | `examples/supported/stdin-result.slo` | Reads remaining stdin as text; success returns `ok` text, ordinary EOF with no bytes returns `ok ""`, ordinary host/input failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no stdin-specific schema field. | Trap stdin, line APIs, prompts, terminal mode, binary/streaming/async stdin. |
|
| `std.io.read_stdin_result` | `() -> (result string i32)` | exp-12 | `examples/supported/stdin-result.slo` | Reads remaining stdin as text; success returns `ok` text, ordinary EOF with no bytes returns `ok ""`, ordinary host/input failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no stdin-specific schema field. | Trap stdin, line APIs, prompts, terminal mode, binary/streaming/async stdin. |
|
||||||
| `std.string.parse_i32_result` | `(string) -> (result i32 i32)` | exp-13 | `examples/supported/string-parse-i32-result.slo` | Parses an entire ASCII decimal signed `i32`; success returns `ok` value, ordinary parse failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no parse-specific schema field. | Trap parse, floats/bools/bytes, trimming, locale/radix/underscore/plus parsing, rich parse errors, Unicode digits, slicing/indexing. |
|
| `std.string.parse_i32_result` | `(string) -> (result i32 i32)` | exp-13 | `examples/supported/string-parse-i32-result.slo` | Parses an entire ASCII decimal signed `i32`; success returns `ok` value, ordinary parse failure returns `err 1`. | Uses existing standard-runtime usage recording if present; no parse-specific schema field. | Trap parse, floats/bools/bytes, trimming, locale/radix/underscore/plus parsing, rich parse errors, Unicode digits, slicing/indexing. |
|
||||||
|
|||||||
@ -6,15 +6,15 @@ Do not edit this file by hand.
|
|||||||
## Stability Tiers
|
## Stability Tiers
|
||||||
|
|
||||||
- `beta-supported`: exported from `lib/std` and covered by source-search, promotion, or facade gates in the current beta line.
|
- `beta-supported`: exported from `lib/std` and covered by source-search, promotion, or facade gates in the current beta line.
|
||||||
- `experimental`: not used for exported `lib/std` helpers in `1.0.0-beta.5`; future releases may mark new helpers this way before they graduate.
|
- `experimental`: not used for exported `lib/std` helpers in `1.0.0-beta.6`; future releases may mark new helpers this way before they graduate.
|
||||||
- `internal`: helper names that are not exported from their module; they are intentionally omitted from this catalog.
|
- `internal`: helper names that are not exported from their module; they are intentionally omitted from this catalog.
|
||||||
|
|
||||||
The catalog is a beta compatibility aid, not a stable `1.0.0` API freeze.
|
The catalog is a beta compatibility aid, not a stable `1.0.0` API freeze.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
- Modules: 17
|
- Modules: 18
|
||||||
- Exported helpers: 539
|
- Exported helpers: 548
|
||||||
- Default tier: `beta-supported`
|
- Default tier: `beta-supported`
|
||||||
|
|
||||||
## Modules
|
## Modules
|
||||||
@ -238,6 +238,22 @@ The catalog is a beta compatibility aid, not a stable `1.0.0` API freeze.
|
|||||||
- `is_negative_f64`
|
- `is_negative_f64`
|
||||||
- `in_range_f64`
|
- `in_range_f64`
|
||||||
|
|
||||||
|
### std.net
|
||||||
|
|
||||||
|
- Path: `lib/std/net.slo`
|
||||||
|
- Tier: `beta-supported`
|
||||||
|
- Exported helpers: 9
|
||||||
|
|
||||||
|
- `tcp_connect_loopback_result`
|
||||||
|
- `tcp_listen_loopback_result`
|
||||||
|
- `tcp_bound_port_result`
|
||||||
|
- `tcp_accept_result`
|
||||||
|
- `tcp_read_all_result`
|
||||||
|
- `tcp_write_text_result`
|
||||||
|
- `tcp_close_result`
|
||||||
|
- `tcp_write_text_ok`
|
||||||
|
- `tcp_close_ok`
|
||||||
|
|
||||||
### std.num
|
### std.num
|
||||||
|
|
||||||
- Path: `lib/std/num.slo`
|
- Path: `lib/std/num.slo`
|
||||||
|
|||||||
Binary file not shown.
@ -5,18 +5,19 @@
|
|||||||
Sanjin Gumbarevic<br>
|
Sanjin Gumbarevic<br>
|
||||||
hermeticum_lab@protonmail.com
|
hermeticum_lab@protonmail.com
|
||||||
|
|
||||||
Publication release: `1.0.0-beta.5`
|
Publication release: `1.0.0-beta.6`
|
||||||
|
|
||||||
Technical behavior baseline: compiler and language support through
|
Technical behavior baseline: compiler and language support through
|
||||||
`1.0.0-beta`; tooling and install workflow through `1.0.0-beta.1`;
|
`1.0.0-beta`; tooling and install workflow through `1.0.0-beta.1`;
|
||||||
runtime/resource foundation through `1.0.0-beta.2`; standard-library
|
runtime/resource foundation through `1.0.0-beta.2`; standard-library
|
||||||
stabilization through `1.0.0-beta.3`; language-usability diagnostics through
|
stabilization through `1.0.0-beta.3`; language-usability diagnostics through
|
||||||
`1.0.0-beta.4`; package/workspace discipline through `1.0.0-beta.5`
|
`1.0.0-beta.4`; package/workspace discipline through `1.0.0-beta.5`;
|
||||||
|
loopback networking foundation through `1.0.0-beta.6`
|
||||||
|
|
||||||
Date: 2026-05-22
|
Date: 2026-05-22
|
||||||
|
|
||||||
Evidence source: paired local Slovo/Glagol monorepo verification and benchmark
|
Evidence source: paired local Slovo/Glagol monorepo verification and benchmark
|
||||||
reruns from a local checkout; beta.5 release-gate verification from the public
|
reruns from a local checkout; beta.6 release-gate verification from the public
|
||||||
monorepo
|
monorepo
|
||||||
|
|
||||||
Maturity: beta
|
Maturity: beta
|
||||||
@ -28,19 +29,21 @@ Slovo. It exists to make the language support boundary inspectable: tokens,
|
|||||||
S-expression tree, AST, typed AST, LLVM IR, hosted native executable, tests,
|
S-expression tree, AST, typed AST, LLVM IR, hosted native executable, tests,
|
||||||
diagnostics, and release documents should agree.
|
diagnostics, and release documents should agree.
|
||||||
|
|
||||||
The current publication release, `1.0.0-beta.5`, keeps the first real
|
The current publication release, `1.0.0-beta.6`, keeps the first real
|
||||||
general-purpose beta toolchain baseline from `1.0.0-beta` and records the
|
general-purpose beta toolchain baseline from `1.0.0-beta` and records the
|
||||||
first post-beta tooling/install hardening update plus the first
|
first post-beta tooling/install hardening update plus the first
|
||||||
runtime/resource foundation update plus the first standard-library
|
runtime/resource foundation update plus the first standard-library
|
||||||
stabilization update plus the first language-usability diagnostics update and
|
stabilization update plus the first language-usability diagnostics update and
|
||||||
the first local package/workspace discipline update. The beta baseline includes
|
the first local package/workspace discipline update plus the first loopback
|
||||||
the completed `u32` / `u64` unsigned compiler and stdlib breadth scope
|
networking foundation update. The beta baseline includes the completed `u32` /
|
||||||
alongside the current nine-kernel benchmark suite. This paper records the
|
`u64` unsigned compiler and stdlib breadth scope, the narrow `std.net`
|
||||||
current beta implementation surface, the benchmark method and results, the
|
loopback TCP runtime family, and the current nine-kernel benchmark suite. This
|
||||||
distinction between Glagol and Lisp-family implementations, the beta.1 tooling
|
paper records the current beta implementation surface, the benchmark method and
|
||||||
update, the beta.2 runtime/resource foundation, the beta.3 standard-library
|
results, the distinction between Glagol and Lisp-family implementations, the
|
||||||
stabilization slice, the beta.4 diagnostics usability slice, the beta.5 package
|
beta.1 tooling update, the beta.2 runtime/resource foundation, the beta.3
|
||||||
discipline slice, and the compiler path from beta to stable.
|
standard-library stabilization slice, the beta.4 diagnostics usability slice,
|
||||||
|
the beta.5 package discipline slice, the beta.6 networking foundation slice,
|
||||||
|
and the compiler path from beta to stable.
|
||||||
|
|
||||||
## 1. Compiler Thesis
|
## 1. Compiler Thesis
|
||||||
|
|
||||||
@ -124,9 +127,9 @@ At the current technical behavior beta baseline, Glagol supports:
|
|||||||
- benchmark scaffolds for Slovo, C, Rust, Python, Clojure, and Common
|
- benchmark scaffolds for Slovo, C, Rust, Python, Clojure, and Common
|
||||||
Lisp/SBCL, with `cold-process` and `hot-loop` timing modes
|
Lisp/SBCL, with `cold-process` and `hot-loop` timing modes
|
||||||
|
|
||||||
The current release, `1.0.0-beta.5`, is a beta package/workspace discipline
|
The current release, `1.0.0-beta.6`, is a beta networking foundation update on
|
||||||
update on the first release line that may honestly use beta maturity language
|
the first release line that may honestly use beta maturity language for this
|
||||||
for this toolchain.
|
toolchain.
|
||||||
|
|
||||||
## 4. Diagnostics And Support Discipline
|
## 4. Diagnostics And Support Discipline
|
||||||
|
|
||||||
@ -285,8 +288,9 @@ The benchmark rows below remain the full-suite `1.0.0-beta` publication
|
|||||||
baseline. `1.0.0-beta.1` changes tooling and install workflow, and
|
baseline. `1.0.0-beta.1` changes tooling and install workflow, and
|
||||||
`1.0.0-beta.2` adds runtime/resource APIs, `1.0.0-beta.3` adds
|
`1.0.0-beta.2` adds runtime/resource APIs, `1.0.0-beta.3` adds
|
||||||
standard-library catalog and composition coverage, `1.0.0-beta.4` improves
|
standard-library catalog and composition coverage, `1.0.0-beta.4` improves
|
||||||
diagnostics, and `1.0.0-beta.5` tightens package/workspace discipline. None of
|
diagnostics, `1.0.0-beta.5` tightens package/workspace discipline, and
|
||||||
these post-beta slices claims changed benchmark performance.
|
`1.0.0-beta.6` adds a narrow loopback networking foundation. None of these
|
||||||
|
post-beta slices claims changed benchmark performance.
|
||||||
|
|
||||||
The exp-123 publication baseline widened the paired same-machine result set
|
The exp-123 publication baseline widened the paired same-machine result set
|
||||||
from seven rows to nine by adding two owned-vector kernels:
|
from seven rows to nine by adding two owned-vector kernels:
|
||||||
@ -374,13 +378,14 @@ coverage and compatibility:
|
|||||||
- package behavior becoming stable before dependency, manifest, and versioning
|
- package behavior becoming stable before dependency, manifest, and versioning
|
||||||
rules are precise
|
rules are precise
|
||||||
|
|
||||||
## 9. Path Beyond `1.0.0-beta.5`
|
## 9. Path Beyond `1.0.0-beta.6`
|
||||||
|
|
||||||
Glagol now implements the first real beta Slovo contract, the first
|
Glagol now implements the first real beta Slovo contract, the first
|
||||||
post-beta tooling/install hardening release, the first runtime/resource
|
post-beta tooling/install hardening release, the first runtime/resource
|
||||||
foundation release, the first standard-library stabilization release, and the
|
foundation release, the first standard-library stabilization release, and the
|
||||||
first diagnostics usability release, and the first package/workspace
|
first diagnostics usability release, and the first package/workspace
|
||||||
discipline release. The remaining path is from beta to stable.
|
discipline release, and the first loopback networking foundation release. The
|
||||||
|
remaining path is from beta to stable.
|
||||||
|
|
||||||
Recommended compiler sequence:
|
Recommended compiler sequence:
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -5,18 +5,19 @@
|
|||||||
Sanjin Gumbarevic<br>
|
Sanjin Gumbarevic<br>
|
||||||
hermeticum_lab@protonmail.com
|
hermeticum_lab@protonmail.com
|
||||||
|
|
||||||
Publication release: `1.0.0-beta.5`
|
Publication release: `1.0.0-beta.6`
|
||||||
|
|
||||||
Technical behavior baseline: language surface through `1.0.0-beta`; tooling
|
Technical behavior baseline: language surface through `1.0.0-beta`; tooling
|
||||||
and install workflow through `1.0.0-beta.1`; runtime/resource foundation through
|
and install workflow through `1.0.0-beta.1`; runtime/resource foundation through
|
||||||
`1.0.0-beta.2`; standard-library stabilization through `1.0.0-beta.3`;
|
`1.0.0-beta.2`; standard-library stabilization through `1.0.0-beta.3`;
|
||||||
language-usability diagnostics through `1.0.0-beta.4`; package/workspace
|
language-usability diagnostics through `1.0.0-beta.4`; package/workspace
|
||||||
discipline through `1.0.0-beta.5`
|
discipline through `1.0.0-beta.5`; loopback networking foundation through
|
||||||
|
`1.0.0-beta.6`
|
||||||
|
|
||||||
Date: 2026-05-22
|
Date: 2026-05-22
|
||||||
|
|
||||||
Evidence source: paired local Slovo/Glagol monorepo verification and benchmark
|
Evidence source: paired local Slovo/Glagol monorepo verification and benchmark
|
||||||
reruns from a local checkout; beta.5 release-gate verification from the public
|
reruns from a local checkout; beta.6 release-gate verification from the public
|
||||||
monorepo
|
monorepo
|
||||||
|
|
||||||
Maturity: beta
|
Maturity: beta
|
||||||
@ -31,26 +32,28 @@ explicit types, explicit failure through `option` and `result`, lexical
|
|||||||
`unsafe`, and native compilation through the Glagol compiler to LLVM IR and
|
`unsafe`, and native compilation through the Glagol compiler to LLVM IR and
|
||||||
hosted executables.
|
hosted executables.
|
||||||
|
|
||||||
The current publication release, `1.0.0-beta.5`, keeps the first real
|
The current publication release, `1.0.0-beta.6`, keeps the first real
|
||||||
general-purpose beta language baseline from `1.0.0-beta` and records the first
|
general-purpose beta language baseline from `1.0.0-beta` and records the first
|
||||||
post-beta tooling/install hardening update plus the first runtime/resource
|
post-beta tooling/install hardening update plus the first runtime/resource
|
||||||
foundation update, the first standard-library stabilization update, and the
|
foundation update, the first standard-library stabilization update, and the
|
||||||
first language-usability diagnostics update, plus the first local
|
first language-usability diagnostics update, plus the first local
|
||||||
package/workspace discipline update. The beta baseline includes the completed
|
package/workspace discipline update, and the first loopback networking
|
||||||
`u32` / `u64` unsigned scope, the staged stdlib breadth that makes ordinary
|
foundation update. The beta baseline includes the completed `u32` / `u64`
|
||||||
command-line programs practical, and the current nine-kernel benchmark suite.
|
unsigned scope, the staged stdlib breadth that makes ordinary command-line
|
||||||
This paper records the current beta technical state, the difference between
|
programs practical, the current narrow `std.net` loopback TCP surface, and the
|
||||||
Slovo and Lisp-family languages, the benchmark methodology, the beta.1 tooling
|
current nine-kernel benchmark suite. This paper records the current beta
|
||||||
update, the beta.2 runtime/resource foundation, the beta.3 standard-library
|
technical state, the difference between Slovo and Lisp-family languages, the
|
||||||
stabilization slice, the beta.4 diagnostics usability slice, the beta.5 package
|
benchmark methodology, the beta.1 tooling update, the beta.2 runtime/resource
|
||||||
discipline slice, and the remaining path from beta to stable.
|
foundation, the beta.3 standard-library stabilization slice, the beta.4
|
||||||
|
diagnostics usability slice, the beta.5 package discipline slice, the beta.6
|
||||||
|
networking foundation slice, and the remaining path from beta to stable.
|
||||||
|
|
||||||
## 1. Scope
|
## 1. Scope
|
||||||
|
|
||||||
This document is a technical state paper for the current beta baseline. It
|
This document is a technical state paper for the current beta baseline. It
|
||||||
summarizes the behavior represented by the paired local Slovo and Glagol
|
summarizes the behavior represented by the paired local Slovo and Glagol
|
||||||
workspaces, with `1.0.0-beta` as the current language-surface baseline and
|
workspaces, with `1.0.0-beta` as the current language-surface baseline and
|
||||||
`1.0.0-beta.5` as the current publication baseline.
|
`1.0.0-beta.6` as the current publication baseline.
|
||||||
|
|
||||||
The support rule remains strict:
|
The support rule remains strict:
|
||||||
|
|
||||||
@ -62,7 +65,7 @@ The support rule remains strict:
|
|||||||
- partial parser recognition or speculative examples do not count as support
|
- partial parser recognition or speculative examples do not count as support
|
||||||
|
|
||||||
Historical `exp-*` releases remain experimental alpha maturity. The current
|
Historical `exp-*` releases remain experimental alpha maturity. The current
|
||||||
publication accompanies `1.0.0-beta.5`.
|
publication accompanies `1.0.0-beta.6`.
|
||||||
|
|
||||||
## 2. Design Thesis
|
## 2. Design Thesis
|
||||||
|
|
||||||
@ -362,8 +365,9 @@ The benchmark rows below remain the full-suite `1.0.0-beta` publication
|
|||||||
baseline. `1.0.0-beta.1` changes tooling and install workflow, and
|
baseline. `1.0.0-beta.1` changes tooling and install workflow, and
|
||||||
`1.0.0-beta.2` adds runtime/resource APIs, `1.0.0-beta.3` adds
|
`1.0.0-beta.2` adds runtime/resource APIs, `1.0.0-beta.3` adds
|
||||||
standard-library catalog and composition coverage, `1.0.0-beta.4` improves
|
standard-library catalog and composition coverage, `1.0.0-beta.4` improves
|
||||||
diagnostics, and `1.0.0-beta.5` tightens package/workspace discipline. None of
|
diagnostics, `1.0.0-beta.5` tightens package/workspace discipline, and
|
||||||
these post-beta slices claims changed benchmark performance.
|
`1.0.0-beta.6` adds a narrow loopback networking foundation. None of these
|
||||||
|
post-beta slices claims changed benchmark performance.
|
||||||
|
|
||||||
The exp-123 publication baseline widened the paired same-machine result set
|
The exp-123 publication baseline widened the paired same-machine result set
|
||||||
from seven rows to nine by adding two owned-vector kernels:
|
from seven rows to nine by adding two owned-vector kernels:
|
||||||
@ -484,7 +488,7 @@ Major remaining gaps before `1.0.0`:
|
|||||||
- semantic versioning and deprecation policy
|
- semantic versioning and deprecation policy
|
||||||
- a clear separation between stable and experimental features
|
- a clear separation between stable and experimental features
|
||||||
|
|
||||||
## 10. Path Beyond `1.0.0-beta.5`
|
## 10. Path Beyond `1.0.0-beta.6`
|
||||||
|
|
||||||
The beta threshold is now real. The next work should treat `1.0.0-beta` as
|
The beta threshold is now real. The next work should treat `1.0.0-beta` as
|
||||||
the language compatibility-governed baseline, `1.0.0-beta.1` as the first
|
the language compatibility-governed baseline, `1.0.0-beta.1` as the first
|
||||||
@ -492,6 +496,7 @@ tooling/install hardening point, `1.0.0-beta.2` as the first runtime/resource
|
|||||||
foundation point, and `1.0.0-beta.3` as the first standard-library
|
foundation point, and `1.0.0-beta.3` as the first standard-library
|
||||||
stabilization point, and `1.0.0-beta.4` as the first diagnostics usability
|
stabilization point, and `1.0.0-beta.4` as the first diagnostics usability
|
||||||
point, and `1.0.0-beta.5` as the first package/workspace discipline point,
|
point, and `1.0.0-beta.5` as the first package/workspace discipline point,
|
||||||
|
and `1.0.0-beta.6` as the first loopback networking foundation point,
|
||||||
then move deliberately toward stable general-purpose status.
|
then move deliberately toward stable general-purpose status.
|
||||||
|
|
||||||
Recommended sequence:
|
Recommended sequence:
|
||||||
|
|||||||
Binary file not shown.
4
examples/projects/std-import-net/slovo.toml
Normal file
4
examples/projects/std-import-net/slovo.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[project]
|
||||||
|
name = "std-import-net"
|
||||||
|
source_root = "src"
|
||||||
|
entry = "main"
|
||||||
94
examples/projects/std-import-net/src/main.slo
Normal file
94
examples/projects/std-import-net/src/main.slo
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
(module main)
|
||||||
|
|
||||||
|
(import std.net (tcp_connect_loopback_result tcp_listen_loopback_result tcp_bound_port_result tcp_accept_result tcp_read_all_result tcp_write_text_result tcp_close_result tcp_write_text_ok tcp_close_ok))
|
||||||
|
|
||||||
|
(fn i32_err_one ((value (result i32 i32))) -> bool
|
||||||
|
(match value
|
||||||
|
((ok payload)
|
||||||
|
false)
|
||||||
|
((err code)
|
||||||
|
(= code 1))))
|
||||||
|
|
||||||
|
(fn string_err_one ((value (result string i32))) -> bool
|
||||||
|
(match value
|
||||||
|
((ok payload)
|
||||||
|
false)
|
||||||
|
((err code)
|
||||||
|
(= code 1))))
|
||||||
|
|
||||||
|
(fn imported_connect_invalid_port_err () -> bool
|
||||||
|
(i32_err_one (tcp_connect_loopback_result 0)))
|
||||||
|
|
||||||
|
(fn imported_listen_invalid_port_err () -> bool
|
||||||
|
(i32_err_one (tcp_listen_loopback_result -1)))
|
||||||
|
|
||||||
|
(fn imported_bound_port_invalid_handle_err () -> bool
|
||||||
|
(i32_err_one (tcp_bound_port_result -1)))
|
||||||
|
|
||||||
|
(fn imported_accept_invalid_listener_err () -> bool
|
||||||
|
(i32_err_one (tcp_accept_result -1)))
|
||||||
|
|
||||||
|
(fn imported_read_invalid_handle_err () -> bool
|
||||||
|
(string_err_one (tcp_read_all_result -1)))
|
||||||
|
|
||||||
|
(fn imported_write_invalid_handle_err () -> bool
|
||||||
|
(i32_err_one (tcp_write_text_result -1 "ping")))
|
||||||
|
|
||||||
|
(fn imported_close_invalid_handle_err () -> bool
|
||||||
|
(i32_err_one (tcp_close_result -1)))
|
||||||
|
|
||||||
|
(fn imported_helper_invalids_false () -> bool
|
||||||
|
(if (tcp_write_text_ok -1 "ping")
|
||||||
|
false
|
||||||
|
(if (tcp_close_ok -1)
|
||||||
|
false
|
||||||
|
true)))
|
||||||
|
|
||||||
|
(fn imported_invalid_paths_ok () -> bool
|
||||||
|
(if (imported_connect_invalid_port_err)
|
||||||
|
(if (imported_listen_invalid_port_err)
|
||||||
|
(if (imported_bound_port_invalid_handle_err)
|
||||||
|
(if (imported_accept_invalid_listener_err)
|
||||||
|
(if (imported_read_invalid_handle_err)
|
||||||
|
(if (imported_write_invalid_handle_err)
|
||||||
|
(if (imported_close_invalid_handle_err)
|
||||||
|
(imported_helper_invalids_false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false))
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(if (imported_invalid_paths_ok)
|
||||||
|
42
|
||||||
|
1))
|
||||||
|
|
||||||
|
(test "explicit std net invalid connect facade"
|
||||||
|
(imported_connect_invalid_port_err))
|
||||||
|
|
||||||
|
(test "explicit std net invalid listen facade"
|
||||||
|
(imported_listen_invalid_port_err))
|
||||||
|
|
||||||
|
(test "explicit std net invalid bound port facade"
|
||||||
|
(imported_bound_port_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit std net invalid accept facade"
|
||||||
|
(imported_accept_invalid_listener_err))
|
||||||
|
|
||||||
|
(test "explicit std net invalid read facade"
|
||||||
|
(imported_read_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit std net invalid write facade"
|
||||||
|
(imported_write_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit std net invalid close facade"
|
||||||
|
(imported_close_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit std net helper invalids facade"
|
||||||
|
(imported_helper_invalids_false))
|
||||||
|
|
||||||
|
(test "explicit std net facade all"
|
||||||
|
(= (main) 42))
|
||||||
4
examples/projects/std-layout-local-net/slovo.toml
Normal file
4
examples/projects/std-layout-local-net/slovo.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[project]
|
||||||
|
name = "std-layout-local-net"
|
||||||
|
source_root = "src"
|
||||||
|
entry = "main"
|
||||||
94
examples/projects/std-layout-local-net/src/main.slo
Normal file
94
examples/projects/std-layout-local-net/src/main.slo
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
(module main)
|
||||||
|
|
||||||
|
(import net (tcp_connect_loopback_result tcp_listen_loopback_result tcp_bound_port_result tcp_accept_result tcp_read_all_result tcp_write_text_result tcp_close_result tcp_write_text_ok tcp_close_ok))
|
||||||
|
|
||||||
|
(fn i32_err_one ((value (result i32 i32))) -> bool
|
||||||
|
(match value
|
||||||
|
((ok payload)
|
||||||
|
false)
|
||||||
|
((err code)
|
||||||
|
(= code 1))))
|
||||||
|
|
||||||
|
(fn string_err_one ((value (result string i32))) -> bool
|
||||||
|
(match value
|
||||||
|
((ok payload)
|
||||||
|
false)
|
||||||
|
((err code)
|
||||||
|
(= code 1))))
|
||||||
|
|
||||||
|
(fn imported_connect_invalid_port_err () -> bool
|
||||||
|
(i32_err_one (tcp_connect_loopback_result 0)))
|
||||||
|
|
||||||
|
(fn imported_listen_invalid_port_err () -> bool
|
||||||
|
(i32_err_one (tcp_listen_loopback_result -1)))
|
||||||
|
|
||||||
|
(fn imported_bound_port_invalid_handle_err () -> bool
|
||||||
|
(i32_err_one (tcp_bound_port_result -1)))
|
||||||
|
|
||||||
|
(fn imported_accept_invalid_listener_err () -> bool
|
||||||
|
(i32_err_one (tcp_accept_result -1)))
|
||||||
|
|
||||||
|
(fn imported_read_invalid_handle_err () -> bool
|
||||||
|
(string_err_one (tcp_read_all_result -1)))
|
||||||
|
|
||||||
|
(fn imported_write_invalid_handle_err () -> bool
|
||||||
|
(i32_err_one (tcp_write_text_result -1 "ping")))
|
||||||
|
|
||||||
|
(fn imported_close_invalid_handle_err () -> bool
|
||||||
|
(i32_err_one (tcp_close_result -1)))
|
||||||
|
|
||||||
|
(fn imported_helper_invalids_false () -> bool
|
||||||
|
(if (tcp_write_text_ok -1 "ping")
|
||||||
|
false
|
||||||
|
(if (tcp_close_ok -1)
|
||||||
|
false
|
||||||
|
true)))
|
||||||
|
|
||||||
|
(fn imported_invalid_paths_ok () -> bool
|
||||||
|
(if (imported_connect_invalid_port_err)
|
||||||
|
(if (imported_listen_invalid_port_err)
|
||||||
|
(if (imported_bound_port_invalid_handle_err)
|
||||||
|
(if (imported_accept_invalid_listener_err)
|
||||||
|
(if (imported_read_invalid_handle_err)
|
||||||
|
(if (imported_write_invalid_handle_err)
|
||||||
|
(if (imported_close_invalid_handle_err)
|
||||||
|
(imported_helper_invalids_false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false)
|
||||||
|
false))
|
||||||
|
|
||||||
|
(fn main () -> i32
|
||||||
|
(if (imported_invalid_paths_ok)
|
||||||
|
42
|
||||||
|
1))
|
||||||
|
|
||||||
|
(test "explicit local net invalid connect facade"
|
||||||
|
(imported_connect_invalid_port_err))
|
||||||
|
|
||||||
|
(test "explicit local net invalid listen facade"
|
||||||
|
(imported_listen_invalid_port_err))
|
||||||
|
|
||||||
|
(test "explicit local net invalid bound port facade"
|
||||||
|
(imported_bound_port_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit local net invalid accept facade"
|
||||||
|
(imported_accept_invalid_listener_err))
|
||||||
|
|
||||||
|
(test "explicit local net invalid read facade"
|
||||||
|
(imported_read_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit local net invalid write facade"
|
||||||
|
(imported_write_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit local net invalid close facade"
|
||||||
|
(imported_close_invalid_handle_err))
|
||||||
|
|
||||||
|
(test "explicit local net helper invalids facade"
|
||||||
|
(imported_helper_invalids_false))
|
||||||
|
|
||||||
|
(test "explicit local net facade all"
|
||||||
|
(= (main) 42))
|
||||||
36
examples/projects/std-layout-local-net/src/net.slo
Normal file
36
examples/projects/std-layout-local-net/src/net.slo
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
(module net (export tcp_connect_loopback_result tcp_listen_loopback_result tcp_bound_port_result tcp_accept_result tcp_read_all_result tcp_write_text_result tcp_close_result tcp_write_text_ok tcp_close_ok))
|
||||||
|
|
||||||
|
(fn tcp_connect_loopback_result ((port i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_connect_loopback_result port))
|
||||||
|
|
||||||
|
(fn tcp_listen_loopback_result ((port i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_listen_loopback_result port))
|
||||||
|
|
||||||
|
(fn tcp_bound_port_result ((handle i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_bound_port_result handle))
|
||||||
|
|
||||||
|
(fn tcp_accept_result ((listener i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_accept_result listener))
|
||||||
|
|
||||||
|
(fn tcp_read_all_result ((handle i32)) -> (result string i32)
|
||||||
|
(std.net.tcp_read_all_result handle))
|
||||||
|
|
||||||
|
(fn tcp_write_text_result ((handle i32) (text string)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_write_text_result handle text))
|
||||||
|
|
||||||
|
(fn tcp_close_result ((handle i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_close_result handle))
|
||||||
|
|
||||||
|
(fn tcp_write_text_ok ((handle i32) (text string)) -> bool
|
||||||
|
(match (tcp_write_text_result handle text)
|
||||||
|
((ok status)
|
||||||
|
true)
|
||||||
|
((err code)
|
||||||
|
false)))
|
||||||
|
|
||||||
|
(fn tcp_close_ok ((handle i32)) -> bool
|
||||||
|
(match (tcp_close_result handle)
|
||||||
|
((ok status)
|
||||||
|
true)
|
||||||
|
((err code)
|
||||||
|
false)))
|
||||||
@ -31,7 +31,9 @@ updated through `exp-66`; fs option helpers updated through `exp-110`; num
|
|||||||
fallback helpers updated through `exp-64`; concrete vec helpers updated
|
fallback helpers updated through `exp-64`; concrete vec helpers updated
|
||||||
through released `exp-108`, including the current concrete
|
through released `exp-108`, including the current concrete
|
||||||
`std/vec_string.slo`, `std/vec_f64.slo`, and `std/vec_bool.slo`
|
`std/vec_string.slo`, `std/vec_f64.slo`, and `std/vec_bool.slo`
|
||||||
prefix/suffix helper scopes.
|
prefix/suffix helper scopes; `1.0.0-beta.6` networking foundation work releases
|
||||||
|
`std/net.slo` as an experimental loopback TCP facade over matching
|
||||||
|
compiler-known runtime calls.
|
||||||
|
|
||||||
This directory is the source home for staged standard library modules and
|
This directory is the source home for staged standard library modules and
|
||||||
examples. exp-44 lets project-mode source explicitly import `std/math.slo` as
|
examples. exp-44 lets project-mode source explicitly import `std/math.slo` as
|
||||||
@ -83,6 +85,13 @@ filesystem status/mutation helpers over `std.fs.exists`, `std.fs.is_file`,
|
|||||||
`std.fs.is_dir`, `std.fs.remove_file_result`, and
|
`std.fs.is_dir`, `std.fs.remove_file_result`, and
|
||||||
`std.fs.create_dir_result`, while keeping handles beta-scoped opaque `i32`
|
`std.fs.create_dir_result`, while keeping handles beta-scoped opaque `i32`
|
||||||
values and leaving directory enumeration deferred;
|
values and leaving directory enumeration deferred;
|
||||||
|
`1.0.0-beta.6` releases `std/net.slo` as an experimental blocking
|
||||||
|
loopback TCP facade over `std.net.tcp_connect_loopback_result`,
|
||||||
|
`std.net.tcp_listen_loopback_result`, `std.net.tcp_bound_port_result`,
|
||||||
|
`std.net.tcp_accept_result`, `std.net.tcp_read_all_result`,
|
||||||
|
`std.net.tcp_write_text_result`, and `std.net.tcp_close_result`, while keeping
|
||||||
|
socket handles beta-scoped opaque `i32` values and leaving DNS, TLS, async,
|
||||||
|
UDP, non-loopback binding, and stable ABI/layout deferred;
|
||||||
exp-76 extends project-mode source search to `std/vec_i32.slo`, a concrete
|
exp-76 extends project-mode source search to `std/vec_i32.slo`, a concrete
|
||||||
source-authored collection facade over the current promoted `std.vec.i32`
|
source-authored collection facade over the current promoted `std.vec.i32`
|
||||||
runtime family; exp-77 extends that facade with concrete option-returning
|
runtime family; exp-77 extends that facade with concrete option-returning
|
||||||
@ -127,12 +136,13 @@ For exp-44, exp-45, exp-47, exp-48, exp-49, exp-52, exp-53, exp-76, exp-94,
|
|||||||
exp-96, exp-97, exp-98, exp-99, exp-103, exp-104, exp-105, exp-107, and
|
exp-96, exp-97, exp-98, exp-99, exp-103, exp-104, exp-105, exp-107, and
|
||||||
exp-108, `std/math.slo`, `std/result.slo`,
|
exp-108, `std/math.slo`, `std/result.slo`,
|
||||||
`std/option.slo`, `std/time.slo`, `std/random.slo`, `std/env.slo`,
|
`std/option.slo`, `std/time.slo`, `std/random.slo`, `std/env.slo`,
|
||||||
`std/fs.slo`, `std/string.slo`, `std/num.slo`, `std/io.slo`,
|
`std/fs.slo`, `std/net.slo`, `std/string.slo`, `std/num.slo`,
|
||||||
`std/process.slo`, `std/cli.slo`, `std/vec_i32.slo`, `std/vec_f64.slo`,
|
`std/io.slo`, `std/process.slo`, `std/cli.slo`, `std/vec_i32.slo`,
|
||||||
`std/vec_i64.slo`, and `std/vec_string.slo` carry explicit export lists.
|
`std/vec_f64.slo`, `std/vec_i64.slo`, and `std/vec_string.slo` carry explicit
|
||||||
|
export lists.
|
||||||
Glagol may address them externally as `std.math`, `std.result`,
|
Glagol may address them externally as `std.math`, `std.result`,
|
||||||
`std.option`, `std.time`, `std.random`, `std.env`, `std.fs`, `std.string`,
|
`std.option`, `std.time`, `std.random`, `std.env`, `std.fs`, `std.string`,
|
||||||
`std.num`, `std.io`, `std.process`, `std.cli`, `std.vec_i32`,
|
`std.net`, `std.num`, `std.io`, `std.process`, `std.cli`, `std.vec_i32`,
|
||||||
`std.vec_f64`, `std.vec_bool`, `std.vec_i64`, and `std.vec_string`.
|
`std.vec_f64`, `std.vec_bool`, `std.vec_i64`, and `std.vec_string`.
|
||||||
The file layout is the contract:
|
The file layout is the contract:
|
||||||
|
|
||||||
@ -153,6 +163,7 @@ The file layout is the contract:
|
|||||||
- `std/random.slo`
|
- `std/random.slo`
|
||||||
- `std/env.slo`
|
- `std/env.slo`
|
||||||
- `std/fs.slo`
|
- `std/fs.slo`
|
||||||
|
- `std/net.slo`
|
||||||
|
|
||||||
This follows a Zig-like standard-library facade discipline in a Slovo-sized
|
This follows a Zig-like standard-library facade discipline in a Slovo-sized
|
||||||
form: flat `std/*.slo` facade files are the staged source surface now, and a
|
form: flat `std/*.slo` facade files are the staged source surface now, and a
|
||||||
@ -261,6 +272,12 @@ over `read_text_result` plus those same concrete parse result families from
|
|||||||
`read_i64_option`, `read_f64_option`, and `read_bool_option` as ordinary
|
`read_i64_option`, `read_f64_option`, and `read_bool_option` as ordinary
|
||||||
source option helpers over those same read/parse result families through the
|
source option helpers over those same read/parse result families through the
|
||||||
exp-109 `std.result.ok_or_none_*` bridge helpers.
|
exp-109 `std.result.ok_or_none_*` bridge helpers.
|
||||||
|
`std/net.slo` is the beta.6 networking foundation source facade. It wraps
|
||||||
|
blocking loopback TCP connect/listen/bound-port/accept/read-all/write-text/
|
||||||
|
close result calls and adds only `tcp_write_text_ok` and `tcp_close_ok` source
|
||||||
|
helpers. It is not a general networking module: DNS, TLS, async IO, UDP,
|
||||||
|
non-loopback binding, socket options, rich host errors, and stable handle ABI
|
||||||
|
remain deferred.
|
||||||
`std/process.slo` includes the exp-52 narrow source wrappers over already
|
`std/process.slo` includes the exp-52 narrow source wrappers over already
|
||||||
released process argument runtime calls and a source-authored `has_arg`
|
released process argument runtime calls and a source-authored `has_arg`
|
||||||
predicate. exp-61 adds `arg_or` and `arg_or_empty` as ordinary source
|
predicate. exp-61 adds `arg_or` and `arg_or_empty` as ordinary source
|
||||||
|
|||||||
36
lib/std/net.slo
Normal file
36
lib/std/net.slo
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
(module net (export tcp_connect_loopback_result tcp_listen_loopback_result tcp_bound_port_result tcp_accept_result tcp_read_all_result tcp_write_text_result tcp_close_result tcp_write_text_ok tcp_close_ok))
|
||||||
|
|
||||||
|
(fn tcp_connect_loopback_result ((port i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_connect_loopback_result port))
|
||||||
|
|
||||||
|
(fn tcp_listen_loopback_result ((port i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_listen_loopback_result port))
|
||||||
|
|
||||||
|
(fn tcp_bound_port_result ((handle i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_bound_port_result handle))
|
||||||
|
|
||||||
|
(fn tcp_accept_result ((listener i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_accept_result listener))
|
||||||
|
|
||||||
|
(fn tcp_read_all_result ((handle i32)) -> (result string i32)
|
||||||
|
(std.net.tcp_read_all_result handle))
|
||||||
|
|
||||||
|
(fn tcp_write_text_result ((handle i32) (text string)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_write_text_result handle text))
|
||||||
|
|
||||||
|
(fn tcp_close_result ((handle i32)) -> (result i32 i32)
|
||||||
|
(std.net.tcp_close_result handle))
|
||||||
|
|
||||||
|
(fn tcp_write_text_ok ((handle i32) (text string)) -> bool
|
||||||
|
(match (tcp_write_text_result handle text)
|
||||||
|
((ok status)
|
||||||
|
true)
|
||||||
|
((err code)
|
||||||
|
false)))
|
||||||
|
|
||||||
|
(fn tcp_close_ok ((handle i32)) -> bool
|
||||||
|
(match (tcp_close_result handle)
|
||||||
|
((ok status)
|
||||||
|
true)
|
||||||
|
((err code)
|
||||||
|
false)))
|
||||||
@ -1,15 +1,18 @@
|
|||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@ -48,6 +51,9 @@ static struct timespec __glagol_time_base;
|
|||||||
#define __GLAGOL_FILE_HANDLE_LIMIT 1024
|
#define __GLAGOL_FILE_HANDLE_LIMIT 1024
|
||||||
static FILE *__glagol_file_handles[__GLAGOL_FILE_HANDLE_LIMIT];
|
static FILE *__glagol_file_handles[__GLAGOL_FILE_HANDLE_LIMIT];
|
||||||
|
|
||||||
|
#define __GLAGOL_NET_HANDLE_LIMIT 1024
|
||||||
|
static int __glagol_net_handles[__GLAGOL_NET_HANDLE_LIMIT];
|
||||||
|
|
||||||
static int64_t __glagol_result_i32_encode(uint32_t status, int32_t payload) {
|
static int64_t __glagol_result_i32_encode(uint32_t status, int32_t payload) {
|
||||||
uint64_t encoded = ((uint64_t)status << 32) | (uint32_t)payload;
|
uint64_t encoded = ((uint64_t)status << 32) | (uint32_t)payload;
|
||||||
return (int64_t)encoded;
|
return (int64_t)encoded;
|
||||||
@ -57,6 +63,54 @@ static int64_t __glagol_result_i32_err(void) {
|
|||||||
return __glagol_result_i32_encode(1, 1);
|
return __glagol_result_i32_encode(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t __glagol_net_handle_insert(int fd) {
|
||||||
|
if (fd < 0 || fd == INT_MAX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t handle = 1; handle < __GLAGOL_NET_HANDLE_LIMIT; handle++) {
|
||||||
|
if (__glagol_net_handles[handle] == 0) {
|
||||||
|
__glagol_net_handles[handle] = fd + 1;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __glagol_net_handle_get(int32_t handle) {
|
||||||
|
if (handle <= 0 || handle >= __GLAGOL_NET_HANDLE_LIMIT) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stored = __glagol_net_handles[handle];
|
||||||
|
return stored == 0 ? -1 : stored - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __glagol_net_handle_take(int32_t handle) {
|
||||||
|
int fd = __glagol_net_handle_get(handle);
|
||||||
|
if (fd >= 0) {
|
||||||
|
__glagol_net_handles[handle] = 0;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __glagol_net_connect_port_is_valid(int32_t port) {
|
||||||
|
return port > 0 && port <= 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __glagol_net_bind_port_is_valid(int32_t port) {
|
||||||
|
return port >= 0 && port <= 65535;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sockaddr_in __glagol_net_loopback_addr(int32_t port) {
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
addr.sin_port = htons((uint16_t)port);
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
void print_i32(int32_t value) {
|
void print_i32(int32_t value) {
|
||||||
printf("%d\n", value);
|
printf("%d\n", value);
|
||||||
}
|
}
|
||||||
@ -433,6 +487,222 @@ int32_t __glagol_fs_close_result(int32_t handle) {
|
|||||||
return fclose(file) == 0 ? 0 : 1;
|
return fclose(file) == 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t __glagol_net_tcp_connect_loopback_result(int32_t port) {
|
||||||
|
if (!__glagol_net_connect_port_is_valid(port)) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in addr = __glagol_net_loopback_addr(port);
|
||||||
|
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
||||||
|
close(fd);
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t handle = __glagol_net_handle_insert(fd);
|
||||||
|
if (handle == 0) {
|
||||||
|
close(fd);
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
return __glagol_result_i32_encode(0, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t __glagol_net_tcp_listen_loopback_result(int32_t port) {
|
||||||
|
if (!__glagol_net_bind_port_is_valid(port)) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
int enabled = 1;
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enabled, sizeof(enabled)) != 0) {
|
||||||
|
close(fd);
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in addr = __glagol_net_loopback_addr(port);
|
||||||
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
||||||
|
close(fd);
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(fd, 1) != 0) {
|
||||||
|
close(fd);
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t handle = __glagol_net_handle_insert(fd);
|
||||||
|
if (handle == 0) {
|
||||||
|
close(fd);
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
return __glagol_result_i32_encode(0, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t __glagol_net_tcp_bound_port_result(int32_t handle) {
|
||||||
|
int fd = __glagol_net_handle_get(handle);
|
||||||
|
if (fd < 0) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
if (getsockname(fd, (struct sockaddr *)&addr, &addr_len) != 0) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
return __glagol_result_i32_encode(0, (int32_t)ntohs(addr.sin_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t __glagol_net_tcp_accept_result(int32_t listener) {
|
||||||
|
int fd = __glagol_net_handle_get(listener);
|
||||||
|
if (fd < 0) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
int accepted;
|
||||||
|
do {
|
||||||
|
accepted = accept(fd, NULL, NULL);
|
||||||
|
} while (accepted < 0 && errno == EINTR);
|
||||||
|
|
||||||
|
if (accepted < 0) {
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t handle = __glagol_net_handle_insert(accepted);
|
||||||
|
if (handle == 0) {
|
||||||
|
close(accepted);
|
||||||
|
return __glagol_result_i32_err();
|
||||||
|
}
|
||||||
|
|
||||||
|
return __glagol_result_i32_encode(0, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *__glagol_net_tcp_read_all_result(int32_t handle) {
|
||||||
|
int fd = __glagol_net_handle_get(handle);
|
||||||
|
if (fd < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity = 1024;
|
||||||
|
size_t length = 0;
|
||||||
|
char *value = malloc(capacity);
|
||||||
|
if (value == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (length == capacity) {
|
||||||
|
if (capacity > SIZE_MAX / 2) {
|
||||||
|
free(value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t next_capacity = capacity * 2;
|
||||||
|
char *next = realloc(value, next_capacity);
|
||||||
|
if (next == NULL) {
|
||||||
|
free(value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = next;
|
||||||
|
capacity = next_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t available = capacity - length;
|
||||||
|
if (available > (size_t)SSIZE_MAX) {
|
||||||
|
available = (size_t)SSIZE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t read_count = recv(fd, value + length, available, 0);
|
||||||
|
if (read_count < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
length += (size_t)read_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length == capacity) {
|
||||||
|
if (capacity == SIZE_MAX) {
|
||||||
|
free(value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *next = realloc(value, capacity + 1);
|
||||||
|
if (next == NULL) {
|
||||||
|
free(value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
value = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
value[length] = '\0';
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t __glagol_net_tcp_write_text_result(int32_t handle, const char *text) {
|
||||||
|
int fd = __glagol_net_handle_get(handle);
|
||||||
|
if (fd < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = strlen(text);
|
||||||
|
size_t written = 0;
|
||||||
|
while (written < length) {
|
||||||
|
size_t remaining = length - written;
|
||||||
|
if (remaining > (size_t)SSIZE_MAX) {
|
||||||
|
remaining = (size_t)SSIZE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
ssize_t sent = send(fd, text + written, remaining, MSG_NOSIGNAL);
|
||||||
|
#else
|
||||||
|
ssize_t sent = send(fd, text + written, remaining, 0);
|
||||||
|
#endif
|
||||||
|
if (sent < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sent == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
written += (size_t)sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t __glagol_net_tcp_close_result(int32_t handle) {
|
||||||
|
int fd = __glagol_net_handle_take(handle);
|
||||||
|
if (fd < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return close(fd) == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void __glagol_allocation_trap(void) {
|
static void __glagol_allocation_trap(void) {
|
||||||
fputs("slovo runtime error: string allocation failed\n", stderr);
|
fputs("slovo runtime error: string allocation failed\n", stderr);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user