replace leading _ for private symbols with keyword hide

This commit is contained in:
2026-07-14 20:19:01 +02:00
parent 5157cf3bcc
commit 267947e79d
31 changed files with 125220 additions and 122709 deletions
+2 -1
View File
@@ -15,7 +15,8 @@ roadmap and milestone history.
- file-local relative imports, import aliases, and qualified member access
- transparent declaration aliases with `Name :: alias package.Member`; functions/type factories,
named types, and globals retain their original declaration or storage identity
- native top-level declarations beginning with `_` are visible only within their source file; locals, fields, parameters, and C declarations are unaffected
- `hide` makes any named top-level declaration file-local; declarations are public by default,
leading underscores are ordinary identifier characters, and imports are always file-local
- relative `.h` imports as synthetic C header package namespaces
- root `main` validation with trap executable recovery for missing or unusable entry points
+9
View File
@@ -177,6 +177,15 @@ mem :: import "@std/mem"
value :: math.sum(other_math.value, 1)
```
Top-level declarations are public by default. Prefix a declaration with `hide`
to keep it local to its source file; leading underscores have no visibility
meaning. Imports are always file-local and cannot be hidden or re-exported:
```bro
hide helper func() i32 { return 42 }
hide State :: struct { value i32 }
```
Current prototype features:
- Newline-terminated, multiline statements; `}` may terminate a block's final statement
+21 -4
View File
@@ -810,7 +810,7 @@
33. explicit I/O provider (implemented)
- `main` may take one canonical `@std/io Io`; parameterless entry points remain valid
- the compiler supplies a file-hidden macOS provider through an external no-argument C wrapper
- the compiler supplies a `hide system` macOS provider through an external no-argument C wrapper
- readers and writers pair an explicit provider with `stdin`, `stdout`, or `stderr`
- `read` and `write` validate provider counts; `write_all` handles partial writes and no progress
- the system provider uses unbuffered libc `read`/`write`, retries interruption, and allocates nothing
@@ -819,8 +819,8 @@
- bare qualified aliases use `Name :: alias package.Member` without adding a keyword
- functions/type factories, named types, and globals transparently retain the target identity;
mutable global aliases therefore share the original storage
- aliases resolve transitively at load time, consume their file-local import, preserve leading-
underscore visibility, and diagnose missing, hidden, unavailable, ambiguous, cyclic, or
- aliases resolve transitively at load time, consume their file-local import, preserve explicit
`hide` visibility, and diagnose missing, hidden, unavailable, ambiguous, cyclic, or
conflicting targets
- root `std` re-exports only `ArrayList(T)` for now; operations remain under `std/arraylist`
@@ -828,7 +828,24 @@
- pointer sigils are highlighted as operators
- type-factory calls in type positions and struct literals are highlighted as functions
36. is it currently possible to access a subpackage from a parent package? if not, maybe it should be
36. transitive package namespaces (spike completed; no language change)
- imports remain file-local implementation details, including explicitly named imports such as
`rl :: import "@vendor/raylib"`; naming an import only chooses its local qualifier
- packages expose declarations, not their imports, so imported namespaces never become public or
transitively reachable package members
- callers import each package they use directly; subdirectory layout does not create namespaces
- this keeps package lookup shallow and deterministic and avoids overloading import aliases with
declaration visibility
36.5. explicit `hide` file-local declarations (implemented)
- `hide name ...` gives any named top-level function, global, native/C record, union, enum,
opaque/distinct type, or declaration/type alias the existing file-local semantics
- declarations remain public by default; a leading underscore is an ordinary identifier and `_`
remains the write-only sink
- hidden native and C declarations with the same name may coexist in separate files, while public
collisions are still diagnosed
- `hide` is reserved for named top-level declarations and is rejected on imports, locals,
parameters, fields, and anonymous declarations
37. add a debug package in `std` that provides debugging utilities
- add `debug.print` function making use of `std/io` to print values to the console
+2 -2
View File
@@ -966,7 +966,7 @@ configure_io_main :: proc(checker: ^Checker) {
return
}
provider_name := symbol.intern(checker.symbols, "_system")
provider_name := symbol.intern(checker.symbols, "system")
provider := ast.INVALID_FUNCTION
for function, function_id in checker.ast_module.functions {
if function.pkg != io_package || function.name != provider_name {
@@ -986,7 +986,7 @@ configure_io_main :: proc(checker: ^Checker) {
checker.template_diagnostics[main_template] = source.add(
checker.diagnostics,
main.span,
"@std/io does not provide the required '_system func() Io' startup implementation",
"@std/io does not provide the required 'hide system func() Io' startup implementation",
)
return
}
+1
View File
@@ -24,6 +24,7 @@ keyword_kind :: proc(text: string) -> token.Kind {
case "distinct": return .Keyword_Distinct
case "alias": return .Keyword_Alias
case "import": return .Keyword_Import
case "hide": return .Keyword_Hide
case "return": return .Keyword_Return
case "try": return .Keyword_Try
case "catch": return .Keyword_Catch
+65 -28
View File
@@ -26,6 +26,7 @@ Parser :: struct {
// struct literal. Nested `(`/`[`/call-arg contexts (delimiter_depth > 0) still
// allow struct literals.
no_struct_literal: bool,
hidden_names: [dynamic]symbol.Id,
}
MAX_EXPRESSION_NESTING :: 256
@@ -37,9 +38,31 @@ token_text :: proc(parser: ^Parser, tok: token.Token) -> string {
return parser.source_file.text[int(tok.span.start):int(tok.span.end)]
}
file_hidden_name :: proc(parser: ^Parser, tok: token.Token) -> bool {
name := token_text(parser, tok)
return len(name) > 1 && name[0] == '_'
file_hidden_name :: proc(parser: ^Parser, name: symbol.Id) -> bool {
for hidden in parser.hidden_names {
if hidden == name {
return true
}
}
return false
}
collect_hidden_names :: proc(parser: ^Parser) {
depth := 0
for item, index in parser.tokens.items {
#partial switch item.kind {
case .Left_Brace:
depth += 1
case .Right_Brace:
depth = max(depth-1, 0)
case .Keyword_Hide:
if depth == 0 && index+1 < len(parser.tokens.items) &&
parser.tokens.items[index+1].kind == .Identifier {
append(&parser.hidden_names, parser.tokens.items[index+1].symbol)
}
case:
}
}
}
span_from :: proc(first, last: source.Span) -> source.Span {
@@ -396,7 +419,7 @@ parse_type_atom :: proc(parser: ^Parser) -> ast.Type_Syntax {
u32(name.symbol),
u32(qualifier),
u32(parser.file),
!symbol.is_valid(qualifier) && file_hidden_name(parser, name),
!symbol.is_valid(qualifier) && file_hidden_name(parser, name.symbol),
)
if current(parser).kind == .Left_Paren {
call := parse_call(parser, qualifier, first, name, 0, false)
@@ -2192,7 +2215,7 @@ parse_while :: proc(parser: ^Parser) -> ast.Stmt_Id {
return id
}
parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
parse_function :: proc(parser: ^Parser, name: token.Token, c_abi, file_hidden: bool) {
advance(parser)
if _, ok := allow(parser, .Left_Paren); !ok {
source.add(parser.diagnostics, current(parser).span, "expected '(' after 'func'")
@@ -2223,7 +2246,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
pkg=parser.pkg,
file=parser.file,
c_abi=c_abi,
file_hidden=!c_abi && file_hidden_name(parser, name),
file_hidden=file_hidden,
has_body=false,
variadic=variadic,
params=params,
@@ -2242,7 +2265,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
pkg=parser.pkg,
file=parser.file,
c_abi=c_abi,
file_hidden=!c_abi && file_hidden_name(parser, name),
file_hidden=file_hidden,
has_body=true,
variadic=variadic,
params=params,
@@ -2388,9 +2411,9 @@ parse_inline_union_type :: proc(parser: ^Parser) -> types.Type {
return types.union_anonymous(&parser.module.type_store, fields[:], tag)
}
parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout: bool, is_union := false) {
parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout, file_hidden: bool, is_union := false) {
start := advance(parser)
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=!c_layout && file_hidden_name(parser, name))
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
// A tagged union spells its discriminant in parens: `union(Enum)` reuses an existing
// enum; `union(enum)` synthesizes one from the variant names after the body is parsed.
tag := types.INVALID
@@ -2452,9 +2475,9 @@ parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout: bool, is_unio
_ = finish_statement(parser)
}
parse_opaque :: proc(parser: ^Parser, name: token.Token) {
parse_opaque :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
start := advance(parser)
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden_name(parser, name))
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
if !types.define_record(&parser.module.type_store, id, nil, false, true, false) {
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
}
@@ -2480,10 +2503,10 @@ synthesize_union_tag :: proc(parser: ^Parser, fields: []types.Field) -> types.Ty
return types.enum_anonymous(&parser.module.type_store, members, types.U16)
}
parse_distinct :: proc(parser: ^Parser, name: token.Token) {
parse_distinct :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
start := advance(parser)
child := parse_type(parser)
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden_name(parser, name))
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
if !types.define_distinct(&parser.module.type_store, id, child) {
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
}
@@ -2493,7 +2516,7 @@ parse_distinct :: proc(parser: ^Parser, name: token.Token) {
_ = finish_statement(parser)
}
parse_alias :: proc(parser: ^Parser, name: token.Token) {
parse_alias :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
start := advance(parser)
saved := parser.cursor
if current(parser).kind == .Identifier && peek(parser).kind == .Dot {
@@ -2510,7 +2533,7 @@ parse_alias :: proc(parser: ^Parser, name: token.Token) {
pkg=parser.pkg,
file=parser.file,
target_pkg=ast.INVALID_PACKAGE,
file_hidden=file_hidden_name(parser, name),
file_hidden=file_hidden,
valid=true,
diagnostic=source.INVALID_DIAGNOSTIC,
})
@@ -2521,7 +2544,7 @@ parse_alias :: proc(parser: ^Parser, name: token.Token) {
}
parser.cursor = saved
child := parse_type(parser)
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden_name(parser, name))
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
if !types.define_alias(&parser.module.type_store, id, child) {
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
}
@@ -2650,7 +2673,7 @@ parse_inline_enum_type :: proc(parser: ^Parser) -> types.Type {
return types.enum_anonymous(&parser.module.type_store, members[:], backing)
}
parse_enum :: proc(parser: ^Parser, name: token.Token) {
parse_enum :: proc(parser: ^Parser, name: token.Token, file_hidden: bool) {
start := advance(parser)
explicit_backing := false
backing := types.INVALID
@@ -2668,7 +2691,7 @@ parse_enum :: proc(parser: ^Parser, name: token.Token) {
_ = finish_statement(parser)
return
}
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden_name(parser, name))
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol), file=u32(parser.file), file_hidden=file_hidden)
if !types.define_enum(&parser.module.type_store, id, backing, members[:], explicit_backing) {
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
}
@@ -2764,13 +2787,18 @@ parse_import :: proc(parser: ^Parser, alias: token.Token, start: token.Token) {
}
parse_top_level :: proc(parser: ^Parser) {
hide_token, file_hidden := allow(parser, .Keyword_Hide)
if current(parser).kind == .Keyword_Import {
if file_hidden {
source.add(parser.diagnostics, hide_token.span, "imports are already file-local and cannot use 'hide'")
}
start := advance(parser)
parse_import(parser, token.Token{}, start)
return
}
if current(parser).kind != .Identifier {
source.add(parser.diagnostics, current(parser).span, "expected a top-level declaration")
message := "expected a declaration name after 'hide'" if file_hidden else "expected a top-level declaration"
source.add(parser.diagnostics, current(parser).span, message)
for current(parser).kind != .Newline && current(parser).kind != .Eof {
advance(parser)
}
@@ -2783,6 +2811,9 @@ parse_top_level :: proc(parser: ^Parser) {
advance(parser)
skip_newlines(parser)
if current(parser).kind == .Keyword_Import {
if file_hidden {
source.add(parser.diagnostics, hide_token.span, "imports are already file-local and cannot use 'hide'")
}
start := advance(parser)
parse_import(parser, name, start)
return
@@ -2791,7 +2822,7 @@ parse_top_level :: proc(parser: ^Parser) {
}
if current(parser).kind == .Keyword_Func || current(parser).kind == .Keyword_C_Func {
c_abi := current(parser).kind == .Keyword_C_Func
parse_function(parser, name, c_abi)
parse_function(parser, name, c_abi, file_hidden)
return
}
type_syntax := types.INVALID
@@ -2812,32 +2843,32 @@ parse_top_level :: proc(parser: ^Parser) {
source.add(parser.diagnostics, span_from(name.span, current(parser).span),
"function declarations do not use '::'; write 'name func(...)' or 'name c_func(...)'")
c_abi := current(parser).kind == .Keyword_C_Func
parse_function(parser, name, c_abi)
parse_function(parser, name, c_abi, file_hidden)
return
}
if operator.kind == .Colon_Colon &&
(current(parser).kind == .Keyword_Struct || current(parser).kind == .Keyword_C_Struct) {
parse_struct(parser, name, current(parser).kind == .Keyword_C_Struct)
parse_struct(parser, name, current(parser).kind == .Keyword_C_Struct, file_hidden)
return
}
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Opaque {
parse_opaque(parser, name)
parse_opaque(parser, name, file_hidden)
return
}
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Union {
parse_struct(parser, name, false, is_union=true)
parse_struct(parser, name, false, file_hidden, is_union=true)
return
}
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Enum {
parse_enum(parser, name)
parse_enum(parser, name, file_hidden)
return
}
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Distinct {
parse_distinct(parser, name)
parse_distinct(parser, name, file_hidden)
return
}
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Alias {
parse_alias(parser, name)
parse_alias(parser, name, file_hidden)
return
}
@@ -2848,7 +2879,7 @@ parse_top_level :: proc(parser: ^Parser) {
name=name.symbol,
pkg=parser.pkg,
file=parser.file,
file_hidden=file_hidden_name(parser, name),
file_hidden=file_hidden,
type=type_syntax,
immutable=operator.kind == .Colon_Colon,
expr=expr,
@@ -2869,6 +2900,9 @@ parse :: proc(
diagnostics=diagnostics,
module=ast.init_module(allocator),
}
parser.hidden_names.allocator = allocator
defer delete(parser.hidden_names)
collect_hidden_names(&parser)
skip_newlines(&parser)
for current(&parser).kind != .Eof {
parse_top_level(&parser)
@@ -2893,6 +2927,9 @@ parse_into :: proc(
pkg=pkg,
file=file,
}
parser.hidden_names.allocator = module.allocator
defer delete(parser.hidden_names)
collect_hidden_names(&parser)
skip_newlines(&parser)
for current(&parser).kind != .Eof {
parse_top_level(&parser)
+1
View File
@@ -60,6 +60,7 @@ Kind :: enum u8 {
Keyword_Distinct,
Keyword_Alias,
Keyword_Import,
Keyword_Hide,
Keyword_Return,
Keyword_Try,
Keyword_Catch,
+37 -11
View File
@@ -7353,13 +7353,38 @@ imports_are_file_local :: proc(t: ^testing.T) {
}
@(test)
leading_underscore_declarations_are_file_hidden :: proc(t: ^testing.T) {
hide_is_rejected_outside_named_top_level_declarations :: proc(t: ^testing.T) {
cases := [?]string{
`hide import "../dep"`,
`hide dep :: import "../dep"`,
`hide func() void {}`,
`main func(hide value i32) void {}`,
`Box :: struct { hide i32 }`,
`main func() void { hide value i32 = 1 }`,
}
for text in cases {
source_file := source.Source{path="test.bro", text=text}
diagnostics := source.init_diagnostics(&source_file)
defer source.destroy_diagnostics(&diagnostics)
symbols := symbol.init_table()
defer symbol.destroy_table(&symbols)
stream := lexer.lex(&source_file, &diagnostics, &symbols)
defer delete(stream.items)
module := parser.parse(&stream, &source_file, &diagnostics)
defer ast.destroy_module(&module)
testing.expect(t, len(diagnostics.items) > 0)
}
}
@(test)
hide_declarations_are_file_hidden :: proc(t: ^testing.T) {
output := "/tmp/brolang-test-hidden-declarations"
defer _ = os.remove(output)
status := compiler_core.compile_package("examples/packages/hidden_valid/app", output)
testing.expect_value(t, status, 0)
state := run_executable(output)
testing.expect_value(t, state.exit_code, 7)
testing.expect_value(t, state.exit_code, 9)
}
@(test)
@@ -7382,11 +7407,11 @@ file_hidden_declarations_are_not_package_members :: proc(t: ^testing.T) {
found_import := false
found_collision := false
for diagnostic in diagnostics.items {
found_sibling = found_sibling || strings.contains(diagnostic.message, "unresolved function '_sibling'")
found_sibling_value = found_sibling_value || strings.contains(diagnostic.message, "unresolved global '_sibling_value'")
found_sibling_type = found_sibling_type || strings.contains(diagnostic.message, "unknown or opaque record type '_Sibling'")
found_import = found_import || strings.contains(diagnostic.message, "package 'dep' has no member '_secret'")
found_collision = found_collision || strings.contains(diagnostic.message, "duplicate function '_collision'")
found_sibling = found_sibling || strings.contains(diagnostic.message, "unresolved function 'sibling'")
found_sibling_value = found_sibling_value || strings.contains(diagnostic.message, "unresolved global 'sibling_value'")
found_sibling_type = found_sibling_type || strings.contains(diagnostic.message, "unknown or opaque record type 'Sibling'")
found_import = found_import || strings.contains(diagnostic.message, "package 'dep' has no member 'secret'")
found_collision = found_collision || strings.contains(diagnostic.message, "duplicate function 'collision'")
}
testing.expect(t, found_sibling)
testing.expect(t, found_sibling_value)
@@ -7513,8 +7538,8 @@ RenamedBox :: alias dep.Box
RenamedPoint :: alias dep.Point
counter :: alias dep.counter
answer :: alias dep.answer
_local_answer :: alias dep.answer
local_answer func() i32 { return _local_answer() }
hide local_answer_alias :: alias dep.answer
local_answer func() i32 { return local_answer_alias() }
Scalar :: alias i32
MaybePoint :: alias ?@dep.Point
Concrete :: alias dep.Box(i32)
@@ -7567,14 +7592,14 @@ declaration_aliases_diagnose_invalid_targets :: proc(t: ^testing.T) {
testing.expect(t, os.make_directory(directory) == nil)
}
dep_text := `visible func() i32 { return 1 }
_hidden func() i32 { return 2 }
hide hidden_target func() i32 { return 2 }
ambiguous func() i32 { return 3 }
ambiguous i32 :: 4
`
facade_text := `dep :: import "../dep"
gone :: import "../gone"
missing :: alias dep.missing
hidden :: alias dep._hidden
hidden :: alias dep.hidden_target
unknown :: alias nope.visible
unavailable :: alias gone.visible
ambiguous :: alias dep.ambiguous
@@ -10589,6 +10614,7 @@ main func() i32 {
@(test)
keywords_are_valid_enum_members_and_tagged_union_variants :: proc(t: ^testing.T) {
testing.expect(t, token.is_keyword(.Keyword_Func))
testing.expect(t, token.is_keyword(.Keyword_Hide))
testing.expect(t, token.is_keyword(.Keyword_C_Longdouble))
testing.expect(t, !token.is_keyword(.Identifier))
testing.expect(t, !token.is_keyword(.Underscore))
+4 -4
View File
@@ -1,13 +1,13 @@
_sibling func() i32 {
hide sibling func() i32 {
return 1
}
_Sibling :: struct {
hide Sibling :: struct {
value i32
}
_sibling_value :: 1
hide sibling_value :: 1
_collision c_func() i32 {
collision c_func() i32 {
return 1
}
+5 -5
View File
@@ -1,17 +1,17 @@
import "../dep"
_collision func() i32 {
hide collision func() i32 {
return 2
}
read_sibling func(value _Sibling) i32 {
return value.value + _sibling_value
read_sibling func(value Sibling) i32 {
return value.value + sibling_value
}
read_sibling_value func() i32 {
return _sibling_value
return sibling_value
}
main func() i32 {
return _sibling() + dep._secret() + read_sibling(_Sibling { value = 1 }) + read_sibling_value()
return sibling() + dep.secret() + read_sibling(Sibling { value = 1 }) + read_sibling_value()
}
+1 -1
View File
@@ -1,3 +1,3 @@
_secret func() i32 {
hide secret c_func() i32 {
return 1
}
+30 -8
View File
@@ -1,14 +1,27 @@
_Thing :: struct {
hide helper func() i32 {
thing Thing = Thing { value = value }
return thing.value
}
hide Thing :: struct {
value i32
}
_value :: 1
_helper func() i32 {
thing _Thing = _Thing { value = _value }
return thing.value
hide Local_Union :: union {
value i32
}
hide Local_Enum :: enum {
value
}
hide Local_Opaque :: opaque
hide Local_Distinct :: distinct i32
hide Local_Alias :: alias i32
hide value :: 1
hide mutable_value i32 = 1
_foreign c_func() i32 {
return 1
}
@@ -17,6 +30,15 @@ _C_Record :: c_struct {
value c_int
}
from_a func() i32 {
return _helper()
hide local_foreign c_func() i32 {
return 1
}
hide Local_C_Record :: c_struct {
value c_int
}
from_a func() i32 {
record Local_C_Record = Local_C_Record { value = 0 }
return helper() + local_foreign() + i32(record.value)
}
+28 -5
View File
@@ -1,14 +1,37 @@
_Thing :: struct {
import "../dep"
hide Thing :: struct {
value i32
}
_value :: 2
hide Local_Union :: union {
value i32
}
_helper func() i32 {
thing _Thing = _Thing { value = _value }
hide Local_Enum :: enum {
value
}
hide Local_Opaque :: opaque
hide Local_Distinct :: distinct i32
hide Local_Alias :: alias i32
hide value :: 2
hide mutable_value i32 = 2
hide helper func() i32 {
thing Thing = Thing { value = value }
return thing.value
}
hide local_foreign c_func() i32 {
return 1
}
hide Local_C_Record :: c_struct {
value c_int
}
Box :: struct {
_value i32
}
@@ -16,5 +39,5 @@ Box :: struct {
from_b func(_input i32) i32 {
_local Box = Box { _value = _input }
record _C_Record = _C_Record { value = 0 }
return _helper() + _local._value + _foreign() + i32(record.value)
return helper() + _local._value + _foreign() + i32(record.value) + dep._visible()
}
@@ -0,0 +1,3 @@
_visible func() i32 {
return 1
}
+10 -10
View File
@@ -2,25 +2,25 @@ arraylist :: import "@std/arraylist"
mem :: import "@std/mem"
std :: import "@std"
_fail_alloc func(_ ?*mut anyopaque, _ usize, _ usize) ?*mut u8 {
hide fail_alloc func(_ ?*mut anyopaque, _ usize, _ usize) ?*mut u8 {
return none
}
_fail_realloc func(_ ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize, _ usize) ?*mut u8 {
hide fail_realloc func(_ ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize, _ usize) ?*mut u8 {
return none
}
_fail_free func(_ ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize) void {}
hide fail_free func(_ ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize) void {}
_fail_vtable mem.AllocatorVTable :: mem.AllocatorVTable {
alloc = _fail_alloc,
realloc = _fail_realloc,
free = _fail_free,
hide fail_vtable mem.AllocatorVTable :: mem.AllocatorVTable {
alloc = fail_alloc,
realloc = fail_realloc,
free = fail_free,
}
_fail_allocator mem.Allocator :: mem.Allocator {
hide fail_allocator mem.Allocator :: mem.Allocator {
context = none,
vtable = &_fail_vtable,
vtable = &fail_vtable,
}
run func() i32 ! mem.AllocError {
@@ -59,7 +59,7 @@ run func() i32 ! mem.AllocError {
}
if (empty_values.items.len != 1) return 8
failed arraylist.ArrayList(i32) = arraylist.init(i32, _fail_allocator)
failed arraylist.ArrayList(i32) = arraylist.init(i32, fail_allocator)
failed_as_expected bool = false
arraylist.append(&failed, 1) catch |_| {
failed_as_expected = true
+30 -30
View File
@@ -1,6 +1,6 @@
io :: import "@std/io"
_read_ok func(_ ?*mut anyopaque, _ io.ReadStream, buffer []mut u8) usize ! io.ReadError {
hide read_ok func(_ ?*mut anyopaque, _ io.ReadStream, buffer []mut u8) usize ! io.ReadError {
if buffer.len == 0 {
return 0
}
@@ -12,52 +12,52 @@ _read_ok func(_ ?*mut anyopaque, _ io.ReadStream, buffer []mut u8) usize ! io.Re
return 2
}
_read_too_much func(_ ?*mut anyopaque, _ io.ReadStream, buffer []mut u8) usize ! io.ReadError {
hide read_too_much func(_ ?*mut anyopaque, _ io.ReadStream, buffer []mut u8) usize ! io.ReadError {
return buffer.len + 1
}
_read_eof func(_ ?*mut anyopaque, _ io.ReadStream, _ []mut u8) usize ! io.ReadError {
hide read_eof func(_ ?*mut anyopaque, _ io.ReadStream, _ []mut u8) usize ! io.ReadError {
return 0
}
_write_short func(_ ?*mut anyopaque, _ io.WriteStream, bytes []u8) usize ! io.WriteError {
hide write_short func(_ ?*mut anyopaque, _ io.WriteStream, bytes []u8) usize ! io.WriteError {
if bytes.len > 2 {
return 2
}
return bytes.len
}
_write_none func(_ ?*mut anyopaque, _ io.WriteStream, _ []u8) usize ! io.WriteError {
hide write_none func(_ ?*mut anyopaque, _ io.WriteStream, _ []u8) usize ! io.WriteError {
return 0
}
_write_too_much func(_ ?*mut anyopaque, _ io.WriteStream, bytes []u8) usize ! io.WriteError {
hide write_too_much func(_ ?*mut anyopaque, _ io.WriteStream, bytes []u8) usize ! io.WriteError {
return bytes.len + 1
}
_ok_vtable io.IoVTable :: io.IoVTable {
read = _read_ok,
write = _write_short,
hide ok_vtable io.IoVTable :: io.IoVTable {
read = read_ok,
write = write_short,
}
_read_bad_vtable io.IoVTable :: io.IoVTable {
read = _read_too_much,
write = _write_short,
hide read_bad_vtable io.IoVTable :: io.IoVTable {
read = read_too_much,
write = write_short,
}
_eof_vtable io.IoVTable :: io.IoVTable {
read = _read_eof,
write = _write_short,
hide eof_vtable io.IoVTable :: io.IoVTable {
read = read_eof,
write = write_short,
}
_write_none_vtable io.IoVTable :: io.IoVTable {
read = _read_ok,
write = _write_none,
hide write_none_vtable io.IoVTable :: io.IoVTable {
read = read_ok,
write = write_none,
}
_write_bad_vtable io.IoVTable :: io.IoVTable {
read = _read_ok,
write = _write_too_much,
hide write_bad_vtable io.IoVTable :: io.IoVTable {
read = read_ok,
write = write_too_much,
}
reader_for func(vtable @io.IoVTable) io.Reader {
@@ -76,39 +76,39 @@ writer_for func(vtable @io.IoVTable) io.Writer {
rejects_bad_read func() bool {
buffer [1]mut u8 = [0]
_ = io.read(reader_for(&_read_bad_vtable), buffer[..]) catch |err| {
_ = io.read(reader_for(&read_bad_vtable), buffer[..]) catch |err| {
return err == .read_failed
}
return false
}
rejects_no_progress func() bool {
io.write_all(writer_for(&_write_none_vtable), "x") catch |err| {
io.write_all(writer_for(&write_none_vtable), "x") catch |err| {
return err == .no_progress
}
return false
}
rejects_bad_write func() bool {
_ = io.write(writer_for(&_write_bad_vtable), "x") catch |err| {
_ = io.write(writer_for(&write_bad_vtable), "x") catch |err| {
return err == .write_failed
}
return false
}
main func(system io.Io) i32 {
main func(system std.Io) i32 {
buffer [2]mut u8 = [0, 0]
count usize :: io.read(reader_for(&_ok_vtable), buffer[..]) catch 0
count usize :: io.read(reader_for(&ok_vtable), buffer[..]) catch 0
if count != 2 or buffer[0] != 'o' or buffer[1] != 'k' {
return 1
}
eof usize :: io.read(reader_for(&_eof_vtable), buffer[..]) catch 1
empty_read usize :: io.read(reader_for(&_read_bad_vtable), buffer[0..0]) catch 1
empty_write usize :: io.write(writer_for(&_write_bad_vtable), "") catch 1
eof usize :: io.read(reader_for(&eof_vtable), buffer[..]) catch 1
empty_read usize :: io.read(reader_for(&read_bad_vtable), buffer[0..0]) catch 1
empty_write usize :: io.write(writer_for(&write_bad_vtable), "") catch 1
if eof != 0 or empty_read != 0 or empty_write != 0 {
return 5
}
io.write_all(writer_for(&_ok_vtable), "partial") catch |_| {
io.write_all(writer_for(&ok_vtable), "partial") catch |_| {
return 2
}
if !rejects_bad_read() or !rejects_no_progress() or !rejects_bad_write() {
+13 -13
View File
@@ -1,30 +1,30 @@
mem :: import "@std/mem"
_probe_count func(context ?*mut anyopaque) void {
hide probe_count func(context ?*mut anyopaque) void {
if context |raw| {
counts *mut usize :: ptrcast!(usize, raw)
counts[0] += 1
}
}
_probe_alloc func(context ?*mut anyopaque, _ usize, _ usize) ?*mut u8 {
_probe_count(context)
hide probe_alloc func(context ?*mut anyopaque, _ usize, _ usize) ?*mut u8 {
probe_count(context)
return none
}
_probe_realloc func(context ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize, _ usize) ?*mut u8 {
_probe_count(context)
hide probe_realloc func(context ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize, _ usize) ?*mut u8 {
probe_count(context)
return none
}
_probe_free func(context ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize) void {
_probe_count(context)
hide probe_free func(context ?*mut anyopaque, _ ?*mut u8, _ usize, _ usize) void {
probe_count(context)
}
_probe_vtable mem.AllocatorVTable :: mem.AllocatorVTable {
alloc = _probe_alloc,
realloc = _probe_realloc,
free = _probe_free,
hide probe_vtable mem.AllocatorVTable :: mem.AllocatorVTable {
alloc = probe_alloc,
realloc = probe_realloc,
free = probe_free,
}
typed_allocator_test func() i32 {
@@ -34,11 +34,11 @@ typed_allocator_test func() i32 {
second_calls [1]mut usize = [0]
first_allocator mem.Allocator :: mem.Allocator {
context = (&first_calls).ptr,
vtable = &_probe_vtable,
vtable = &probe_vtable,
}
second_allocator mem.Allocator :: mem.Allocator {
context = (&second_calls).ptr,
vtable = &_probe_vtable,
vtable = &probe_vtable,
}
_ = mem.raw_alloc(first_allocator, 1, 1)
+7 -7
View File
@@ -74,7 +74,7 @@ write_all func(writer Writer, bytes []u8) void ! WriteError {
return
}
_system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError {
hide system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError {
request usize = buffer.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
@@ -91,7 +91,7 @@ _system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize !
}
}
_system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError {
hide system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError {
fd c_int :: c_int(stream)
request usize = bytes.len
maximum usize :: usize(maxval!(c_long))
@@ -109,14 +109,14 @@ _system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! Wr
}
}
_system_vtable IoVTable :: IoVTable {
read = _system_read,
write = _system_write,
hide system_vtable IoVTable :: IoVTable {
read = system_read,
write = system_write,
}
_system func() Io {
hide system func() Io {
return Io {
context = none,
vtable = &_system_vtable,
vtable = &system_vtable,
}
}
+24 -24
View File
@@ -41,25 +41,25 @@ eql func($T type, left, right []T) bool {
return true
}
_empty_storage [1]mut u64 = [0]
hide empty_storage [1]mut u64 = [0]
_empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&_empty_storage).ptr)
hide empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
return pointer[..count]
}
empty func($T type) []mut T {
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
if count == 0 {
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
element_size usize :: sizeof!(T)
if element_size == 0 {
return _empty_slice(T, count)
return empty_slice(T, count)
}
if count > divtrunc!(maxval!(usize), element_size) {
return .out_of_memory
@@ -79,12 +79,12 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
}
if new_count == 0 {
free(allocator, memory)
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
element_size usize :: sizeof!(T)
if element_size == 0 {
return _empty_slice(T, new_count)
return empty_slice(T, new_count)
}
if new_count > divtrunc!(maxval!(usize), element_size) {
return .out_of_memory
@@ -116,9 +116,9 @@ free func($T type, allocator Allocator, memory []mut T) void {
}
}
_malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
hide malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
_power_of_two func(value usize) bool {
hide power_of_two func(value usize) bool {
if value == 0 {
return false
}
@@ -135,12 +135,12 @@ _power_of_two func(value usize) bool {
return true
}
_c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
if alignment <= _malloc_alignment {
if alignment <= malloc_alignment {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
@@ -153,8 +153,8 @@ _c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
return ptrcast!(u8, memory[0])
}
_c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
@@ -164,11 +164,11 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
}
if memory |old_memory| {
if alignment <= _malloc_alignment {
if alignment <= malloc_alignment {
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = _c_alloc(none, new_size, alignment)
new_memory ?*mut u8 = c_alloc(none, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
if new_size < copy_size {
@@ -183,20 +183,20 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
return new_memory
}
return _c_alloc(none, new_size, alignment)
return c_alloc(none, new_size, alignment)
}
_c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
hide c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
c.free(memory)
}
_c_vtable AllocatorVTable :: AllocatorVTable {
alloc = _c_alloc,
realloc = _c_realloc,
free = _c_free,
hide c_vtable AllocatorVTable :: AllocatorVTable {
alloc = c_alloc,
realloc = c_realloc,
free = c_free,
}
c_allocator Allocator :: Allocator {
context = none,
vtable = &_c_vtable,
vtable = &c_vtable,
}
+2
View File
@@ -1,3 +1,5 @@
import "io"
import "arraylist"
Io :: alias io.Io
ArrayList :: alias arraylist.ArrayList
+19 -19
View File
@@ -20,17 +20,17 @@ Token :: struct {
kind Kind
}
_is_alpha func(value u8) bool {
hide is_alpha func(value u8) bool {
return value == '_' or
value >= 'a' and value <= 'z' or
value >= 'A' and value <= 'Z'
}
_is_digit func(value u8) bool {
hide is_digit func(value u8) bool {
return value >= '0' and value <= '9'
}
_word_kind func(word []u8) Kind {
hide word_kind func(word []u8) Kind {
# ponytail: enough keywords for the demo; add the full language set when a parser needs it.
if mem.eql(word, "func") or mem.eql(word, "void") {
return .keyword
@@ -38,7 +38,7 @@ _word_kind func(word []u8) Kind {
return .identifier
}
_append func(tokens @mut std.ArrayList(Token), kind Kind, start, end usize) void ! mem.AllocError {
hide append_token func(tokens @mut std.ArrayList(Token), kind Kind, start, end usize) void ! mem.AllocError {
try arraylist.append(tokens, Token {
start = start,
length = end - start,
@@ -54,19 +54,19 @@ lex func(source []u8, tokens @mut std.ArrayList(Token)) void ! mem.AllocError {
if value == ' ' or value == '\t' or value == '\r' {
cursor += 1
} else if value == '\n' {
try _append(tokens, .newline, cursor, cursor + 1)
try append_token(tokens, .newline, cursor, cursor + 1)
cursor += 1
} else if value == '#' {
while cursor < source.len and source[cursor] != '\n' : cursor += 1 {}
} else if _is_alpha(value) {
} else if is_alpha(value) {
start usize :: cursor
cursor += 1
while cursor < source.len and (_is_alpha(source[cursor]) or _is_digit(source[cursor])) : cursor += 1 {}
try _append(tokens, _word_kind(source[start..cursor]), start, cursor)
} else if _is_digit(value) {
while cursor < source.len and (is_alpha(source[cursor]) or is_digit(source[cursor])) : cursor += 1 {}
try append_token(tokens, word_kind(source[start..cursor]), start, cursor)
} else if is_digit(value) {
start usize :: cursor
while cursor < source.len and _is_digit(source[cursor]) : cursor += 1 {}
try _append(tokens, .integer, start, cursor)
while cursor < source.len and is_digit(source[cursor]) : cursor += 1 {}
try append_token(tokens, .integer, start, cursor)
} else if value == '"' {
start usize :: cursor
cursor += 1
@@ -78,9 +78,9 @@ lex func(source []u8, tokens @mut std.ArrayList(Token)) void ! mem.AllocError {
}
if cursor < source.len and source[cursor] == '"' {
cursor += 1
try _append(tokens, .string, start, cursor)
try append_token(tokens, .string, start, cursor)
} else {
try _append(tokens, .invalid, start, cursor)
try append_token(tokens, .invalid, start, cursor)
}
} else {
start usize :: cursor
@@ -88,14 +88,14 @@ lex func(source []u8, tokens @mut std.ArrayList(Token)) void ! mem.AllocError {
if value == ':' and cursor < source.len and source[cursor] == ':' {
cursor += 1
}
try _append(tokens, .punctuation, start, cursor)
try append_token(tokens, .punctuation, start, cursor)
}
}
try _append(tokens, .eof, cursor, cursor)
try append_token(tokens, .eof, cursor, cursor)
return
}
_kind_name func(kind Kind) *c_char {
hide kind_name func(kind Kind) *c_char {
return match kind {
.invalid: "invalid"
.eof: "eof"
@@ -108,8 +108,8 @@ _kind_name func(kind Kind) *c_char {
}
}
_print_token func(source []u8, token Token) void {
_ = c.printf("%-11s", _kind_name(token.kind))
hide print_token func(source []u8, token Token) void {
_ = c.printf("%-11s", kind_name(token.kind))
if token.length != 0 {
_ = c.printf(" `")
i usize = 0
@@ -149,7 +149,7 @@ main func() i32 {
}
for tokens.items |token| {
_print_token(source, token)
print_token(source, token)
}
return 0
}
+7 -7
View File
@@ -74,7 +74,7 @@ write_all func(writer Writer, bytes []u8) void ! WriteError {
return
}
_system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError {
hide system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize ! ReadError {
request usize = buffer.len
maximum usize :: usize(maxval!(c_long))
if request > maximum {
@@ -91,7 +91,7 @@ _system_read func(_ ?*mut anyopaque, stream ReadStream, buffer []mut u8) usize !
}
}
_system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError {
hide system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! WriteError {
fd c_int :: c_int(stream)
request usize = bytes.len
maximum usize :: usize(maxval!(c_long))
@@ -109,14 +109,14 @@ _system_write func(_ ?*mut anyopaque, stream WriteStream, bytes []u8) usize ! Wr
}
}
_system_vtable IoVTable :: IoVTable {
read = _system_read,
write = _system_write,
hide system_vtable IoVTable :: IoVTable {
read = system_read,
write = system_write,
}
_system func() Io {
hide system func() Io {
return Io {
context = none,
vtable = &_system_vtable,
vtable = &system_vtable,
}
}
+24 -24
View File
@@ -41,25 +41,25 @@ eql func($T type, left, right []T) bool {
return true
}
_empty_storage [1]mut u64 = [0]
hide empty_storage [1]mut u64 = [0]
_empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&_empty_storage).ptr)
hide empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
return pointer[..count]
}
empty func($T type) []mut T {
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
if count == 0 {
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
element_size usize :: sizeof!(T)
if element_size == 0 {
return _empty_slice(T, count)
return empty_slice(T, count)
}
if count > divtrunc!(maxval!(usize), element_size) {
return .out_of_memory
@@ -79,12 +79,12 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
}
if new_count == 0 {
free(allocator, memory)
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
element_size usize :: sizeof!(T)
if element_size == 0 {
return _empty_slice(T, new_count)
return empty_slice(T, new_count)
}
if new_count > divtrunc!(maxval!(usize), element_size) {
return .out_of_memory
@@ -116,9 +116,9 @@ free func($T type, allocator Allocator, memory []mut T) void {
}
}
_malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
hide malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
_power_of_two func(value usize) bool {
hide power_of_two func(value usize) bool {
if value == 0 {
return false
}
@@ -135,12 +135,12 @@ _power_of_two func(value usize) bool {
return true
}
_c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
if alignment <= _malloc_alignment {
if alignment <= malloc_alignment {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
@@ -153,8 +153,8 @@ _c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
return ptrcast!(u8, memory[0])
}
_c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
@@ -164,11 +164,11 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
}
if memory |old_memory| {
if alignment <= _malloc_alignment {
if alignment <= malloc_alignment {
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = _c_alloc(none, new_size, alignment)
new_memory ?*mut u8 = c_alloc(none, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
if new_size < copy_size {
@@ -183,20 +183,20 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
return new_memory
}
return _c_alloc(none, new_size, alignment)
return c_alloc(none, new_size, alignment)
}
_c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
hide c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
c.free(memory)
}
_c_vtable AllocatorVTable :: AllocatorVTable {
alloc = _c_alloc,
realloc = _c_realloc,
free = _c_free,
hide c_vtable AllocatorVTable :: AllocatorVTable {
alloc = c_alloc,
realloc = c_realloc,
free = c_free,
}
c_allocator Allocator :: Allocator {
context = none,
vtable = &_c_vtable,
vtable = &c_vtable,
}
+21 -21
View File
@@ -27,21 +27,21 @@ raw_free func(allocator Allocator, memory ?*mut u8, size usize, alignment usize)
allocator.vtable.free(allocator.context, memory, size, alignment)
}
_empty_storage [1]mut u64 = [0]
hide empty_storage [1]mut u64 = [0]
_empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&_empty_storage).ptr)
hide empty_slice func($T type, count usize) []mut T {
pointer *mut T :: ptrcast!(T, (&empty_storage).ptr)
return pointer[..count]
}
alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
if count == 0 {
return _empty_slice(T, 0)
return empty_slice(T, 0)
}
element_size usize :: sizeof!(T)
if element_size == 0 {
return _empty_slice(T, count)
return empty_slice(T, count)
}
if count > maxval!(usize) / element_size {
return .out_of_memory
@@ -61,9 +61,9 @@ free func($T type, allocator Allocator, memory []mut T) void {
}
}
_malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
hide malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
_power_of_two func(value usize) bool {
hide power_of_two func(value usize) bool {
if value == 0 {
return false
}
@@ -80,12 +80,12 @@ _power_of_two func(value usize) bool {
return true
}
_c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
if alignment <= _malloc_alignment {
if alignment <= malloc_alignment {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
@@ -98,8 +98,8 @@ _c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
return ptrcast!(u8, memory[0])
}
_c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if _power_of_two(alignment) == false {
hide c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
@@ -109,11 +109,11 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
}
if memory |old_memory| {
if alignment <= _malloc_alignment {
if alignment <= malloc_alignment {
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = _c_alloc(none, new_size, alignment)
new_memory ?*mut u8 = c_alloc(none, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
if new_size < copy_size {
@@ -128,20 +128,20 @@ _c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usi
return new_memory
}
return _c_alloc(none, new_size, alignment)
return c_alloc(none, new_size, alignment)
}
_c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
hide c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
c.free(memory)
}
_c_vtable AllocatorVTable :: AllocatorVTable {
alloc = _c_alloc,
realloc = _c_realloc,
free = _c_free,
hide c_vtable AllocatorVTable :: AllocatorVTable {
alloc = c_alloc,
realloc = c_realloc,
free = c_free,
}
c_allocator Allocator :: Allocator {
context = none,
vtable = &_c_vtable,
vtable = &c_vtable,
}
+4
View File
@@ -51,6 +51,7 @@ module.exports = grammar({
),
function_declaration: $ => seq(
optional('hide'),
field('name', $.identifier),
field('kind', choice('func', 'c_func')),
field('parameters', $.parameter_list),
@@ -64,6 +65,7 @@ module.exports = grammar({
),
type_declaration: $ => prec(1, seq(
optional('hide'),
field('name', $.identifier),
'::',
repeat($._newline),
@@ -79,6 +81,7 @@ module.exports = grammar({
)),
global_constant_declaration: $ => seq(
optional('hide'),
field('name', $.identifier),
optional(field('type', $.type)),
'::',
@@ -87,6 +90,7 @@ module.exports = grammar({
),
global_variable_declaration: $ => seq(
optional('hide'),
field('name', $.identifier),
optional(field('type', $.type)),
'=',
@@ -60,6 +60,7 @@
"distinct"
"alias"
"import"
"hide"
"return"
"try"
"catch"
+48
View File
@@ -103,6 +103,18 @@
"function_declaration": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "hide"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "name",
@@ -225,6 +237,18 @@
"content": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "hide"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "name",
@@ -287,6 +311,18 @@
"global_constant_declaration": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "hide"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "name",
@@ -335,6 +371,18 @@
"global_variable_declaration": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "hide"
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "name",
+4
View File
@@ -2576,6 +2576,10 @@
"type": "func",
"named": false
},
{
"type": "hide",
"named": false
},
{
"type": "i16",
"named": false
+124751 -122484
View File
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,16 @@ Core syntax
io :: import "@std/io"
hide private_value :: 1
hide private_counter i32 = 0
hide Private :: opaque
hide private_sum func(a, b i32) i32 {
return a + b
}
Status :: enum {
ok
bad
@@ -30,6 +40,38 @@ sum func(a, b i32) i32 ! Status {
(identifier)
(string
(string_content)))
(global_constant_declaration
(identifier)
(expression
(integer)))
(global_variable_declaration
(identifier)
(type
(builtin_type))
(expression
(integer)))
(type_declaration
(identifier)
(opaque_type))
(function_declaration
(identifier)
(parameter_list
(parameter
(identifier)
(identifier)
(type
(builtin_type))))
(type
(builtin_type))
(block
(statement
(return_statement
(expression
(binary_expression
(expression
(identifier))
(expression
(identifier))))))))
(type_declaration
(identifier)
(enum_type
@@ -1,7 +1,10 @@
hide helper func() void {}
# <- keyword
main func() void {
_ = sizeof!(i32)
# ^^^^^^ function.builtin
# ^ operator
# ^ operator
_ = sizeof(i32)
# ^^^^^^ function
}