feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

+15
View File
@@ -0,0 +1,15 @@
public round(value: Decimal, places: Int) (result: Decimal) {
result = dever.system.decimal_round(value, places)
}
public parse(value: Text) (result: Decimal?) {
result = dever.system.decimal_parse(value)
}
public to_text(value: Decimal) (result: Text) {
result = dever.system.decimal_to_text(value)
}
public from_int(value: Int) (result: Decimal) {
result = dever.system.decimal_from_int(value)
}
+84
View File
@@ -0,0 +1,84 @@
public serve() () {
dever.system.api_serve()
}
# Upload is a compiler-owned affine POST input. upload_filename, upload_content_type
# and upload_size borrow its metadata; close_upload consumes its temporary file.
public close_upload(upload: Upload) () {
dever.system.upload_close(upload)
}
public type Error {
error Invalid
error Unauthorized
error Forbidden
error NotFound
error Conflict
error TooManyRequests
}
public type SameSite {
Strict
Lax
None
}
public type CookieOptions {
path: Text
domain: Text?
same_site: SameSite
secure: Bool
http_only: Bool
max_age: Int?
}
public secure_cookie_options() (options: CookieOptions) {
options = CookieOptions {
path = "/"
domain = null
same_site = SameSite.Lax
secure = true
http_only = true
max_age = null
}
}
public request_id() (id: Text) {
id = dever.system.api_request_id()
}
public method() (value: Text) {
value = dever.system.api_method()
}
public path() (value: Text) {
value = dever.system.api_path()
}
public client_address() (value: Text?) {
value = dever.system.api_client_address()
}
public header(name: Text) (value: Text?) {
value = dever.system.api_header(name)
}
public cookie(name: Text) (value: Text?) {
value = dever.system.api_cookie(name)
}
public secret_cookie(name: Text) (value: Secret?) {
value = dever.system.api_secret_cookie(name)
}
public set_header(name: Text, value: Text) () {
dever.system.api_response_header(name, value)
}
public set_cookie(name: Text, value: Text, options: CookieOptions) () {
dever.system.api_response_cookie(name, value, options)
}
public set_secret_cookie(name: Text, value: Secret, options: CookieOptions) () {
dever.system.api_response_secret_cookie(name, value, options)
}
+68
View File
@@ -0,0 +1,68 @@
public type Claims {
subject: Text
session: Text
tenant: Text?
site: Text
}
public type Permission {
key: Text
component: Text
domain: Text
site: Text
action: Text
method: Text
}
public issue(subject: Text, session: Text, tenant: Text?) (token: Secret) {
token = dever.system.auth_issue(subject, session, tenant)
}
public issue_cookie(subject: Text, session: Text, tenant: Text?) () {
dever.system.auth_issue_cookie(subject, session, tenant)
}
public clear_cookie() () {
dever.system.auth_clear_cookie()
}
public id() (value: Text) {
value = dever.system.auth_id()
}
public session() (value: Text) {
value = dever.system.auth_session()
}
public user_id() (value: Int?) {
value = dever.system.auth_user_id()
}
public tenant_id() (value: Int?) {
value = dever.system.auth_tenant_id()
}
public permissions() (values: List<Permission>) {
values = dever.system.auth_permissions()
}
public save_role(
id: Text,
name: Text,
all_permissions: Bool,
permission_keys: List<Text>
) () {
dever.system.auth_save_role(id, name, all_permissions, permission_keys)
}
public grant_role(user_id: Int, role_id: Text) () {
dever.system.auth_grant_role(user_id, role_id)
}
public revoke_role(user_id: Int, role_id: Text) () {
dever.system.auth_revoke_role(user_id, role_id)
}
public disable_role(role_id: Text) () {
dever.system.auth_disable_role(role_id)
}
+53
View File
@@ -0,0 +1,53 @@
public type DecodeResult {
Decoded(text: Text)
error Failed(message: Text)
}
public type BufferResult {
Ready(bytes: Bytes)
error Failed(message: Text)
}
public from_text(text: Text) (bytes: Bytes) {
bytes = dever.system.bytes_from_text(text)
}
public to_text(bytes: Bytes) (text: Text) {
text = decoded(dever.system.bytes_to_text(bytes))
}
decoded(result: DecodeResult.Decoded(value)) (text: Text) {
text = value
}
decoded(result: DecodeResult.Failed(message)) (text: Text) {
fail(DecodeResult.Failed(message))
}
public from_ints(values: List<Int>) (bytes: Bytes) {
bytes = ready(dever.system.bytes_from_ints(values))
}
public length(bytes: Bytes) (length: Int) {
length = dever.system.bytes_length(bytes)
}
public at(bytes: Bytes, index: Int) (value: Int?) {
value = dever.system.bytes_at(bytes, index)
}
public slice(bytes: Bytes, start: Int, end: Int) (result: Bytes) {
result = ready(dever.system.bytes_slice(bytes, start, end))
}
ready(result: BufferResult.Ready(bytes)) (value: Bytes) {
value = bytes
}
ready(result: BufferResult.Failed(message)) (value: Bytes) {
fail(BufferResult.Failed(message))
}
public concat(left: Bytes, right: Bytes) (bytes: Bytes) {
bytes = dever.system.bytes_concat(left, right)
}
+62
View File
@@ -0,0 +1,62 @@
public type TokenResult {
Ready(value: Secret)
error Failed(message: Text)
}
public type HashResult {
Ready(value: Text)
error Failed(message: Text)
}
public type VerifyResult {
Ready(value: Bool)
error Failed(message: Text)
}
public token(bytes: Int) (value: Secret) {
value = token_value(dever.system.crypto_token(bytes))
}
token_value(result: TokenResult.Ready(value)) (secret: Secret) {
secret = value
}
token_value(result: TokenResult.Failed(message)) (secret: Secret) {
fail(TokenResult.Failed(message))
}
public password_hash(password: Secret) (value: Text) {
value = hash_value(dever.system.crypto_password_hash(password))
}
hash_value(result: HashResult.Ready(value)) (hash: Text) {
hash = value
}
hash_value(result: HashResult.Failed(message)) (hash: Text) {
fail(HashResult.Failed(message))
}
public password_verify(password: Secret, hash: Text) (value: Bool) {
value = verify_value(dever.system.crypto_password_verify(password, hash))
}
verify_value(result: VerifyResult.Ready(value)) (valid: Bool) {
valid = value
}
verify_value(result: VerifyResult.Failed(message)) (valid: Bool) {
fail(VerifyResult.Failed(message))
}
public sha256(bytes: Bytes) (value: Bytes) pure {
value = dever.system.crypto_sha256(bytes)
}
public hmac_sha256(key: Secret, bytes: Bytes) (value: Bytes) pure {
value = dever.system.crypto_hmac_sha256(key, bytes)
}
public constant_time_eq(left: Bytes, right: Bytes) (equal: Bool) pure {
equal = dever.system.crypto_constant_time_eq(left, right)
}
+13
View File
@@ -0,0 +1,13 @@
# Database failures retain their category across services and transactions.
public type Error {
error Pool(message: Text)
error PoolExhausted(message: Text)
error Connection(message: Text)
error Timeout(message: Text)
error Cancelled(message: Text)
error Database(message: Text)
error Constraint(message: Text)
error NotFound(message: Text)
error InvalidData(message: Text)
error Migration(message: Text)
}
+262
View File
@@ -0,0 +1,262 @@
public type PoolLimits {
idle_ms: Int
chunk_bytes: Int
read_ms: Int
}
public type StreamRequest {
method: Text
target: Text
headers: List<Header>
body: AsyncStream<dever.io.ReadEvent>
}
public type StreamResponse {
status: Int
headers: List<Header>
body: AsyncStream<dever.io.ReadEvent>
}
public type ClientResult {
Ready(client: dever.system.HttpClient)
error Failed(message: Text)
}
public type StreamResponseResult {
Read(response: StreamResponse)
error Failed(message: Text)
}
public default_pool_limits() (result: PoolLimits) {
result = PoolLimits {
idle_ms = 10000
chunk_bytes = 65536
read_ms = 60000
}
}
public client(
origin: Text,
tls: dever.system.ClientTls,
limits: Limits,
pool: PoolLimits
) (client: dever.system.HttpClient) {
client = ready_client(dever.system.http_client(origin, tls, limits, pool))
}
ready_client(result: ClientResult.Ready(client)) (value: dever.system.HttpClient) {
value = client
}
ready_client(result: ClientResult.Failed(message)) (value: dever.system.HttpClient) {
fail(ClientResult.Failed(message))
}
public request(client: dever.system.HttpClient, request: Request) (
response: Response
) {
response = read_response(dever.system.http_request(client, request))
}
public open(client: dever.system.HttpClient, request: Request) (
response: StreamResponse
) {
response = read_stream_response(dever.system.http_open(client, request))
}
public open_stream(client: dever.system.HttpClient, request: StreamRequest) (
response: StreamResponse
) {
response = read_stream_response(dever.system.http_open_stream(client, request))
}
read_stream_response(result: StreamResponseResult.Read(response)) (
value: StreamResponse
) {
value = response
}
read_stream_response(result: StreamResponseResult.Failed(message)) (
value: StreamResponse
) {
fail(StreamResponseResult.Failed(message))
}
public close_client(client: dever.system.HttpClient) () {
closed(dever.system.http_close_client(client))
}
public serve_tls(
route: handler(request: Request) (response: Response),
listener: dever.system.Listener,
limits: Limits,
tls: dever.system.ServerTls
) () {
dever.system.http_serve_tls(route, listener, limits, tls)
}
public serve_live_tls(
route: handler(request: Request, reply: dever.system.HttpReply) (),
listener: dever.system.Listener,
limits: Limits,
live: LiveLimits,
tls: dever.system.ServerTls
) () {
dever.system.http_serve_live_tls(route, listener, limits, live, tls)
}
public type Header {
name: Text
value: Bytes
}
public type Request {
method: Text
target: Text
headers: List<Header>
body: Bytes
}
public type Response {
status: Int
headers: List<Header>
body: Bytes
}
public type Limits {
header_bytes: Int
body_bytes: Int
timeout_ms: Int
connections: Int
http2: Http2Limits?
}
# streams 为每连接并发流数;窗口限制协议层未消费的接收正文。
public type Http2Limits {
streams: Int
stream_window_bytes: Int
connection_window_bytes: Int
}
public default_http2_limits() (result: Http2Limits) {
result = Http2Limits {
streams = 16
stream_window_bytes = 65535
connection_window_bytes = 262144
}
}
public type LiveLimits {
chunk_bytes: Int
idle_ms: Int
heartbeat_ms: Int
}
public default_live_limits() (result: LiveLimits) {
result = LiveLimits {
chunk_bytes = 65536
idle_ms = 60000
heartbeat_ms = 15000
}
}
public type ResponseResult {
Read(response: Response)
error Failed(message: Text)
}
public default_limits() (result: Limits) {
result = Limits {
header_bytes = 8192
body_bytes = 1048576
timeout_ms = 5000
connections = 32
http2 = null
}
}
public header(name: Text, value: Text) (result: Header) {
result = Header {
name = text.lower(name)
value = dever.bytes.from_text(value)
}
}
# 返回第一个匹配项的原始值;重复头保留在 headers 列表中。
public header_value(headers: List<Header>, name: Text) (value: Bytes?) {
value = found_header(find(named_header, headers, text.lower(name)))
}
named_header(header: Header, name: Text) (matches: Bool) {
matches = text.lower(header.name) == name
}
found_header(header: null) (value: Bytes?) {
value = null
}
found_header(header: Header) (value: Bytes?) {
value = header.value
}
# serve 是长驻任务,调用者用 run/stop 管理生命周期;故障沿任务作用域传播。
public serve(
route: handler(request: Request) (response: Response),
listener: dever.system.Listener,
limits: Limits
) () {
dever.system.http_serve(route, listener, limits)
}
# 单次请求,无连接池或重试;address 为数字 IP,Host 由请求头指定。
public send(address: Text, port: Int, request: Request, limits: Limits) (
response: Response
) {
response = read_response(dever.system.http_send(address, port, request, limits))
}
read_response(result: ResponseResult.Read(response)) (value: Response) {
value = response
}
read_response(result: ResponseResult.Failed(message)) (value: Response) {
fail(ResponseResult.Failed(message))
}
# handler 可发送完整正文、逐块写入、SSE,或升级 WebSocket;返回即结束会话。
public serve_live(
route: handler(request: Request, reply: dever.system.HttpReply) (),
listener: dever.system.Listener,
limits: Limits,
live: LiveLimits
) () {
dever.system.http_serve_live(route, listener, limits, live)
}
public respond(reply: dever.system.HttpReply, response: Response) () {
wrote(dever.system.http_respond(reply, response))
}
public start(reply: dever.system.HttpReply, status: Int, headers: List<Header>) () {
wrote(dever.system.http_start(reply, status, headers))
}
public write(reply: dever.system.HttpReply, bytes: Bytes) () {
wrote(dever.system.http_write(reply, bytes))
}
public finish(reply: dever.system.HttpReply) () {
closed(dever.system.http_finish(reply))
}
wrote(result: dever.io.WriteResult.Done) () {}
wrote(result: dever.io.WriteResult.Failed(message)) () {
fail(dever.io.WriteResult.Failed(message))
}
closed(result: dever.io.CloseResult.Closed) () {}
closed(result: dever.io.CloseResult.Failed(message)) () {
fail(dever.io.CloseResult.Failed(message))
}
+7
View File
@@ -0,0 +1,7 @@
public from_text(text: Text) (id: Id) {
id = dever.system.id_from_text(text)
}
public to_text(id: Id) (text: Text) {
text = dever.system.id_to_text(id)
}
+108
View File
@@ -0,0 +1,108 @@
public type OpenResult {
Opened(file: dever.system.File)
error Failed(message: Text)
}
public type ReadState {
Read(bytes: Bytes)
End
}
public type ReadResult {
Done(state: ReadState)
error Failed(message: Text)
}
type SystemReadResult {
Read(bytes: Bytes)
End
error Failed(message: Text)
}
public type WriteResult {
Done
error Failed(message: Text)
}
public type CloseResult {
Closed
error Failed(message: Text)
}
public type ReadEvent {
Chunk(bytes: Bytes)
error Failed(message: Text)
}
public type ReadStreamResult {
Streaming(stream: Stream<ReadEvent>)
error Failed(message: Text)
}
public println(text: Text) () {
dever.system.stdout_write(text + "\n")
}
public open(path: Text) (file: dever.system.File) {
file = opened(dever.system.file_open(path))
}
public create(path: Text) (file: dever.system.File) {
file = opened(dever.system.file_create(path))
}
opened(result: OpenResult.Opened(file)) (value: dever.system.File) {
value = file
}
opened(result: OpenResult.Failed(message)) (value: dever.system.File) {
fail(OpenResult.Failed(message))
}
public read(file: dever.system.File, limit: Int) (state: ReadState) {
state = read_state(dever.system.file_read(file, limit))
}
read_state(result: SystemReadResult.Read(bytes)) (state: ReadState) {
state = ReadState.Read(bytes)
}
read_state(result: SystemReadResult.End) (state: ReadState) {
state = ReadState.End
}
read_state(result: SystemReadResult.Failed(message)) (state: ReadState) {
fail(ReadResult.Failed(message))
}
public write(file: dever.system.File, bytes: Bytes) () {
wrote(dever.system.file_write(file, bytes))
}
wrote(result: WriteResult.Done) () {}
wrote(result: WriteResult.Failed(message)) () {
fail(WriteResult.Failed(message))
}
public close(file: dever.system.File) () {
closed(dever.system.file_close(file))
}
closed(result: CloseResult.Closed) () {}
closed(result: CloseResult.Failed(message)) () {
fail(CloseResult.Failed(message))
}
public chunks(file: dever.system.File, limit: Int) (stream: Stream<ReadEvent>) {
stream = read_stream(dever.system.file_chunks(file, limit))
}
read_stream(result: ReadStreamResult.Streaming(stream)) (value: Stream<ReadEvent>) {
value = stream
}
read_stream(result: ReadStreamResult.Failed(message)) (value: Stream<ReadEvent>) {
fail(ReadStreamResult.Failed(message))
}
+3
View File
@@ -0,0 +1,3 @@
public serve() () {
dever.system.job_serve()
}
+76
View File
@@ -0,0 +1,76 @@
# JSON values and capture result choices live in dever.json.value.
public parse(source: Text) (document: dever.json.value.Document) {
document = dever.json.parse.parse(source)
}
public stringify(document: dever.json.value.Document) (text: Text) {
text = dever.json.write.stringify(document)
}
public node(document: dever.json.value.Document, id: Int) (result: dever.json.value.Value?) {
result = get(document.nodes, id)
}
public property(document: dever.json.value.Document, id: Int, name: Text) (result: Int?) {
result = object_property(node(document, id), name)
}
object_property(value: dever.json.value.Value.Object(members), name: Text) (
result: Int?
) {
result = get(members, name)
}
object_property(value: null, name: Text) (result: Int?) {
result = null
}
object_property(value: other, name: Text) (result: Int?) {
result = null
}
type ElementState {
target: Int
index: Int
found: Int?
}
public element(document: dever.json.value.Document, id: Int, index: Int) (result: Int?) {
result = array_element(node(document, id), index)
}
array_element(value: dever.json.value.Value.Array(children), index: Int) (result: Int?) {
state = reduce_until(
element_at,
children,
ElementState {
target = index
index = 0
found = null
}
)
result = state.found
}
array_element(value: null, index: Int) (result: Int?) {
result = null
}
array_element(value: other, index: Int) (result: Int?) {
result = null
}
element_at(id: Int, state: ElementState) (next: ElementState, stop: Bool) {
next = selected(state.index == state.target, id, state)
next.index = state.index + 1
stop = state.index >= state.target
}
selected(matches: true, id: Int, state: ElementState) (next: ElementState) {
next = state
next.found = id
}
selected(matches: false, id: Int, state: ElementState) (next: ElementState) {
next = state
}
+149
View File
@@ -0,0 +1,149 @@
type Phase {
Start
Sign
Zero
Integer
Point
Fraction
Exponent
ExponentSign
ExponentDigits
Invalid
}
public valid(raw: Text) (result: Bool) {
phase = reduce(advance, text.split(raw, ""), Phase.Start)
result = complete(phase)
}
advance(character: Text, phase: Phase.Start) (result: Phase) {
result = start(character)
}
advance(character: Text, phase: Phase.Sign) (result: Phase) {
result = integer_start(character)
}
advance(character: Text, phase: Phase.Zero) (result: Phase) {
result = after_integer(character)
}
advance(character: Text, phase: Phase.Integer) (result: Phase) {
result = integer_digit(text.contains("0123456789", character), character)
}
advance(character: Text, phase: Phase.Point) (result: Phase) {
result = digit(text.contains("0123456789", character), Phase.Fraction)
}
advance(character: Text, phase: Phase.Fraction) (result: Phase) {
result = fraction_digit(text.contains("0123456789", character), character)
}
advance(character: Text, phase: Phase.Exponent) (result: Phase) {
result = exponent_start(character)
}
advance(character: Text, phase: Phase.ExponentSign) (result: Phase) {
result = digit(text.contains("0123456789", character), Phase.ExponentDigits)
}
advance(character: Text, phase: Phase.ExponentDigits) (result: Phase) {
result = digit(text.contains("0123456789", character), Phase.ExponentDigits)
}
advance(character: Text, phase: Phase.Invalid) (result: Phase) {
result = Phase.Invalid
}
start(character: "-") (result: Phase) {
result = Phase.Sign
}
start(character: other) (result: Phase) {
result = integer_start(character)
}
integer_start(character: "0") (result: Phase) {
result = Phase.Zero
}
integer_start(character: other) (result: Phase) {
result = digit(text.contains("123456789", character), Phase.Integer)
}
digit(valid: true, phase: Phase) (result: Phase) {
result = phase
}
digit(valid: false, phase: Phase) (result: Phase) {
result = Phase.Invalid
}
integer_digit(valid: true, character: Text) (result: Phase) {
result = Phase.Integer
}
integer_digit(valid: false, character: Text) (result: Phase) {
result = after_integer(character)
}
after_integer(character: ".") (result: Phase) {
result = Phase.Point
}
after_integer(character: other) (result: Phase) {
result = exponent(character)
}
fraction_digit(valid: true, character: Text) (result: Phase) {
result = Phase.Fraction
}
fraction_digit(valid: false, character: Text) (result: Phase) {
result = exponent(character)
}
exponent(character: "e") (result: Phase) {
result = Phase.Exponent
}
exponent(character: "E") (result: Phase) {
result = Phase.Exponent
}
exponent(character: other) (result: Phase) {
result = Phase.Invalid
}
exponent_start(character: "+") (result: Phase) {
result = Phase.ExponentSign
}
exponent_start(character: "-") (result: Phase) {
result = Phase.ExponentSign
}
exponent_start(character: other) (result: Phase) {
result = digit(text.contains("0123456789", character), Phase.ExponentDigits)
}
complete(phase: Phase.Zero) (result: Bool) {
result = true
}
complete(phase: Phase.Integer) (result: Bool) {
result = true
}
complete(phase: Phase.Fraction) (result: Bool) {
result = true
}
complete(phase: Phase.ExponentDigits) (result: Bool) {
result = true
}
complete(phase: other) (result: Bool) {
result = false
}
+388
View File
@@ -0,0 +1,388 @@
type Expect {
RootValue
RootDone
ArrayFirst
ArrayValue
ArrayNext
ObjectFirst
ObjectKey
ObjectColon
ObjectValue
ObjectNext
}
type Frame {
expect: Expect
children: List<Int>
members: Map<Text, Int>
key: Text
}
type State {
stack: Map<Int, Frame>
depth: Int
nodes: Map<Int, dever.json.value.Value>
next_id: Int
root: Int?
failure: Text
position: Int
}
public parse(source: Text) (document: dever.json.value.Document) {
document = scanned(result(dever.json.scan.scan(source)), length(source))
}
scanned(result: dever.json.scan.Result.Scanned(tokens), end: Int) (
document: dever.json.value.Document
) recover("scanner failures become public JSON parse failures") {
state = reduce_until(
token,
tokens,
State {
stack = {
0 = frame(Expect.RootValue)
}
depth = 0
nodes = {}
next_id = 0
root = null
failure = ""
position = 0
}
)
document = finish(state.failure == "", state, end)
}
scanned(result: dever.json.scan.Result.Failed(position, message), end: Int) (
document: dever.json.value.Document
) recover("scanner failures become public JSON parse failures") {
fail(dever.json.value.ParseResult.Failed(position, message))
}
frame(expect: Expect) (result: Frame) {
result = Frame {
expect = expect
children = []
members = {}
key = ""
}
}
finish(valid: false, state: State, end: Int) (document: dever.json.value.Document) {
fail(dever.json.value.ParseResult.Failed(state.position, state.failure))
}
finish(valid: true, state: State, end: Int) (document: dever.json.value.Document) {
document = balanced(state.depth == 0, state, end)
}
balanced(complete: false, state: State, end: Int) (document: dever.json.value.Document) {
fail(dever.json.value.ParseResult.Failed(end, "unterminated JSON container"))
}
balanced(complete: true, state: State, end: Int) (document: dever.json.value.Document) {
document = root(state.root, state.nodes, end)
}
root(id: null, nodes: Map<Int, dever.json.value.Value>, end: Int) (
document: dever.json.value.Document
) {
fail(dever.json.value.ParseResult.Failed(end, "expected a JSON value"))
}
root(id: Int, nodes: Map<Int, dever.json.value.Value>, end: Int) (
document: dever.json.value.Document
) {
document = dever.json.value.Document {
root = id
nodes = nodes
}
}
token(token: dever.json.scan.Token, state: State) (next: State, stop: Bool) {
positioned = state
positioned.position = token.position
next = current(get(state.stack, state.depth), token.kind, positioned)
stop = next.failure != ""
}
current(frame: null, kind: dever.json.scan.Kind, state: State) (next: State) {
next = invalid_state("invalid JSON parser stack", state)
}
current(frame: Frame, kind: dever.json.scan.Kind, state: State) (next: State) {
next = expected(frame.expect, kind, frame, state)
}
expected(
expect: Expect.RootValue,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = value(kind, state)
}
expected(
expect: Expect.RootDone,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = invalid_state("unexpected content after the JSON value", state)
}
expected(
expect: Expect.ArrayFirst,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = array_first(kind, frame, state)
}
expected(
expect: Expect.ArrayValue,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = value(kind, state)
}
expected(
expect: Expect.ArrayNext,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = array_next(kind, frame, state)
}
expected(
expect: Expect.ObjectFirst,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = object_first(kind, frame, state)
}
expected(
expect: Expect.ObjectKey,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = object_key(kind, frame, state)
}
expected(
expect: Expect.ObjectColon,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = object_colon(kind, frame, state)
}
expected(
expect: Expect.ObjectValue,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = value(kind, state)
}
expected(
expect: Expect.ObjectNext,
kind: dever.json.scan.Kind,
frame: Frame,
state: State
) (next: State) {
next = object_next(kind, frame, state)
}
value(kind: dever.json.scan.Kind.Scalar(value), state: State) (next: State) {
next = commit(value, state)
}
value(kind: dever.json.scan.Kind.ArrayOpen, state: State) (next: State) {
next = open(state.depth < dever.json.value.maximum_depth(), Expect.ArrayFirst, state)
}
value(kind: dever.json.scan.Kind.ObjectOpen, state: State) (next: State) {
next = open(state.depth < dever.json.value.maximum_depth(), Expect.ObjectFirst, state)
}
value(kind: other, state: State) (next: State) {
next = invalid_state("expected a JSON value", state)
}
open(allowed: false, expect: Expect, state: State) (next: State) {
next = invalid_state("JSON nesting exceeds 256 containers", state)
}
open(allowed: true, expect: Expect, state: State) (next: State) {
next = state
next.depth = state.depth + 1
next.stack = put(state.stack, next.depth, frame(expect))
}
array_first(kind: dever.json.scan.Kind.ArrayClose, frame: Frame, state: State) (
next: State
) {
next = close(dever.json.value.Value.Array(frame.children), state)
}
array_first(kind: other, frame: Frame, state: State) (next: State) {
next = value(kind, state)
}
array_next(kind: dever.json.scan.Kind.ArrayClose, frame: Frame, state: State) (
next: State
) {
next = close(dever.json.value.Value.Array(frame.children), state)
}
array_next(kind: dever.json.scan.Kind.Comma, frame: Frame, state: State) (next: State) {
next = expecting(Expect.ArrayValue, frame, state)
}
array_next(kind: other, frame: Frame, state: State) (next: State) {
next = invalid_state("expected ',' or ']' after an array element", state)
}
object_first(kind: dever.json.scan.Kind.ObjectClose, frame: Frame, state: State) (
next: State
) {
next = close(dever.json.value.Value.Object(frame.members), state)
}
object_first(kind: other, frame: Frame, state: State) (next: State) {
next = object_key(kind, frame, state)
}
object_key(kind: dever.json.scan.Kind.Scalar(value), frame: Frame, state: State) (
next: State
) {
next = key_value(value, frame, state)
}
object_key(kind: other, frame: Frame, state: State) (next: State) {
next = invalid_state("expected a quoted JSON object name", state)
}
key_value(value: dever.json.value.Value.String(key), frame: Frame, state: State) (
next: State
) {
next = unique_key(get(frame.members, key) == null, key, frame, state)
}
key_value(value: other, frame: Frame, state: State) (next: State) {
next = invalid_state("expected a quoted JSON object name", state)
}
unique_key(unique: false, key: Text, frame: Frame, state: State) (next: State) {
next = invalid_state("duplicate JSON object name: " + key, state)
}
unique_key(unique: true, key: Text, frame: Frame, state: State) (next: State) {
keyed = frame
keyed.key = key
next = expecting(Expect.ObjectColon, keyed, state)
}
object_colon(kind: dever.json.scan.Kind.Colon, frame: Frame, state: State) (next: State) {
next = expecting(Expect.ObjectValue, frame, state)
}
object_colon(kind: other, frame: Frame, state: State) (next: State) {
next = invalid_state("expected ':' after a JSON object name", state)
}
object_next(kind: dever.json.scan.Kind.ObjectClose, frame: Frame, state: State) (
next: State
) {
next = close(dever.json.value.Value.Object(frame.members), state)
}
object_next(kind: dever.json.scan.Kind.Comma, frame: Frame, state: State) (next: State) {
next = expecting(Expect.ObjectKey, frame, state)
}
object_next(kind: other, frame: Frame, state: State) (next: State) {
next = invalid_state("expected ',' or '}' after an object member", state)
}
expecting(expect: Expect, frame: Frame, state: State) (next: State) {
updated = frame
updated.expect = expect
next = state
next.stack = put(state.stack, state.depth, updated)
}
close(value: dever.json.value.Value, state: State) (next: State) {
parent = state
parent.stack = remove(state.stack, state.depth)
parent.depth = state.depth - 1
next = commit(value, parent)
}
commit(value: dever.json.value.Value, state: State) (next: State) {
inserted = state
inserted.nodes = put(state.nodes, state.next_id, value)
inserted.next_id = state.next_id + 1
next = attach(get(state.stack, state.depth), state.next_id, inserted)
}
attach(frame: null, id: Int, state: State) (next: State) {
next = invalid_state("invalid JSON parser parent", state)
}
attach(frame: Frame, id: Int, state: State) (next: State) {
next = attach_expected(frame.expect, frame, id, state)
}
attach_expected(expect: Expect.RootValue, frame: Frame, id: Int, state: State) (
next: State
) {
next = expecting(Expect.RootDone, frame, state)
next.root = id
}
attach_expected(expect: Expect.ArrayFirst, frame: Frame, id: Int, state: State) (
next: State
) {
next = append_child(frame, id, state)
}
attach_expected(expect: Expect.ArrayValue, frame: Frame, id: Int, state: State) (
next: State
) {
next = append_child(frame, id, state)
}
attach_expected(expect: Expect.ObjectValue, frame: Frame, id: Int, state: State) (
next: State
) {
updated = frame
updated.members = put(frame.members, frame.key, id)
next = expecting(Expect.ObjectNext, updated, state)
}
attach_expected(expect: other, frame: Frame, id: Int, state: State) (next: State) {
next = invalid_state("unexpected JSON value", state)
}
append_child(frame: Frame, id: Int, state: State) (next: State) {
updated = frame
updated.children = append(frame.children, id)
next = expecting(Expect.ArrayNext, updated, state)
}
invalid_state(message: Text, state: State) (next: State) {
next = state
next.failure = message
}
+442
View File
@@ -0,0 +1,442 @@
public type Kind {
Scalar(value: dever.json.value.Value)
ObjectOpen
ObjectClose
ArrayOpen
ArrayClose
Colon
Comma
}
public type Token {
kind: Kind
position: Int
}
public type Result {
Scanned(tokens: List<Token>)
error Failed(position: Int, message: Text)
}
type Mode {
Normal
Word
String
Escape
Unicode
LowSlash
LowU
}
type State {
tokens: List<Token>
mode: Mode
buffer: Text
position: Int
start: Int
unicode: Int
digits: Int
high: Int
failure: Text
error_position: Int
}
public scan(source: Text) (tokens: List<Token>) {
state = reduce_until(
character,
text.split(source + " ", ""),
State {
tokens = []
mode = Mode.Normal
buffer = ""
position = 0
start = 0
unicode = 0
digits = 0
high = 0
failure = ""
error_position = 0
}
)
tokens = finish(state.failure == "", state, length(source))
}
finish(valid: false, state: State, end: Int) (tokens: List<Token>) {
fail(Result.Failed(state.error_position, state.failure))
}
finish(valid: true, state: State, end: Int) (tokens: List<Token>) {
tokens = finish_mode(state.mode, state.tokens, end)
}
finish_mode(mode: Mode.Normal, tokens: List<Token>, end: Int) (result: List<Token>) {
result = tokens
}
finish_mode(mode: other, tokens: List<Token>, end: Int) (result: List<Token>) {
fail(Result.Failed(end, "unterminated JSON string or escape"))
}
character(value: Text, state: State) (next: State, stop: Bool) {
next = consume(state.mode, value, state)
next.position = state.position + 1
stop = next.failure != ""
}
consume(mode: Mode.Normal, value: Text, state: State) (next: State) {
next = normal(value, state)
}
consume(mode: Mode.Word, value: Text, state: State) (next: State) {
next = word(text.contains(" \t\r\n{}[]:,\"", value), value, state)
}
consume(mode: Mode.String, value: Text, state: State) (next: State) {
next = string(value, state)
}
consume(mode: Mode.Escape, value: Text, state: State) (next: State) {
next = escape(value, state)
}
consume(mode: Mode.Unicode, value: Text, state: State) (next: State) {
next = unicode_digit(text.index_of("0123456789abcdef", text.lower(value)), state)
}
consume(mode: Mode.LowSlash, value: Text, state: State) (next: State) {
next = low_slash(value == "\\", state)
}
consume(mode: Mode.LowU, value: Text, state: State) (next: State) {
next = low_u(value == "u", state)
}
normal(value: "{", state: State) (next: State) {
next = emit(Kind.ObjectOpen, state.position, state)
}
normal(value: "}", state: State) (next: State) {
next = emit(Kind.ObjectClose, state.position, state)
}
normal(value: "[", state: State) (next: State) {
next = emit(Kind.ArrayOpen, state.position, state)
}
normal(value: "]", state: State) (next: State) {
next = emit(Kind.ArrayClose, state.position, state)
}
normal(value: ":", state: State) (next: State) {
next = emit(Kind.Colon, state.position, state)
}
normal(value: ",", state: State) (next: State) {
next = emit(Kind.Comma, state.position, state)
}
normal(value: "\"", state: State) (next: State) {
next = state
next.mode = Mode.String
next.start = state.position
next.buffer = ""
}
normal(value: other, state: State) (next: State) {
next = whitespace(text.contains(" \t\r\n", value), value, state)
}
whitespace(space: true, value: Text, state: State) (next: State) {
next = state
}
whitespace(space: false, value: Text, state: State) (next: State) {
next = state
next.mode = Mode.Word
next.start = state.position
next.buffer = value
}
word(ended: false, value: Text, state: State) (next: State) {
next = state
next.buffer = state.buffer + value
}
word(ended: true, value: Text, state: State) (next: State) {
finished = atom(state.buffer, state)
next = after_word(finished.failure == "", value, finished)
}
after_word(valid: true, value: Text, state: State) (next: State) {
next = normal(value, state)
}
after_word(valid: false, value: Text, state: State) (next: State) {
next = state
}
atom(raw: "true", state: State) (next: State) {
next = scalar(dever.json.value.Value.Boolean(true), state)
}
atom(raw: "false", state: State) (next: State) {
next = scalar(dever.json.value.Value.Boolean(false), state)
}
atom(raw: "null", state: State) (next: State) {
next = scalar(dever.json.value.Value.Null, state)
}
atom(raw: other, state: State) (next: State) {
next = number(dever.json.number.valid(raw), raw, state)
}
number(valid: true, raw: Text, state: State) (next: State) {
next = scalar(dever.json.value.Value.Number(raw), state)
}
number(valid: false, raw: Text, state: State) (next: State) {
next = invalid_state(state.start, "invalid JSON literal or number", state)
}
scalar(value: dever.json.value.Value, state: State) (next: State) {
next = emit(Kind.Scalar(value), state.start, state)
next.mode = Mode.Normal
}
emit(kind: Kind, position: Int, state: State) (next: State) {
next = state
next.tokens = append(
state.tokens,
Token {
kind = kind
position = position
}
)
}
invalid_state(position: Int, message: Text, state: State) (next: State) {
next = state
next.failure = message
next.error_position = position
}
string(value: "\"", state: State) (next: State) {
next = scalar(dever.json.value.Value.String(state.buffer), state)
}
string(value: "\\", state: State) (next: State) {
next = state
next.mode = Mode.Escape
}
string(value: other, state: State) (next: State) {
next = string_character(text.codepoint(value), value, state)
}
string_character(code: Int, value: Text, state: State) (next: State) {
next = string_control(code < 32, value, state)
}
string_character(code: null, value: Text, state: State) (next: State) {
next = invalid_state(state.position, "invalid Unicode character", state)
}
string_control(control: true, value: Text, state: State) (next: State) {
next = invalid_state(state.position, "unescaped control character in JSON string", state)
}
string_control(control: false, value: Text, state: State) (next: State) {
next = decoded(value, state)
}
decoded(value: Text, state: State) (next: State) {
next = state
next.buffer = state.buffer + value
next.mode = Mode.String
}
escape(value: "\"", state: State) (next: State) {
next = decoded("\"", state)
}
escape(value: "\\", state: State) (next: State) {
next = decoded("\\", state)
}
escape(value: "/", state: State) (next: State) {
next = decoded("/", state)
}
escape(value: "b", state: State) (next: State) {
next = decoded("\u{8}", state)
}
escape(value: "f", state: State) (next: State) {
next = decoded("\u{c}", state)
}
escape(value: "n", state: State) (next: State) {
next = decoded("\n", state)
}
escape(value: "r", state: State) (next: State) {
next = decoded("\r", state)
}
escape(value: "t", state: State) (next: State) {
next = decoded("\t", state)
}
escape(value: "u", state: State) (next: State) {
next = state
next.mode = Mode.Unicode
next.unicode = 0
next.digits = 0
}
escape(value: other, state: State) (next: State) {
next = invalid_state(state.position, "invalid JSON string escape", state)
}
unicode_digit(digit: null, state: State) (next: State) {
next = invalid_state(state.position, "expected four hexadecimal escape digits", state)
}
unicode_digit(digit: Int, state: State) (next: State) {
advanced = state
advanced.unicode = state.unicode * 16 + digit
advanced.digits = state.digits + 1
next = unicode_ready(advanced.digits == 4, advanced)
}
unicode_ready(ready: false, state: State) (next: State) {
next = state
}
unicode_ready(ready: true, state: State) (next: State) {
next = unicode_unit(state.high == 0, state.unicode, state)
}
unicode_unit(first: true, code: Int, state: State) (next: State) {
next = first_unit(code, state)
}
unicode_unit(first: false, code: Int, state: State) (next: State) {
next = second_unit(code >= 56320 and code <= 57343, code, state)
}
first_unit(code: Int >= 55296 and <= 56319, state: State) (next: State) {
next = state
next.high = code
next.mode = Mode.LowSlash
}
first_unit(code: Int >= 56320 and <= 57343, state: State) (next: State) {
next = invalid_state(state.position, "unpaired low Unicode surrogate", state)
}
first_unit(code: other, state: State) (next: State) {
next = scalar_character(text.from_codepoint(code), state)
}
second_unit(valid: false, code: Int, state: State) (next: State) {
next = invalid_state(state.position, "expected a low Unicode surrogate", state)
}
second_unit(valid: true, code: Int, state: State) (next: State) {
next = scalar_character(
text.from_codepoint(65536 + (state.high - 55296) * 1024 + code - 56320),
state
)
}
scalar_character(value: Text, state: State) (next: State) {
next = decoded(value, state)
next.high = 0
}
scalar_character(value: null, state: State) (next: State) {
next = invalid_state(state.position, "invalid Unicode scalar", state)
}
low_slash(valid: true, state: State) (next: State) {
next = state
next.mode = Mode.LowU
}
low_slash(valid: false, state: State) (next: State) {
next = invalid_state(state.position, "expected a low Unicode surrogate escape", state)
}
low_u(valid: true, state: State) (next: State) {
next = escape("u", state)
}
low_u(valid: false, state: State) (next: State) {
next = invalid_state(state.position, "expected a low Unicode surrogate escape", state)
}
public quote(value: Text) (result: Text) {
result = "\"" + text.join(each(quoted_character, text.split(value, "")), "") + "\""
}
quoted_character(value: "\"") (result: Text) {
result = "\\\""
}
quoted_character(value: "\\") (result: Text) {
result = "\\\\"
}
quoted_character(value: "\u{8}") (result: Text) {
result = "\\b"
}
quoted_character(value: "\u{c}") (result: Text) {
result = "\\f"
}
quoted_character(value: "\n") (result: Text) {
result = "\\n"
}
quoted_character(value: "\r") (result: Text) {
result = "\\r"
}
quoted_character(value: "\t") (result: Text) {
result = "\\t"
}
quoted_character(value: other) (result: Text) {
result = quoted_code(text.codepoint(value), value)
}
quoted_code(code: Int, value: Text) (result: Text) {
result = quote_control(code < 32, code, value)
}
quoted_code(code: null, value: Text) (result: Text) {
result = value
}
quote_control(control: false, code: Int, value: Text) (result: Text) {
result = value
}
quote_control(control: true, code: Int, value: Text) (result: Text) {
result = "\\u00" + hex_digit(code // 16) + hex_digit(code % 16)
}
hex_digit(value: Int) (result: Text) {
result = hex_character(text.at("0123456789abcdef", value))
}
hex_character(value: Text) (result: Text) {
result = value
}
hex_character(value: null) (result: Text) {
result = ""
}
+29
View File
@@ -0,0 +1,29 @@
# Nodes use consecutive postorder IDs starting at zero. Children precede their parent.
public type Value {
Null
Boolean(value: Bool)
Number(raw: Text)
String(text: Text)
Array(children: List<Int>)
Object(members: Map<Text, Int>)
}
public type Document {
root: Int
nodes: Map<Int, Value>
}
# Parse positions are zero-based Unicode scalar offsets, including the EOF position.
public type ParseResult {
Parsed(document: Document)
error Failed(position: Int, message: Text)
}
public type WriteResult {
Written(text: Text)
error Failed(node: Int, message: Text)
}
public maximum_depth() (result: Int) {
result = 256
}
+269
View File
@@ -0,0 +1,269 @@
type Encoded {
text: Text
depth: Int
failure: Text
}
type State {
document: dever.json.value.Document
encoded: Map<Int, Encoded>
index: Int
failure: Text
}
type Children {
encoded: Map<Int, Encoded>
parent: Int
pieces: List<Text>
depth: Int
size: Int
failure: Text
}
# The output budget also bounds expansion of user-constructed shared child graphs.
maximum_size() (result: Int) {
result = 16777216
}
public stringify(document: dever.json.value.Document) (text: Text) {
state = reduce_until(
node,
entries(document.nodes),
State {
document = document
encoded = {}
index = 0
failure = ""
}
)
text = finish(state.failure == "", state)
}
finish(valid: false, state: State) (text: Text) {
fail(dever.json.value.WriteResult.Failed(state.index, state.failure))
}
finish(valid: true, state: State) (text: Text) {
text = root(get(state.encoded, state.document.root), state.document.root)
}
root(value: null, id: Int) (text: Text) {
fail(
dever.json.value.WriteResult.Failed(
id,
"JSON root does not refer to a document node"
)
)
}
root(value: Encoded, id: Int) (text: Text) {
text = value.text
}
# Iteration supplies a count; lookup uses IDs, so Map insertion order is immaterial.
node(entry: MapEntry<Int, dever.json.value.Value>, state: State) (
next: State,
stop: Bool
) {
encoded = document_node(get(state.document.nodes, state.index), state)
next = store(encoded.failure == "", encoded, state)
stop = next.failure != ""
}
document_node(value: null, state: State) (result: Encoded) {
result = failed("JSON node IDs must be consecutive from zero")
}
document_node(value: dever.json.value.Value, state: State) (result: Encoded) {
encoded = encode(value, state)
result = bounded(length(encoded.text) <= maximum_size(), encoded)
}
store(valid: false, encoded: Encoded, state: State) (next: State) {
next = state
next.failure = encoded.failure
}
store(valid: true, encoded: Encoded, state: State) (next: State) {
next = state
next.encoded = put(state.encoded, state.index, encoded)
next.index = state.index + 1
}
bounded(valid: true, encoded: Encoded) (result: Encoded) {
result = encoded
}
bounded(valid: false, encoded: Encoded) (result: Encoded) {
result = failed("JSON output exceeds 16777216 Unicode scalars")
}
encoded(text: Text) (result: Encoded) {
result = Encoded {
text = text
depth = 0
failure = ""
}
}
failed(message: Text) (result: Encoded) {
result = Encoded {
text = ""
depth = 0
failure = message
}
}
encode(value: dever.json.value.Value.Null, state: State) (result: Encoded) {
result = encoded("null")
}
encode(value: dever.json.value.Value.Boolean(boolean), state: State) (result: Encoded) {
result = encoded(boolean_text(boolean))
}
encode(value: dever.json.value.Value.Number(raw), state: State) (result: Encoded) {
result = number(dever.json.number.valid(raw), raw)
}
encode(value: dever.json.value.Value.String(string), state: State) (result: Encoded) {
result = encoded(dever.json.scan.quote(string))
}
encode(value: dever.json.value.Value.Array(children), state: State) (result: Encoded) {
built = reduce_until(array_child, children, new_children(state))
result = container(built.failure == "", "[", "]", built)
}
encode(value: dever.json.value.Value.Object(members), state: State) (result: Encoded) {
built = reduce_until(object_child, entries(members), new_children(state))
result = container(built.failure == "", "{", "}", built)
}
boolean_text(value: true) (result: Text) {
result = "true"
}
boolean_text(value: false) (result: Text) {
result = "false"
}
number(valid: true, raw: Text) (result: Encoded) {
result = encoded(raw)
}
number(valid: false, raw: Text) (result: Encoded) {
result = failed("invalid JSON number spelling")
}
new_children(state: State) (result: Children) {
result = Children {
encoded = state.encoded
parent = state.index
pieces = []
depth = 1
size = 2
failure = ""
}
}
array_child(id: Int, state: Children) (next: Children, stop: Bool) {
next = child(id >= 0 and id < state.parent, id, "", state)
stop = next.failure != ""
}
object_child(member: MapEntry<Text, Int>, state: Children) (next: Children, stop: Bool) {
next = child(
member.value >= 0 and member.value < state.parent,
member.value,
dever.json.scan.quote(member.key) + ":",
state
)
stop = next.failure != ""
}
child(valid: false, id: Int, prefix: Text, state: Children) (next: Children) {
next = child_failure("JSON child references must precede their parent", state)
}
child(valid: true, id: Int, prefix: Text, state: Children) (next: Children) {
next = child_value(get(state.encoded, id), prefix, state)
}
child_value(value: null, prefix: Text, state: Children) (next: Children) {
next = child_failure("JSON child node is missing", state)
}
child_value(value: Encoded, prefix: Text, state: Children) (next: Children) {
size = state.size + length(prefix) + length(value.text) + separator_size(
length(state.pieces) > 0
)
next = child_size(size <= maximum_size(), size, value, prefix, state)
}
separator_size(needed: true) (result: Int) {
result = 1
}
separator_size(needed: false) (result: Int) {
result = 0
}
child_size(valid: false, size: Int, value: Encoded, prefix: Text, state: Children) (
next: Children
) {
next = child_failure("JSON output exceeds 16777216 Unicode scalars", state)
}
child_size(valid: true, size: Int, value: Encoded, prefix: Text, state: Children) (
next: Children
) {
next = state
next.pieces = append(state.pieces, prefix + value.text)
next.depth = maximum(state.depth, value.depth + 1)
next.size = size
}
maximum(left: Int, right: Int) (result: Int) {
result = larger(left >= right, left, right)
}
larger(left_larger: true, left: Int, right: Int) (result: Int) {
result = left
}
larger(left_larger: false, left: Int, right: Int) (result: Int) {
result = right
}
child_failure(message: Text, state: Children) (next: Children) {
next = state
next.failure = message
}
container(valid: false, open: Text, close: Text, state: Children) (result: Encoded) {
result = failed(state.failure)
}
container(valid: true, open: Text, close: Text, state: Children) (result: Encoded) {
result = container_depth(
state.depth <= dever.json.value.maximum_depth(),
open,
close,
state
)
}
container_depth(valid: false, open: Text, close: Text, state: Children) (
result: Encoded
) {
result = failed("JSON nesting exceeds 256 containers")
}
container_depth(valid: true, open: Text, close: Text, state: Children) (result: Encoded) {
result = Encoded {
text = open + text.join(state.pieces, ",") + close
depth = state.depth
failure = ""
}
}
+15
View File
@@ -0,0 +1,15 @@
public debug(message: Text, fields: Map<Text, Text>) () {
dever.system.log_debug(message, fields)
}
public info(message: Text, fields: Map<Text, Text>) () {
dever.system.log_info(message, fields)
}
public warn(message: Text, fields: Map<Text, Text>) () {
dever.system.log_warn(message, fields)
}
public error(message: Text, fields: Map<Text, Text>) () {
dever.system.log_error(message, fields)
}
+134
View File
@@ -0,0 +1,134 @@
public type ConnectResult {
Connected(socket: dever.system.Socket)
error Failed(message: Text)
}
public type ListenResult {
Listening(listener: dever.system.Listener)
error Failed(message: Text)
}
public type PortResult {
Bound(port: Int)
error Failed(message: Text)
}
public type ReadStreamResult {
Streaming(stream: AsyncStream<dever.io.ReadEvent>)
error Failed(message: Text)
}
type SystemReadResult {
Read(bytes: Bytes)
End
error Failed(message: Text)
}
public connect(host: Text, port: Int) (socket: dever.system.Socket) {
socket = connected(dever.system.tcp_connect(host, port))
}
# 有界连接使用数值 IP,避免把 DNS 解析误称为受此超时控制。
public connect_timeout(address: Text, port: Int, milliseconds: Int) (socket: dever.system.Socket) {
socket = connected(dever.system.tcp_connect_timeout(address, port, milliseconds))
}
public accept(listener: dever.system.Listener) (socket: dever.system.Socket) {
socket = connected(dever.system.tcp_accept(listener))
}
connected(result: ConnectResult.Connected(socket)) (value: dever.system.Socket) {
value = socket
}
connected(result: ConnectResult.Failed(message)) (value: dever.system.Socket) {
fail(ConnectResult.Failed(message))
}
public listen(host: Text, port: Int) (listener: dever.system.Listener) {
listener = listening(dever.system.tcp_listen(host, port))
}
listening(result: ListenResult.Listening(listener)) (value: dever.system.Listener) {
value = listener
}
listening(result: ListenResult.Failed(message)) (value: dever.system.Listener) {
fail(ListenResult.Failed(message))
}
public port(listener: dever.system.Listener) (port: Int) {
port = bound(dever.system.tcp_port(listener))
}
bound(result: PortResult.Bound(port)) (value: Int) {
value = port
}
bound(result: PortResult.Failed(message)) (value: Int) {
fail(PortResult.Failed(message))
}
public read(socket: dever.system.Socket, limit: Int) (state: dever.io.ReadState) {
state = read_state(dever.system.tcp_read(socket, limit))
}
read_state(result: SystemReadResult.Read(bytes)) (state: dever.io.ReadState) {
state = dever.io.ReadState.Read(bytes)
}
read_state(result: SystemReadResult.End) (state: dever.io.ReadState) {
state = dever.io.ReadState.End
}
read_state(result: SystemReadResult.Failed(message)) (state: dever.io.ReadState) {
fail(dever.io.ReadResult.Failed(message))
}
public write(socket: dever.system.Socket, bytes: Bytes) () {
wrote(dever.system.tcp_write(socket, bytes))
}
public timeout(socket: dever.system.Socket, milliseconds: Int) () {
wrote(dever.system.tcp_timeout(socket, milliseconds))
}
wrote(result: dever.io.WriteResult.Done) () {}
wrote(result: dever.io.WriteResult.Failed(message)) () {
fail(dever.io.WriteResult.Failed(message))
}
public close(socket: dever.system.Socket) () {
closed(dever.system.tcp_close(socket))
}
public close_listener(listener: dever.system.Listener) () {
closed(dever.system.tcp_close_listener(listener))
}
closed(result: dever.io.CloseResult.Closed) () {}
closed(result: dever.io.CloseResult.Failed(message)) () {
fail(dever.io.CloseResult.Failed(message))
}
public chunks(socket: dever.system.Socket, limit: Int) (stream: AsyncStream<dever.io.ReadEvent>) {
stream = read_stream(dever.system.tcp_chunks(socket, limit))
}
read_stream(result: ReadStreamResult.Streaming(stream)) (
value: AsyncStream<dever.io.ReadEvent>
) {
value = stream
}
read_stream(result: ReadStreamResult.Failed(message)) (
value: AsyncStream<dever.io.ReadEvent>
) {
fail(ReadStreamResult.Failed(message))
}
public connections(listener: dever.system.Listener) (result: AsyncStream<ConnectResult>) {
result = dever.system.tcp_connections(listener)
}
+26
View File
@@ -0,0 +1,26 @@
public type Output {
code: Int
stdout: Bytes
stderr: Bytes
}
public type Error {
error Failed(message: Text)
}
public type ArgumentsResult {
Read(values: List<Text>)
error Failed(message: Text)
}
public arguments() (values: List<Text>) {
values = arguments_value(dever.system.process_arguments())
}
arguments_value(result: ArgumentsResult.Read(values)) (value: List<Text>) {
value = values
}
arguments_value(result: ArgumentsResult.Failed(message)) (value: List<Text>) {
fail(ArgumentsResult.Failed(message))
}
+3
View File
@@ -0,0 +1,3 @@
public key() (value: Text) {
value = dever.system.site_key()
}
+21
View File
@@ -0,0 +1,21 @@
public type Event {
event: Text
data: Text
id: Text?
retry_ms: Int?
}
# 自动输出 Content-Type、默认 no-cache 和空闲心跳;重连位置由 Request 头读取。
public start(reply: dever.system.HttpReply, headers: List<dever.http.Header>) () {
wrote(dever.system.sse_start(reply, headers))
}
public send(reply: dever.system.HttpReply, event: Event) () {
wrote(dever.system.sse_send(reply, event))
}
wrote(result: dever.io.WriteResult.Done) () {}
wrote(result: dever.io.WriteResult.Failed(message)) () {
fail(dever.io.WriteResult.Failed(message))
}
+16
View File
@@ -0,0 +1,16 @@
public type PutResult {
Stored(key: Uuid)
error Failed(message: Text)
}
public put(upload: Upload) (key: Uuid) {
key = stored(dever.system.upload_store(upload))
}
stored(result: PutResult.Stored(key)) (value: Uuid) {
value = key
}
stored(result: PutResult.Failed(message)) (value: Uuid) {
fail(PutResult.Failed(message))
}
+14
View File
@@ -0,0 +1,14 @@
# 第一个 tick 在一个周期后;落后的周期跳过,不积压待处理 tick。
public ticks(millis: Int) (values: AsyncStream<Int>) {
values = dever.system.task_ticks(millis)
}
public sleep(millis: Int) () {
slept(dever.system.task_sleep(millis))
}
slept(result: dever.time.SleepResult.Done) () {}
slept(result: dever.time.SleepResult.Failed(message)) () {
fail(dever.time.SleepResult.Failed(message))
}
+144
View File
@@ -0,0 +1,144 @@
public type ClockResult {
Read(value: Int)
error Failed(message: Text)
}
public type SleepResult {
Done
error Failed(message: Text)
}
public unix_millis() (value: Int) {
value = clock_value(dever.system.time_unix_millis())
}
public monotonic_nanos() (value: Int) {
value = clock_value(dever.system.time_monotonic_nanos())
}
clock_value(result: ClockResult.Read(value)) (clock: Int) {
clock = value
}
clock_value(result: ClockResult.Failed(message)) (clock: Int) {
fail(ClockResult.Failed(message))
}
public sleep(millis: Int) () {
slept(dever.system.time_sleep(millis))
}
slept(result: SleepResult.Done) () {}
slept(result: SleepResult.Failed(message)) () {
fail(SleepResult.Failed(message))
}
public type DateTimeResult {
Read(value: DateTime)
error Failed(message: Text)
}
datetime_value(result: DateTimeResult.Read(value)) (output: DateTime) pure {
output = value
}
datetime_value(result: DateTimeResult.Failed(message)) (output: DateTime) pure {
fail(DateTimeResult.Failed(message))
}
public type DateResult {
Read(value: Date)
error Failed(message: Text)
}
date_value(result: DateResult.Read(value)) (output: Date) pure {
output = value
}
date_value(result: DateResult.Failed(message)) (output: Date) pure {
fail(DateResult.Failed(message))
}
public type TimeResult {
Read(value: Time)
error Failed(message: Text)
}
time_value(result: TimeResult.Read(value)) (output: Time) pure {
output = value
}
time_value(result: TimeResult.Failed(message)) (output: Time) pure {
fail(TimeResult.Failed(message))
}
public type DurationResult {
Read(value: Duration)
error Failed(message: Text)
}
duration_value(result: DurationResult.Read(value)) (output: Duration) pure {
output = value
}
duration_value(result: DurationResult.Failed(message)) (output: Duration) pure {
fail(DurationResult.Failed(message))
}
public type TextResult {
Read(value: Text)
error Failed(message: Text)
}
text_value(result: TextResult.Read(value)) (output: Text) pure {
output = value
}
text_value(result: TextResult.Failed(message)) (output: Text) pure {
fail(TextResult.Failed(message))
}
public now() (output: DateTime) {
output = datetime_value(dever.system.time_now())
}
public parse_datetime(text: Text) (output: DateTime) pure {
output = datetime_value(dever.system.time_parse_datetime(text))
}
public format_datetime(value: DateTime) (output: Text) pure {
output = text_value(dever.system.time_format_datetime(value))
}
public parse_date(text: Text) (output: Date) pure {
output = date_value(dever.system.time_parse_date(text))
}
public format_date(value: Date) (output: Text) pure {
output = text_value(dever.system.time_format_date(value))
}
public parse_time(text: Text) (output: Time) pure {
output = time_value(dever.system.time_parse_time(text))
}
public format_time(value: Time) (output: Text) pure {
output = text_value(dever.system.time_format_time(value))
}
public add(value: DateTime, duration: Duration) (output: DateTime) pure {
output = datetime_value(dever.system.time_add(value, duration))
}
public subtract(value: DateTime, duration: Duration) (output: DateTime) pure {
output = datetime_value(dever.system.time_subtract(value, duration))
}
public difference(later: DateTime, earlier: DateTime) (output: Duration) pure {
output = duration_value(dever.system.time_difference(later, earlier))
}
public duration(millis: Int) (output: Duration) pure {
output = dever.system.time_duration(millis)
}
+39
View File
@@ -0,0 +1,39 @@
public type ClientResult {
Ready(config: dever.system.ClientTls)
error Failed(message: Text)
}
public type ServerResult {
Ready(config: dever.system.ServerTls)
error Failed(message: Text)
}
# 内置公共 CA;校验证书链、有效期和连接目标名称。
public system() (config: dever.system.ClientTls) {
config = dever.system.tls_system()
}
# 仅信任给定 PEM CA;不提供跳过校验的模式。
public client(ca_pem: Bytes) (config: dever.system.ClientTls) {
config = client_config(dever.system.tls_client(ca_pem))
}
client_config(result: ClientResult.Ready(config)) (value: dever.system.ClientTls) {
value = config
}
client_config(result: ClientResult.Failed(message)) (value: dever.system.ClientTls) {
fail(ClientResult.Failed(message))
}
public server(cert_pem: Bytes, key_pem: Bytes) (config: dever.system.ServerTls) {
config = server_config(dever.system.tls_server(cert_pem, key_pem))
}
server_config(result: ServerResult.Ready(config)) (value: dever.system.ServerTls) {
value = config
}
server_config(result: ServerResult.Failed(message)) (value: dever.system.ServerTls) {
fail(ServerResult.Failed(message))
}
+111
View File
@@ -0,0 +1,111 @@
public open(url: Text, tls: dever.system.ClientTls, limits: Limits) (
socket: dever.system.WebSocket
) {
socket = connected(dever.system.ws_open(url, tls, limits))
}
public type Limits {
message_bytes: Int
idle_ms: Int
write_ms: Int
}
public type Message {
Text(value: Text)
Binary(value: Bytes)
Ping(value: Bytes)
Pong(value: Bytes)
}
public type ConnectResult {
Connected(socket: dever.system.WebSocket)
error Failed(message: Text)
}
public type ReceiveState {
Read(message: Message)
End
}
public type ReceiveResult {
Done(state: ReceiveState)
error Failed(message: Text)
}
type SystemReceiveResult {
Read(message: Message)
End
error Failed(message: Text)
}
public type MessageEvent {
Read(message: Message)
error Failed(message: Text)
}
public default_limits() (result: Limits) {
result = Limits {
message_bytes = 1048576
idle_ms = 60000
write_ms = 5000
}
}
public accept(reply: dever.system.HttpReply, limits: Limits) (socket: dever.system.WebSocket) {
socket = connected(dever.system.ws_accept(reply, limits))
}
public connect(address: Text, port: Int, target: Text, limits: Limits) (
socket: dever.system.WebSocket
) {
socket = connected(dever.system.ws_connect(address, port, target, limits))
}
connected(result: ConnectResult.Connected(socket)) (value: dever.system.WebSocket) {
value = socket
}
connected(result: ConnectResult.Failed(message)) (value: dever.system.WebSocket) {
fail(ConnectResult.Failed(message))
}
public send(socket: dever.system.WebSocket, message: Message) () {
wrote(dever.system.ws_send(socket, message))
}
wrote(result: dever.io.WriteResult.Done) () {}
wrote(result: dever.io.WriteResult.Failed(message)) () {
fail(dever.io.WriteResult.Failed(message))
}
public receive(socket: dever.system.WebSocket) (state: ReceiveState) {
state = receive_state(dever.system.ws_receive(socket))
}
receive_state(result: SystemReceiveResult.Read(message)) (state: ReceiveState) {
state = ReceiveState.Read(message)
}
receive_state(result: SystemReceiveResult.End) (state: ReceiveState) {
state = ReceiveState.End
}
receive_state(result: SystemReceiveResult.Failed(message)) (state: ReceiveState) {
fail(ReceiveResult.Failed(message))
}
# 拉取时处理协议控制帧;自然关闭结束序列,协议故障产生最后一个 Failed。
public messages(socket: dever.system.WebSocket) (result: AsyncStream<MessageEvent>) {
result = dever.system.ws_messages(socket)
}
public close(socket: dever.system.WebSocket, code: Int, reason: Text) () {
closed(dever.system.ws_close(socket, code, reason))
}
closed(result: dever.io.CloseResult.Closed) () {}
closed(result: dever.io.CloseResult.Failed(message)) () {
fail(dever.io.CloseResult.Failed(message))
}
+11
View File
@@ -0,0 +1,11 @@
public from_int(value: Int) (result: Float) {
result = dever.system.float_from_int(value)
}
public parse(value: Text) (result: Float?) {
result = dever.system.float_parse(value)
}
public to_text(value: Float) (result: Text) {
result = dever.system.float_to_text(value)
}
+7
View File
@@ -0,0 +1,7 @@
public parse(value: Text) (result: Int?) {
result = dever.system.int_parse(value)
}
public to_text(value: Int) (result: Text) {
result = dever.system.int_to_text(value)
}
+31
View File
@@ -0,0 +1,31 @@
public sqrt(value: Float) (result: Float) {
result = dever.system.float_sqrt(value)
}
public sin(value: Float) (result: Float) {
result = dever.system.float_sin(value)
}
public cos(value: Float) (result: Float) {
result = dever.system.float_cos(value)
}
public log(value: Float) (result: Float) {
result = dever.system.float_log(value)
}
public pow(value: Float, exponent: Float) (result: Float) {
result = dever.system.float_pow(value, exponent)
}
public is_nan(value: Float) (result: Bool) {
result = dever.system.float_is_nan(value)
}
public is_finite(value: Float) (result: Bool) {
result = dever.system.float_is_finite(value)
}
public is_infinite(value: Float) (result: Bool) {
result = dever.system.float_is_infinite(value)
}
+89
View File
@@ -0,0 +1,89 @@
public trim(value: Text) (result: Text) {
result = dever.system.text_trim(value)
}
public lower(value: Text) (result: Text) {
result = dever.system.text_lower(value)
}
public upper(value: Text) (result: Text) {
result = dever.system.text_upper(value)
}
public codepoint(value: Text) (result: Int?) {
result = dever.system.text_codepoint(value)
}
public from_codepoint(value: Int) (result: Text?) {
result = dever.system.text_from_codepoint(value)
}
public at(value: Text, index: Int) (result: Text?) {
result = dever.system.text_at(value, index)
}
public slice(value: Text, start: Int, end: Int) (result: Text?) {
result = dever.system.text_slice(value, start, end)
}
public index_of(value: Text, pattern: Text) (result: Int?) {
result = dever.system.text_index_of(value, pattern)
}
public contains(value: Text, pattern: Text) (result: Bool) {
result = dever.system.text_contains(value, pattern)
}
public starts_with(value: Text, prefix: Text) (result: Bool) {
result = dever.system.text_starts_with(value, prefix)
}
public ends_with(value: Text, suffix: Text) (result: Bool) {
result = dever.system.text_ends_with(value, suffix)
}
public split(value: Text, separator: Text) (result: List<Text>) {
result = dever.system.text_split(value, separator)
}
public replace(value: Text, pattern: Text, replacement: Text) (result: Text) {
result = dever.system.text_replace(value, pattern, replacement)
}
public is_empty(value: Text) (result: Bool) {
result = length(value) == 0
}
type JoinState {
text: Text
separator: Text
first: Bool
}
public join(values: List<Text>, separator: Text) (result: Text) {
state = reduce(
join_piece,
values,
JoinState {
text = ""
separator = separator
first = true
}
)
result = state.text
}
join_piece(value: Text, state: JoinState) (result: JoinState) {
result = join_next(state.first, value, state)
}
join_next(first: true, value: Text, state: JoinState) (result: JoinState) {
result = state
result.text = value
result.first = false
}
join_next(first: false, value: Text, state: JoinState) (result: JoinState) {
result = state
result.text = state.text + state.separator + value
}
+7
View File
@@ -0,0 +1,7 @@
public parse(value: Text) (result: Uuid?) {
result = dever.system.uuid_parse(value)
}
public to_text(value: Uuid) (result: Text) {
result = dever.system.uuid_to_text(value)
}