c interop type foundation
This commit is contained in:
+537
-28
@@ -4,9 +4,12 @@ import "../ast"
|
||||
import "../source"
|
||||
import "../symbol"
|
||||
import "../token"
|
||||
import "../types"
|
||||
import "base:intrinsics"
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
Parser :: struct {
|
||||
tokens: ^token.Stream,
|
||||
@@ -80,36 +83,225 @@ invalid_expr :: proc(parser: ^Parser, span: source.Span, message: string) -> ast
|
||||
|
||||
is_type_token :: proc(kind: token.Kind) -> bool {
|
||||
#partial switch kind {
|
||||
case .Keyword_Int, .Keyword_I8, .Keyword_I16, .Keyword_I32, .Keyword_I64, .Keyword_Void:
|
||||
case .Keyword_Int, .Keyword_I8, .Keyword_I16, .Keyword_I32, .Keyword_I64,
|
||||
.Keyword_U8, .Keyword_U16, .Keyword_U32, .Keyword_U64,
|
||||
.Keyword_Isize, .Keyword_Usize, .Keyword_F32, .Keyword_F64,
|
||||
.Keyword_C_Char, .Keyword_C_Schar, .Keyword_C_Uchar,
|
||||
.Keyword_C_Short, .Keyword_C_Ushort, .Keyword_C_Int, .Keyword_C_Uint,
|
||||
.Keyword_C_Long, .Keyword_C_Ulong, .Keyword_C_Longlong, .Keyword_C_Ulonglong,
|
||||
.Keyword_C_Float, .Keyword_C_Double, .Keyword_C_Longdouble,
|
||||
.Keyword_Void, .Identifier, .Question, .At, .Star, .Left_Bracket:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
decode_character :: proc(parser: ^Parser, tok: token.Token) -> (u64, bool) {
|
||||
text := token_text(parser, tok)
|
||||
if len(text) < 3 {
|
||||
return 0, false
|
||||
}
|
||||
contents := text[1:len(text)-1]
|
||||
if len(contents) == 2 && contents[0] == '\\' {
|
||||
switch contents[1] {
|
||||
case '0': return 0, true
|
||||
case 'n': return '\n', true
|
||||
case 'r': return '\r', true
|
||||
case 't': return '\t', true
|
||||
case '\\': return '\\', true
|
||||
case '\'': return '\'', true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
value, width := utf8.decode_rune_in_string(contents)
|
||||
return u64(value), width == len(contents)
|
||||
}
|
||||
|
||||
parse_type_constant :: proc(parser: ^Parser) -> (u64, bool) {
|
||||
negative := false
|
||||
if _, ok := allow(parser, .Minus); ok {
|
||||
negative = true
|
||||
}
|
||||
tok := current(parser)
|
||||
if tok.kind == .Integer {
|
||||
advance(parser)
|
||||
value, ok := parse_integer_magnitude(token_text(parser, tok))
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
if negative {
|
||||
return transmute(u64)-i64(value), true
|
||||
}
|
||||
return value, true
|
||||
}
|
||||
if !negative && tok.kind == .Character {
|
||||
advance(parser)
|
||||
return decode_character(parser, tok)
|
||||
}
|
||||
source.add(parser.diagnostics, tok.span, "expected an integer or character constant")
|
||||
return 0, false
|
||||
}
|
||||
|
||||
parse_type :: proc(parser: ^Parser) -> ast.Type_Syntax {
|
||||
tok := current(parser)
|
||||
if tok.kind == .Question {
|
||||
advance(parser)
|
||||
child := parse_type(parser)
|
||||
return types.intern(&parser.module.type_store, types.Node{kind=.Optional, child=child})
|
||||
}
|
||||
if tok.kind == .At || tok.kind == .Star {
|
||||
many := tok.kind == .Star
|
||||
advance(parser)
|
||||
_, mutable := allow(parser, .Keyword_Mut)
|
||||
child := parse_type(parser)
|
||||
return types.intern(&parser.module.type_store, types.Node{
|
||||
kind=.Pointer,
|
||||
child=child,
|
||||
mutable=mutable,
|
||||
many=many,
|
||||
})
|
||||
}
|
||||
if tok.kind == .Left_Bracket {
|
||||
advance(parser)
|
||||
node := types.Node{}
|
||||
if _, ok := allow(parser, .Right_Bracket); ok {
|
||||
node.kind = .Slice
|
||||
} else if _, ok := allow(parser, .Semicolon); ok {
|
||||
node.kind = .Slice
|
||||
node.has_sentinel = true
|
||||
node.sentinel, _ = parse_type_constant(parser)
|
||||
if _, ok = allow(parser, .Right_Bracket); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected ']' after sentinel slice type")
|
||||
}
|
||||
} else {
|
||||
node.kind = .Array
|
||||
if _, ok := allow(parser, .Underscore); ok {
|
||||
node.inferred_count = true
|
||||
} else {
|
||||
count, ok := parse_type_constant(parser)
|
||||
if ok {
|
||||
node.count = count
|
||||
}
|
||||
}
|
||||
if _, ok := allow(parser, .Semicolon); ok {
|
||||
node.has_sentinel = true
|
||||
node.sentinel, _ = parse_type_constant(parser)
|
||||
}
|
||||
if _, ok := allow(parser, .Right_Bracket); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected ']' after array type")
|
||||
}
|
||||
}
|
||||
_, node.mutable = allow(parser, .Keyword_Mut)
|
||||
node.child = parse_type(parser)
|
||||
return types.intern(&parser.module.type_store, node)
|
||||
}
|
||||
#partial switch tok.kind {
|
||||
case .Keyword_Int:
|
||||
advance(parser)
|
||||
return .Int
|
||||
return types.INT
|
||||
case .Keyword_I8:
|
||||
advance(parser)
|
||||
return .I8
|
||||
return types.I8
|
||||
case .Keyword_I16:
|
||||
advance(parser)
|
||||
return .I16
|
||||
return types.I16
|
||||
case .Keyword_I32:
|
||||
advance(parser)
|
||||
return .I32
|
||||
return types.I32
|
||||
case .Keyword_I64:
|
||||
advance(parser)
|
||||
return .I64
|
||||
return types.I64
|
||||
case .Keyword_U8:
|
||||
advance(parser)
|
||||
return types.U8
|
||||
case .Keyword_U16:
|
||||
advance(parser)
|
||||
return types.U16
|
||||
case .Keyword_U32:
|
||||
advance(parser)
|
||||
return types.U32
|
||||
case .Keyword_U64:
|
||||
advance(parser)
|
||||
return types.U64
|
||||
case .Keyword_Isize:
|
||||
advance(parser)
|
||||
return types.ISIZE
|
||||
case .Keyword_Usize:
|
||||
advance(parser)
|
||||
return types.USIZE
|
||||
case .Keyword_F32:
|
||||
advance(parser)
|
||||
return types.F32
|
||||
case .Keyword_F64:
|
||||
advance(parser)
|
||||
return types.F64
|
||||
case .Keyword_C_Char:
|
||||
advance(parser)
|
||||
return types.C_CHAR
|
||||
case .Keyword_C_Schar:
|
||||
advance(parser)
|
||||
return types.C_SCHAR
|
||||
case .Keyword_C_Uchar:
|
||||
advance(parser)
|
||||
return types.C_UCHAR
|
||||
case .Keyword_C_Short:
|
||||
advance(parser)
|
||||
return types.C_SHORT
|
||||
case .Keyword_C_Ushort:
|
||||
advance(parser)
|
||||
return types.C_USHORT
|
||||
case .Keyword_C_Int:
|
||||
advance(parser)
|
||||
return types.C_INT
|
||||
case .Keyword_C_Uint:
|
||||
advance(parser)
|
||||
return types.C_UINT
|
||||
case .Keyword_C_Long:
|
||||
advance(parser)
|
||||
return types.C_LONG
|
||||
case .Keyword_C_Ulong:
|
||||
advance(parser)
|
||||
return types.C_ULONG
|
||||
case .Keyword_C_Longlong:
|
||||
advance(parser)
|
||||
return types.C_LONGLONG
|
||||
case .Keyword_C_Ulonglong:
|
||||
advance(parser)
|
||||
return types.C_ULONGLONG
|
||||
case .Keyword_C_Float:
|
||||
advance(parser)
|
||||
return types.C_FLOAT
|
||||
case .Keyword_C_Double:
|
||||
advance(parser)
|
||||
return types.C_DOUBLE
|
||||
case .Keyword_C_Longdouble:
|
||||
advance(parser)
|
||||
return types.C_LONGDOUBLE
|
||||
case .Keyword_Void:
|
||||
advance(parser)
|
||||
return .Void
|
||||
return types.VOID
|
||||
case .Identifier:
|
||||
first := advance(parser)
|
||||
name := first
|
||||
qualifier := symbol.INVALID
|
||||
if _, ok := allow(parser, .Dot); ok {
|
||||
qualifier = first.symbol
|
||||
if current(parser).kind != .Identifier {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected a type name after '.'")
|
||||
return types.INVALID
|
||||
}
|
||||
name = advance(parser)
|
||||
}
|
||||
return types.named(
|
||||
&parser.module.type_store,
|
||||
u32(parser.pkg),
|
||||
u32(name.symbol),
|
||||
u32(qualifier),
|
||||
u32(parser.file),
|
||||
)
|
||||
}
|
||||
source.add(parser.diagnostics, tok.span, "expected a type")
|
||||
return .Invalid
|
||||
return types.INVALID
|
||||
}
|
||||
|
||||
skip_parenthesized :: proc(parser: ^Parser) -> source.Span {
|
||||
@@ -168,6 +360,93 @@ parse_call :: proc(parser: ^Parser, qualifier: symbol.Id, first, name: token.Tok
|
||||
})
|
||||
}
|
||||
|
||||
parse_array_literal :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
start := advance(parser)
|
||||
parser.delimiter_depth += 1
|
||||
defer parser.delimiter_depth -= 1
|
||||
args: [dynamic]ast.Expr_Id
|
||||
args.allocator = parser.module.allocator
|
||||
skip_newlines(parser)
|
||||
for current(parser).kind != .Right_Bracket && current(parser).kind != .Eof {
|
||||
append(&args, parse_expression_bp(parser, 0, nesting+1))
|
||||
skip_newlines(parser)
|
||||
if _, ok := allow(parser, .Comma); ok {
|
||||
skip_newlines(parser)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
end, ok := allow(parser, .Right_Bracket)
|
||||
if !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected ']' after array literal")
|
||||
end = start
|
||||
}
|
||||
return add_expr(parser, ast.Expr{
|
||||
kind=.Array,
|
||||
span=span_from(start.span, end.span),
|
||||
args=args[:],
|
||||
left=ast.INVALID_EXPR,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
|
||||
parse_struct_literal :: proc(
|
||||
parser: ^Parser,
|
||||
qualifier: symbol.Id,
|
||||
first, name: token.Token,
|
||||
nesting: int,
|
||||
) -> ast.Expr_Id {
|
||||
left_brace := advance(parser)
|
||||
parser.delimiter_depth += 1
|
||||
defer parser.delimiter_depth -= 1
|
||||
args: [dynamic]ast.Expr_Id
|
||||
args.allocator = parser.module.allocator
|
||||
skip_newlines(parser)
|
||||
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
|
||||
field := current(parser)
|
||||
if field.kind != .Identifier {
|
||||
source.add(parser.diagnostics, field.span, "expected a keyed struct field initializer")
|
||||
break
|
||||
}
|
||||
advance(parser)
|
||||
if _, ok := allow(parser, .Equal); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected '=' after struct field name")
|
||||
}
|
||||
skip_newlines(parser)
|
||||
value := parse_expression_bp(parser, 0, nesting+1)
|
||||
append(&args, add_expr(parser, ast.Expr{
|
||||
kind=.Keyed,
|
||||
span=span_from(field.span, parser.module.exprs[value].span),
|
||||
name=field.symbol,
|
||||
left=value,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
}))
|
||||
skip_newlines(parser)
|
||||
if _, ok := allow(parser, .Comma); ok {
|
||||
skip_newlines(parser)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
right_brace, ok := allow(parser, .Right_Brace)
|
||||
if !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected '}' after struct literal")
|
||||
right_brace = left_brace
|
||||
}
|
||||
return add_expr(parser, ast.Expr{
|
||||
kind=.Struct_Literal,
|
||||
span=source.Span{file=name.span.file, start=first.span.start, end=right_brace.span.end},
|
||||
qualifier=qualifier,
|
||||
name=name.symbol,
|
||||
args=args[:],
|
||||
left=ast.INVALID_EXPR,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
|
||||
parse_integer_magnitude :: proc(text: string) -> (u64, bool) {
|
||||
value: u64
|
||||
for byte in transmute([]byte)text {
|
||||
@@ -203,6 +482,58 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Character:
|
||||
advance(parser)
|
||||
value, ok := decode_character(parser, tok)
|
||||
if !ok {
|
||||
return invalid_expr(parser, tok.span, "character literal must contain one Unicode code point")
|
||||
}
|
||||
return add_expr(parser, ast.Expr{
|
||||
kind=.Integer,
|
||||
span=tok.span,
|
||||
integer=value,
|
||||
left=ast.INVALID_EXPR,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Float:
|
||||
advance(parser)
|
||||
value, ok := strconv.parse_f64(token_text(parser, tok))
|
||||
if !ok {
|
||||
return invalid_expr(parser, tok.span, "invalid floating-point literal")
|
||||
}
|
||||
return add_expr(parser, ast.Expr{
|
||||
kind=.Float,
|
||||
span=tok.span,
|
||||
integer=transmute(u64)value,
|
||||
left=ast.INVALID_EXPR,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .String:
|
||||
advance(parser)
|
||||
value := decode_import_path(parser, tok)
|
||||
id := u64(len(parser.module.strings))
|
||||
append(&parser.module.strings, value)
|
||||
return add_expr(parser, ast.Expr{
|
||||
kind=.String,
|
||||
span=tok.span,
|
||||
integer=id,
|
||||
left=ast.INVALID_EXPR,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Keyword_None:
|
||||
advance(parser)
|
||||
return add_expr(parser, ast.Expr{
|
||||
kind=.None,
|
||||
span=tok.span,
|
||||
left=ast.INVALID_EXPR,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Left_Bracket:
|
||||
return parse_array_literal(parser, nesting)
|
||||
case .Identifier:
|
||||
first := advance(parser)
|
||||
name := first
|
||||
@@ -217,6 +548,9 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
if current(parser).kind == .Left_Paren {
|
||||
return parse_call(parser, qualifier, first, name, nesting)
|
||||
}
|
||||
if current(parser).kind == .Left_Brace {
|
||||
return parse_struct_literal(parser, qualifier, first, name, nesting)
|
||||
}
|
||||
return add_expr(parser, ast.Expr{
|
||||
kind=.Name,
|
||||
span=span_from(first.span, name.span),
|
||||
@@ -262,6 +596,8 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
|
||||
infix_binding_power :: proc(kind: token.Kind) -> (left, right: int, ok: bool) {
|
||||
#partial switch kind {
|
||||
case .Keyword_Orelse:
|
||||
return 2, 3, true
|
||||
case .Plus:
|
||||
return 10, 11, true
|
||||
}
|
||||
@@ -270,7 +606,7 @@ infix_binding_power :: proc(kind: token.Kind) -> (left, right: int, ok: bool) {
|
||||
|
||||
prefix_binding_power :: proc(kind: token.Kind) -> (right: int, ok: bool) {
|
||||
#partial switch kind {
|
||||
case .Minus:
|
||||
case .Minus, .Ampersand:
|
||||
return 20, true
|
||||
}
|
||||
return 0, false
|
||||
@@ -293,7 +629,7 @@ parse_expression_bp :: proc(parser: ^Parser, minimum_binding_power, nesting: int
|
||||
operand := parse_expression_bp(parser, right_power, nesting+1)
|
||||
operand_expr := parser.module.exprs[operand]
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Negate,
|
||||
kind=.Address if operator.kind == .Ampersand else .Negate,
|
||||
span=span_from(operator.span, operand_expr.span),
|
||||
left=operand,
|
||||
right=ast.INVALID_EXPR,
|
||||
@@ -306,17 +642,99 @@ parse_expression_bp :: proc(parser: ^Parser, minimum_binding_power, nesting: int
|
||||
skip_newlines(parser)
|
||||
}
|
||||
for {
|
||||
if current(parser).kind == .Caret || current(parser).kind == .Question {
|
||||
operator := advance(parser)
|
||||
left_expr := parser.module.exprs[left]
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Deref if operator.kind == .Caret else .Unwrap,
|
||||
span=span_from(left_expr.span, operator.span),
|
||||
left=left,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
continue
|
||||
}
|
||||
if current(parser).kind == .Dot {
|
||||
advance(parser)
|
||||
field := current(parser)
|
||||
if field.kind != .Identifier {
|
||||
left = invalid_expr(parser, field.span, "expected a field name after '.'")
|
||||
continue
|
||||
}
|
||||
advance(parser)
|
||||
left_expr := parser.module.exprs[left]
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Field,
|
||||
span=span_from(left_expr.span, field.span),
|
||||
name=field.symbol,
|
||||
left=left,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
continue
|
||||
}
|
||||
if current(parser).kind == .Left_Bracket {
|
||||
start_token := advance(parser)
|
||||
parser.delimiter_depth += 1
|
||||
skip_newlines(parser)
|
||||
start_expr := ast.INVALID_EXPR
|
||||
end_expr := ast.INVALID_EXPR
|
||||
slicing := false
|
||||
if _, ok := allow(parser, .Range); ok {
|
||||
slicing = true
|
||||
} else {
|
||||
start_expr = parse_expression_bp(parser, 0, nesting+1)
|
||||
skip_newlines(parser)
|
||||
if _, ok := allow(parser, .Range); ok {
|
||||
slicing = true
|
||||
}
|
||||
}
|
||||
skip_newlines(parser)
|
||||
if slicing && current(parser).kind != .Right_Bracket {
|
||||
end_expr = parse_expression_bp(parser, 0, nesting+1)
|
||||
skip_newlines(parser)
|
||||
}
|
||||
end_token, ok := allow(parser, .Right_Bracket)
|
||||
if !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected ']' after index or slice")
|
||||
end_token = start_token
|
||||
}
|
||||
parser.delimiter_depth -= 1
|
||||
left_expr := parser.module.exprs[left]
|
||||
if slicing {
|
||||
args := make([]ast.Expr_Id, 2, parser.module.allocator)
|
||||
args[0] = start_expr
|
||||
args[1] = end_expr
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Slice,
|
||||
span=span_from(left_expr.span, end_token.span),
|
||||
args=args,
|
||||
left=left,
|
||||
right=ast.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else {
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Index,
|
||||
span=span_from(left_expr.span, end_token.span),
|
||||
left=left,
|
||||
right=start_expr,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
left_power, right_power, ok := infix_binding_power(current(parser).kind)
|
||||
if !ok || left_power < minimum_binding_power {
|
||||
break
|
||||
}
|
||||
advance(parser)
|
||||
operator := advance(parser)
|
||||
skip_newlines(parser)
|
||||
right := parse_expression_bp(parser, right_power, nesting+1)
|
||||
left_expr := parser.module.exprs[left]
|
||||
right_expr := parser.module.exprs[right]
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Add,
|
||||
kind=.Orelse if operator.kind == .Keyword_Orelse else .Add,
|
||||
span=span_from(left_expr.span, right_expr.span),
|
||||
left=left,
|
||||
right=right,
|
||||
@@ -381,6 +799,31 @@ parse_return :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
return id
|
||||
}
|
||||
|
||||
starts_declared_type :: proc(parser: ^Parser) -> bool {
|
||||
if current(parser).kind != .Left_Bracket {
|
||||
return is_type_token(current(parser).kind)
|
||||
}
|
||||
depth := 0
|
||||
cursor := parser.cursor
|
||||
for cursor < len(parser.tokens.items) {
|
||||
kind := parser.tokens.items[cursor].kind
|
||||
if kind == .Left_Bracket {
|
||||
depth += 1
|
||||
} else if kind == .Right_Bracket {
|
||||
depth -= 1
|
||||
if depth == 0 {
|
||||
cursor += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
cursor += 1
|
||||
}
|
||||
if cursor < len(parser.tokens.items) && parser.tokens.items[cursor].kind == .Keyword_Mut {
|
||||
cursor += 1
|
||||
}
|
||||
return cursor < len(parser.tokens.items) && is_type_token(parser.tokens.items[cursor].kind)
|
||||
}
|
||||
|
||||
parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
if current(parser).kind == .Keyword_Return {
|
||||
return parse_return(parser)
|
||||
@@ -389,9 +832,9 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
if current(parser).kind == .Identifier || current(parser).kind == .Underscore {
|
||||
start_cursor := parser.cursor
|
||||
name := advance(parser)
|
||||
type_syntax := ast.Type_Syntax.Invalid
|
||||
type_syntax := types.INVALID
|
||||
had_type := false
|
||||
if is_type_token(current(parser).kind) {
|
||||
if starts_declared_type(parser) {
|
||||
type_syntax = parse_type(parser)
|
||||
had_type = true
|
||||
}
|
||||
@@ -413,6 +856,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
name=name.symbol,
|
||||
type=type_syntax,
|
||||
immutable=immutable,
|
||||
target=ast.INVALID_EXPR,
|
||||
expr=expr,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
@@ -422,6 +866,19 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
|
||||
}
|
||||
|
||||
expr := parse_expression(parser)
|
||||
if _, ok := allow(parser, .Equal); ok {
|
||||
skip_newlines(parser)
|
||||
value := parse_expression(parser)
|
||||
id := ast.stmt_id(len(parser.module.statements))
|
||||
append(&parser.module.statements, ast.Stmt{
|
||||
kind=.Assignment,
|
||||
span=span_from(parser.module.exprs[expr].span, parser.module.exprs[value].span),
|
||||
target=expr,
|
||||
expr=value,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
return id
|
||||
}
|
||||
id := ast.stmt_id(len(parser.module.statements))
|
||||
append(&parser.module.statements, ast.Stmt{
|
||||
kind=.Expression,
|
||||
@@ -541,6 +998,57 @@ parse_function :: proc(parser: ^Parser, name: token.Token, c_abi: bool) {
|
||||
})
|
||||
}
|
||||
|
||||
parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout: bool) {
|
||||
start := advance(parser)
|
||||
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol))
|
||||
ended_by_newline := current(parser).kind == .Newline
|
||||
skip_newlines(parser)
|
||||
if current(parser).kind != .Left_Brace {
|
||||
if !c_layout {
|
||||
source.add(parser.diagnostics, start.span, "native struct declarations require a body")
|
||||
}
|
||||
if !types.define_struct(&parser.module.type_store, id, nil, c_layout, true) {
|
||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||
}
|
||||
if !ended_by_newline {
|
||||
_ = finish_statement(parser)
|
||||
}
|
||||
return
|
||||
}
|
||||
advance(parser)
|
||||
fields: [dynamic]types.Field
|
||||
fields.allocator = parser.module.allocator
|
||||
defer delete(fields)
|
||||
skip_newlines(parser)
|
||||
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
|
||||
if current(parser).kind != .Identifier {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected a struct field name")
|
||||
for current(parser).kind != .Newline &&
|
||||
current(parser).kind != .Right_Brace &&
|
||||
current(parser).kind != .Eof {
|
||||
advance(parser)
|
||||
}
|
||||
skip_newlines(parser)
|
||||
continue
|
||||
}
|
||||
field_name := advance(parser)
|
||||
field_type := parse_type(parser)
|
||||
append(&fields, types.Field{name=u32(field_name.symbol), type=field_type})
|
||||
if _, ok := allow(parser, .Comma); ok {
|
||||
skip_newlines(parser)
|
||||
continue
|
||||
}
|
||||
_ = finish_statement(parser, true)
|
||||
}
|
||||
if _, ok := allow(parser, .Right_Brace); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected '}' after struct fields")
|
||||
}
|
||||
if !types.define_struct(&parser.module.type_store, id, fields[:], c_layout, false) {
|
||||
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
|
||||
}
|
||||
_ = finish_statement(parser)
|
||||
}
|
||||
|
||||
decode_import_path :: proc(parser: ^Parser, tok: token.Token) -> string {
|
||||
text := token_text(parser, tok)
|
||||
if len(text) < 2 {
|
||||
@@ -553,6 +1061,13 @@ decode_import_path :: proc(parser: ^Parser, tok: token.Token) -> string {
|
||||
if value == '\\' && index+1 < len(text)-1 {
|
||||
index += 1
|
||||
value = text[index]
|
||||
switch value {
|
||||
case 'n': value = '\n'
|
||||
case 'r': value = '\r'
|
||||
case 't': value = '\t'
|
||||
case '0': value = 0
|
||||
case:
|
||||
}
|
||||
}
|
||||
strings.write_byte(&builder, value)
|
||||
}
|
||||
@@ -621,7 +1136,7 @@ parse_top_level :: proc(parser: ^Parser) {
|
||||
}
|
||||
parser.cursor = saved
|
||||
}
|
||||
type_syntax := ast.Type_Syntax.Invalid
|
||||
type_syntax := types.INVALID
|
||||
if is_type_token(current(parser).kind) {
|
||||
type_syntax = parse_type(parser)
|
||||
}
|
||||
@@ -634,23 +1149,17 @@ parse_top_level :: proc(parser: ^Parser) {
|
||||
advance(parser)
|
||||
skip_newlines(parser)
|
||||
|
||||
c_abi := false
|
||||
if operator.kind == .Colon_Colon &&
|
||||
current(parser).kind == .Identifier &&
|
||||
token_text(parser, current(parser)) == "c" {
|
||||
saved := parser.cursor
|
||||
c_abi = true
|
||||
advance(parser)
|
||||
skip_newlines(parser)
|
||||
if current(parser).kind != .Keyword_Func {
|
||||
c_abi = false
|
||||
parser.cursor = saved
|
||||
}
|
||||
}
|
||||
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Func {
|
||||
(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)
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
expr := parse_expression(parser)
|
||||
_ = ast.global_id(len(parser.module.globals))
|
||||
|
||||
Reference in New Issue
Block a user