package-type imports

This commit is contained in:
2026-06-10 00:08:33 +02:00
parent 087fdb45d5
commit d6e03b6f08
104 changed files with 1799 additions and 273 deletions
+126 -15
View File
@@ -3,16 +3,24 @@ package parser
import "../ast"
import "../source"
import "../token"
import "core:fmt"
import "core:strconv"
import "core:strings"
Parser :: struct {
tokens: ^token.Stream,
diagnostics: ^source.Diagnostics,
module: ast.Module,
pkg: int,
file: int,
cursor: int,
delimiter_depth: int,
}
span_from :: proc(first, last: source.Span) -> source.Span {
return source.Span{file=first.file, start=first.start, end=last.end}
}
current :: proc(parser: ^Parser) -> token.Token {
return parser.tokens.items[min(parser.cursor, len(parser.tokens.items)-1)]
}
@@ -93,7 +101,7 @@ parse_type :: proc(parser: ^Parser) -> ast.Type_Syntax {
return .Invalid
}
parse_call :: proc(parser: ^Parser, name: token.Token) -> int {
parse_call :: proc(parser: ^Parser, qualifier: string, first, name: token.Token) -> int {
left_paren := advance(parser)
parser.delimiter_depth += 1
defer parser.delimiter_depth -= 1
@@ -116,7 +124,8 @@ parse_call :: proc(parser: ^Parser, name: token.Token) -> int {
}
return add_expr(parser, ast.Expr{
kind=.Call,
span=source.Span{start=name.span.start, end=right_paren.span.end},
span=source.Span{file=name.span.file, start=first.span.start, end=right_paren.span.end},
qualifier=qualifier,
text=name.text,
args=args[:],
left=ast.INVALID_ID,
@@ -143,14 +152,24 @@ parse_primary :: proc(parser: ^Parser) -> int {
diagnostic=-1,
})
case .Identifier:
advance(parser)
first := advance(parser)
name := first
qualifier := ""
if _, ok := allow(parser, .Dot); ok {
if current(parser).kind != .Identifier {
return invalid_expr(parser, current(parser).span, "expected a package member after '.'")
}
qualifier = first.text
name = advance(parser)
}
if current(parser).kind == .Left_Paren {
return parse_call(parser, tok)
return parse_call(parser, qualifier, first, name)
}
return add_expr(parser, ast.Expr{
kind=.Name,
span=tok.span,
text=tok.text,
span=span_from(first.span, name.span),
qualifier=qualifier,
text=name.text,
left=ast.INVALID_ID,
right=ast.INVALID_ID,
diagnostic=-1,
@@ -198,7 +217,7 @@ parse_expression :: proc(parser: ^Parser) -> int {
right_expr := parser.module.exprs[right]
left = add_expr(parser, ast.Expr{
kind=.Add,
span=source.Span{start=left_expr.span.start, end=right_expr.span.end},
span=span_from(left_expr.span, right_expr.span),
left=left,
right=right,
diagnostic=-1,
@@ -210,12 +229,12 @@ parse_expression :: proc(parser: ^Parser) -> int {
return left
}
finish_statement :: proc(parser: ^Parser) -> int {
finish_statement :: proc(parser: ^Parser, allow_closing_brace := false) -> int {
if current(parser).kind == .Newline {
skip_newlines(parser)
return -1
}
if current(parser).kind == .Eof {
if current(parser).kind == .Eof || allow_closing_brace && current(parser).kind == .Right_Brace {
return -1
}
diagnostic := source.add(
@@ -240,7 +259,7 @@ parse_return :: proc(parser: ^Parser) -> int {
id := len(parser.module.statements)
append(&parser.module.statements, ast.Stmt{
kind=.Return,
span=source.Span{start=start.span.start, end=end.span.end},
span=span_from(start.span, end.span),
name="_",
expr=ast.INVALID_ID,
diagnostic=-1,
@@ -251,7 +270,7 @@ parse_return :: proc(parser: ^Parser) -> int {
id := len(parser.module.statements)
append(&parser.module.statements, ast.Stmt{
kind=.Return,
span=source.Span{start=start.span.start, end=parser.module.exprs[expr].span.end},
span=span_from(start.span, parser.module.exprs[expr].span),
expr=expr,
diagnostic=-1,
})
@@ -286,7 +305,7 @@ parse_statement :: proc(parser: ^Parser) -> int {
id := len(parser.module.statements)
append(&parser.module.statements, ast.Stmt{
kind=kind,
span=source.Span{start=name.span.start, end=parser.module.exprs[expr].span.end},
span=span_from(name.span, parser.module.exprs[expr].span),
name=name.text,
type=type_syntax,
immutable=immutable,
@@ -367,7 +386,7 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
skip_newlines(parser)
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
append(&body, parse_statement(parser))
if diagnostic := finish_statement(parser); diagnostic >= 0 {
if diagnostic := finish_statement(parser, true); diagnostic >= 0 {
statement_id := len(parser.module.statements)
append(&parser.module.statements, ast.Stmt{
kind=.Invalid,
@@ -384,8 +403,10 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
end = func_token
}
append(&parser.module.functions, ast.Function{
span=source.Span{start=name.span.start, end=end.span.end},
span=span_from(name.span, end.span),
name=name.text,
pkg=parser.pkg,
file=parser.file,
c_abi=c_abi,
params=params,
result=result,
@@ -394,7 +415,63 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
})
}
decode_import_path :: proc(parser: ^Parser, tok: token.Token) -> string {
if len(tok.text) < 2 {
return fmt.aprintf("", allocator=parser.module.allocator)
}
builder := strings.builder_make(parser.module.allocator)
defer strings.builder_destroy(&builder)
for index := 1; index < len(tok.text)-1; index += 1 {
value := tok.text[index]
if value == '\\' && index+1 < len(tok.text)-1 {
index += 1
value = tok.text[index]
}
strings.write_byte(&builder, value)
}
return fmt.aprintf("%s", strings.to_string(builder), allocator=parser.module.allocator)
}
parse_import :: proc(parser: ^Parser, alias: token.Token, start: token.Token) {
skip_newlines(parser)
path_token := current(parser)
if path_token.kind != .String {
source.add(parser.diagnostics, path_token.span, "expected an import path string")
if path_token.kind != .Newline && path_token.kind != .Eof {
advance(parser)
}
append(&parser.module.imports, ast.Import{
span=start.span,
alias=alias.text,
pkg=parser.pkg,
file=parser.file,
target=-1,
valid=false,
diagnostic=-1,
})
_ = finish_statement(parser)
return
}
advance(parser)
append(&parser.module.imports, ast.Import{
span=span_from(start.span, path_token.span),
alias=alias.text,
path=decode_import_path(parser, path_token),
pkg=parser.pkg,
file=parser.file,
target=-1,
valid=true,
diagnostic=-1,
})
_ = finish_statement(parser)
}
parse_top_level :: proc(parser: ^Parser) {
if current(parser).kind == .Keyword_Import {
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")
for current(parser).kind != .Newline && current(parser).kind != .Eof {
@@ -404,6 +481,17 @@ parse_top_level :: proc(parser: ^Parser) {
return
}
name := advance(parser)
if current(parser).kind == .Colon_Colon {
saved := parser.cursor
advance(parser)
skip_newlines(parser)
if current(parser).kind == .Keyword_Import {
start := advance(parser)
parse_import(parser, name, start)
return
}
parser.cursor = saved
}
type_syntax := ast.Type_Syntax.Invalid
if is_type_token(current(parser).kind) {
type_syntax = parse_type(parser)
@@ -430,8 +518,10 @@ parse_top_level :: proc(parser: ^Parser) {
expr := parse_expression(parser)
append(&parser.module.globals, ast.Global{
span=source.Span{start=name.span.start, end=parser.module.exprs[expr].span.end},
span=span_from(name.span, parser.module.exprs[expr].span),
name=name.text,
pkg=parser.pkg,
file=parser.file,
type=type_syntax,
immutable=operator.kind == .Colon_Colon,
expr=expr,
@@ -457,3 +547,24 @@ parse :: proc(
}
return parser.module
}
parse_into :: proc(
stream: ^token.Stream,
diagnostics: ^source.Diagnostics,
module: ^ast.Module,
pkg, file: int,
) {
parser := Parser{
tokens=stream,
diagnostics=diagnostics,
module=module^,
pkg=pkg,
file=file,
}
skip_newlines(&parser)
for current(&parser).kind != .Eof {
parse_top_level(&parser)
skip_newlines(&parser)
}
module^ = parser.module
}