diff --git a/build.bat b/build.bat
index 41e32f5ed..050789bbc 100644
--- a/build.bat
+++ b/build.bat
@@ -111,7 +111,7 @@ call build_vendor.bat
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
-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
diff --git a/build_odin.sh b/build_odin.sh
index 2a2505c97..589aeb550 100755
--- a/build_odin.sh
+++ b/build_odin.sh
@@ -27,11 +27,13 @@ error() {
if [ -z "$LLVM_CONFIG" ]; then
# darwin, linux, openbsd
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-12)" ]; then LLVM_CONFIG="llvm-config-12"
elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11"
# freebsd
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-config12)" ]; then LLVM_CONFIG="llvm-config-12"
elif [ -n "$(command -v llvm-config11)" ]; then LLVM_CONFIG="llvm-config-11"
@@ -117,7 +119,7 @@ build_odin() {
}
run_demo() {
- ./odin run examples/demo/demo.odin -file
+ ./odin run examples/demo/demo.odin -file -- Hellope World
}
if [ $# -eq 0 ]; then
diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin
index 968a26f8f..ca8dbf4c5 100644
--- a/core/math/big/internal.odin
+++ b/core/math/big/internal.odin
@@ -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.used = digits
- return nil
+ return internal_clamp(dest)
}
internal_random :: proc { internal_int_random, }
diff --git a/core/math/math.odin b/core/math/math.odin
index dddff4079..696293f70 100644
--- a/core/math/math.odin
+++ b/core/math/math.odin
@@ -2312,17 +2312,17 @@ F32_NORMALIZE :: 0
F32_RADIX :: 2
F32_ROUNDS :: 1
-F64_DIG :: 15 // # of decimal digits of precision
-F64_EPSILON :: 2.2204460492503131e-016 // smallest such that 1.0+F64_EPSILON != 1.0
-F64_MANT_DIG :: 53 // # of bits in mantissa
-F64_MAX :: 1.7976931348623158e+308 // max value
-F64_MAX_10_EXP :: 308 // max decimal exponent
-F64_MAX_EXP :: 1024 // max binary exponent
-F64_MIN :: 2.2250738585072014e-308 // min positive value
-F64_MIN_10_EXP :: -307 // min decimal exponent
-F64_MIN_EXP :: -1021 // min binary exponent
-F64_RADIX :: 2 // exponent radix
-F64_ROUNDS :: 1 // addition rounding: near
+F64_DIG :: 15 // Number of representable decimal digits.
+F64_EPSILON :: 2.2204460492503131e-016 // Smallest number such that `1.0 + F64_EPSILON != 1.0`.
+F64_MANT_DIG :: 53 // Number of bits in the mantissa.
+F64_MAX :: 1.7976931348623158e+308 // Maximum representable value.
+F64_MAX_10_EXP :: 308 // Maximum base-10 exponent yielding normalized value.
+F64_MAX_EXP :: 1024 // One greater than the maximum possible base-2 exponent yielding normalized value.
+F64_MIN :: 2.2250738585072014e-308 // Minimum positive normalized value.
+F64_MIN_10_EXP :: -307 // Minimum base-10 exponent yielding normalized value.
+F64_MIN_EXP :: -1021 // One greater than the minimum possible base-2 exponent yielding normalized value.
+F64_RADIX :: 2 // Exponent radix.
+F64_ROUNDS :: 1 // Addition rounding: near.
F16_MASK :: 0x1f
diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin
index d15df46ad..082ae3cd8 100644
--- a/core/mem/virtual/arena.odin
+++ b/core/mem/virtual/arena.odin
@@ -51,7 +51,7 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
// Initialization of an `Arena` to be a `.Static` variant.
// A static arena contains a single `Memory_Block` allocated with virtual memory.
@(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.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
arena.total_used = 0
diff --git a/core/net/socket.odin b/core/net/socket.odin
index 40fa6ab56..1bfa52257 100644
--- a/core/net/socket.odin
+++ b/core/net/socket.odin
@@ -148,7 +148,29 @@ recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_en
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.
@@ -168,7 +190,20 @@ send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_writte
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) {
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) {
return _set_blocking(socket, should_block)
-}
\ No newline at end of file
+}
diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin
index 6d3f111d1..ba48959fb 100644
--- a/core/net/socket_linux.odin
+++ b/core/net/socket_linux.odin
@@ -125,7 +125,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (An
}
@(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
if endpoint.port == 0 {
return 0, .Port_Required
diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin
index 2d85029e8..f1d3e08b8 100644
--- a/core/odin/ast/clone.odin
+++ b/core/odin/ast/clone.odin
@@ -7,7 +7,7 @@ import "core:reflect"
import "core:odin/tokenizer"
_ :: 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.pos = pos
n.end = end
@@ -23,6 +23,15 @@ new :: proc($T: typeid, pos, end: tokenizer.Pos) -> ^T {
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_node,
clone_expr,
diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin
index bbfaf9114..39bd77055 100644
--- a/core/odin/parser/parser.odin
+++ b/core/odin/parser/parser.odin
@@ -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))
}
}
-
- end := body.end
+
+ end: tokenizer.Pos
+ if body != nil {
+ end = body.end
+ }
if else_stmt != nil {
end = else_stmt.end
}
@@ -850,7 +853,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
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.in_pos = in_tok.pos
range_stmt.expr = rhs
@@ -910,7 +913,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
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.vals = vals
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")
- 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.init = init
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)
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.op = in_tok
as.rhs = rhs
@@ -1010,14 +1013,14 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
body.stmts = clauses[:]
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.body = body
ts.switch_pos = tok.pos
return ts
} else {
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.cond = cond
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 {
eq := expect_token(p, .Eq)
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.sep = eq.pos
fv.value = value
@@ -1137,7 +1140,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl
body.stmts = decls[:]
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.tok = tok
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))
}
- 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.for_pos = for_tok.pos
range_stmt.val0 = val0
@@ -1304,7 +1307,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
case ^ast.Return_Stmt:
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
return ds
@@ -1341,8 +1344,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if tok.kind != .Fallthrough && p.curr_tok.kind == .Ident {
label = parse_ident(p)
}
- end := label.end if label != nil else end_pos(tok)
- s := ast.new(ast.Branch_Stmt, tok.pos, end)
+ s := ast.new(ast.Branch_Stmt, tok.pos, label)
s.tok = tok
s.label = label
expect_semicolon(p, s)
@@ -1366,7 +1368,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
if p.curr_tok.kind != .Colon {
end := list[len(list)-1]
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
return us
}
@@ -1416,13 +1418,13 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
bd.tok = tok
bd.name = name
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
return es
case "force_inline", "force_no_inline":
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
return es
case "unroll":
@@ -1444,7 +1446,8 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
return ast.new(ast.Bad_Stmt, tok.pos, end_pos(tag))
case:
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.name = name
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")
}
- bs := ast.new(ast.Block_Stmt, stmt.pos, stmt.end)
+ bs := ast.new(ast.Block_Stmt, stmt.pos, stmt)
bs.open = stmt.pos
bs.stmts = make([]^ast.Stmt, 1)
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 '..'")
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
return e
}
@@ -1808,7 +1811,7 @@ parse_ident_list :: proc(p: ^Parser, allow_poly_names: bool) -> []^ast.Expr {
if is_blank_ident(ident) {
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
append(&list, poly_name)
} else {
@@ -2154,7 +2157,7 @@ parse_inlining_operand :: proc(p: ^Parser, lhs: bool, tok: tokenizer.Token) -> ^
e.inlining = pi
case:
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
}
@@ -2204,7 +2207,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Distinct:
tok := advance_token(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.type = type
return dt
@@ -2215,7 +2218,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
switch name.text {
case "type":
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.type = type
return hp
@@ -2319,7 +2322,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tag_call := parse_call_expr(p, tag)
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.type = type
return rt
@@ -2328,7 +2331,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return parse_inlining_operand(p, lhs, name)
case:
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.name = name.text
te.expr = expr
@@ -2456,7 +2460,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Pointer:
tok := expect_token(p, .Pointer)
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.elem = elem
return ptr
@@ -2470,7 +2474,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Pointer)
close := expect_token(p, .Close_Bracket)
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.pointer = tok.pos
t.close = close.pos
@@ -2480,7 +2484,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Dynamic)
close := expect_token(p, .Close_Bracket)
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.dynamic_pos = tok.pos
da.close = close.pos
@@ -2500,7 +2504,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
close := expect_token(p, .Close_Bracket)
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.len = count
at.close = close.pos
@@ -2514,7 +2518,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
expect_token(p, .Close_Bracket)
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.key = key
mt.value = value
@@ -2755,7 +2759,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
expect_token(p, .Close_Bracket)
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.row_count = row_count
mt.column_count = column_count
@@ -2893,7 +2897,7 @@ parse_elem_list :: proc(p: ^Parser) -> []^ast.Expr {
eq := expect_token(p, .Eq)
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.sep = eq.pos
fv.value = value
@@ -2962,7 +2966,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
}
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.sep = eq.pos
fv.value = value
@@ -2993,7 +2997,7 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
o := ast.unparen_expr(operand)
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.call = ce
return sce
@@ -3101,7 +3105,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case .Ident:
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.op = tok
sel.field = field
@@ -3127,7 +3131,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
type.op = question
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.type = type
@@ -3145,7 +3149,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case .Ident:
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.op = tok
sel.field = field
@@ -3225,7 +3229,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
close := expect_token(p, .Close_Paren)
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.open = open.pos
tc.type = type
@@ -3237,7 +3241,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
op := advance_token(p)
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.expr = expr
return ac
@@ -3247,8 +3251,8 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
.And:
op := advance_token(p)
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.expr = expr
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)
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.expr = expr
return ue
@@ -3266,7 +3270,7 @@ parse_unary_expr :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
case .Period:
op := advance_token(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
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")
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.op = op
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[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.op = op
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)
}
- 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]
return es
}
diff --git a/core/runtime/default_allocators_nil.odin b/core/runtime/default_allocators_nil.odin
index a340050eb..eee6a7998 100644
--- a/core/runtime/default_allocators_nil.odin
+++ b/core/runtime/default_allocators_nil.odin
@@ -35,7 +35,7 @@ nil_allocator :: proc() -> Allocator {
when ODIN_OS == .Freestanding {
default_allocator_proc :: nil_allocator_proc
default_allocator :: nil_allocator
-}
+}
@@ -78,9 +78,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
panic_allocator :: proc() -> Allocator {
return Allocator{
- procedure = nil_allocator_proc,
+ procedure = panic_allocator_proc,
data = nil,
}
}
-
-
diff --git a/core/runtime/os_specific_darwin.odin b/core/runtime/os_specific_darwin.odin
index 33136c92f..5de9a7d57 100644
--- a/core/runtime/os_specific_darwin.odin
+++ b/core/runtime/os_specific_darwin.odin
@@ -4,7 +4,7 @@ package runtime
import "core:intrinsics"
_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 {
return 0, _OS_Errno(-ret)
}
diff --git a/core/slice/slice.odin b/core/slice/slice.odin
index 107f48fb2..748bd28f7 100644
--- a/core/slice/slice.odin
+++ b/core/slice/slice.odin
@@ -49,7 +49,7 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte {
```
```
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)
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))
if n >= 0 {
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
}
+/*
+ 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)
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
- where intrinsics.type_is_ordered(T) #no_bounds_check {
-
- n := len(array)
- switch n {
- case 0:
- 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
- }
+ where intrinsics.type_is_ordered(T) #no_bounds_check
+{
+ // I would like to use binary_search_by(array, key, cmp) here, but it doesn't like it:
+ // Cannot assign value 'cmp' of type 'proc($E, $E) -> Ordering' to 'proc(i32, i32) -> Ordering' in argument
+ return binary_search_by(array, key, proc(key: T, element: T) -> Ordering {
switch {
- case array[m] < key:
- lo = m + 1
- case key < array[m]:
- hi = m - 1
- case:
- return m, true
+ case element < key: return .Less
+ case element > key: return .Greater
+ case: return .Equal
}
- }
-
- 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)
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
}
+// 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)
any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
for v in s {
diff --git a/core/strings/strings.odin b/core/strings/strings.odin
index 2f36eddbe..539829a1a 100644
--- a/core/strings/strings.odin
+++ b/core/strings/strings.odin
@@ -885,6 +885,7 @@ Splits a string into parts based on a separator. If n < count of seperators, the
Inputs:
- s: The string to split.
- 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)
Returns:
diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin
index 0cf90ed3b..1ca60d494 100644
--- a/core/sys/linux/bits.odin
+++ b/core/sys/linux/bits.odin
@@ -718,7 +718,7 @@ Perf_Event_Sample_Type_Bits :: enum {
}
/// Describes field sets to include in mmaped page
-Perf_Read_Format :: enum {
+Perf_Read_Format_Bits :: enum {
TOTAL_TIME_ENABLED = 0,
TOTAL_TIME_RUNNING = 1,
ID = 2,
diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin
index 8789ca2d1..afa7faf33 100644
--- a/core/sys/linux/types.odin
+++ b/core/sys/linux/types.odin
@@ -283,6 +283,8 @@ Perf_Flags :: bit_set[Perf_Flags_Bits; uint]
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_Event_Sample_Type :: bit_set[Perf_Event_Sample_Type_Bits; u64]
diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin
index 9e2294c71..801e483e7 100644
--- a/core/sys/windows/gdi32.odin
+++ b/core/sys/windows/gdi32.odin
@@ -10,6 +10,8 @@ foreign gdi32 {
DeleteObject :: proc(ho: HGDIOBJ) -> BOOL ---
SetBkColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
+ CreateCompatibleDC :: proc(hdc: HDC) -> HDC ---
+
CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH ---
CreateDIBitmap :: proc(
@@ -81,6 +83,11 @@ foreign gdi32 {
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
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 {
diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin
index 439b96078..6108f4738 100644
--- a/core/sys/windows/kernel32.odin
+++ b/core/sys/windows/kernel32.odin
@@ -291,6 +291,14 @@ foreign kernel32 {
hTemplateFile: 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 ---
FindNextFileW :: proc(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL ---
FindClose :: proc(findFile: HANDLE) -> BOOL ---
@@ -354,6 +362,9 @@ foreign kernel32 {
LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> 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(
hDirectory: HANDLE,
@@ -422,7 +433,7 @@ foreign kernel32 {
GetConsoleWindow :: proc() -> HWND ---
GetConsoleScreenBufferInfo :: proc(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: PCONSOLE_SCREEN_BUFFER_INFO) -> 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 ---
SetConsoleCursorInfo :: proc(hConsoleOutput: HANDLE, lpConsoleCursorInfo: PCONSOLE_CURSOR_INFO) -> BOOL ---
diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin
index f8dac242a..360cab738 100644
--- a/core/sys/windows/types.odin
+++ b/core/sys/windows/types.odin
@@ -1971,6 +1971,16 @@ BITMAPINFO :: struct {
bmiColors: [1]RGBQUAD,
}
+BITMAP :: struct {
+ bmType: LONG,
+ bmWidth: LONG,
+ bmHeight: LONG,
+ bmWidthBytes: LONG,
+ bmPlanes: WORD,
+ bmBitsPixel: WORD,
+ bmBits: LPVOID,
+}
+
// pixel types
PFD_TYPE_RGBA :: 0
PFD_TYPE_COLORINDEX :: 1
diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin
index cce9b3245..81884f3da 100644
--- a/core/sys/windows/user32.odin
+++ b/core/sys/windows/user32.odin
@@ -161,6 +161,8 @@ foreign user32 {
MonitorFromRect :: proc(lprc: LPRECT, 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 ---
+
+ EnumWindows :: proc(lpEnumFunc: Window_Enum_Proc, lParam: LPARAM) -> BOOL ---
SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> 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
+Window_Enum_Proc :: #type proc "stdcall" (HWND, LPARAM) -> BOOL
USER_DEFAULT_SCREEN_DPI :: 96
DPI_AWARENESS_CONTEXT :: distinct HANDLE
diff --git a/core/thread/thread.odin b/core/thread/thread.odin
index 9ba03203f..9fcc5b84f 100644
--- a/core/thread/thread.odin
+++ b/core/thread/thread.odin
@@ -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)
- 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)
}
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),
- size_of(T2) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
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)
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
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)
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
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
- where size_of(T) <= size_of(rawptr) {
+ where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T))t.data
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.data = rawptr(fn)
t.user_index = 1
+
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 {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(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
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2))t.data
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)
}
t := create(thread_proc, priority)
t.data = rawptr(fn)
t.user_index = 2
+
arg1, arg2 := arg1, arg2
- mem.copy(&t.user_args[0], &arg1, size_of(arg1))
- mem.copy(&t.user_args[1], &arg2, size_of(arg2))
+ user_args := mem.slice_to_bytes(t.user_args[:])
+
+ n := copy(user_args, mem.ptr_to_bytes(&arg1))
+ _ = copy(user_args[n:], mem.ptr_to_bytes(&arg2))
+
if self_cleanup {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(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
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3))t.data
assert(t.user_index >= 3)
- arg1 := (^T1)(&t.user_args[0])^
- arg2 := (^T2)(&t.user_args[1])^
- arg3 := (^T3)(&t.user_args[2])^
+
+ user_args := mem.slice_to_bytes(t.user_args[:])
+ 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)
}
t := create(thread_proc, priority)
t.data = rawptr(fn)
t.user_index = 3
+
arg1, arg2, arg3 := arg1, arg2, arg3
- mem.copy(&t.user_args[0], &arg1, size_of(arg1))
- mem.copy(&t.user_args[1], &arg2, size_of(arg2))
- mem.copy(&t.user_args[2], &arg3, size_of(arg3))
+ user_args := mem.slice_to_bytes(t.user_args[:])
+
+ 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 {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(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
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3, T4))t.data
assert(t.user_index >= 4)
- arg1 := (^T1)(&t.user_args[0])^
- arg2 := (^T2)(&t.user_args[1])^
- arg3 := (^T3)(&t.user_args[2])^
- arg4 := (^T4)(&t.user_args[3])^
+
+ user_args := mem.slice_to_bytes(t.user_args[:])
+ 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):]))^
+ arg4 := (^T4)(raw_data(user_args[size_of(T1) + size_of(T2) + size_of(T3):]))^
+
fn(arg1, arg2, arg3, arg4)
}
t := create(thread_proc, priority)
t.data = rawptr(fn)
t.user_index = 4
+
arg1, arg2, arg3, arg4 := arg1, arg2, arg3, arg4
- mem.copy(&t.user_args[0], &arg1, size_of(arg1))
- mem.copy(&t.user_args[1], &arg2, size_of(arg2))
- mem.copy(&t.user_args[2], &arg3, size_of(arg3))
- mem.copy(&t.user_args[3], &arg4, size_of(arg4))
+ user_args := mem.slice_to_bytes(t.user_args[:])
+
+ n := copy(user_args, mem.ptr_to_bytes(&arg1))
+ 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 {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(t)
return t
}
-
_select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context {
ctx, ok := init_context.?
if !ok {
diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin
index 0e92c94bb..372b2dfa8 100644
--- a/examples/all/all_vendor.odin
+++ b/examples/all/all_vendor.odin
@@ -39,6 +39,8 @@ import nvg "vendor:nanovg"
import nvg_gl "vendor:nanovg/gl"
import fontstash "vendor:fontstash"
+import xlib "vendor:x11/xlib"
+
_ :: botan_bindings
_ :: botan_blake2b
_ :: keccak
@@ -76,4 +78,6 @@ _ :: lua_5_4
_ :: nvg
_ :: nvg_gl
-_ :: fontstash
\ No newline at end of file
+_ :: fontstash
+
+_ :: xlib
\ No newline at end of file
diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin
index 00dd8a171..417011281 100644
--- a/examples/demo/demo.odin
+++ b/examples/demo/demo.odin
@@ -44,7 +44,13 @@ the_basics :: proc() {
fmt.println("\n# 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
// A comment
diff --git a/src/checker.cpp b/src/checker.cpp
index 961000cf7..f17f50544 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -6123,9 +6123,6 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("calculate global init order");
calculate_global_init_order(c);
- TIME_SECTION("check test procedures");
- check_test_procedures(c);
-
TIME_SECTION("add type info for type definitions");
add_type_info_for_type_definitions(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");
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");
check_unchecked_bodies(c);
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index effd9d28e..f61c297bd 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -21,8 +21,8 @@
#include "llvm_backend_stmt.cpp"
#include "llvm_backend_proc.cpp"
-char *get_default_microarchitecture() {
- char * default_march = "generic";
+String get_default_microarchitecture() {
+ String default_march = str_lit("generic");
if (build_context.metrics.arch == TargetArch_amd64) {
// 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
if (ODIN_LLVM_MINIMUM_VERSION_12) {
if (build_context.metrics.os == TargetOs_freestanding) {
- default_march = "x86-64";
+ default_march = str_lit("x86-64");
} 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;
}
- char const *host_cpu_name = LLVMGetHostCPUName();
- char const *llvm_cpu = get_default_microarchitecture();
+ String host_cpu_name = copy_string(permanent_allocator(), make_string_c(LLVMGetHostCPUName()));
+ String llvm_cpu = get_default_microarchitecture();
char const *llvm_features = "";
if (build_context.microarch.len != 0) {
if (build_context.microarch == "native") {
llvm_cpu = host_cpu_name;
} 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();
}
}
@@ -2578,7 +2578,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
for (auto const &entry : gen->modules) {
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
- target, target_triple, llvm_cpu,
+ target, target_triple, (const char *)llvm_cpu.text,
llvm_features,
code_gen_level,
reloc_mode,
diff --git a/src/main.cpp b/src/main.cpp
index b8abe94f4..14f7e84ec 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -199,19 +199,19 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
}
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(1, "%.*s command [arguments]", LIT(argv0));
print_usage_line(0, "Commands:");
- print_usage_line(1, "build compile 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, "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, "strip-semicolon parse, type check, and remove 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, "doc generate documentation on a directory of .odin files");
- print_usage_line(1, "version print version");
- print_usage_line(1, "report print information useful to reporting a bug");
+ 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, "run Same as 'build', but also then runs the newly compiled executable.");
+ print_usage_line(1, "check Parses, and type checks a directory of .odin files.");
+ print_usage_line(1, "strip-semicolon Parses, type checks, and removes unneeded semicolons from the entire program.");
+ print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package.");
+ print_usage_line(1, "doc Generates documentation on a directory of .odin files.");
+ print_usage_line(1, "version Prints version.");
+ print_usage_line(1, "report Prints information useful to reporting a bug.");
print_usage_line(0, "");
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`");
@@ -1580,45 +1580,45 @@ gb_internal void remove_temp_files(lbGenerator *gen) {
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(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
print_usage_line(0, "");
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, "Use `-file` to build a single file instead.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "odin build . # Build package in current directory");
- print_usage_line(3, "odin build
# Build package in ");
- print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point.");
+ print_usage_line(3, "odin build . Builds package in current directory.");
+ print_usage_line(3, "odin build Builds package in .");
+ print_usage_line(3, "odin build filename.odin -file Builds single-file package, must contain entry point.");
} else if (command == "run") {
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, '-- ', to specify args for the output.");
print_usage_line(2, "Examples:");
- print_usage_line(3, "odin run . # Build and run package in current directory");
- print_usage_line(3, "odin run # Build and run package in ");
- 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 . Builds and runs package in current directory.");
+ print_usage_line(3, "odin run Builds and runs package in .");
+ print_usage_line(3, "odin run filename.odin -file Builds and runs single-file package, must contain entry point.");
} 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(3, "odin check . # Type check package in current directory");
- print_usage_line(3, "odin check # Type check package in ");
- print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point.");
+ print_usage_line(3, "odin check . Type checks package in current directory.");
+ print_usage_line(3, "odin check Type checks package in .");
+ print_usage_line(3, "odin check filename.odin -file Type checks single-file package, must contain entry point.");
} 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") {
- 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(3, "odin doc . # Generate documentation on package in current directory");
- print_usage_line(3, "odin doc # Generate documentation on package in ");
- print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package.");
+ print_usage_line(3, "odin doc . Generates documentation on package in current directory.");
+ print_usage_line(3, "odin doc Generates documentation on package in .");
+ print_usage_line(3, "odin doc filename.odin -file Generates documentation on single-file package.");
} else if (command == "version") {
- print_usage_line(1, "version print version");
+ print_usage_line(1, "version Prints version.");
} else if (command == "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";
@@ -1642,237 +1642,240 @@ gb_internal void print_show_help(String const arg0, String const &command) {
if (doc) {
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(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(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, "");
}
if (run_or_build) {
print_usage_line(1, "-out:");
- 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(0, "");
print_usage_line(1, "-o:");
- 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) {
- print_usage_line(2, "Accepted values: none, minimal, size, speed, aggressive");
- } else {
- print_usage_line(2, "Accepted values: none, minimal, size, speed");
+ print_usage_line(3, "-o:aggressive");
}
- 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, "");
}
if (check) {
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(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(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(1, "-export-timings:");
- 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(3, "-export-timings:json Export compile time stats to JSON");
- print_usage_line(3, "-export-timings:csv Export compile time stats to CSV");
+ print_usage_line(3, "-export-timings:json Exports compile time stats to JSON.");
+ print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV.");
print_usage_line(0, "");
print_usage_line(1, "-export-timings-file:");
- 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(0, "");
print_usage_line(1, "-thread-count:");
- 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(0, "");
}
if (check_only) {
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(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, "");
}
if (run_or_build) {
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, "");
} else if (strip_semicolon) {
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, "");
}
if (check) {
print_usage_line(1, "-collection:=");
- 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, "Usage in Code:");
print_usage_line(3, "import \"shared:foo\"");
print_usage_line(0, "");
print_usage_line(1, "-define:=");
- 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, "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, "");
}
if (build) {
print_usage_line(1, "-build-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(3, "-build-mode:exe Build as an executable");
- print_usage_line(3, "-build-mode:dll Build as a dynamically linked library");
- print_usage_line(3, "-build-mode:shared Build as a dynamically linked library");
- print_usage_line(3, "-build-mode:obj Build as an object file");
- print_usage_line(3, "-build-mode:object Build as an object file");
- print_usage_line(3, "-build-mode:assembly Build as an assembly file");
- print_usage_line(3, "-build-mode:assembler Build as an assembly file");
- print_usage_line(3, "-build-mode:asm Build 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 Build as an LLVM IR file");
+ print_usage_line(3, "-build-mode:exe Builds as an executable.");
+ print_usage_line(3, "-build-mode:dll Builds 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 Builds as an object file.");
+ print_usage_line(3, "-build-mode:object Builds as an object file.");
+ print_usage_line(3, "-build-mode:assembly Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:assembler Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:asm Builds as an assembly file.");
+ print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file.");
+ print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file.");
print_usage_line(0, "");
}
if (check) {
print_usage_line(1, "-target:");
- 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, "");
}
if (run_or_build) {
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(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(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(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(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(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(1, "-use-separate-modules");
print_usage_line(1, "[EXPERIMENTAL]");
- 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, "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(0, "");
}
if (check) {
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, "");
}
if (check) {
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, "-vet-unused");
- print_usage_line(2, "-vet-shadowing");
- print_usage_line(2, "-vet-using-stmt");
+ print_usage_line(3, "-vet-unused");
+ print_usage_line(3, "-vet-shadowing");
+ print_usage_line(3, "-vet-using-stmt");
print_usage_line(0, "");
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(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(1, "-vet-using-stmt");
- 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, "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(0, "");
print_usage_line(1, "-vet-using-param");
- 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, "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(0, "");
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 deprecated syntax");
- print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)");
+ 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, "Does not err on unneeded tokens (unlike -strict-style).");
print_usage_line(0, "");
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, "");
}
if (check) {
print_usage_line(1, "-ignore-unknown-attributes");
- print_usage_line(2, "Ignores unknown attributes");
- print_usage_line(2, "This can be used with metaprogramming tools");
+ print_usage_line(2, "Ignores unknown attributes.");
+ print_usage_line(2, "This can be used with metaprogramming tools.");
print_usage_line(0, "");
if (command != "test") {
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, "");
}
}
if (test_only) {
print_usage_line(1, "-test-name:");
- print_usage_line(2, "Run specific test only by name");
+ print_usage_line(2, "Runs specific test only by name.");
print_usage_line(0, "");
}
if (run_or_build) {
print_usage_line(1, "-minimum-os-version:");
- 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, "(Only used when target is Darwin)");
+ print_usage_line(2, "Sets the minimum OS version targeted by the application.");
+ print_usage_line(2, "Example: -minimum-os-version:12.0.0");
+ print_usage_line(2, "(Only used when target is Darwin.)");
print_usage_line(0, "");
print_usage_line(1, "-extra-linker-flags:");
- 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(1, "-extra-assembler-flags:");
- 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(1, "-microarch:");
- 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(3, "-microarch:sandybridge");
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(1, "-reloc-mode:");
- print_usage_line(2, "Specifies the reloc mode");
- print_usage_line(2, "Options:");
- print_usage_line(3, "default");
- print_usage_line(3, "static");
- print_usage_line(3, "pic");
- print_usage_line(3, "dynamic-no-pic");
+ print_usage_line(2, "Specifies the reloc mode.");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-reloc-mode:default");
+ print_usage_line(3, "-reloc-mode:static");
+ print_usage_line(3, "-reloc-mode:pic");
+ print_usage_line(3, "-reloc-mode:dynamic-no-pic");
print_usage_line(0, "");
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(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, "");
}
if (check) {
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(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(1, "-strict-style");
- 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 deprecated syntax");
+ 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 deprecated syntax.");
print_usage_line(0, "");
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(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(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(1, "-error-pos-style:");
- print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)");
- print_usage_line(2, "'odin' file/path(45:3)");
- print_usage_line(2, "'unix' file/path:45:3:");
+ print_usage_line(2, "Available options:");
+ print_usage_line(3, "-error-pos-style: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(1, "-max-error-count:");
- print_usage_line(2, "Set 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, "If not set, the default max error count is %d", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
+ 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, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT);
print_usage_line(0, "");
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, "");
}
if (run_or_build) {
print_usage_line(1, "-sanitize:");
- print_usage_line(1, "Enables sanitization analysis");
- print_usage_line(1, "Options are 'address', 'memory', and 'thread'");
- print_usage_line(1, "NOTE: This flag can be used multiple times");
+ print_usage_line(2, "Enables sanitization analysis.");
+ print_usage_line(2, "Available options:");
+ 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, "");
}
@@ -1956,27 +1962,27 @@ gb_internal void print_show_help(String const arg0, String const &command) {
#if defined(GB_SYSTEM_WINDOWS)
print_usage_line(1, "-ignore-vs-search");
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(1, "-resource:");
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(0, "");
print_usage_line(1, "-pdb-name:");
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(0, "");
print_usage_line(1, "-subsystem: