mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Merge pull request #1788 from odin-lang/image-general-loader
Generalized `core:image` loader
This commit is contained in:
@@ -45,7 +45,7 @@ main :: proc() {
|
|||||||
|
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
stderr("No input file specified.\n")
|
stderr("No input file specified.\n")
|
||||||
err := load(slice=TEST, buf=&buf, known_gzip_size=len(TEST))
|
err := load(data=TEST, buf=&buf, known_gzip_size=len(TEST))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
stdout("Displaying test vector: ")
|
stdout("Displaying test vector: ")
|
||||||
stdout(bytes.buffer_to_string(&buf))
|
stdout(bytes.buffer_to_string(&buf))
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ E_Deflate :: compress.Deflate_Error
|
|||||||
|
|
||||||
GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le))
|
GZIP_MAX_PAYLOAD_SIZE :: i64(max(u32le))
|
||||||
|
|
||||||
load :: proc{load_from_slice, load_from_file, load_from_context}
|
load :: proc{load_from_bytes, load_from_file, load_from_context}
|
||||||
|
|
||||||
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
@@ -112,16 +112,16 @@ load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_siz
|
|||||||
|
|
||||||
err = E_General.File_Not_Found
|
err = E_General.File_Not_Found
|
||||||
if ok {
|
if ok {
|
||||||
err = load_from_slice(data, buf, len(data), expected_output_size)
|
err = load_from_bytes(data, buf, len(data), expected_output_size)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
load_from_slice :: proc(slice: []u8, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
load_from_bytes :: proc(data: []byte, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
|
||||||
buf := buf
|
buf := buf
|
||||||
|
|
||||||
z := &compress.Context_Memory_Input{
|
z := &compress.Context_Memory_Input{
|
||||||
input_data = slice,
|
input_data = data,
|
||||||
output = buf,
|
output = buf,
|
||||||
}
|
}
|
||||||
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator)
|
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator)
|
||||||
|
|||||||
@@ -54,9 +54,10 @@ Image :: struct {
|
|||||||
*/
|
*/
|
||||||
background: Maybe(RGB_Pixel_16),
|
background: Maybe(RGB_Pixel_16),
|
||||||
metadata: Image_Metadata,
|
metadata: Image_Metadata,
|
||||||
|
which: Which_File_Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
Image_Metadata :: union {
|
Image_Metadata :: union #shared_nil {
|
||||||
^Netpbm_Info,
|
^Netpbm_Info,
|
||||||
^PNG_Info,
|
^PNG_Info,
|
||||||
^QOI_Info,
|
^QOI_Info,
|
||||||
@@ -172,6 +173,7 @@ General_Image_Error :: enum {
|
|||||||
Unable_To_Write_File,
|
Unable_To_Write_File,
|
||||||
|
|
||||||
// Invalid
|
// Invalid
|
||||||
|
Unsupported_Format,
|
||||||
Invalid_Signature,
|
Invalid_Signature,
|
||||||
Invalid_Input_Image,
|
Invalid_Input_Image,
|
||||||
Image_Dimensions_Too_Large,
|
Image_Dimensions_Too_Large,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package image
|
||||||
|
|
||||||
|
import "core:mem"
|
||||||
|
import "core:os"
|
||||||
|
import "core:bytes"
|
||||||
|
|
||||||
|
Loader_Proc :: #type proc(data: []byte, options: Options, allocator: mem.Allocator) -> (img: ^Image, err: Error)
|
||||||
|
Destroy_Proc :: #type proc(img: ^Image)
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_internal_loaders: [Which_File_Type]Loader_Proc
|
||||||
|
_internal_destroyers: [Which_File_Type]Destroy_Proc
|
||||||
|
|
||||||
|
register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
|
||||||
|
assert(loader != nil)
|
||||||
|
assert(destroyer != nil)
|
||||||
|
assert(_internal_loaders[kind] == nil)
|
||||||
|
_internal_loaders[kind] = loader
|
||||||
|
|
||||||
|
assert(_internal_destroyers[kind] == nil)
|
||||||
|
_internal_destroyers[kind] = destroyer
|
||||||
|
}
|
||||||
|
|
||||||
|
load :: proc{
|
||||||
|
load_from_bytes,
|
||||||
|
load_from_file,
|
||||||
|
}
|
||||||
|
|
||||||
|
load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||||
|
loader := _internal_loaders[which(data)]
|
||||||
|
if loader == nil {
|
||||||
|
return nil, .Unsupported_Format
|
||||||
|
}
|
||||||
|
return loader(data, options, allocator)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||||
|
data, ok := os.read_entire_file(filename, allocator)
|
||||||
|
defer delete(data, allocator)
|
||||||
|
if ok {
|
||||||
|
return load_from_bytes(data, options, allocator)
|
||||||
|
} else {
|
||||||
|
return nil, .Unable_To_Read_File
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy :: proc(img: ^Image, allocator := context.allocator) {
|
||||||
|
if img == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
context.allocator = allocator
|
||||||
|
destroyer := _internal_destroyers[img.which]
|
||||||
|
if destroyer != nil {
|
||||||
|
destroyer(img)
|
||||||
|
} else {
|
||||||
|
assert(img.metadata == nil)
|
||||||
|
bytes.buffer_destroy(&img.pixels)
|
||||||
|
free(img)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ BINARY :: Formats{.P4, .P5, .P6} + PAM + PFM
|
|||||||
|
|
||||||
load :: proc {
|
load :: proc {
|
||||||
load_from_file,
|
load_from_file,
|
||||||
load_from_buffer,
|
load_from_bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
load_from_file :: proc(filename: string, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||||
@@ -40,13 +40,14 @@ load_from_file :: proc(filename: string, allocator := context.allocator) -> (img
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return load_from_buffer(data)
|
return load_from_bytes(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
load_from_buffer :: proc(data: []byte, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
load_from_bytes :: proc(data: []byte, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
img = new(Image)
|
img = new(Image)
|
||||||
|
img.which = .NetPBM
|
||||||
|
|
||||||
header: Header; defer header_destroy(&header)
|
header: Header; defer header_destroy(&header)
|
||||||
header_size: int
|
header_size: int
|
||||||
@@ -749,3 +750,14 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for
|
|||||||
// We couldn't find a suitable format
|
// We couldn't find a suitable format
|
||||||
return {}, false
|
return {}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(init, private)
|
||||||
|
_register :: proc() {
|
||||||
|
loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) {
|
||||||
|
return load_from_bytes(data, allocator)
|
||||||
|
}
|
||||||
|
destroyer :: proc(img: ^Image) {
|
||||||
|
_ = destroy(img)
|
||||||
|
}
|
||||||
|
image.register(.NetPBM, loader, destroyer)
|
||||||
|
}
|
||||||
+13
-9
@@ -18,7 +18,6 @@ import "core:compress/zlib"
|
|||||||
import "core:image"
|
import "core:image"
|
||||||
|
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:strings"
|
|
||||||
import "core:hash"
|
import "core:hash"
|
||||||
import "core:bytes"
|
import "core:bytes"
|
||||||
import "core:io"
|
import "core:io"
|
||||||
@@ -318,13 +317,12 @@ read_header :: proc(ctx: ^$C) -> (image.PNG_IHDR, Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
chunk_type_to_name :: proc(type: ^image.PNG_Chunk_Type) -> string {
|
chunk_type_to_name :: proc(type: ^image.PNG_Chunk_Type) -> string {
|
||||||
t := transmute(^u8)type
|
return string(([^]u8)(type)[:4])
|
||||||
return strings.string_from_ptr(t, 4)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
load_from_slice :: proc(slice: []u8, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||||
ctx := &compress.Context_Memory_Input{
|
ctx := &compress.Context_Memory_Input{
|
||||||
input_data = slice,
|
input_data = data,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -344,10 +342,9 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont
|
|||||||
defer delete(data)
|
defer delete(data)
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
return load_from_slice(data, options)
|
return load_from_bytes(data, options)
|
||||||
} else {
|
} else {
|
||||||
img = new(Image)
|
return nil, .Unable_To_Read_File
|
||||||
return img, .Unable_To_Read_File
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,6 +372,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
if img == nil {
|
if img == nil {
|
||||||
img = new(Image)
|
img = new(Image)
|
||||||
}
|
}
|
||||||
|
img.which = .PNG
|
||||||
|
|
||||||
info := new(image.PNG_Info)
|
info := new(image.PNG_Info)
|
||||||
img.metadata = info
|
img.metadata = info
|
||||||
@@ -1639,4 +1637,10 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
load :: proc{load_from_file, load_from_slice, load_from_context}
|
load :: proc{load_from_file, load_from_bytes, load_from_context}
|
||||||
|
|
||||||
|
|
||||||
|
@(init, private)
|
||||||
|
_register :: proc() {
|
||||||
|
image.register(.PNG, load_from_bytes, destroy)
|
||||||
|
}
|
||||||
+11
-6
@@ -180,9 +180,9 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato
|
|||||||
|
|
||||||
save :: proc{save_to_memory, save_to_file}
|
save :: proc{save_to_memory, save_to_file}
|
||||||
|
|
||||||
load_from_slice :: proc(slice: []u8, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||||
ctx := &compress.Context_Memory_Input{
|
ctx := &compress.Context_Memory_Input{
|
||||||
input_data = slice,
|
input_data = data,
|
||||||
}
|
}
|
||||||
|
|
||||||
img, err = load_from_context(ctx, options, allocator)
|
img, err = load_from_context(ctx, options, allocator)
|
||||||
@@ -196,10 +196,9 @@ load_from_file :: proc(filename: string, options := Options{}, allocator := cont
|
|||||||
defer delete(data)
|
defer delete(data)
|
||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
return load_from_slice(data, options)
|
return load_from_bytes(data, options)
|
||||||
} else {
|
} else {
|
||||||
img = new(Image)
|
return nil, .Unable_To_Read_File
|
||||||
return img, .Unable_To_Read_File
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +224,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
if img == nil {
|
if img == nil {
|
||||||
img = new(Image)
|
img = new(Image)
|
||||||
}
|
}
|
||||||
|
img.which = .QOI
|
||||||
|
|
||||||
if .return_metadata in options {
|
if .return_metadata in options {
|
||||||
info := new(image.QOI_Info)
|
info := new(image.QOI_Info)
|
||||||
@@ -359,7 +359,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
load :: proc{load_from_file, load_from_slice, load_from_context}
|
load :: proc{load_from_file, load_from_bytes, load_from_context}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cleanup of image-specific data.
|
Cleanup of image-specific data.
|
||||||
@@ -404,3 +404,8 @@ qoi_hash :: #force_inline proc(pixel: RGBA_Pixel) -> (index: u8) {
|
|||||||
|
|
||||||
return u8((i1 + i2 + i3 + i4) & 63)
|
return u8((i1 + i2 + i3 + i4) & 63)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(init, private)
|
||||||
|
_register :: proc() {
|
||||||
|
image.register(.QOI, load_from_bytes, destroy)
|
||||||
|
}
|
||||||
@@ -12,7 +12,6 @@ package tga
|
|||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:image"
|
import "core:image"
|
||||||
import "core:compress"
|
|
||||||
import "core:bytes"
|
import "core:bytes"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|
||||||
|
|||||||
+17
-11
@@ -6,6 +6,7 @@ Which_File_Type :: enum {
|
|||||||
Unknown,
|
Unknown,
|
||||||
|
|
||||||
BMP,
|
BMP,
|
||||||
|
DjVu, // AT&T DjVu file format
|
||||||
EXR,
|
EXR,
|
||||||
FLIF,
|
FLIF,
|
||||||
GIF,
|
GIF,
|
||||||
@@ -14,7 +15,7 @@ Which_File_Type :: enum {
|
|||||||
JPEG,
|
JPEG,
|
||||||
JPEG_2000,
|
JPEG_2000,
|
||||||
JPEG_XL,
|
JPEG_XL,
|
||||||
PBM, PGM, PPM, PAM, PFM, // NetPBM family
|
NetPBM, // NetPBM family
|
||||||
PIC, // Softimage PIC
|
PIC, // Softimage PIC
|
||||||
PNG, // Portable Network Graphics
|
PNG, // Portable Network Graphics
|
||||||
PSD, // Photoshop PSD
|
PSD, // Photoshop PSD
|
||||||
@@ -88,6 +89,11 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
|
|||||||
switch {
|
switch {
|
||||||
case s[:2] == "BM":
|
case s[:2] == "BM":
|
||||||
return .BMP
|
return .BMP
|
||||||
|
case s[:8] == "AT&TFORM":
|
||||||
|
switch s[12:16] {
|
||||||
|
case "DJVU", "DJVM":
|
||||||
|
return .DjVu
|
||||||
|
}
|
||||||
case s[:4] == "\x76\x2f\x31\x01":
|
case s[:4] == "\x76\x2f\x31\x01":
|
||||||
return .EXR
|
return .EXR
|
||||||
case s[:6] == "GIF87a", s[:6] == "GIF89a":
|
case s[:6] == "GIF87a", s[:6] == "GIF89a":
|
||||||
@@ -111,16 +117,16 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
|
|||||||
switch s[2] {
|
switch s[2] {
|
||||||
case '\t', '\n', '\r':
|
case '\t', '\n', '\r':
|
||||||
switch s[1] {
|
switch s[1] {
|
||||||
case '1', '4':
|
case '1', '4': // PBM
|
||||||
return .PBM
|
return .NetPBM
|
||||||
case '2', '5':
|
case '2', '5': // PGM
|
||||||
return .PGM
|
return .NetPBM
|
||||||
case '3', '6':
|
case '3', '6': // PPM
|
||||||
return .PPM
|
return .NetPBM
|
||||||
case '7':
|
case '7': // PAM
|
||||||
return .PAM
|
return .NetPBM
|
||||||
case 'F', 'f':
|
case 'F', 'f': // PFM
|
||||||
return .PFM
|
return .NetPBM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case s[:8] == "\x89PNG\r\n\x1a\n":
|
case s[:8] == "\x89PNG\r\n\x1a\n":
|
||||||
|
|||||||
@@ -62,8 +62,10 @@ import fmt "core:fmt"
|
|||||||
import hash "core:hash"
|
import hash "core:hash"
|
||||||
|
|
||||||
import image "core:image"
|
import image "core:image"
|
||||||
|
import netpbm "core:image/netpbm"
|
||||||
import png "core:image/png"
|
import png "core:image/png"
|
||||||
import qoi "core:image/qoi"
|
import qoi "core:image/qoi"
|
||||||
|
import tga "core:image/tga"
|
||||||
|
|
||||||
import io "core:io"
|
import io "core:io"
|
||||||
import log "core:log"
|
import log "core:log"
|
||||||
@@ -164,8 +166,10 @@ _ :: xml
|
|||||||
_ :: fmt
|
_ :: fmt
|
||||||
_ :: hash
|
_ :: hash
|
||||||
_ :: image
|
_ :: image
|
||||||
|
_ :: netpbm
|
||||||
_ :: png
|
_ :: png
|
||||||
_ :: qoi
|
_ :: qoi
|
||||||
|
_ :: tga
|
||||||
_ :: io
|
_ :: io
|
||||||
_ :: log
|
_ :: log
|
||||||
_ :: math
|
_ :: math
|
||||||
|
|||||||
+10
-38
@@ -4356,6 +4356,9 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false);
|
String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false);
|
||||||
|
if (is_blank_ident(import_name)) {
|
||||||
|
force_use = true;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE(bill, 2019-05-19): If the directory path is not a valid entity name, force the user to assign a custom one
|
// NOTE(bill, 2019-05-19): If the directory path is not a valid entity name, force the user to assign a custom one
|
||||||
// if (import_name.len == 0 || import_name == "_") {
|
// if (import_name.len == 0 || import_name == "_") {
|
||||||
@@ -4363,17 +4366,13 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
if (import_name.len == 0 || is_blank_ident(import_name)) {
|
if (import_name.len == 0 || is_blank_ident(import_name)) {
|
||||||
if (id->is_using) {
|
if (id->import_name.string == "") {
|
||||||
// TODO(bill): Should this be a warning?
|
String invalid_name = id->fullpath;
|
||||||
} else {
|
invalid_name = get_invalid_import_name(invalid_name);
|
||||||
if (id->import_name.string == "") {
|
|
||||||
String invalid_name = id->fullpath;
|
|
||||||
invalid_name = get_invalid_import_name(invalid_name);
|
|
||||||
|
|
||||||
error(id->token, "Import name %.*s, is not a valid identifier. Perhaps you want to reference the package by a different name like this: import <new_name> \"%.*s\" ", LIT(invalid_name), LIT(invalid_name));
|
error(id->token, "Import name %.*s, is not a valid identifier. Perhaps you want to reference the package by a different name like this: import <new_name> \"%.*s\" ", LIT(invalid_name), LIT(invalid_name));
|
||||||
} else {
|
} else {
|
||||||
error(token, "Import name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string));
|
error(token, "Import name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GB_ASSERT(id->import_name.pos.line != 0);
|
GB_ASSERT(id->import_name.pos.line != 0);
|
||||||
@@ -4383,38 +4382,11 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
|
|||||||
scope);
|
scope);
|
||||||
|
|
||||||
add_entity(ctx, parent_scope, nullptr, e);
|
add_entity(ctx, parent_scope, nullptr, e);
|
||||||
if (force_use || id->is_using) {
|
if (force_use) {
|
||||||
add_entity_use(ctx, nullptr, e);
|
add_entity_use(ctx, nullptr, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id->is_using) {
|
|
||||||
if (parent_scope->flags & ScopeFlag_Global) {
|
|
||||||
error(id->import_name, "built-in package imports cannot use using");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(bill): Add imported entities to this file's scope
|
|
||||||
for_array(elem_index, scope->elements.entries) {
|
|
||||||
String name = scope->elements.entries[elem_index].key.string;
|
|
||||||
Entity *e = scope->elements.entries[elem_index].value;
|
|
||||||
if (e->scope == parent_scope) continue;
|
|
||||||
|
|
||||||
if (is_entity_exported(e, true)) {
|
|
||||||
Entity *found = scope_lookup_current(parent_scope, name);
|
|
||||||
if (found != nullptr) {
|
|
||||||
// NOTE(bill):
|
|
||||||
// Date: 2019-03-17
|
|
||||||
// The order has to be the other way around as `using` adds the entity into the that
|
|
||||||
// file scope otherwise the error would be the wrong way around
|
|
||||||
redeclaration_error(name, found, e);
|
|
||||||
} else {
|
|
||||||
add_entity_with_name(ctx, parent_scope, e->identifier, e, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scope->flags |= ScopeFlag_HasBeenImported;
|
scope->flags |= ScopeFlag_HasBeenImported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-10
@@ -1160,11 +1160,10 @@ Ast *ast_package_decl(AstFile *f, Token token, Token name, CommentGroup *docs, C
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *ast_import_decl(AstFile *f, Token token, bool is_using, Token relpath, Token import_name,
|
Ast *ast_import_decl(AstFile *f, Token token, Token relpath, Token import_name,
|
||||||
CommentGroup *docs, CommentGroup *comment) {
|
CommentGroup *docs, CommentGroup *comment) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_ImportDecl);
|
Ast *result = alloc_ast_node(f, Ast_ImportDecl);
|
||||||
result->ImportDecl.token = token;
|
result->ImportDecl.token = token;
|
||||||
result->ImportDecl.is_using = is_using;
|
|
||||||
result->ImportDecl.relpath = relpath;
|
result->ImportDecl.relpath = relpath;
|
||||||
result->ImportDecl.import_name = import_name;
|
result->ImportDecl.import_name = import_name;
|
||||||
result->ImportDecl.docs = docs;
|
result->ImportDecl.docs = docs;
|
||||||
@@ -4382,7 +4381,6 @@ Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) {
|
|||||||
CommentGroup *docs = f->lead_comment;
|
CommentGroup *docs = f->lead_comment;
|
||||||
Token token = expect_token(f, Token_import);
|
Token token = expect_token(f, Token_import);
|
||||||
Token import_name = {};
|
Token import_name = {};
|
||||||
bool is_using = kind != ImportDecl_Standard;
|
|
||||||
|
|
||||||
switch (f->curr_token.kind) {
|
switch (f->curr_token.kind) {
|
||||||
case Token_Ident:
|
case Token_Ident:
|
||||||
@@ -4393,22 +4391,18 @@ Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_using && is_blank_ident(import_name)) {
|
|
||||||
syntax_error(import_name, "Illegal import name: '_'");
|
|
||||||
}
|
|
||||||
|
|
||||||
Token file_path = expect_token_after(f, Token_String, "import");
|
Token file_path = expect_token_after(f, Token_String, "import");
|
||||||
|
|
||||||
Ast *s = nullptr;
|
Ast *s = nullptr;
|
||||||
if (f->curr_proc != nullptr) {
|
if (f->curr_proc != nullptr) {
|
||||||
syntax_error(import_name, "You cannot use 'import' within a procedure. This must be done at the file scope");
|
syntax_error(import_name, "Cannot use 'import' within a procedure. This must be done at the file scope");
|
||||||
s = ast_bad_decl(f, import_name, file_path);
|
s = ast_bad_decl(f, import_name, file_path);
|
||||||
} else {
|
} else {
|
||||||
s = ast_import_decl(f, token, is_using, file_path, import_name, docs, f->line_comment);
|
s = ast_import_decl(f, token, file_path, import_name, docs, f->line_comment);
|
||||||
array_add(&f->imports, s);
|
array_add(&f->imports, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_using) {
|
if (kind != ImportDecl_Standard) {
|
||||||
syntax_error(import_name, "'using import' is not allowed, please use the import name explicitly");
|
syntax_error(import_name, "'using import' is not allowed, please use the import name explicitly");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -585,7 +585,6 @@ AST_KIND(_DeclBegin, "", bool) \
|
|||||||
Token import_name; \
|
Token import_name; \
|
||||||
CommentGroup *docs; \
|
CommentGroup *docs; \
|
||||||
CommentGroup *comment; \
|
CommentGroup *comment; \
|
||||||
bool is_using; \
|
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(ForeignImportDecl, "foreign import declaration", struct { \
|
AST_KIND(ForeignImportDecl, "foreign import declaration", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
|
|||||||
Reference in New Issue
Block a user