replace leading _ for private symbols with keyword hide
This commit is contained in:
+2
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -60,6 +60,7 @@ Kind :: enum u8 {
|
||||
Keyword_Distinct,
|
||||
Keyword_Alias,
|
||||
Keyword_Import,
|
||||
Keyword_Hide,
|
||||
Keyword_Return,
|
||||
Keyword_Try,
|
||||
Keyword_Catch,
|
||||
|
||||
+37
-11
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,3 +1,3 @@
|
||||
_secret func() i32 {
|
||||
hide secret c_func() i32 {
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import "io"
|
||||
import "arraylist"
|
||||
|
||||
Io :: alias io.Io
|
||||
ArrayList :: alias arraylist.ArrayList
|
||||
|
||||
+19
-19
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -2576,6 +2576,10 @@
|
||||
"type": "func",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "hide",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "i16",
|
||||
"named": false
|
||||
|
||||
+124751
-122484
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user