package-type imports
This commit is contained in:
+126
-15
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user