This commit is contained in:
gingerBill
2023-12-12 17:11:42 +00:00
38 changed files with 6245 additions and 328 deletions
+1 -1
View File
@@ -111,7 +111,7 @@ call build_vendor.bat
if %errorlevel% neq 0 goto end_of_build if %errorlevel% neq 0 goto end_of_build
rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native
if %release_mode% EQU 0 odin run examples/demo if %release_mode% EQU 0 odin run examples/demo -- Hellope World
del *.obj > NUL 2> NUL del *.obj > NUL 2> NUL
+3 -1
View File
@@ -27,11 +27,13 @@ error() {
if [ -z "$LLVM_CONFIG" ]; then if [ -z "$LLVM_CONFIG" ]; then
# darwin, linux, openbsd # darwin, linux, openbsd
if [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17" if [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17"
elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14"
elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13" elif [ -n "$(command -v llvm-config-13)" ]; then LLVM_CONFIG="llvm-config-13"
elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12" elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12"
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11" elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
# freebsd # freebsd
elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config-17" elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config-17"
elif [ -n "$(command -v llvm-config14)" ]; then LLVM_CONFIG="llvm-config-14"
elif [ -n "$(command -v llvm-config13)" ]; then LLVM_CONFIG="llvm-config-13" elif [ -n "$(command -v llvm-config13)" ]; then LLVM_CONFIG="llvm-config-13"
elif [ -n "$(command -v llvm-config12)" ]; then LLVM_CONFIG="llvm-config-12" elif [ -n "$(command -v llvm-config12)" ]; then LLVM_CONFIG="llvm-config-12"
elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11" elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11"
@@ -117,7 +119,7 @@ build_odin() {
} }
run_demo() { run_demo() {
./odin run examples/demo/demo.odin -file ./odin run examples/demo/demo.odin -file -- Hellope World
} }
if [ $# -eq 0 ]; then if [ $# -eq 0 ]; then
+1 -1
View File
@@ -2856,7 +2856,7 @@ internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator
dest.digit[digits - 1] &= ((1 << uint(bits)) - 1) dest.digit[digits - 1] &= ((1 << uint(bits)) - 1)
} }
dest.used = digits dest.used = digits
return nil return internal_clamp(dest)
} }
internal_random :: proc { internal_int_random, } internal_random :: proc { internal_int_random, }
+11 -11
View File
@@ -2312,17 +2312,17 @@ F32_NORMALIZE :: 0
F32_RADIX :: 2 F32_RADIX :: 2
F32_ROUNDS :: 1 F32_ROUNDS :: 1
F64_DIG :: 15 // # of decimal digits of precision F64_DIG :: 15 // Number of representable decimal digits.
F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0 F64_EPSILON :: 2.2204460492503131e-016 // Smallest number such that `1.0 + F64_EPSILON != 1.0`.
F64_MANT_DIG :: 53 // # of bits in mantissa F64_MANT_DIG :: 53 // Number of bits in the mantissa.
F64_MAX :: 1.7976931348623158e+308 // max value F64_MAX :: 1.7976931348623158e+308 // Maximum representable value.
F64_MAX_10_EXP :: 308 // max decimal exponent F64_MAX_10_EXP :: 308 // Maximum base-10 exponent yielding normalized value.
F64_MAX_EXP :: 1024 // max binary exponent F64_MAX_EXP :: 1024 // One greater than the maximum possible base-2 exponent yielding normalized value.
F64_MIN :: 2.2250738585072014e-308 // min positive value F64_MIN :: 2.2250738585072014e-308 // Minimum positive normalized value.
F64_MIN_10_EXP :: -307 // min decimal exponent F64_MIN_10_EXP :: -307 // Minimum base-10 exponent yielding normalized value.
F64_MIN_EXP :: -1021 // min binary exponent F64_MIN_EXP :: -1021 // One greater than the minimum possible base-2 exponent yielding normalized value.
F64_RADIX :: 2 // exponent radix F64_RADIX :: 2 // Exponent radix.
F64_ROUNDS :: 1 // addition rounding: near F64_ROUNDS :: 1 // Addition rounding: near.
F16_MASK :: 0x1f F16_MASK :: 0x1f
+1 -1
View File
@@ -51,7 +51,7 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
// Initialization of an `Arena` to be a `.Static` variant. // Initialization of an `Arena` to be a `.Static` variant.
// A static arena contains a single `Memory_Block` allocated with virtual memory. // A static arena contains a single `Memory_Block` allocated with virtual memory.
@(require_results) @(require_results)
arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) { arena_init_static :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_STATIC_RESERVE_SIZE, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
arena.kind = .Static arena.kind = .Static
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
arena.total_used = 0 arena.total_used = 0
+38 -3
View File
@@ -148,7 +148,29 @@ recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_en
return _recv_udp(socket, buf) return _recv_udp(socket, buf)
} }
recv :: proc{recv_tcp, recv_udp} /*
Receive data from into a buffer from any socket.
Note: `remote_endpoint` parameter is non-nil only if the socket type is UDP. On TCP sockets it
will always return `nil`.
*/
recv_any :: proc(socket: Any_Socket, buf: []byte) -> (
bytes_read: int,
remote_endpoint: Maybe(Endpoint),
err: Network_Error,
) {
switch socktype in socket {
case TCP_Socket:
bytes_read, err := recv_tcp(socktype, buf)
return bytes_read, nil, err
case UDP_Socket:
bytes_read, endpoint, err := recv_udp(socktype, buf)
return bytes_read, endpoint, err
case: panic("Not supported")
}
}
recv :: proc{recv_tcp, recv_udp, recv_any}
/* /*
Repeatedly sends data until the entire buffer is sent. Repeatedly sends data until the entire buffer is sent.
@@ -168,7 +190,20 @@ send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_writte
return _send_udp(socket, buf, to) return _send_udp(socket, buf, to)
} }
send :: proc{send_tcp, send_udp} send_any :: proc(socket: Any_Socket, buf: []byte, to: Maybe(Endpoint) = nil) -> (
bytes_written: int,
err: Network_Error,
) {
switch socktype in socket {
case TCP_Socket:
return send_tcp(socktype, buf)
case UDP_Socket:
return send_udp(socktype, buf, to.(Endpoint))
case: panic("Not supported")
}
}
send :: proc{send_tcp, send_udp, send_any}
shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) {
return _shutdown(socket, manner) return _shutdown(socket, manner)
@@ -180,4 +215,4 @@ set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc :=
set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
return _set_blocking(socket, should_block) return _set_blocking(socket, should_block)
} }
+1 -1
View File
@@ -125,7 +125,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (An
} }
@(private) @(private)
_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (tcp_sock: TCP_Socket, err: Network_Error) { _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (TCP_Socket, Network_Error) {
errno: linux.Errno errno: linux.Errno
if endpoint.port == 0 { if endpoint.port == 0 {
return 0, .Port_Required return 0, .Port_Required
+10 -1
View File
@@ -7,7 +7,7 @@ import "core:reflect"
import "core:odin/tokenizer" import "core:odin/tokenizer"
_ :: intrinsics _ :: intrinsics
new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T { new_from_positions :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
n, _ := mem.new(T) n, _ := mem.new(T)
n.pos = pos n.pos = pos
n.end = end n.end = end
@@ -23,6 +23,15 @@ new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
return n return n
} }
new_from_pos_and_end_node :: proc($T: typeid, pos: tokenizer.Pos, end: ^Node) -> ^T {
return new(T, pos, end != nil ? end.end : pos)
}
new :: proc {
new_from_positions,
new_from_pos_and_end_node,
}
clone :: proc{ clone :: proc{
clone_node, clone_node,
clone_expr, clone_expr,
+51 -47
View File
@@ -786,8 +786,11 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
else_stmt = ast.new(ast.Bad_Stmt, p.curr_tok.pos, end_pos(p.curr_tok)) else_stmt = ast.new(ast.Bad_Stmt, p.curr_tok.pos, end_pos(p.curr_tok))
} }
} }
end := body.end end: tokenizer.Pos
if body != nil {
end = body.end
}
if else_stmt != nil { if else_stmt != nil {
end = else_stmt.end end = else_stmt.end
} }
@@ -850,7 +853,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body = parse_body(p) body = parse_body(p)
} }
range_stmt := ast.new(ast.Range_Stmt, tok.pos, body.end) range_stmt := ast.new(ast.Range_Stmt, tok.pos, body)
range_stmt.for_pos = tok.pos range_stmt.for_pos = tok.pos
range_stmt.in_pos = in_tok.pos range_stmt.in_pos = in_tok.pos
range_stmt.expr = rhs range_stmt.expr = rhs
@@ -910,7 +913,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
rhs = assign_stmt.rhs[0] rhs = assign_stmt.rhs[0]
} }
range_stmt := ast.new(ast.Range_Stmt, tok.pos, body.end) range_stmt := ast.new(ast.Range_Stmt, tok.pos, body)
range_stmt.for_pos = tok.pos range_stmt.for_pos = tok.pos
range_stmt.vals = vals range_stmt.vals = vals
range_stmt.in_pos = assign_stmt.op.pos range_stmt.in_pos = assign_stmt.op.pos
@@ -920,7 +923,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
} }
cond_expr := convert_stmt_to_expr(p, cond, "boolean expression") cond_expr := convert_stmt_to_expr(p, cond, "boolean expression")
for_stmt := ast.new(ast.For_Stmt, tok.pos, body.end) for_stmt := ast.new(ast.For_Stmt, tok.pos, body)
for_stmt.for_pos = tok.pos for_stmt.for_pos = tok.pos
for_stmt.init = init for_stmt.init = init
for_stmt.cond = cond_expr for_stmt.cond = cond_expr
@@ -976,7 +979,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
lhs[0] = new_blank_ident(p, tok.pos) lhs[0] = new_blank_ident(p, tok.pos)
rhs[0] = parse_expr(p, true) rhs[0] = parse_expr(p, true)
as := ast.new(ast.Assign_Stmt, tok.pos, rhs[0].end) as := ast.new(ast.Assign_Stmt, tok.pos, rhs[0])
as.lhs = lhs as.lhs = lhs
as.op = in_tok as.op = in_tok
as.rhs = rhs as.rhs = rhs
@@ -1010,14 +1013,14 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body.stmts = clauses[:] body.stmts = clauses[:]
if is_type_switch { if is_type_switch {
ts := ast.new(ast.Type_Switch_Stmt, tok.pos, body.end) ts := ast.new(ast.Type_Switch_Stmt, tok.pos, body)
ts.tag = tag ts.tag = tag
ts.body = body ts.body = body
ts.switch_pos = tok.pos ts.switch_pos = tok.pos
return ts return ts
} else { } else {
cond := convert_stmt_to_expr(p, tag, "switch expression") cond := convert_stmt_to_expr(p, tag, "switch expression")
ts := ast.new(ast.Switch_Stmt, tok.pos, body.end) ts := ast.new(ast.Switch_Stmt, tok.pos, body)
ts.init = init ts.init = init
ts.cond = cond ts.cond = cond
ts.body = body ts.body = body
@@ -1044,7 +1047,7 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
if p.curr_tok.kind == .Eq { if p.curr_tok.kind == .Eq {
eq := expect_token(p, .Eq) eq := expect_token(p, .Eq)
value := parse_value(p) value := parse_value(p)
fv := ast.new(ast.Field_Value, elem.pos, value.end) fv := ast.new(ast.Field_Value, elem.pos, value)
fv.field = elem fv.field = elem
fv.sep = eq.pos fv.sep = eq.pos
fv.value = value fv.value = value
@@ -1137,7 +1140,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl
body.stmts = decls[:] body.stmts = decls[:]
body.close = close.pos body.close = close.pos
decl := ast.new(ast.Foreign_Block_Decl, tok.pos, body.end) decl := ast.new(ast.Foreign_Block_Decl, tok.pos, body)
decl.docs = docs decl.docs = docs
decl.tok = tok decl.tok = tok
decl.foreign_library = foreign_library decl.foreign_library = foreign_library
@@ -1248,7 +1251,7 @@ parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast
return ast.new(ast.Bad_Stmt, inline_tok.pos, end_pos(p.prev_tok)) return ast.new(ast.Bad_Stmt, inline_tok.pos, end_pos(p.prev_tok))
} }
range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body.end) range_stmt := ast.new(ast.Inline_Range_Stmt, inline_tok.pos, body)
range_stmt.inline_pos = inline_tok.pos range_stmt.inline_pos = inline_tok.pos
range_stmt.for_pos = for_tok.pos range_stmt.for_pos = for_tok.pos
range_stmt.val0 = val0 range_stmt.val0 = val0
@@ -1304,7 +1307,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
case ^ast.Return_Stmt: case ^ast.Return_Stmt:
error(p, s.pos, "you cannot defer a return statement") error(p, s.pos, "you cannot defer a return statement")
} }
ds := ast.new(ast.Defer_Stmt, tok.pos, stmt.end) ds := ast.new(ast.Defer_Stmt, tok.pos, stmt)
ds.stmt = stmt ds.stmt = stmt
return ds return ds
@@ -1341,8 +1344,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident { if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident {
label = parse_ident(p) label = parse_ident(p)
} }
end := label.end if label != nil else end_pos(tok) s := ast.new(ast.Branch_Stmt, tok.pos, label)
s := ast.new(ast.Branch_Stmt, tok.pos, end)
s.tok = tok s.tok = tok
s.label = label s.label = label
expect_semicolon(p, s) expect_semicolon(p, s)
@@ -1366,7 +1368,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if p.curr_tok.kind != .Colon { if p.curr_tok.kind != .Colon {
end := list[len(list)-1] end := list[len(list)-1]
expect_semicolon(p, end) expect_semicolon(p, end)
us := ast.new(ast.Using_Stmt, tok.pos, end.end) us := ast.new(ast.Using_Stmt, tok.pos, end)
us.list = list us.list = list
return us return us
} }
@@ -1416,13 +1418,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
bd.tok = tok bd.tok = tok
bd.name = name bd.name = name
ce := parse_call_expr(p, bd) ce := parse_call_expr(p, bd)
es := ast.new(ast.Expr_Stmt, ce.pos, ce.end) es := ast.new(ast.Expr_Stmt, ce.pos, ce)
es.expr = ce es.expr = ce
return es return es
case "force_inline", "force_no_inline": case "force_inline", "force_no_inline":
expr := parse_inlining_operand(p, true, tag) expr := parse_inlining_operand(p, true, tag)
es := ast.new(ast.Expr_Stmt, expr.pos, expr.end) es := ast.new(ast.Expr_Stmt, expr.pos, expr)
es.expr = expr es.expr = expr
return es return es
case "unroll": case "unroll":
@@ -1444,7 +1446,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag)) return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag))
case: case:
stmt := parse_stmt(p) stmt := parse_stmt(p)
te := ast.new(ast.Tag_Stmt, tok.pos, stmt.pos) end := stmt.pos if stmt != nil else end_pos(tok)
te := ast.new(ast.Tag_Stmt, tok.pos, end)
te.op = tok te.op = tok
te.name = name te.name = name
te.stmt = stmt te.stmt = stmt
@@ -1572,7 +1575,7 @@ convert_stmt_to_body :: proc(p: ^Parser, stmt: ^ast.Stmt) -> ^ast.Stmt {
error(p, stmt.pos, "expected a non-empty statement") error(p, stmt.pos, "expected a non-empty statement")
} }
bs := ast.new(ast.Block_Stmt, stmt.pos, stmt.end) bs := ast.new(ast.Block_Stmt, stmt.pos, stmt)
bs.open = stmt.pos bs.open = stmt.pos
bs.stmts = make([]^ast.Stmt, 1) bs.stmts = make([]^ast.Stmt, 1)
bs.stmts[0] = stmt bs.stmts[0] = stmt
@@ -1741,7 +1744,7 @@ parse_var_type :: proc(p: ^Parser, flags: ast.Field_Flags) -> ^ast.Expr {
error(p, tok.pos, "variadic field missing type after '..'") error(p, tok.pos, "variadic field missing type after '..'")
type = ast.new(ast.Bad_Expr, tok.pos, end_pos(tok)) type = ast.new(ast.Bad_Expr, tok.pos, end_pos(tok))
} }
e := ast.new(ast.Ellipsis, type.pos, type.end) e := ast.new(ast.Ellipsis, type.pos, type)
e.expr = type e.expr = type
return e return e
} }
@@ -1808,7 +1811,7 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr {
if is_blank_ident(ident) { if is_blank_ident(ident) {
error(p, ident.pos, "invalid polymorphic type definition with a blank identifier") error(p, ident.pos, "invalid polymorphic type definition with a blank identifier")
} }
poly_name := ast.new(ast.Poly_Type, tok.pos, ident.end) poly_name := ast.new(ast.Poly_Type, tok.pos, ident)
poly_name.type = ident poly_name.type = ident
append(&list, poly_name) append(&list, poly_name)
} else { } else {
@@ -2154,7 +2157,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
e.inlining = pi e.inlining = pi
case: case:
error(p, tok.pos, "'%s' must be followed by a procedure literal or call", tok.text) error(p, tok.pos, "'%s' must be followed by a procedure literal or call", tok.text)
return ast.new(ast.Bad_Expr, tok.pos, expr.end) return ast.new(ast.Bad_Expr, tok.pos, expr)
} }
return expr return expr
} }
@@ -2204,7 +2207,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Distinct: case .Distinct:
tok := advance_token(p) tok := advance_token(p)
type := parse_type(p) type := parse_type(p)
dt := ast.new(ast.Distinct_Type, tok.pos, type.end) dt := ast.new(ast.Distinct_Type, tok.pos, type)
dt.tok = tok.kind dt.tok = tok.kind
dt.type = type dt.type = type
return dt return dt
@@ -2215,7 +2218,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
switch name.text { switch name.text {
case "type": case "type":
type := parse_type(p) type := parse_type(p)
hp := ast.new(ast.Helper_Type, tok.pos, type.end) hp := ast.new(ast.Helper_Type, tok.pos, type)
hp.tok = tok.kind hp.tok = tok.kind
hp.type = type hp.type = type
return hp return hp
@@ -2319,7 +2322,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tag_call := parse_call_expr(p, tag) tag_call := parse_call_expr(p, tag)
type := parse_type(p) type := parse_type(p)
rt := ast.new(ast.Relative_Type, tok.pos, type.end) rt := ast.new(ast.Relative_Type, tok.pos, type)
rt.tag = tag_call rt.tag = tag_call
rt.type = type rt.type = type
return rt return rt
@@ -2328,7 +2331,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return parse_inlining_operand(p, lhs, name) return parse_inlining_operand(p, lhs, name)
case: case:
expr := parse_expr(p, lhs) expr := parse_expr(p, lhs)
te := ast.new(ast.Tag_Expr, tok.pos, expr.pos) end := expr.pos if expr != nil else end_pos(tok)
te := ast.new(ast.Tag_Expr, tok.pos, end)
te.op = tok te.op = tok
te.name = name.text te.name = name.text
te.expr = expr te.expr = expr
@@ -2456,7 +2460,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Pointer: case .Pointer:
tok := expect_token(p, .Pointer) tok := expect_token(p, .Pointer)
elem := parse_type(p) elem := parse_type(p)
ptr := ast.new(ast.Pointer_Type, tok.pos, elem.end) ptr := ast.new(ast.Pointer_Type, tok.pos, elem)
ptr.pointer = tok.pos ptr.pointer = tok.pos
ptr.elem = elem ptr.elem = elem
return ptr return ptr
@@ -2470,7 +2474,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Pointer) tok := expect_token(p, .Pointer)
close := expect_token(p, .Close_Bracket) close := expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
t := ast.new(ast.Multi_Pointer_Type, open.pos, elem.end) t := ast.new(ast.Multi_Pointer_Type, open.pos, elem)
t.open = open.pos t.open = open.pos
t.pointer = tok.pos t.pointer = tok.pos
t.close = close.pos t.close = close.pos
@@ -2480,7 +2484,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Dynamic) tok := expect_token(p, .Dynamic)
close := expect_token(p, .Close_Bracket) close := expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
da := ast.new(ast.Dynamic_Array_Type, open.pos, elem.end) da := ast.new(ast.Dynamic_Array_Type, open.pos, elem)
da.open = open.pos da.open = open.pos
da.dynamic_pos = tok.pos da.dynamic_pos = tok.pos
da.close = close.pos da.close = close.pos
@@ -2500,7 +2504,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
} }
close := expect_token(p, .Close_Bracket) close := expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
at := ast.new(ast.Array_Type, open.pos, elem.end) at := ast.new(ast.Array_Type, open.pos, elem)
at.open = open.pos at.open = open.pos
at.len = count at.len = count
at.close = close.pos at.close = close.pos
@@ -2514,7 +2518,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
expect_token(p, .Close_Bracket) expect_token(p, .Close_Bracket)
value := parse_type(p) value := parse_type(p)
mt := ast.new(ast.Map_Type, tok.pos, value.end) mt := ast.new(ast.Map_Type, tok.pos, value)
mt.tok_pos = tok.pos mt.tok_pos = tok.pos
mt.key = key mt.key = key
mt.value = value mt.value = value
@@ -2755,7 +2759,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
expect_token(p, .Close_Bracket) expect_token(p, .Close_Bracket)
elem := parse_type(p) elem := parse_type(p)
mt := ast.new(ast.Matrix_Type, tok.pos, elem.end) mt := ast.new(ast.Matrix_Type, tok.pos, elem)
mt.tok_pos = tok.pos mt.tok_pos = tok.pos
mt.row_count = row_count mt.row_count = row_count
mt.column_count = column_count mt.column_count = column_count
@@ -2893,7 +2897,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
eq := expect_token(p, .Eq) eq := expect_token(p, .Eq)
value := parse_value(p) value := parse_value(p)
fv := ast.new(ast.Field_Value, elem.pos, value.end) fv := ast.new(ast.Field_Value, elem.pos, value)
fv.field = elem fv.field = elem
fv.sep = eq.pos fv.sep = eq.pos
fv.value = value fv.value = value
@@ -2962,7 +2966,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
} }
value := parse_value(p) value := parse_value(p)
fv := ast.new(ast.Field_Value, arg.pos, value.end) fv := ast.new(ast.Field_Value, arg.pos, value)
fv.field = arg fv.field = arg
fv.sep = eq.pos fv.sep = eq.pos
fv.value = value fv.value = value
@@ -2993,7 +2997,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
o := ast.unparen_expr(operand) o := ast.unparen_expr(operand)
if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right { if se, ok := o.derived.(^ast.Selector_Expr); ok && se.op.kind == .Arrow_Right {
sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce.end) sce := ast.new(ast.Selector_Call_Expr, ce.pos, ce)
sce.expr = o sce.expr = o
sce.call = ce sce.call = ce
return sce return sce
@@ -3101,7 +3105,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case .Ident: case .Ident:
field := parse_ident(p) field := parse_ident(p)
sel := ast.new(ast.Selector_Expr, operand.pos, field.end) sel := ast.new(ast.Selector_Expr, operand.pos, field)
sel.expr = operand sel.expr = operand
sel.op = tok sel.op = tok
sel.field = field sel.field = field
@@ -3127,7 +3131,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
type.op = question type.op = question
type.expr = nil type.expr = nil
ta := ast.new(ast.Type_Assertion, operand.pos, type.end) ta := ast.new(ast.Type_Assertion, operand.pos, type)
ta.expr = operand ta.expr = operand
ta.type = type ta.type = type
@@ -3145,7 +3149,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case .Ident: case .Ident:
field := parse_ident(p) field := parse_ident(p)
sel := ast.new(ast.Selector_Expr, operand.pos, field.end) sel := ast.new(ast.Selector_Expr, operand.pos, field)
sel.expr = operand sel.expr = operand
sel.op = tok sel.op = tok
sel.field = field sel.field = field
@@ -3225,7 +3229,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
close := expect_token(p, .Close_Paren) close := expect_token(p, .Close_Paren)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
tc := ast.new(ast.Type_Cast, tok.pos, expr.end) tc := ast.new(ast.Type_Cast, tok.pos, expr)
tc.tok = tok tc.tok = tok
tc.open = open.pos tc.open = open.pos
tc.type = type tc.type = type
@@ -3237,7 +3241,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
op := advance_token(p) op := advance_token(p)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
ac := ast.new(ast.Auto_Cast, op.pos, expr.end) ac := ast.new(ast.Auto_Cast, op.pos, expr)
ac.op = op ac.op = op
ac.expr = expr ac.expr = expr
return ac return ac
@@ -3247,8 +3251,8 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
.And: .And:
op := advance_token(p) op := advance_token(p)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
ue := ast.new(ast.Unary_Expr, op.pos, expr.end) ue := ast.new(ast.Unary_Expr, op.pos, expr)
ue.op = op ue.op = op
ue.expr = expr ue.expr = expr
return ue return ue
@@ -3258,7 +3262,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
error(p, op.pos, "unary '%s' operator is not supported", op.text) error(p, op.pos, "unary '%s' operator is not supported", op.text)
expr := parse_unary_expr(p, lhs) expr := parse_unary_expr(p, lhs)
ue := ast.new(ast.Unary_Expr, op.pos, expr.end) ue := ast.new(ast.Unary_Expr, op.pos, expr)
ue.op = op ue.op = op
ue.expr = expr ue.expr = expr
return ue return ue
@@ -3266,7 +3270,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Period: case .Period:
op := advance_token(p) op := advance_token(p)
field := parse_ident(p) field := parse_ident(p)
ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field.end) ise := ast.new(ast.Implicit_Selector_Expr, op.pos, field)
ise.field = field ise.field = field
return ise return ise
@@ -3407,7 +3411,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
error(p, p.curr_tok.pos, "no right-hand side in assignment statement") error(p, p.curr_tok.pos, "no right-hand side in assignment statement")
return ast.new(ast.Bad_Stmt, start_tok.pos, end_pos(p.curr_tok)) return ast.new(ast.Bad_Stmt, start_tok.pos, end_pos(p.curr_tok))
} }
stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1].end) stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1])
stmt.lhs = lhs stmt.lhs = lhs
stmt.op = op stmt.op = op
stmt.rhs = rhs stmt.rhs = rhs
@@ -3424,7 +3428,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
rhs := make([]^ast.Expr, 1) rhs := make([]^ast.Expr, 1)
rhs[0] = expr rhs[0] = expr
stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1].end) stmt := ast.new(ast.Assign_Stmt, lhs[0].pos, rhs[len(rhs)-1])
stmt.lhs = lhs stmt.lhs = lhs
stmt.op = op stmt.op = op
stmt.rhs = rhs stmt.rhs = rhs
@@ -3466,7 +3470,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
error(p, op.pos, "postfix '%s' statement is not supported", op.text) error(p, op.pos, "postfix '%s' statement is not supported", op.text)
} }
es := ast.new(ast.Expr_Stmt, lhs[0].pos, lhs[0].end) es := ast.new(ast.Expr_Stmt, lhs[0].pos, lhs[0])
es.expr = lhs[0] es.expr = lhs[0]
return es return es
} }
+2 -4
View File
@@ -35,7 +35,7 @@ nil_allocator :: proc() -> Allocator {
when ODIN_OS == .Freestanding { when ODIN_OS == .Freestanding {
default_allocator_proc :: nil_allocator_proc default_allocator_proc :: nil_allocator_proc
default_allocator :: nil_allocator default_allocator :: nil_allocator
} }
@@ -78,9 +78,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
panic_allocator :: proc() -> Allocator { panic_allocator :: proc() -> Allocator {
return Allocator{ return Allocator{
procedure = nil_allocator_proc, procedure = panic_allocator_proc,
data = nil, data = nil,
} }
} }
+1 -1
View File
@@ -4,7 +4,7 @@ package runtime
import "core:intrinsics" import "core:intrinsics"
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { _os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
ret := intrinsics.syscall(4, 1, uintptr(raw_data(data)), uintptr(len(data))) ret := intrinsics.syscall(0x2000004, 1, uintptr(raw_data(data)), uintptr(len(data)))
if ret < 0 { if ret < 0 {
return 0, _OS_Errno(-ret) return 0, _OS_Errno(-ret)
} }
+117 -36
View File
@@ -49,7 +49,7 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte {
``` ```
``` ```
small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0, small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0} 2, 0, 0, 0}
large_items := slice.reinterpret([]i64, small_items) large_items := slice.reinterpret([]i64, small_items)
assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes. assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
``` ```
@@ -78,7 +78,7 @@ swap_between :: proc(a, b: $T/[]$E) {
n := builtin.min(len(a), len(b)) n := builtin.min(len(a), len(b))
if n >= 0 { if n >= 0 {
ptr_swap_overlapping(&a[0], &b[0], size_of(E)*n) ptr_swap_overlapping(&a[0], &b[0], size_of(E)*n)
} }
} }
@@ -117,46 +117,93 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
return -1, false return -1, false
} }
/*
Binary search searches the given slice for the given element.
If the slice is not sorted, the returned index is unspecified and meaningless.
If the value is found then the returned int is the index of the matching element.
If there are multiple matches, then any one of the matches could be returned.
If the value is not found then the returned int is the index where a matching
element could be inserted while maintaining sorted order.
# Examples
Looks up a series of four elements. The first is found, with a
uniquely determined position; the second and third are not
found; the fourth could match any position in `[1, 4]`.
```
index: int
found: bool
s := []i32{0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}
index, found = slice.binary_search(s, 13)
assert(index == 9 && found == true)
index, found = slice.binary_search(s, 4)
assert(index == 7 && found == false)
index, found = slice.binary_search(s, 100)
assert(index == 13 && found == false)
index, found = slice.binary_search(s, 1)
assert(index >= 1 && index <= 4 && found == true)
```
For slices of more complex types see: binary_search_by
*/
@(require_results) @(require_results)
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool) binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
where intrinsics.type_is_ordered(T) #no_bounds_check { where intrinsics.type_is_ordered(T) #no_bounds_check
{
n := len(array) // I would like to use binary_search_by(array, key, cmp) here, but it doesn't like it:
switch n { // Cannot assign value 'cmp' of type 'proc($E, $E) -> Ordering' to 'proc(i32, i32) -> Ordering' in argument
case 0: return binary_search_by(array, key, proc(key: T, element: T) -> Ordering {
return -1, false
case 1:
if array[0] == key {
return 0, true
}
return -1, false
}
lo, hi := 0, n-1
for array[hi] != array[lo] && key >= array[lo] && key <= array[hi] {
when intrinsics.type_is_ordered_numeric(T) {
// NOTE(bill): This is technically interpolation search
m := lo + int((key - array[lo]) * T(hi - lo) / (array[hi] - array[lo]))
} else {
m := lo + (hi - lo)/2
}
switch { switch {
case array[m] < key: case element < key: return .Less
lo = m + 1 case element > key: return .Greater
case key < array[m]: case: return .Equal
hi = m - 1
case:
return m, true
} }
} })
if key == array[lo] {
return lo, true
}
return -1, false
} }
@(require_results)
binary_search_by :: proc(array: $A/[]$T, key: T, f: proc(T, T) -> Ordering) -> (index: int, found: bool) #no_bounds_check {
// INVARIANTS:
// - 0 <= left <= (left + size = right) <= len(array)
// - f returns .Less for everything in array[:left]
// - f returns .Greater for everything in array[right:]
size := len(array)
left := 0
right := size
for left < right {
mid := left + size / 2
// Steps to verify this is in-bounds:
// 1. We note that `size` is strictly positive due to the loop condition
// 2. Therefore `size/2 < size`
// 3. Adding `left` to both sides yields `(left + size/2) < (left + size)`
// 4. We know from the invariant that `left + size <= len(array)`
// 5. Therefore `left + size/2 < self.len()`
cmp := f(key, array[mid])
left = mid + 1 if cmp == .Less else left
right = mid if cmp == .Greater else right
switch cmp {
case .Equal: return mid, true
case .Less: left = mid + 1
case .Greater: right = mid
}
size = right - left
}
return left, false
}
@(require_results) @(require_results)
equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
@@ -463,6 +510,40 @@ min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_
return return
} }
// Find the index of the (first) minimum element in a slice.
@(require_results)
min_index :: proc(s: $S/[]$T) -> (min_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
if len(s) == 0 {
return -1, false
}
min_index = 0
min_value := s[0]
for v, i in s[1:] {
if v < min_value {
min_value = v
min_index = i+1
}
}
return min_index, true
}
// Find the index of the (first) maximum element in a slice.
@(require_results)
max_index :: proc(s: $S/[]$T) -> (max_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
if len(s) == 0 {
return -1, false
}
max_index = 0
max_value := s[0]
for v, i in s[1:] {
if v > max_value {
max_value = v
max_index = i+1
}
}
return max_index, true
}
@(require_results) @(require_results)
any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) { any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
for v in s { for v in s {
+1
View File
@@ -885,6 +885,7 @@ Splits a string into parts based on a separator. If n < count of seperators, the
Inputs: Inputs:
- s: The string to split. - s: The string to split.
- sep: The separator string used to split the input string. - sep: The separator string used to split the input string.
- n: The maximum amount of parts to split the string into.
- allocator: (default is context.allocator) - allocator: (default is context.allocator)
Returns: Returns:
+1 -1
View File
@@ -718,7 +718,7 @@ Perf_Event_Sample_Type_Bits :: enum {
} }
/// Describes field sets to include in mmaped page /// Describes field sets to include in mmaped page
Perf_Read_Format :: enum { Perf_Read_Format_Bits :: enum {
TOTAL_TIME_ENABLED = 0, TOTAL_TIME_ENABLED = 0,
TOTAL_TIME_RUNNING = 1, TOTAL_TIME_RUNNING = 1,
ID = 2, ID = 2,
+2
View File
@@ -283,6 +283,8 @@ Perf_Flags :: bit_set[Perf_Flags_Bits; uint]
Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64] Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64]
Perf_Read_Format :: distinct bit_set[Perf_Read_Format_Bits; u64]
Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64] Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64]
Perf_Event_Sample_Type :: bit_set[Perf_Event_Sample_Type_Bits; u64] Perf_Event_Sample_Type :: bit_set[Perf_Event_Sample_Type_Bits; u64]
+7
View File
@@ -10,6 +10,8 @@ foreign gdi32 {
DeleteObject :: proc(ho: HGDIOBJ) -> BOOL --- DeleteObject :: proc(ho: HGDIOBJ) -> BOOL ---
SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF --- SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
CreateCompatibleDC :: proc(hdc: HDC) -> HDC ---
CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH ---
CreateDIBitmap :: proc( CreateDIBitmap :: proc(
@@ -81,6 +83,11 @@ foreign gdi32 {
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL --- GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH --- CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH ---
GetObjectW :: proc(h: HANDLE, c: c_int, pv: LPVOID) -> int ---
CreateCompatibleBitmap :: proc(hdc: HDC, cx, cy: c_int) -> HBITMAP ---
BitBlt :: proc(hdc: HDC, x, y, cx, cy: c_int, hdcSrc: HDC, x1, y1: c_int, rop: DWORD) -> BOOL ---
GetDIBits :: proc(hdc: HDC, hbm: HBITMAP, start, cLines: UINT, lpvBits: LPVOID, lpbmi: ^BITMAPINFO, usage: UINT) -> int ---
} }
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF { RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
+12 -1
View File
@@ -291,6 +291,14 @@ foreign kernel32 {
hTemplateFile: HANDLE, hTemplateFile: HANDLE,
) -> HANDLE --- ) -> HANDLE ---
GetFileTime :: proc(
hFile: HANDLE,
lpCreationTime: LPFILETIME,
lpLastAccessTime: LPFILETIME,
lpLastWriteTime: LPFILETIME,
) -> BOOL ---
CompareFileTime :: proc(lpFileTime1: LPFILETIME, lpFileTime2: LPFILETIME) -> LONG ---
FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE --- FindFirstFileW :: proc(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE ---
FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL --- FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL ---
FindClose :: proc(findFile: HANDLE) -> BOOL --- FindClose :: proc(findFile: HANDLE) -> BOOL ---
@@ -354,6 +362,9 @@ foreign kernel32 {
LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID ---
LocalFree :: proc(mem: LPVOID) -> LPVOID --- LocalFree :: proc(mem: LPVOID) -> LPVOID ---
GlobalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID ---
GlobalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID ---
GlobalFree :: proc(mem: LPVOID) -> LPVOID ---
ReadDirectoryChangesW :: proc( ReadDirectoryChangesW :: proc(
hDirectory: HANDLE, hDirectory: HANDLE,
@@ -422,7 +433,7 @@ foreign kernel32 {
GetConsoleWindow :: proc() -> HWND --- GetConsoleWindow :: proc() -> HWND ---
GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL --- GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> BOOL ---
SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL --- SetConsoleScreenBufferSize :: proc(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL ---
SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute : BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL --- SetConsoleWindowInfo :: proc(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: ^SMALL_RECT) -> BOOL ---
GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- GetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL --- SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
+10
View File
@@ -1971,6 +1971,16 @@ BITMAPINFO :: struct {
bmiColors: [1]RGBQUAD, bmiColors: [1]RGBQUAD,
} }
BITMAP :: struct {
bmType: LONG,
bmWidth: LONG,
bmHeight: LONG,
bmWidthBytes: LONG,
bmPlanes: WORD,
bmBitsPixel: WORD,
bmBits: LPVOID,
}
// pixel types // pixel types
PFD_TYPE_RGBA :: 0 PFD_TYPE_RGBA :: 0
PFD_TYPE_COLORINDEX :: 1 PFD_TYPE_COLORINDEX :: 1
+3
View File
@@ -161,6 +161,8 @@ foreign user32 {
MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR --- MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR ---
MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR --- MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR ---
EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL --- EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL ---
EnumWindows :: proc(lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL ---
SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT --- SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT ---
GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT --- GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT ---
@@ -311,6 +313,7 @@ Monitor_From_Flags :: enum DWORD {
} }
Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL
Window_Enum_Proc :: #type proc "stdcall" (HWND, LPARAM) -> BOOL
USER_DEFAULT_SCREEN_DPI :: 96 USER_DEFAULT_SCREEN_DPI :: 96
DPI_AWARENESS_CONTEXT :: distinct HANDLE DPI_AWARENESS_CONTEXT :: distinct HANDLE
+55 -38
View File
@@ -116,26 +116,21 @@ run_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(
} }
run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T) <= size_of(rawptr) { where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
create_and_start_with_poly_data(data, fn, init_context, priority, true) create_and_start_with_poly_data(data, fn, init_context, priority, true)
} }
run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr) {
create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true) create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true)
} }
run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true) create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true)
} }
run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true) create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true)
} }
@@ -178,7 +173,7 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co
} }
create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T) <= size_of(rawptr) { where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T))t.data fn := cast(proc(T))t.data
assert(t.user_index >= 1) assert(t.user_index >= 1)
@@ -188,96 +183,118 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 1 t.user_index = 1
data := data data := data
mem.copy(&t.user_args[0], &data, size_of(data))
mem.copy(&t.user_args[0], &data, size_of(T))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr) {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2))t.data fn := cast(proc(T1, T2))t.data
assert(t.user_index >= 2) assert(t.user_index >= 2)
arg1 := (^T1)(&t.user_args[0])^
arg2 := (^T2)(&t.user_args[1])^ user_args := mem.slice_to_bytes(t.user_args[:])
arg1 := (^T1)(raw_data(user_args))^
arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
fn(arg1, arg2) fn(arg1, arg2)
} }
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 2 t.user_index = 2
arg1, arg2 := arg1, arg2 arg1, arg2 := arg1, arg2
mem.copy(&t.user_args[0], &arg1, size_of(arg1)) user_args := mem.slice_to_bytes(t.user_args[:])
mem.copy(&t.user_args[1], &arg2, size_of(arg2))
n := copy(user_args, mem.ptr_to_bytes(&arg1))
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg2))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3))t.data fn := cast(proc(T1, T2, T3))t.data
assert(t.user_index >= 3) assert(t.user_index >= 3)
arg1 := (^T1)(&t.user_args[0])^
arg2 := (^T2)(&t.user_args[1])^ user_args := mem.slice_to_bytes(t.user_args[:])
arg3 := (^T3)(&t.user_args[2])^ arg1 := (^T1)(raw_data(user_args))^
arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^
fn(arg1, arg2, arg3) fn(arg1, arg2, arg3)
} }
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 3 t.user_index = 3
arg1, arg2, arg3 := arg1, arg2, arg3 arg1, arg2, arg3 := arg1, arg2, arg3
mem.copy(&t.user_args[0], &arg1, size_of(arg1)) user_args := mem.slice_to_bytes(t.user_args[:])
mem.copy(&t.user_args[1], &arg2, size_of(arg2))
mem.copy(&t.user_args[2], &arg3, size_of(arg3)) n := copy(user_args, mem.ptr_to_bytes(&arg1))
n += copy(user_args[n:], mem.ptr_to_bytes(&arg2))
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg3))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
where size_of(T1) <= size_of(rawptr), where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
size_of(T2) <= size_of(rawptr),
size_of(T3) <= size_of(rawptr) {
thread_proc :: proc(t: ^Thread) { thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3, T4))t.data fn := cast(proc(T1, T2, T3, T4))t.data
assert(t.user_index >= 4) assert(t.user_index >= 4)
arg1 := (^T1)(&t.user_args[0])^
arg2 := (^T2)(&t.user_args[1])^ user_args := mem.slice_to_bytes(t.user_args[:])
arg3 := (^T3)(&t.user_args[2])^ arg1 := (^T1)(raw_data(user_args))^
arg4 := (^T4)(&t.user_args[3])^ arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^
arg4 := (^T4)(raw_data(user_args[size_of(T1) + size_of(T2) + size_of(T3):]))^
fn(arg1, arg2, arg3, arg4) fn(arg1, arg2, arg3, arg4)
} }
t := create(thread_proc, priority) t := create(thread_proc, priority)
t.data = rawptr(fn) t.data = rawptr(fn)
t.user_index = 4 t.user_index = 4
arg1, arg2, arg3, arg4 := arg1, arg2, arg3, arg4 arg1, arg2, arg3, arg4 := arg1, arg2, arg3, arg4
mem.copy(&t.user_args[0], &arg1, size_of(arg1)) user_args := mem.slice_to_bytes(t.user_args[:])
mem.copy(&t.user_args[1], &arg2, size_of(arg2))
mem.copy(&t.user_args[2], &arg3, size_of(arg3)) n := copy(user_args, mem.ptr_to_bytes(&arg1))
mem.copy(&t.user_args[3], &arg4, size_of(arg4)) n += copy(user_args[n:], mem.ptr_to_bytes(&arg2))
n += copy(user_args[n:], mem.ptr_to_bytes(&arg3))
_ = copy(user_args[n:], mem.ptr_to_bytes(&arg4))
if self_cleanup { if self_cleanup {
t.flags += {.Self_Cleanup} t.flags += {.Self_Cleanup}
} }
t.init_context = init_context t.init_context = init_context
start(t) start(t)
return t return t
} }
_select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context { _select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context {
ctx, ok := init_context.? ctx, ok := init_context.?
if !ok { if !ok {
+5 -1
View File
@@ -39,6 +39,8 @@ import nvg "vendor:nanovg"
import nvg_gl "vendor:nanovg/gl" import nvg_gl "vendor:nanovg/gl"
import fontstash "vendor:fontstash" import fontstash "vendor:fontstash"
import xlib "vendor:x11/xlib"
_ :: botan_bindings _ :: botan_bindings
_ :: botan_blake2b _ :: botan_blake2b
_ :: keccak _ :: keccak
@@ -76,4 +78,6 @@ _ :: lua_5_4
_ :: nvg _ :: nvg
_ :: nvg_gl _ :: nvg_gl
_ :: fontstash _ :: fontstash
_ :: xlib
+7 -1
View File
@@ -44,7 +44,13 @@ the_basics :: proc() {
fmt.println("\n# the basics") fmt.println("\n# the basics")
{ // The Basics { // The Basics
fmt.println("Hellope")
// os.args holds the path to the current executable and any arguments passed to it.
if len(os.args) == 1 {
fmt.printf("Hellope from %v.\n", os.args[0])
} else {
fmt.printf("%v, %v! from %v.\n", os.args[1], os.args[2], os.args[0])
}
// Lexical elements and literals // Lexical elements and literals
// A comment // A comment
+5 -3
View File
@@ -6123,9 +6123,6 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("calculate global init order"); TIME_SECTION("calculate global init order");
calculate_global_init_order(c); calculate_global_init_order(c);
TIME_SECTION("check test procedures");
check_test_procedures(c);
TIME_SECTION("add type info for type definitions"); TIME_SECTION("add type info for type definitions");
add_type_info_for_type_definitions(c); add_type_info_for_type_definitions(c);
check_merge_queues_into_arrays(c); check_merge_queues_into_arrays(c);
@@ -6136,6 +6133,11 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("generate minimum dependency set"); TIME_SECTION("generate minimum dependency set");
generate_minimum_dependency_set(c, c->info.entry_point); generate_minimum_dependency_set(c, c->info.entry_point);
// NOTE(laytan): has to be ran after generate_minimum_dependency_set,
// because that collects the test procedures.
TIME_SECTION("check test procedures");
check_test_procedures(c);
TIME_SECTION("check bodies have all been checked"); TIME_SECTION("check bodies have all been checked");
check_unchecked_bodies(c); check_unchecked_bodies(c);
+9 -9
View File
@@ -21,8 +21,8 @@
#include "llvm_backend_stmt.cpp" #include "llvm_backend_stmt.cpp"
#include "llvm_backend_proc.cpp" #include "llvm_backend_proc.cpp"
char *get_default_microarchitecture() { String get_default_microarchitecture() {
char * default_march = "generic"; String default_march = str_lit("generic");
if (build_context.metrics.arch == TargetArch_amd64) { if (build_context.metrics.arch == TargetArch_amd64) {
// NOTE(bill): x86-64-v2 is more than enough for everyone // NOTE(bill): x86-64-v2 is more than enough for everyone
// //
@@ -32,9 +32,9 @@ char *get_default_microarchitecture() {
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
if (ODIN_LLVM_MINIMUM_VERSION_12) { if (ODIN_LLVM_MINIMUM_VERSION_12) {
if (build_context.metrics.os == TargetOs_freestanding) { if (build_context.metrics.os == TargetOs_freestanding) {
default_march = "x86-64"; default_march = str_lit("x86-64");
} else { } else {
default_march = "x86-64-v2"; default_march = str_lit("x86-64-v2");
} }
} }
} }
@@ -2509,16 +2509,16 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
code_mode = LLVMCodeModelKernel; code_mode = LLVMCodeModelKernel;
} }
char const *host_cpu_name = LLVMGetHostCPUName(); String host_cpu_name = copy_string(permanent_allocator(), make_string_c(LLVMGetHostCPUName()));
char const *llvm_cpu = get_default_microarchitecture(); String llvm_cpu = get_default_microarchitecture();
char const *llvm_features = ""; char const *llvm_features = "";
if (build_context.microarch.len != 0) { if (build_context.microarch.len != 0) {
if (build_context.microarch == "native") { if (build_context.microarch == "native") {
llvm_cpu = host_cpu_name; llvm_cpu = host_cpu_name;
} else { } else {
llvm_cpu = alloc_cstring(permanent_allocator(), build_context.microarch); llvm_cpu = copy_string(permanent_allocator(), build_context.microarch);
} }
if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) { if (llvm_cpu == host_cpu_name) {
llvm_features = LLVMGetHostCPUFeatures(); llvm_features = LLVMGetHostCPUFeatures();
} }
} }
@@ -2578,7 +2578,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
for (auto const &entry : gen->modules) { for (auto const &entry : gen->modules) {
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine( LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
target, target_triple, llvm_cpu, target, target_triple, (const char *)llvm_cpu.text,
llvm_features, llvm_features,
code_gen_level, code_gen_level,
reloc_mode, reloc_mode,
+140 -134
View File
@@ -199,19 +199,19 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
} }
gb_internal void usage(String argv0) { gb_internal void usage(String argv0) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0)); print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(argv0));
print_usage_line(0, "Usage:"); print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:"); print_usage_line(0, "Commands:");
print_usage_line(1, "build compile directory of .odin files, as an executable."); print_usage_line(1, "build Compiles directory of .odin files, as an executable.");
print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); print_usage_line(1, " One must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse, and type check a directory of .odin files"); print_usage_line(1, "check Parses, and type checks a directory of .odin files.");
print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program"); print_usage_line(1, "strip-semicolon Parses, type checks, and removes unneeded semicolons from the entire program.");
print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package"); print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
print_usage_line(1, "doc generate documentation on a directory of .odin files"); print_usage_line(1, "doc Generates documentation on a directory of .odin files.");
print_usage_line(1, "version print version"); print_usage_line(1, "version Prints version.");
print_usage_line(1, "report print information useful to reporting a bug"); print_usage_line(1, "report Prints information useful to reporting a bug.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(0, "For further details on a command, invoke command help:"); print_usage_line(0, "For further details on a command, invoke command help:");
print_usage_line(1, "e.g. `odin build -help` or `odin help build`"); print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
@@ -1580,45 +1580,45 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
gb_internal void print_show_help(String const arg0, String const &command) { gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0)); print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0));
print_usage_line(0, "Usage:"); print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command)); print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
print_usage_line(0, ""); print_usage_line(0, "");
if (command == "build") { if (command == "build") {
print_usage_line(1, "build Compile directory of .odin files as an executable."); print_usage_line(1, "build Compiles directory of .odin files as an executable.");
print_usage_line(2, "One must contain the program's entry point, all must be in the same package."); print_usage_line(2, "One must contain the program's entry point, all must be in the same package.");
print_usage_line(2, "Use `-file` to build a single file instead."); print_usage_line(2, "Use `-file` to build a single file instead.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin build . # Build package in current directory"); print_usage_line(3, "odin build . Builds package in current directory.");
print_usage_line(3, "odin build <dir> # Build package in <dir>"); print_usage_line(3, "odin build <dir> Builds package in <dir>.");
print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point."); print_usage_line(3, "odin build filename.odin -file Builds single-file package, must contain entry point.");
} else if (command == "run") { } else if (command == "run") {
print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable."); print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable.");
print_usage_line(2, "Append an empty flag and then the args, '-- <args>', to specify args for the output."); print_usage_line(2, "Append an empty flag and then the args, '-- <args>', to specify args for the output.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin run . # Build and run package in current directory"); print_usage_line(3, "odin run . Builds and runs package in current directory.");
print_usage_line(3, "odin run <dir> # Build and run package in <dir>"); print_usage_line(3, "odin run <dir> Builds and runs package in <dir>.");
print_usage_line(3, "odin run filename.odin -file # Build and run single-file package, must contain entry point."); print_usage_line(3, "odin run filename.odin -file Builds and runs single-file package, must contain entry point.");
} else if (command == "check") { } else if (command == "check") {
print_usage_line(1, "check Parse and type check directory of .odin files"); print_usage_line(1, "check Parses and type checks directory of .odin files.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin check . # Type check package in current directory"); print_usage_line(3, "odin check . Type checks package in current directory.");
print_usage_line(3, "odin check <dir> # Type check package in <dir>"); print_usage_line(3, "odin check <dir> Type checks package in <dir>.");
print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point."); print_usage_line(3, "odin check filename.odin -file Type checks single-file package, must contain entry point.");
} else if (command == "test") { } else if (command == "test") {
print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package"); print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
} else if (command == "doc") { } else if (command == "doc") {
print_usage_line(1, "doc generate documentation from a directory of .odin files"); print_usage_line(1, "doc Generates documentation from a directory of .odin files.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "odin doc . # Generate documentation on package in current directory"); print_usage_line(3, "odin doc . Generates documentation on package in current directory.");
print_usage_line(3, "odin doc <dir> # Generate documentation on package in <dir>"); print_usage_line(3, "odin doc <dir> Generates documentation on package in <dir>.");
print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package."); print_usage_line(3, "odin doc filename.odin -file Generates documentation on single-file package.");
} else if (command == "version") { } else if (command == "version") {
print_usage_line(1, "version print version"); print_usage_line(1, "version Prints version.");
} else if (command == "strip-semicolon") { } else if (command == "strip-semicolon") {
print_usage_line(1, "strip-semicolon"); print_usage_line(1, "strip-semicolon");
print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project"); print_usage_line(2, "Parses and type checks .odin file(s) and then removes unneeded semicolons from the entire project.");
} }
bool doc = command == "doc"; bool doc = command == "doc";
@@ -1642,237 +1642,240 @@ gb_internal void print_show_help(String const arg0, String const &command) {
if (doc) { if (doc) {
print_usage_line(1, "-short"); print_usage_line(1, "-short");
print_usage_line(2, "Show shortened documentation for the packages"); print_usage_line(2, "Shows shortened documentation for the packages.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-all-packages"); print_usage_line(1, "-all-packages");
print_usage_line(2, "Generates documentation for all packages used in the current project"); print_usage_line(2, "Generates documentation for all packages used in the current project.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-doc-format"); print_usage_line(1, "-doc-format");
print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)"); print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling).");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-out:<filepath>"); print_usage_line(1, "-out:<filepath>");
print_usage_line(2, "Set the file name of the outputted executable"); print_usage_line(2, "Sets the file name of the outputted executable.");
print_usage_line(2, "Example: -out:foo.exe"); print_usage_line(2, "Example: -out:foo.exe");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-o:<string>"); print_usage_line(1, "-o:<string>");
print_usage_line(2, "Set the optimization mode for compilation"); print_usage_line(2, "Sets the optimization mode for compilation.");
print_usage_line(2, "Available options:");
print_usage_line(3, "-o:none");
print_usage_line(3, "-o:minimal");
print_usage_line(3, "-o:size");
print_usage_line(3, "-o:speed");
if (LB_USE_NEW_PASS_SYSTEM) { if (LB_USE_NEW_PASS_SYSTEM) {
print_usage_line(2, "Accepted values: none, minimal, size, speed, aggressive"); print_usage_line(3, "-o:aggressive");
} else {
print_usage_line(2, "Accepted values: none, minimal, size, speed");
} }
print_usage_line(2, "Example: -o:speed"); print_usage_line(2, "The default is -o:minimal.");
print_usage_line(2, "The default is -o:minimal");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-show-timings"); print_usage_line(1, "-show-timings");
print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds"); print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-show-more-timings"); print_usage_line(1, "-show-more-timings");
print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds"); print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-show-system-calls"); print_usage_line(1, "-show-system-calls");
print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler"); print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-export-timings:<format>"); print_usage_line(1, "-export-timings:<format>");
print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`"); print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`.");
print_usage_line(2, "Available options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "-export-timings:json Export compile time stats to JSON"); print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
print_usage_line(3, "-export-timings:csv Export compile time stats to CSV"); print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-export-timings-file:<filename>"); print_usage_line(1, "-export-timings-file:<filename>");
print_usage_line(2, "Specify the filename for `-export-timings`"); print_usage_line(2, "Specifies the filename for `-export-timings`.");
print_usage_line(2, "Example: -export-timings-file:timings.json"); print_usage_line(2, "Example: -export-timings-file:timings.json");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-thread-count:<integer>"); print_usage_line(1, "-thread-count:<integer>");
print_usage_line(2, "Override the number of threads the compiler will use to compile with"); print_usage_line(2, "Overrides the number of threads the compiler will use to compile with.");
print_usage_line(2, "Example: -thread-count:2"); print_usage_line(2, "Example: -thread-count:2");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check_only) { if (check_only) {
print_usage_line(1, "-show-unused"); print_usage_line(1, "-show-unused");
print_usage_line(2, "Shows unused package declarations within the current project"); print_usage_line(2, "Shows unused package declarations within the current project.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-show-unused-with-location"); print_usage_line(1, "-show-unused-with-location");
print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location"); print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-keep-temp-files"); print_usage_line(1, "-keep-temp-files");
print_usage_line(2, "Keeps the temporary files generated during compilation"); print_usage_line(2, "Keeps the temporary files generated during compilation.");
print_usage_line(0, ""); print_usage_line(0, "");
} else if (strip_semicolon) { } else if (strip_semicolon) {
print_usage_line(1, "-keep-temp-files"); print_usage_line(1, "-keep-temp-files");
print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files"); print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-collection:<name>=<filepath>"); print_usage_line(1, "-collection:<name>=<filepath>");
print_usage_line(2, "Defines a library collection used for imports"); print_usage_line(2, "Defines a library collection used for imports.");
print_usage_line(2, "Example: -collection:shared=dir/to/shared"); print_usage_line(2, "Example: -collection:shared=dir/to/shared");
print_usage_line(2, "Usage in Code:"); print_usage_line(2, "Usage in Code:");
print_usage_line(3, "import \"shared:foo\""); print_usage_line(3, "import \"shared:foo\"");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-define:<name>=<value>"); print_usage_line(1, "-define:<name>=<value>");
print_usage_line(2, "Defines a scalar boolean, integer or string as global constant"); print_usage_line(2, "Defines a scalar boolean, integer or string as global constant.");
print_usage_line(2, "Example: -define:SPAM=123"); print_usage_line(2, "Example: -define:SPAM=123");
print_usage_line(2, "To use: #config(SPAM, default_value)"); print_usage_line(2, "Usage in code:");
print_usage_line(3, "#config(SPAM, default_value)");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (build) { if (build) {
print_usage_line(1, "-build-mode:<mode>"); print_usage_line(1, "-build-mode:<mode>");
print_usage_line(2, "Sets the build mode"); print_usage_line(2, "Sets the build mode.");
print_usage_line(2, "Available options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "-build-mode:exe Build as an executable"); print_usage_line(3, "-build-mode:exe Builds as an executable.");
print_usage_line(3, "-build-mode:dll Build as a dynamically linked library"); print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library.");
print_usage_line(3, "-build-mode:shared Build as a dynamically linked library"); print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library.");
print_usage_line(3, "-build-mode:obj Build as an object file"); print_usage_line(3, "-build-mode:obj Builds as an object file.");
print_usage_line(3, "-build-mode:object Build as an object file"); print_usage_line(3, "-build-mode:object Builds as an object file.");
print_usage_line(3, "-build-mode:assembly Build as an assembly file"); print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
print_usage_line(3, "-build-mode:assembler Build as an assembly file"); print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
print_usage_line(3, "-build-mode:asm Build as an assembly file"); print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file"); print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file"); print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-target:<string>"); print_usage_line(1, "-target:<string>");
print_usage_line(2, "Sets the target for the executable to be built in"); print_usage_line(2, "Sets the target for the executable to be built in.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-debug"); print_usage_line(1, "-debug");
print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'"); print_usage_line(2, "Enables debug information, and defines the global constant ODIN_DEBUG to be 'true'.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-disable-assert"); print_usage_line(1, "-disable-assert");
print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'"); print_usage_line(2, "Disables the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-no-bounds-check"); print_usage_line(1, "-no-bounds-check");
print_usage_line(2, "Disables bounds checking program wide"); print_usage_line(2, "Disables bounds checking program wide.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-no-crt"); print_usage_line(1, "-no-crt");
print_usage_line(2, "Disables automatic linking with the C Run Time"); print_usage_line(2, "Disables automatic linking with the C Run Time.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-no-thread-local"); print_usage_line(1, "-no-thread-local");
print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded"); print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-lld"); print_usage_line(1, "-lld");
print_usage_line(2, "Use the LLD linker rather than the default"); print_usage_line(2, "Uses the LLD linker rather than the default.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-use-separate-modules"); print_usage_line(1, "-use-separate-modules");
print_usage_line(1, "[EXPERIMENTAL]"); print_usage_line(1, "[EXPERIMENTAL]");
print_usage_line(2, "The backend generates multiple build units which are then linked together"); print_usage_line(2, "The backend generates multiple build units which are then linked together.");
print_usage_line(2, "Normally, a single build unit is generated for a standard project"); print_usage_line(2, "Normally, a single build unit is generated for a standard project.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-no-threaded-checker"); print_usage_line(1, "-no-threaded-checker");
print_usage_line(2, "Disabled multithreading in the semantic checker stage"); print_usage_line(2, "Disables multithreading in the semantic checker stage.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-vet"); print_usage_line(1, "-vet");
print_usage_line(2, "Do extra checks on the code"); print_usage_line(2, "Does extra checks on the code.");
print_usage_line(2, "Extra checks include:"); print_usage_line(2, "Extra checks include:");
print_usage_line(2, "-vet-unused"); print_usage_line(3, "-vet-unused");
print_usage_line(2, "-vet-shadowing"); print_usage_line(3, "-vet-shadowing");
print_usage_line(2, "-vet-using-stmt"); print_usage_line(3, "-vet-using-stmt");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-unused"); print_usage_line(1, "-vet-unused");
print_usage_line(2, "Checks for unused declarations"); print_usage_line(2, "Checks for unused declarations.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-shadowing"); print_usage_line(1, "-vet-shadowing");
print_usage_line(2, "Checks for variable shadowing within procedures"); print_usage_line(2, "Checks for variable shadowing within procedures.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-using-stmt"); print_usage_line(1, "-vet-using-stmt");
print_usage_line(2, "Checks for the use of 'using' as a statement"); print_usage_line(2, "Checks for the use of 'using' as a statement.");
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-using-param"); print_usage_line(1, "-vet-using-param");
print_usage_line(2, "Checks for the use of 'using' on procedure parameters"); print_usage_line(2, "Checks for the use of 'using' on procedure parameters.");
print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-style"); print_usage_line(1, "-vet-style");
print_usage_line(2, "Errs on missing trailing commas followed by a newline"); print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
print_usage_line(2, "Errs on deprecated syntax"); print_usage_line(2, "Errs on deprecated syntax.");
print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)"); print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style).");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-vet-semicolon"); print_usage_line(1, "-vet-semicolon");
print_usage_line(2, "Errs on unneeded semicolons"); print_usage_line(2, "Errs on unneeded semicolons.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-ignore-unknown-attributes"); print_usage_line(1, "-ignore-unknown-attributes");
print_usage_line(2, "Ignores unknown attributes"); print_usage_line(2, "Ignores unknown attributes.");
print_usage_line(2, "This can be used with metaprogramming tools"); print_usage_line(2, "This can be used with metaprogramming tools.");
print_usage_line(0, ""); print_usage_line(0, "");
if (command != "test") { if (command != "test") {
print_usage_line(1, "-no-entry-point"); print_usage_line(1, "-no-entry-point");
print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)"); print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure).");
print_usage_line(0, ""); print_usage_line(0, "");
} }
} }
if (test_only) { if (test_only) {
print_usage_line(1, "-test-name:<string>"); print_usage_line(1, "-test-name:<string>");
print_usage_line(2, "Run specific test only by name"); print_usage_line(2, "Runs specific test only by name.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-minimum-os-version:<string>"); print_usage_line(1, "-minimum-os-version:<string>");
print_usage_line(2, "Sets the minimum OS version targeted by the application"); print_usage_line(2, "Sets the minimum OS version targeted by the application.");
print_usage_line(2, "e.g. -minimum-os-version:12.0.0"); print_usage_line(2, "Example: -minimum-os-version:12.0.0");
print_usage_line(2, "(Only used when target is Darwin)"); print_usage_line(2, "(Only used when target is Darwin.)");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-extra-linker-flags:<string>"); print_usage_line(1, "-extra-linker-flags:<string>");
print_usage_line(2, "Adds extra linker specific flags in a string"); print_usage_line(2, "Adds extra linker specific flags in a string.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-extra-assembler-flags:<string>"); print_usage_line(1, "-extra-assembler-flags:<string>");
print_usage_line(2, "Adds extra assembler specific flags in a string"); print_usage_line(2, "Adds extra assembler specific flags in a string.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-microarch:<string>"); print_usage_line(1, "-microarch:<string>");
print_usage_line(2, "Specifies the specific micro-architecture for the build in a string"); print_usage_line(2, "Specifies the specific micro-architecture for the build in a string.");
print_usage_line(2, "Examples:"); print_usage_line(2, "Examples:");
print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:sandybridge");
print_usage_line(3, "-microarch:native"); print_usage_line(3, "-microarch:native");
@@ -1880,74 +1883,77 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-reloc-mode:<string>"); print_usage_line(1, "-reloc-mode:<string>");
print_usage_line(2, "Specifies the reloc mode"); print_usage_line(2, "Specifies the reloc mode.");
print_usage_line(2, "Options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "default"); print_usage_line(3, "-reloc-mode:default");
print_usage_line(3, "static"); print_usage_line(3, "-reloc-mode:static");
print_usage_line(3, "pic"); print_usage_line(3, "-reloc-mode:pic");
print_usage_line(3, "dynamic-no-pic"); print_usage_line(3, "-reloc-mode:dynamic-no-pic");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-disable-red-zone"); print_usage_line(1, "-disable-red-zone");
print_usage_line(2, "Disable red zone on a supported freestanding target"); print_usage_line(2, "Disables red zone on a supported freestanding target.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-dynamic-map-calls"); print_usage_line(1, "-dynamic-map-calls");
print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution"); print_usage_line(2, "Uses dynamic map calls to minimize code generation at the cost of runtime execution.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (check) { if (check) {
print_usage_line(1, "-disallow-do"); print_usage_line(1, "-disallow-do");
print_usage_line(2, "Disallows the 'do' keyword in the project"); print_usage_line(2, "Disallows the 'do' keyword in the project.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-default-to-nil-allocator"); print_usage_line(1, "-default-to-nil-allocator");
print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing"); print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-strict-style"); print_usage_line(1, "-strict-style");
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons"); print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
print_usage_line(2, "Errs on missing trailing commas followed by a newline"); print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
print_usage_line(2, "Errs on deprecated syntax"); print_usage_line(2, "Errs on deprecated syntax.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-ignore-warnings"); print_usage_line(1, "-ignore-warnings");
print_usage_line(2, "Ignores warning messages"); print_usage_line(2, "Ignores warning messages.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-warnings-as-errors"); print_usage_line(1, "-warnings-as-errors");
print_usage_line(2, "Treats warning messages as error messages"); print_usage_line(2, "Treats warning messages as error messages.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-terse-errors"); print_usage_line(1, "-terse-errors");
print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line"); print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-error-pos-style:<string>"); print_usage_line(1, "-error-pos-style:<string>");
print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)"); print_usage_line(2, "Available options:");
print_usage_line(2, "'odin' file/path(45:3)"); print_usage_line(3, "-error-pos-style:unix file/path:45:3:");
print_usage_line(2, "'unix' file/path:45:3:"); print_usage_line(3, "-error-pos-style:odin file/path(45:3)");
print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-max-error-count:<integer>"); print_usage_line(1, "-max-error-count:<integer>");
print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates"); print_usage_line(2, "Sets the maximum number of errors that can be displayed before the compiler terminates.");
print_usage_line(2, "Must be an integer >0"); print_usage_line(2, "Must be an integer >0.");
print_usage_line(2, "If not set, the default max error count is %d", DEFAULT_MAX_ERROR_COLLECTOR_COUNT); print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-foreign-error-procedures"); print_usage_line(1, "-foreign-error-procedures");
print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit"); print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
if (run_or_build) { if (run_or_build) {
print_usage_line(1, "-sanitize:<string>"); print_usage_line(1, "-sanitize:<string>");
print_usage_line(1, "Enables sanitization analysis"); print_usage_line(2, "Enables sanitization analysis.");
print_usage_line(1, "Options are 'address', 'memory', and 'thread'"); print_usage_line(2, "Available options:");
print_usage_line(1, "NOTE: This flag can be used multiple times"); print_usage_line(3, "-sanitize:address");
print_usage_line(3, "-sanitize:memory");
print_usage_line(3, "-sanitize:thread");
print_usage_line(2, "NOTE: This flag can be used multiple times.");
print_usage_line(0, ""); print_usage_line(0, "");
} }
@@ -1956,27 +1962,27 @@ gb_internal void print_show_help(String const arg0, String const &command) {
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
print_usage_line(1, "-ignore-vs-search"); print_usage_line(1, "-ignore-vs-search");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Ignores the Visual Studio search for library paths"); print_usage_line(2, "Ignores the Visual Studio search for library paths.");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-resource:<filepath>"); print_usage_line(1, "-resource:<filepath>");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Defines the resource file for the executable"); print_usage_line(2, "Defines the resource file for the executable.");
print_usage_line(2, "Example: -resource:path/to/file.rc"); print_usage_line(2, "Example: -resource:path/to/file.rc");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-pdb-name:<filepath>"); print_usage_line(1, "-pdb-name:<filepath>");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Defines the generated PDB name when -debug is enabled"); print_usage_line(2, "Defines the generated PDB name when -debug is enabled.");
print_usage_line(2, "Example: -pdb-name:different.pdb"); print_usage_line(2, "Example: -pdb-name:different.pdb");
print_usage_line(0, ""); print_usage_line(0, "");
print_usage_line(1, "-subsystem:<option>"); print_usage_line(1, "-subsystem:<option>");
print_usage_line(2, "[Windows only]"); print_usage_line(2, "[Windows only]");
print_usage_line(2, "Defines the subsystem for the application"); print_usage_line(2, "Defines the subsystem for the application.");
print_usage_line(2, "Available options:"); print_usage_line(2, "Available options:");
print_usage_line(3, "console"); print_usage_line(3, "-subsystem:console");
print_usage_line(3, "windows"); print_usage_line(3, "-subsystem:windows");
print_usage_line(0, ""); print_usage_line(0, "");
#endif #endif
@@ -2538,6 +2544,7 @@ int main(int arg_count, char const **arg_ptr) {
} }
} }
String default_march = get_default_microarchitecture();
if (print_microarch_list) { if (print_microarch_list) {
if (build_context.microarch != "?") { if (build_context.microarch != "?") {
gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch)); gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch));
@@ -2548,8 +2555,6 @@ int main(int arg_count, char const **arg_ptr) {
String march_list = target_microarch_list[build_context.metrics.arch]; String march_list = target_microarch_list[build_context.metrics.arch];
String_Iterator it = {march_list, 0}; String_Iterator it = {march_list, 0};
String default_march = make_string_c(get_default_microarchitecture());
for (;;) { for (;;) {
String str = string_split_iterator(&it, ','); String str = string_split_iterator(&it, ',');
if (str == "") break; if (str == "") break;
@@ -2568,6 +2573,7 @@ int main(int arg_count, char const **arg_ptr) {
} }
if (build_context.show_debug_messages) { if (build_context.show_debug_messages) {
debugf("Selected microarch: %.*s\n", LIT(default_march));
for_array(i, build_context.build_paths) { for_array(i, build_context.build_paths) {
String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path));
+26 -3
View File
@@ -1,9 +1,26 @@
ODIN=../../odin ODIN=../../odin
PYTHON=$(shell which python3) PYTHON=$(shell which python3)
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ all: c_libc_test \
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test match_test c_libc_test net_test \ compress_test \
fmt_test crypto_test \
download_test_assets \
encoding_test \
filepath_test \
fmt_test \
hash_test \
i18n_test \
image_test \
linalg_glsl_math_test \
match_test \
math_test \
net_test \
noise_test \
os_exit_test \
reflect_test \
slice_test \
strings_test \
thread_test
download_test_assets: download_test_assets:
$(PYTHON) download_assets.py $(PYTHON) download_assets.py
@@ -44,6 +61,9 @@ filepath_test:
reflect_test: reflect_test:
$(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect $(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect
slice_test:
$(ODIN) run slice/test_core_slice.odin -file -out:test_core_slice
os_exit_test: os_exit_test:
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0 $(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
@@ -61,3 +81,6 @@ net_test:
fmt_test: fmt_test:
$(ODIN) run fmt -out:test_core_fmt $(ODIN) run fmt -out:test_core_fmt
thread_test:
$(ODIN) run thread -out:test_core_thread
+10
View File
@@ -66,6 +66,11 @@ echo Running core:reflect tests
echo --- echo ---
%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b %PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b
echo ---
echo Running core:slice tests
echo ---
%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe || exit /b
echo --- echo ---
echo Running core:text/i18n tests echo Running core:text/i18n tests
echo --- echo ---
@@ -85,3 +90,8 @@ echo ---
echo Running core:container tests echo Running core:container tests
echo --- echo ---
%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b %PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b
echo ---
echo Running core:thread tests
echo ---
%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b
+63
View File
@@ -1,6 +1,7 @@
package test_core_slice package test_core_slice
import "core:slice" import "core:slice"
import "core:strings"
import "core:testing" import "core:testing"
import "core:fmt" import "core:fmt"
import "core:os" import "core:os"
@@ -30,6 +31,7 @@ when ODIN_TEST {
main :: proc() { main :: proc() {
t := testing.T{} t := testing.T{}
test_sort_with_indices(&t) test_sort_with_indices(&t)
test_binary_search(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 { if TEST_fail > 0 {
@@ -180,3 +182,64 @@ test_sort_by_indices :: proc(t: ^testing.T) {
} }
} }
} }
@test
test_binary_search :: proc(t: ^testing.T) {
builder := strings.Builder{}
defer strings.builder_destroy(&builder)
test_search :: proc(t: ^testing.T, b: ^strings.Builder, s: []i32, v: i32) -> (int, bool) {
log(t, fmt.sbprintf(b, "Searching for %v in %v", v, s))
strings.builder_reset(b)
index, found := slice.binary_search(s, v)
log(t, fmt.sbprintf(b, "index: %v, found: %v", index, found))
strings.builder_reset(b )
return index, found
}
index: int
found: bool
s := []i32{0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}
index, found = test_search(t, &builder, s, 13)
expect(t, index == 9, "Expected index to be 9.")
expect(t, found == true, "Expected found to be true.")
index, found = test_search(t, &builder, s, 4)
expect(t, index == 7, "Expected index to be 7.")
expect(t, found == false, "Expected found to be false.")
index, found = test_search(t, &builder, s, 100)
expect(t, index == 13, "Expected index to be 13.")
expect(t, found == false, "Expected found to be false.")
index, found = test_search(t, &builder, s, 1)
expect(t, index >= 1 && index <= 4, "Expected index to be 1, 2, 3, or 4.")
expect(t, found == true, "Expected found to be true.")
index, found = test_search(t, &builder, s, -1)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == false, "Expected found to be false.")
a := []i32{}
index, found = test_search(t, &builder, a, 13)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == false, "Expected found to be false.")
b := []i32{1}
index, found = test_search(t, &builder, b, 13)
expect(t, index == 1, "Expected index to be 1.")
expect(t, found == false, "Expected found to be false.")
index, found = test_search(t, &builder, b, 1)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == true, "Expected found to be true.")
index, found = test_search(t, &builder, b, 0)
expect(t, index == 0, "Expected index to be 0.")
expect(t, found == false, "Expected found to be false.")
}
+84
View File
@@ -0,0 +1,84 @@
package test_core_thread
import "core:testing"
import "core:thread"
import "core:fmt"
import "core:os"
TEST_count := 0
TEST_fail := 0
t := &testing.T{}
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
poly_data_test(t)
if TEST_fail > 0 {
os.exit(1)
}
}
@(test)
poly_data_test :: proc(_t: ^testing.T) {
MAX :: size_of(rawptr) * thread.MAX_USER_ARGUMENTS
@static poly_data_test_t: ^testing.T
poly_data_test_t = _t
b: [MAX]byte = 8
t1 := thread.create_and_start_with_poly_data(b, proc(b: [MAX]byte) {
b_expect: [MAX]byte = 8
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
})
defer free(t1)
b1: [3]uintptr = 1
b2: [MAX / 2]byte = 3
t2 := thread.create_and_start_with_poly_data2(b1, b2, proc(b: [3]uintptr, b2: [MAX / 2]byte) {
b_expect: [3]uintptr = 1
b2_expect: [MAX / 2]byte = 3
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct")
})
defer free(t2)
t3 := thread.create_and_start_with_poly_data3(b1, b2, uintptr(333), proc(b: [3]uintptr, b2: [MAX / 2]byte, b3: uintptr) {
b_expect: [3]uintptr = 1
b2_expect: [MAX / 2]byte = 3
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
expect(poly_data_test_t, b2 == b2_expect, "thread poly data not correct")
expect(poly_data_test_t, b3 == 333, "thread poly data not correct")
})
defer free(t3)
t4 := thread.create_and_start_with_poly_data4(uintptr(111), b1, uintptr(333), u8(5), proc(n: uintptr, b: [3]uintptr, n2: uintptr, n4: u8) {
b_expect: [3]uintptr = 1
expect(poly_data_test_t, n == 111, "thread poly data not correct")
expect(poly_data_test_t, b == b_expect, "thread poly data not correct")
expect(poly_data_test_t, n2 == 333, "thread poly data not correct")
expect(poly_data_test_t, n4 == 5, "thread poly data not correct")
})
defer free(t4)
thread.join_multiple(t1, t2, t3, t4)
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+8 -21
View File
@@ -16,23 +16,9 @@ when ODIN_OS == .Windows {
} }
} else when ODIN_OS == .Linux { } else when ODIN_OS == .Linux {
when RAYGUI_SHARED { when RAYGUI_SHARED {
// Note(bumbread): can't panic here, because the users might be expecting to foreign import lib "linux/libraygui.so"
// only use raylib. Let's have them get the error at link-time instead..
//#panic("Cannot link libraygui.so: not in the vendor collection")
// Note(bumbread): unless we import something the rest of the bindings will
// make a compile-time error. This is a bit ugly for now, but in the future
// raygui probably needs to be in a separate package.
foreign import lib {"_"}
} else { } else {
// #panic("Cannot link libraygui.a: not in the vendor collection") foreign import lib "linux/libraygui.a"
// TODO(bumbread): apparently this one was missing. This might need
// to get rebuilt for linux
// foreign import lib {
// "linux/libraygui.a",
// // "system:dl",
// // "system:pthread",
// }
foreign import lib {"_"}
} }
} else when ODIN_OS == .Darwin { } else when ODIN_OS == .Darwin {
when ODIN_ARCH == .arm64 { when ODIN_ARCH == .arm64 {
@@ -238,6 +224,7 @@ SCROLLBAR_RIGHT_SIDE :: 1
@(default_calling_convention="c") @(default_calling_convention="c")
foreign lib { foreign lib {
@(link_name="raylib_version") version: cstring
// Global gui state control functions // Global gui state control functions
GuiEnable :: proc() --- // Enable gui controls (global state) GuiEnable :: proc() --- // Enable gui controls (global state)
@@ -293,17 +280,17 @@ foreign lib {
// Basic controls set // Basic controls set
GuiLabel :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Label control, shows text GuiLabel :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Label control, shows text
GuiButton :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Button control, returns true when clicked GuiButton :: proc(bounds: Rectangle, text: cstring) -> bool --- // Button control, returns true when clicked
GuiLabelButton :: proc(bounds: Rectangle, text: cstring) -> c.int --- // Label button control, show true when clicked GuiLabelButton :: proc(bounds: Rectangle, text: cstring) -> bool --- // Label button control, show true when clicked
GuiToggle :: proc(bounds: Rectangle, text: cstring, active: ^bool) -> c.int --- // Toggle Button control, returns true when active GuiToggle :: proc(bounds: Rectangle, text: cstring, active: ^bool) -> c.int --- // Toggle Button control, returns true when active
GuiToggleGroup :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Toggle Group control, returns active toggle index GuiToggleGroup :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Toggle Group control, returns active toggle index
GuiCheckBox :: proc(bounds: Rectangle, text: cstring, checked: ^bool) -> c.int --- // Check Box control, returns true when active GuiCheckBox :: proc(bounds: Rectangle, text: cstring, checked: ^bool) -> bool --- // Check Box control, returns true when active
GuiComboBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Combo Box control, returns selected item index GuiComboBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int) -> c.int --- // Combo Box control, returns selected item index
GuiDropdownBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int, editMode: bool) -> c.int --- // Dropdown Box control, returns selected item GuiDropdownBox :: proc(bounds: Rectangle, text: cstring, active: ^c.int, editMode: bool) -> bool --- // Dropdown Box control, returns selected item
GuiSpinner :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Spinner control, returns selected value GuiSpinner :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Spinner control, returns selected value
GuiValueBox :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Value Box control, updates input text with numbers GuiValueBox :: proc(bounds: Rectangle, text: cstring, value: ^c.int, minValue, maxValue: c.int, editMode: bool) -> c.int --- // Value Box control, updates input text with numbers
GuiTextBox :: proc(bounds: Rectangle, text: cstring, textSize: c.int, editMode: bool) -> c.int --- // Text Box control, updates input text GuiTextBox :: proc(bounds: Rectangle, text: cstring, textSize: c.int, editMode: bool) -> bool --- // Text Box control, updates input text
GuiSlider :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider control, returns selected value GuiSlider :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider control, returns selected value
GuiSliderBar :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider Bar control, returns selected value GuiSliderBar :: proc(bounds: Rectangle, textLeft: cstring, textRight: cstring, value: ^f32, minValue: f32, maxValue: f32) -> c.int --- // Slider Bar control, returns selected value
+8 -8
View File
@@ -163,21 +163,21 @@ PixelFormatEnum :: enum u32 {
ABGR32 = ABGR8888 when ODIN_ENDIAN == .Big else RGBA8888, ABGR32 = ABGR8888 when ODIN_ENDIAN == .Big else RGBA8888,
YV12 = /**< Planar mode: Y + V + U (3 planes) */ YV12 = /**< Planar mode: Y + V + U (3 planes) */
'Y'<<24 | 'V'<<16 | '1'<<8 | '2'<<0, 'Y'<<0 | 'V'<<8 | '1'<<16 | '2'<<24,
IYUV = /**< Planar mode: Y + U + V (3 planes) */ IYUV = /**< Planar mode: Y + U + V (3 planes) */
'I'<<24 | 'Y'<<16 | 'U'<<8 | 'V'<<0, 'I'<<0 | 'Y'<<8 | 'U'<<16 | 'V'<<24,
YUY2 = /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */ YUY2 = /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */
'Y'<<24 | 'U'<<16 | 'Y'<<8 | '2'<<0, 'Y'<<0 | 'U'<<8 | 'Y'<<16 | '2'<<24,
UYVY = /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */ UYVY = /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
'U'<<24 | 'Y'<<16 | 'V'<<8 | 'Y'<<0, 'U'<<0 | 'Y'<<8 | 'V'<<16 | 'Y'<<24,
YVYU = /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */ YVYU = /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
'Y'<<24 | 'V'<<16 | 'Y'<<8 | 'U'<<0, 'Y'<<0 | 'V'<<8 | 'Y'<<16 | 'U'<<24,
NV12 = /**< Planar mode: Y + U/V interleaved (2 planes) */ NV12 = /**< Planar mode: Y + U/V interleaved (2 planes) */
'N'<<24 | 'V'<<16 | '1'<<8 | '2'<<0, 'N'<<0 | 'V'<<8 | '1'<<16 | '2'<<24,
NV21 = /**< Planar mode: Y + V/U interleaved (2 planes) */ NV21 = /**< Planar mode: Y + V/U interleaved (2 planes) */
'N'<<24 | 'V'<<16 | '2'<<8 | '1'<<0, 'N'<<0 | 'V'<<8 | '2'<<16 | '1'<<24,
EXTERNAL_OES = /**< Android video texture format */ EXTERNAL_OES = /**< Android video texture format */
'O'<<24 | 'E'<<16 | 'S'<<8 | ' '<<0, 'O'<<0 | 'E'<<8 | 'S'<<16 | ' '<<24,
} }
+4
View File
@@ -0,0 +1,4 @@
# TODO(flysand): Remove this file.
*.i
+651
View File
@@ -0,0 +1,651 @@
//+build linux, freebsd, openbsd
package xlib
// Special values for many types. Most of these constants
// aren't attached to a specific type.
None :: 0
ParentRelative :: 1
CopyFromParent :: 0
PointerWindow :: 0
InputFocus :: 1
PointerRoot :: 1
AnyPropertyType :: 0
AnyKey :: 0
AnyButton :: 0
AllTemporary :: 0
CurrentTime :: 0
NoSymbol :: 0
XA_WM_CLASS :: Atom(67)
XA_WM_CLIENT_MACHINE :: Atom(36)
XA_WM_COMMAND :: Atom(34)
XA_WM_HINTS :: Atom(35)
XA_WM_ICON_NAME :: Atom(37)
XA_WM_ICON_SIZE :: Atom(38)
XA_WM_NAME :: Atom(39)
XA_WM_NORMAL_HINTS :: Atom(40)
XA_WM_SIZE_HINTS :: Atom(41)
XA_WM_TRANSIENT_FOR :: Atom(68)
XA_WM_ZOOM_HINTS :: Atom(42)
// NOTE(flysand): Some implementations return Status as enum, other return it
// as an integer. I will make it a status.
Status :: enum i32 {
Success = 0,
BadRequest = 1,
BadValue = 2,
BadWindow = 3,
BadPixmap = 4,
BadAtom = 5,
BadCursor = 6,
BadFont = 7,
BadMatch = 8,
BadDrawable = 9,
BadAccess = 10,
BadAlloc = 11,
BadColor = 12,
BadGC = 13,
BadIDChoice = 14,
BadName = 15,
BadLength = 16,
BadImplementation = 17,
FirstExtensionError = 128,
LastExtensionError = 255,
}
ByteOrder :: enum i32 {
LSBFirst = 0,
MSBFirst = 1,
}
Gravity :: enum i32 {
ForgetGravity = 0,
UnmapGravity = 0,
NorthWestGravity = 1,
NorthGravity = 2,
NorthEastGravity = 3,
WestGravity = 4,
CenterGravity = 5,
EastGravity = 6,
SouthWestGravity = 7,
SouthGravity = 8,
SouthEastGravity = 9,
StaticGravity = 10,
}
BackingStore :: enum i32 {
NotUseful = 0,
WhenMapped = 1,
Always = 2,
}
MouseButton :: enum i32 {
Button1 = 1,
Button2 = 2,
Button3 = 3,
Button4 = 4,
Button5 = 5,
}
EventMask :: bit_set[EventMaskBits; int]
EventMaskBits :: enum i32 {
KeyPress = 0,
KeyRelease = 1,
ButtonPress = 2,
ButtonRelease = 3,
EnterWindow = 4,
LeaveWindow = 5,
PointerMotion = 6,
PointerMotionHint = 7,
Button1Motion = 8,
Button2Motion = 9,
Button3Motion = 10,
Button4Motion = 11,
Button5Motion = 12,
ButtonMotion = 13,
KeymapState = 14,
Exposure = 15,
VisibilityChange = 16,
StructureNotify = 17,
ResizeRedirect = 18,
SubstructureNotify = 19,
SubstructureRedirect = 20,
FocusChange = 21,
PropertyChange = 22,
ColormapChange = 23,
OwnerGrabButton = 24,
}
EventType :: enum i32 {
KeyPress = 2,
KeyRelease = 3,
ButtonPress = 4,
ButtonRelease = 5,
MotionNotify = 6,
EnterNotify = 7,
LeaveNotify = 8,
FocusIn = 9,
FocusOut = 10,
KeymapNotify = 11,
Expose = 12,
GraphicsExpose = 13,
NoExpose = 14,
VisibilityNotify = 15,
CreateNotify = 16,
DestroyNotify = 17,
UnmapNotify = 18,
MapNotify = 19,
MapRequest = 20,
ReparentNotify = 21,
ConfigureNotify = 22,
ConfigureRequest = 23,
GravityNotify = 24,
ResizeRequest = 25,
CirculateNotify = 26,
CirculateRequest = 27,
PropertyNotify = 28,
SelectionClear = 29,
SelectionRequest = 30,
SelectionNotify = 31,
ColormapNotify = 32,
ClientMessage = 33,
MappingNotify = 34,
GenericEvent = 35,
}
InputMask :: bit_set[InputMaskBits; i32]
InputMaskBits :: enum {
ShiftMask = 0,
LockMask = 1,
ControlMask = 2,
Mod1Mask = 3,
Mod2Mask = 4,
Mod3Mask = 5,
Mod4Mask = 6,
Mod5Mask = 7,
Button1Mask = 8,
Button2Mask = 9,
Button3Mask = 10,
Button4Mask = 11,
Button5Mask = 12,
AnyModifier = 15,
}
NotifyMode :: enum i32 {
NotifyNormal = 0,
NotifyGrab = 1,
NotifyUngrab = 2,
NotifyWhileGrabbed = 3,
}
NotifyDetail :: enum i32 {
NotifyAncestor = 0,
NotifyVirtual = 1,
NotifyInferior = 2,
NotifyNonlinear = 3,
NotifyNonlinearVirtual = 4,
NotifyPointer = 5,
NotifyPointerRoot = 6,
NotifyDetailNone = 7,
}
MappingRequest :: enum i32 {
MappingModifier = 0,
MappingKeyboard = 1,
MappingPointer = 2,
}
VisibilityState :: enum i32 {
VisibilityUnobscured = 0,
VisibilityPartiallyObscured = 1,
VisibilityFullyObscured = 2,
}
ColormapState :: enum i32 {
ColormapUninstalled = 0,
ColormapInstalled = 1,
}
PropertyState :: enum i32 {
PropertyNewValue = 0,
PropertyDelete = 1,
}
CloseMode :: enum i32 {
DestroyAll = 0,
RetainPermanent = 1,
RetainTemporary = 2,
}
EventQueueMode :: enum i32 {
QueuedAlready = 0,
QueuedAfterReading = 1,
QueuedAfterFlush = 2,
}
WindowAttributeMask :: bit_set[WindowAttributeMaskBits; int]
WindowAttributeMaskBits :: enum {
CWBackPixmap = 0,
CWBackPixel = 1,
CWBorderPixmap = 2,
CWBorderPixel = 3,
CWBitGravity = 4,
CWWinGravity = 5,
CWBackingStore = 6,
CWBackingPlanes = 7,
CWBackingPixel = 8,
CWOverrideRedirect = 9,
CWSaveUnder = 10,
CWEventMask = 11,
CWDontPropagate = 12,
CWColormap = 13,
CWCursor = 14,
}
WindowClass :: enum i32 {
CopyFromParent = 0,
InputOutput = 1,
InputOnly = 2,
}
WindowChangesMask :: bit_set[WindowChangesMaskBits; i32]
WindowChangesMaskBits :: enum {
CWX = 0,
CWY = 1,
CWWidth = 2,
CWHeight = 3,
CWBorderWidth = 4,
CWSibling = 5,
CWStackMode = 6,
}
WindowStacking :: enum i32 {
Above = 0,
Below = 1,
TopIf = 2,
BottomIf = 3,
Opposite = 4,
}
CirculationDirection :: enum i32 {
RaiseLowest = 0,
LowerHighest = 1,
}
CirculationRequest :: enum i32 {
PlaceOnTop = 0,
PlaceOnBottom = 1,
}
WindowMapState :: enum i32 {
IsUnmapped = 0,
IsUnviewable = 1,
IsViewable = 2,
}
KeyMask :: enum u32 {
ShiftMask = 0,
LockMask = 1,
ControlMask = 2,
Mod1Mask = 3,
Mod2Mask = 4,
Mod3Mask = 5,
Mod4Mask = 6,
Mod5Mask = 7,
}
CursorShape :: enum u32 {
XC_X_cursor = 0,
XC_arrow = 2,
XC_based_arrow_down = 4,
XC_based_arrow_up = 6,
XC_boat = 8,
XC_bogosity = 10,
XC_bottom_left_corner = 12,
XC_bottom_right_corner = 14,
XC_bottom_side = 16,
XC_bottom_tee = 18,
XC_box_spiral = 20,
XC_center_ptr = 22,
XC_circle = 24,
XC_clock = 26,
XC_coffee_mug = 28,
XC_cross = 30,
XC_cross_reverse = 32,
XC_crosshair = 34,
XC_diamond_cross = 36,
XC_dot = 38,
XC_dotbox = 40,
XC_double_arrow = 42,
XC_draft_large = 44,
XC_draft_small = 46,
XC_draped_box = 48,
XC_exchange = 50,
XC_fleur = 52,
XC_gobbler = 54,
XC_gumby = 56,
XC_hand1 = 58,
XC_hand2 = 60,
XC_heart = 62,
XC_icon = 64,
XC_iron_cross = 66,
XC_left_ptr = 68,
XC_left_side = 70,
XC_left_tee = 72,
XC_leftbutton = 74,
XC_ll_angle = 76,
XC_lr_angle = 78,
XC_man = 80,
XC_middlebutton = 82,
XC_mouse = 84,
XC_pencil = 86,
XC_pirate = 88,
XC_plus = 90,
XC_question_arrow = 92,
XC_right_ptr = 94,
XC_right_side = 96,
XC_right_tee = 98,
XC_rightbutton = 100,
XC_rtl_logo = 102,
XC_sailboat = 104,
XC_sb_down_arrow = 106,
XC_sb_h_double_arrow = 108,
XC_sb_left_arrow = 110,
XC_sb_right_arrow = 112,
XC_sb_up_arrow = 114,
XC_sb_v_double_arrow = 116,
XC_shuttle = 118,
XC_sizing = 120,
XC_spider = 122,
XC_spraycan = 124,
XC_star = 126,
XC_target = 128,
XC_tcross = 130,
XC_top_left_arrow = 132,
XC_top_left_corner = 134,
XC_top_right_corner = 136,
XC_top_side = 138,
XC_top_tee = 140,
XC_trek = 142,
XC_ul_angle = 144,
XC_umbrella = 146,
XC_ur_angle = 148,
XC_watch = 150,
XC_xterm = 152,
XC_num_glyphs = 154,
}
ColorFormat :: enum u32 {
XcmsUndefinedFormat = 0x00000000,
XcmsCIEXYZFormat = 0x00000001,
XcmsCIEuvYFormat = 0x00000002,
XcmsCIExyYFormat = 0x00000003,
XcmsCIELabFormat = 0x00000004,
XcmsCIELuvFormat = 0x00000005,
XcmsTekHVCFormat = 0x00000006,
XcmsRGBFormat = 0x80000000,
XcmsRGBiFormat = 0x80000001,
}
ColormapAlloc :: enum i32 {
AllocNone = 0,
AllocAll = 1,
}
ColorFlags :: bit_set[ColorFlagsBits; i32]
ColorFlagsBits :: enum {
DoRed = 0,
DoGreen = 1,
DoBlue = 2,
}
GCAttributeMask :: bit_set[GCAttributeMaskBits; uint]
GCAttributeMaskBits :: enum {
GCFunction = 0,
GCPlaneMask = 1,
GCForeground = 2,
GCBackground = 3,
GCLineWidth = 4,
GCLineStyle = 5,
GCCapStyle = 6,
GCJoinStyle = 7,
GCFillStyle = 8,
GCFillRule = 9,
GCTile = 10,
GCStipple = 11,
GCTileStipXOrigin = 12,
GCTileStipYOrigin = 13,
GCFont = 14,
GCSubwindowMode = 15,
GCGraphicsExposures= 16,
GCClipXOrigin = 17,
GCClipYOrigin = 18,
GCClipMask = 19,
GCDashOffset = 20,
GCDashList = 21,
GCArcMode = 22,
}
GCFunction :: enum i32 {
GXclear = 0x0, // 0
GXand = 0x1, // src & dst
GXandReverse = 0x2, // src & ~dst
GXcopy = 0x3, // src
GXandInverted = 0x4, // ~src & dst
GXnoop = 0x5, // dst
GXxor = 0x6, // src ~ dst
GXor = 0x7, // src | dst
GXnor = 0x8, // ~src & ~dst
GXequiv = 0x9, // ~src ~ dst
GXinvert = 0xa, // ~dst
GXorReverse = 0xb, // src | ~dst
GXcopyInverted = 0xc, // ~src
GXorInverted = 0xd, // ~src | dst
GXnand = 0xe, // ~src | ~dst
GXset = 0xf, // 1
}
LineStyle :: enum i32 {
LineSolid = 0,
LineOnOffDash = 1,
LineDoubleDash = 2,
}
CapStyle :: enum i32 {
CapNotLast = 0,
CapButt = 1,
CapRound = 2,
CapProjecting = 3,
}
JoinStyle :: enum i32 {
JoinMiter = 0,
JoinRound = 1,
JoinBevel = 2,
}
FillStyle :: enum i32 {
FillSolid = 0,
FillTiled = 1,
FillStippled = 2,
FillOpaqueStippled = 3,
}
FillRule :: enum i32 {
EvenOddRule = 0,
WindingRule = 1,
}
ArcMode :: enum i32 {
ArcChord = 0,
ArcPieSlice = 1,
}
SubwindowMode :: enum i32 {
ClipByChildren = 0,
IncludeInferiors = 1,
}
CoordMode :: enum i32 {
CoordModeOrigin = 0,
CoordModePrevious = 1,
}
Shape :: enum i32 {
Complex = 0,
Nonconvex = 1,
Convex = 2,
}
FontDirection :: enum i32 {
FontLeftToRight = 0,
FontRightToLeft = 1,
}
ImageFormat :: enum i32 {
XYBitmap = 0,
XYPixmap = 1,
ZPixmap = 2,
}
SaveSetChangeMode :: enum i32 {
SetModeInsert = 0,
SetModeDelete = 1,
}
ScreenSaverBlanking :: enum i32 {
DontPreferBlanking = 0,
PreferBlanking = 1,
DefaultBlanking = 2,
}
ScreenSavingExposures :: enum i32 {
DontAllowExposures = 0,
AllowExposures = 1,
DefaultExposures = 2,
}
ScreenSaverForceMode :: enum i32 {
ScreenSaverReset = 0,
ScreenSaverActive = 1,
}
AccessControlMode :: enum i32 {
DisableAccess = 0,
EnableAccess = 1,
}
GrabMode :: enum i32 {
GrabModeSync = 0,
GrabModeAsync = 1,
}
AllowEventsMode :: enum i32 {
AsyncPointer = 0,
SyncPointer = 1,
ReplayPointer = 2,
AsyncKeyboard = 3,
SyncKeyboard = 4,
ReplayKeyboard = 5,
AsyncBoth = 6,
SyncBoth = 7,
}
FocusRevert :: enum i32 {
RevertToNone = 0,
RevertToPointerRoot = 1,
RevertToParent = 2,
}
KeyboardControlMask :: bit_set[KeyboardControlMaskBits; int]
KeyboardControlMaskBits :: enum {
KBKeyClickPercent = 0,
KBBellPercent = 1,
KBBellPitch = 2,
KBBellDuration = 3,
KBLed = 4,
KBLedMode = 5,
KBKey = 6,
KBAutoRepeatMode = 7,
}
KeyboardAutoRepeatMode :: enum i32 {
AutoRepeatModeOff = 0,
AutoRepeatModeOn = 1,
AutoRepeatModeDefault = 2,
}
KeyboardLedMode :: enum i32 {
LedModeOff = 0,
LedModeOn = 1,
}
WMHints :: bit_set[WMHintsBits; uint]
WMHintsBits :: enum {
InputHint = 0,
StateHint = 1,
IconPixmapHint = 2,
IconWindowHint = 3,
IconPositionHint = 4,
IconMaskHint = 5,
WindowGroupHint = 6,
XUrgencyHint = 8,
}
WMHintState :: enum i32 {
WithdrawnState = 0,
NormalState = 1,
IconicState = 3,
}
AllHints :: WMHints{
.InputHint,
.StateHint,
.IconPixmapHint,
.IconWindowHint,
.IconPositionHint,
.IconMaskHint,
.WindowGroupHint,
}
SizeHints :: bit_set[SizeHintsBits; uint]
SizeHintsBits :: enum {
USPosition = 0,
USSize = 1,
PPosition = 2,
PSize = 3,
PMinSize = 4,
PMaxSize = 5,
PResizeInc = 6,
PAspect = 7,
PBaseSize = 8,
PWinGravity = 9,
}
VisualInfoMask :: bit_set[VisualInfoMaskBits; int]
VisualInfoMaskBits :: enum {
VisualIDMask = 0,
VisualScreenMask = 1,
VisualDepthMask = 2,
VisualClassMask = 3,
VisualRedMaskMask = 4,
VisualGreenMaskMask = 5,
VisualBlueMaskMask = 6,
VisualColormapSizeMask = 7,
VisualBitsPerRGBMask = 8,
}
VisualNoMask :: VisualInfoMask {}
VisualAllMask :: VisualInfoMask {
.VisualIDMask,
.VisualScreenMask,
.VisualDepthMask,
.VisualClassMask,
.VisualRedMaskMask,
.VisualGreenMaskMask,
.VisualBlueMaskMask,
.VisualColormapSizeMask,
.VisualBitsPerRGBMask,
}
+1681
View File
File diff suppressed because it is too large Load Diff
+1909
View File
File diff suppressed because it is too large Load Diff
+1307
View File
File diff suppressed because it is too large Load Diff