mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
"[]=" now works as overload. Improved eval resolution. Added $$FUNCPTR
This commit is contained in:
committed by
Christoffer Lerno
parent
05d4ec55f6
commit
db06f99445
@@ -3,6 +3,7 @@
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::core::builtin;
|
||||
import libc;
|
||||
import std::hash;
|
||||
|
||||
fault IteratorResult
|
||||
{
|
||||
@@ -157,4 +158,5 @@ macro uint ichar.hash(ichar c) = c;
|
||||
macro uint long.hash(long i) = (uint)((i >> 32) ^ i);
|
||||
macro uint ulong.hash(ulong i) = (uint)((i >> 32) ^ i);
|
||||
macro uint bool.hash(bool b) = (uint)b;
|
||||
macro uint typeid.hash(typeid t) = (uint)(((uptr)t >> 32) ^ (uptr)t);
|
||||
macro uint typeid.hash(typeid t) = (uint)(((uptr)t >> 32) ^ (uptr)t);
|
||||
macro uint char[].hash(char[] c) = (uint)fnv32a::encode(c);
|
||||
41
lib/std/hash/fnv32a.c3
Normal file
41
lib/std/hash/fnv32a.c3
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::hash::fnv32a;
|
||||
|
||||
define Fnv32a = distinct uint;
|
||||
|
||||
private const FNV32A_START = 0x811c9dc5;
|
||||
private const FNV32A_MUL = 0x01000193;
|
||||
|
||||
private macro void @update(uint &h, char x) => h = (h * FNV32A_MUL) ^ x;
|
||||
|
||||
fn void Fnv32a.init(Fnv32a* this)
|
||||
{
|
||||
*this = FNV32A_START;
|
||||
}
|
||||
|
||||
fn void Fnv32a.update(Fnv32a* this, char[] data)
|
||||
{
|
||||
uint h = (uint)*this;
|
||||
foreach (char x : data)
|
||||
{
|
||||
@update(h, x);
|
||||
}
|
||||
*this = (Fnv32a)h;
|
||||
}
|
||||
|
||||
macro void Fnv32a.update_char(Fnv32a* this, char c)
|
||||
{
|
||||
@update(*this, x);
|
||||
}
|
||||
|
||||
fn uint encode(char[] data)
|
||||
{
|
||||
uint h = FNV32A_START;
|
||||
foreach (char x : data)
|
||||
{
|
||||
@update(h, x);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
@@ -22,13 +22,13 @@ struct HashMap
|
||||
}
|
||||
|
||||
/**
|
||||
* @require capacity > 0
|
||||
* @require load_factor > 0.0 && load_factor < 1.0
|
||||
* @require map.table.len == 0
|
||||
* @require capacity < MAXIMUM_CAPACITY
|
||||
* @require allocator != null
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !map.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
* @require allocator != null "The allocator must be non-null"
|
||||
**/
|
||||
fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::current_allocator())
|
||||
fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::temp_allocator())
|
||||
{
|
||||
capacity = math::next_power_of_2(capacity);
|
||||
map.allocator = allocator;
|
||||
@@ -37,7 +37,7 @@ fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, flo
|
||||
map.table = array::make(Entry*, capacity, allocator);
|
||||
}
|
||||
|
||||
fn void HashMap.init_from_map(HashMap* map, HashMap* other_map, Allocator* allocator = mem::current_allocator())
|
||||
fn void HashMap.init_from_map(HashMap* map, HashMap* other_map, Allocator* allocator = mem::temp_allocator())
|
||||
{
|
||||
map.init(other_map.table.len, other_map.load_factor, allocator);
|
||||
map.put_all_for_create(other_map);
|
||||
@@ -59,7 +59,7 @@ fn Value*! HashMap.get_ref(HashMap* map, Key key)
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
fn Value! HashMap.get(HashMap* map, Key key)
|
||||
fn Value! HashMap.get(HashMap* map, Key key) @operator([])
|
||||
{
|
||||
return *map.get_ref(key) @inline;
|
||||
}
|
||||
@@ -70,8 +70,13 @@ fn bool HashMap.has_key(HashMap* map, Key key)
|
||||
return try(map.get_ref(key));
|
||||
}
|
||||
|
||||
fn bool HashMap.set(HashMap* map, Key key, Value value)
|
||||
fn bool HashMap.set(HashMap* map, Key key, Value value) @operator([]=)
|
||||
{
|
||||
// If the map isn't initialized, use the defaults to initialize it.
|
||||
if (!map.allocator)
|
||||
{
|
||||
map.init();
|
||||
}
|
||||
uint hash = rehash(key.hash());
|
||||
uint index = index_for(hash, map.table.len);
|
||||
for (Entry *e = map.table[index]; e != null; e = e.next)
|
||||
@@ -106,20 +111,17 @@ fn void HashMap.clear(HashMap* map)
|
||||
|
||||
fn void HashMap.destroy(HashMap* map)
|
||||
{
|
||||
if (!map.allocator) return;
|
||||
map.clear();
|
||||
map.free(map.table.ptr);
|
||||
map.table = Entry*[] {};
|
||||
}
|
||||
fn Key[] HashMap.key_tlist(HashMap* map)
|
||||
{
|
||||
return map.key_list(mem::temp_allocator());
|
||||
}
|
||||
|
||||
fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = null)
|
||||
fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = mem::temp_allocator())
|
||||
{
|
||||
if (!map.count) return Key[] {};
|
||||
|
||||
Key[] list = array::make(Key, map.count, allocator ?: map.allocator);
|
||||
Key[] list = array::make(Key, map.count, allocator);
|
||||
usize index = 0;
|
||||
foreach (Entry* entry : map.table)
|
||||
{
|
||||
@@ -132,15 +134,10 @@ fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = null)
|
||||
return list;
|
||||
}
|
||||
|
||||
fn Value[] HashMap.value_tlist(HashMap* map)
|
||||
{
|
||||
return map.value_list(mem::temp_allocator());
|
||||
}
|
||||
|
||||
fn Value[] HashMap.value_list(HashMap* map, Allocator* allocator = null)
|
||||
fn Value[] HashMap.value_list(HashMap* map, Allocator* allocator = mem::temp_allocator())
|
||||
{
|
||||
if (!map.count) return Value[] {};
|
||||
Value[] list = array::make(Value, map.count, allocator ?: map.allocator);
|
||||
Value[] list = array::make(Value, map.count, allocator);
|
||||
usize index = 0;
|
||||
foreach (Entry* entry : map.table)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module hash;
|
||||
module std::hash;
|
||||
import libc;
|
||||
|
||||
// Code adapted from Odin's hash.odin
|
||||
|
||||
@@ -345,7 +345,6 @@ struct TypeInfo_
|
||||
TypeInfoCompressedKind subtype : 4;
|
||||
Type *type;
|
||||
SourceSpan span;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
@@ -773,6 +772,13 @@ typedef struct
|
||||
Range range;
|
||||
} ExprSubscript;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ExprId expr;
|
||||
DeclId method;
|
||||
ExprId index;
|
||||
} ExprSubscriptAssign;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ExprId left;
|
||||
@@ -1105,6 +1111,7 @@ struct Expr_
|
||||
ExprBuiltinAccess builtin_access_expr;
|
||||
ExprCatchUnwrap catch_unwrap_expr; // 24
|
||||
ExprSubscript subscript_expr; // 12
|
||||
ExprSubscriptAssign subscript_assign_expr;
|
||||
ExprAccess access_expr; // 16
|
||||
ExprDesignator designator_expr; // 16
|
||||
ExprIdentifier identifier_expr; // 24
|
||||
@@ -1837,6 +1844,7 @@ extern const char *kw_return;
|
||||
extern const char *kw_type;
|
||||
extern const char *kw_FILE;
|
||||
extern const char *kw_FUNC;
|
||||
extern const char *kw_FUNCPTR;
|
||||
extern const char *kw_LINE;
|
||||
extern const char *kw_LINEREAL;
|
||||
extern const char *kw_incr;
|
||||
|
||||
@@ -356,6 +356,8 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
MACRO_COPY_EXPRID(expr->slice_assign_expr.left);
|
||||
MACRO_COPY_EXPRID(expr->slice_assign_expr.right);
|
||||
return expr;
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
UNREACHABLE
|
||||
case EXPR_SLICE:
|
||||
case EXPR_SUBSCRIPT:
|
||||
case EXPR_SUBSCRIPT_ADDR:
|
||||
|
||||
@@ -240,6 +240,7 @@ typedef enum
|
||||
EXPR_SLICE_COPY,
|
||||
EXPR_SUBSCRIPT,
|
||||
EXPR_SUBSCRIPT_ADDR,
|
||||
EXPR_SUBSCRIPT_ASSIGN,
|
||||
EXPR_POINTER_OFFSET,
|
||||
EXPR_STRINGIFY,
|
||||
EXPR_ARGV_TO_SUBARRAY,
|
||||
|
||||
@@ -132,6 +132,7 @@ bool expr_may_addr(Expr *expr)
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -319,6 +320,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
case EXPR_ARGV_TO_SUBARRAY:
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_ASM:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
UNREACHABLE
|
||||
case EXPR_NOP:
|
||||
return true;
|
||||
@@ -703,6 +705,7 @@ bool expr_is_pure(Expr *expr)
|
||||
case EXPR_TRY_UNWRAP:
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
return false;
|
||||
case EXPR_CAST:
|
||||
return exprid_is_pure(expr->cast_expr.expr);
|
||||
|
||||
@@ -5688,6 +5688,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
return;
|
||||
case EXPR_TYPEID:
|
||||
case EXPR_GROUP:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
// These are folded in the semantic analysis step.
|
||||
UNREACHABLE
|
||||
case EXPR_IDENTIFIER:
|
||||
|
||||
@@ -849,6 +849,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
UNREACHABLE
|
||||
case EXPR_BUILTIN_ACCESS:
|
||||
|
||||
@@ -953,6 +954,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
||||
case EXPR_SLICE:
|
||||
case EXPR_SUBSCRIPT:
|
||||
case EXPR_RETVAL:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
case EXPR_TYPEID_INFO:
|
||||
if (type_size(expr->type) > type_size(type)) return expr;
|
||||
return NULL;
|
||||
|
||||
@@ -1247,13 +1247,7 @@ static inline bool sema_analyse_operator_element_set(Decl *method)
|
||||
{
|
||||
TypeInfo *rtype;
|
||||
Decl **params;
|
||||
if (!sema_analyse_operator_common(method, &rtype, ¶ms, 3)) return false;
|
||||
if (rtype->type->canonical != type_void)
|
||||
{
|
||||
SEMA_ERROR(rtype, "The return type should be 'void'.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return sema_analyse_operator_common(method, &rtype, ¶ms, 3);
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_operator_len(Decl *method)
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
|
||||
const char *ct_eval_error = "EVAL_ERROR";
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SUBSCRIPT_EVAL_VALUE,
|
||||
SUBSCRIPT_EVAL_REF,
|
||||
SUBSCRIPT_EVAL_ASSIGN
|
||||
} SubscriptEval;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool macro;
|
||||
@@ -17,7 +24,7 @@ typedef struct
|
||||
Signature *signature;
|
||||
} CalledDecl;
|
||||
|
||||
static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, bool is_addr);
|
||||
static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, SubscriptEval eval_type);
|
||||
static inline bool sema_expr_analyse_pointer_offset(SemaContext *context, Expr *expr);
|
||||
static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr);
|
||||
static inline bool sema_expr_analyse_group(SemaContext *context, Expr *expr);
|
||||
@@ -208,31 +215,68 @@ Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr)
|
||||
return context->macro_varargs[(size_t)index_val.i.low];
|
||||
}
|
||||
|
||||
const char *sema_ct_eval_expr(SemaContext *c, const char *expr_type, Expr *inner, TokenType *type, Path **path_ref, bool report_missing)
|
||||
Expr *sema_ct_eval_expr(SemaContext *c, bool is_type_eval, Expr *inner, bool report_missing)
|
||||
{
|
||||
Path *path = NULL;
|
||||
if (!sema_analyse_expr(c, inner)) return false;
|
||||
if (!expr_is_const_string(inner))
|
||||
{
|
||||
SEMA_ERROR(inner, "'%s' expects a constant string as the argument.", expr_type);
|
||||
return ct_eval_error;
|
||||
}
|
||||
const char *interned_version = NULL;
|
||||
if (!splitpathref(inner->const_expr.string.chars, inner->const_expr.string.len, path_ref, &interned_version, type))
|
||||
{
|
||||
SEMA_ERROR(inner, "A valid name was expected here.");
|
||||
return ct_eval_error;
|
||||
}
|
||||
if (*path_ref) (*path_ref)->span = inner->span;
|
||||
if (*type == TOKEN_INVALID_TOKEN)
|
||||
{
|
||||
if (report_missing)
|
||||
{
|
||||
SEMA_ERROR(inner, "'%s' could not be found, did you spell it right?", interned_version);
|
||||
return ct_eval_error;
|
||||
}
|
||||
SEMA_ERROR(inner, "'%s' expects a constant string as the argument.", is_type_eval ? "$evaltype" : "$eval");
|
||||
return NULL;
|
||||
}
|
||||
return interned_version;
|
||||
const char *interned_version = NULL;
|
||||
TokenType token = sema_splitpathref(inner->const_expr.string.chars, inner->const_expr.string.len, &path, &interned_version);
|
||||
switch (token)
|
||||
{
|
||||
case TOKEN_CONST_IDENT:
|
||||
inner->identifier_expr.is_const = true;
|
||||
break;
|
||||
case TOKEN_IDENT:
|
||||
if (!interned_version)
|
||||
{
|
||||
if (report_missing)
|
||||
{
|
||||
SEMA_ERROR(inner, "'%.*s' could not be found, did you spell it right?", (int)inner->const_expr.string.len, inner->const_expr.string.chars);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
inner->identifier_expr.is_const = false;
|
||||
break;
|
||||
case TYPE_TOKENS:
|
||||
{
|
||||
TypeInfo *info = type_info_new_base(type_from_token(token), inner->span);
|
||||
inner->expr_kind = EXPR_TYPEINFO;
|
||||
inner->resolve_status = RESOLVE_NOT_DONE;
|
||||
inner->type_expr = info;
|
||||
return inner;
|
||||
}
|
||||
case TOKEN_TYPE_IDENT:
|
||||
{
|
||||
TypeInfo *info = type_info_new(TYPE_INFO_IDENTIFIER, inner->span);
|
||||
info->unresolved.name = interned_version;
|
||||
info->unresolved.path = path;
|
||||
info->resolve_status = RESOLVE_NOT_DONE;
|
||||
inner->expr_kind = EXPR_TYPEINFO;
|
||||
inner->resolve_status = RESOLVE_NOT_DONE;
|
||||
inner->type_expr = info;
|
||||
return inner;
|
||||
}
|
||||
default:
|
||||
if (is_type_eval)
|
||||
{
|
||||
SEMA_ERROR(inner, "Only valid types may be resolved with $evaltype.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(inner, "Only plain function, variable and constant names may be resolved with $eval.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
inner->expr_kind = EXPR_IDENTIFIER;
|
||||
inner->resolve_status = RESOLVE_NOT_DONE;
|
||||
inner->identifier_expr.ident = interned_version;
|
||||
inner->identifier_expr.path = path;
|
||||
return inner;
|
||||
}
|
||||
|
||||
static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl)
|
||||
@@ -308,6 +352,7 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
case EXPR_CT_IDENT:
|
||||
return true;
|
||||
case EXPR_IDENTIFIER:
|
||||
@@ -433,6 +478,7 @@ ERR:
|
||||
bool sema_expr_check_assign(SemaContext *c, Expr *expr)
|
||||
{
|
||||
if (!sema_binary_is_expr_lvalue(expr, expr)) return false;
|
||||
if (expr->expr_kind == EXPR_SUBSCRIPT_ASSIGN) return true;
|
||||
if (expr->expr_kind == EXPR_BITACCESS || expr->expr_kind == EXPR_ACCESS) expr = expr->access_expr.parent;
|
||||
if (expr->expr_kind == EXPR_IDENTIFIER)
|
||||
{
|
||||
@@ -2177,7 +2223,56 @@ static bool sema_subscript_rewrite_index_const_list(Expr *const_list, Expr *inde
|
||||
return expr_rewrite_to_const_initializer_index(const_list->type, const_list->const_expr.initializer, result, idx);
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, bool is_addr)
|
||||
/**
|
||||
* Find index type or overload for subscript.
|
||||
*/
|
||||
static Expr *sema_expr_find_index_type_or_overload_for_subscript(SemaContext *context, Expr *current_expr, SubscriptEval eval_type, Type **index_type_ptr, Decl **overload_ptr)
|
||||
{
|
||||
Decl *overload = NULL;
|
||||
switch (eval_type)
|
||||
{
|
||||
case SUBSCRIPT_EVAL_REF:
|
||||
overload = sema_find_operator(context, current_expr, OVERLOAD_ELEMENT_REF);
|
||||
break;
|
||||
case SUBSCRIPT_EVAL_VALUE:
|
||||
overload = sema_find_operator(context, current_expr, OVERLOAD_ELEMENT_AT);
|
||||
break;
|
||||
case SUBSCRIPT_EVAL_ASSIGN:
|
||||
overload = sema_find_operator(context, current_expr, OVERLOAD_ELEMENT_SET);
|
||||
if (overload)
|
||||
{
|
||||
*overload_ptr = overload;
|
||||
assert(vec_size(overload->func_decl.signature.params) == 3);
|
||||
*index_type_ptr = overload->func_decl.signature.params[2]->type;
|
||||
return current_expr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Overload found for [] and &[]
|
||||
if (overload)
|
||||
{
|
||||
*overload_ptr = overload;
|
||||
assert(overload->func_decl.signature.rtype);
|
||||
*index_type_ptr = type_infoptr(overload->func_decl.signature.rtype)->type;
|
||||
return current_expr;
|
||||
}
|
||||
// Otherwise, see if we have an indexed type.
|
||||
Type *inner_type = type_get_indexed_type(current_expr->type);
|
||||
if (inner_type)
|
||||
{
|
||||
*index_type_ptr = inner_type;
|
||||
*overload_ptr = NULL;
|
||||
return current_expr;
|
||||
}
|
||||
if (type_is_substruct(current_expr->type))
|
||||
{
|
||||
Expr *embedded_struct = expr_access_inline_member(current_expr, current_expr->type->decl);
|
||||
return sema_expr_find_index_type_or_overload_for_subscript(context, embedded_struct, eval_type, index_type_ptr, overload_ptr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, SubscriptEval eval_type)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_SUBSCRIPT || expr->expr_kind == EXPR_SUBSCRIPT_ADDR);
|
||||
|
||||
@@ -2196,7 +2291,6 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
Type *underlying_type = type_flatten(subscripted->type);
|
||||
|
||||
Type *current_type = underlying_type;
|
||||
Expr *current_expr = subscripted;
|
||||
|
||||
int64_t index_value = -1;
|
||||
bool start_from_end = expr->subscript_expr.range.start_from_end;
|
||||
@@ -2208,7 +2302,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
SEMA_ERROR(index, "The index may not be negative.");
|
||||
return false;
|
||||
}
|
||||
int64_t size = current_type == type_untypedlist ? vec_size(current_expr->const_expr.untyped_list) : current_type->array.len;
|
||||
int64_t size = current_type == type_untypedlist ? vec_size(subscripted->const_expr.untyped_list) : current_type->array.len;
|
||||
assert(size >= 0 && "Unexpected overflow");
|
||||
if (!int_fits(index->const_expr.ixx, TYPE_I64) || size == 0)
|
||||
{
|
||||
@@ -2246,13 +2340,14 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
// 4. If we are indexing into a complist
|
||||
if (underlying_type == type_untypedlist)
|
||||
{
|
||||
if (is_addr)
|
||||
if (eval_type == SUBSCRIPT_EVAL_REF)
|
||||
{
|
||||
SEMA_ERROR(subscripted, "You need to use && to take the address of a temporary.");
|
||||
return false;
|
||||
}
|
||||
// 4a. This may either be an initializer list or a CT value
|
||||
while (current_expr->expr_kind == EXPR_CT_IDENT) current_expr = current_expr->ct_ident_expr.decl->var.init_expr;
|
||||
Expr *current_expr = subscripted;
|
||||
while (subscripted->expr_kind == EXPR_CT_IDENT) current_expr = current_expr->ct_ident_expr.decl->var.init_expr;
|
||||
|
||||
// 4b. Now we need to check that we actually have a valid type.
|
||||
if (index_value < 0)
|
||||
@@ -2260,39 +2355,50 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
SEMA_ERROR(index, "To subscript an untyped list a compile time integer index is needed.");
|
||||
return false;
|
||||
}
|
||||
expr_replace(expr, subscripted->const_expr.untyped_list[index_value]);
|
||||
if (eval_type == SUBSCRIPT_EVAL_ASSIGN) TODO;
|
||||
expr_replace(expr, current_expr->const_expr.untyped_list[index_value]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!sema_cast_rvalue(context, current_expr)) return false;
|
||||
if (!sema_cast_rvalue(context, subscripted)) return false;
|
||||
|
||||
Type *inner_type = sema_subscript_find_indexable_type_recursively(¤t_type, ¤t_expr);
|
||||
if (!inner_type)
|
||||
Decl *overload = NULL;
|
||||
Type *index_type = NULL;
|
||||
Expr *current_expr = sema_expr_find_index_type_or_overload_for_subscript(context, subscripted, eval_type, &index_type, &overload);
|
||||
if (!index_type)
|
||||
{
|
||||
Decl *decl = NULL;
|
||||
if (is_addr) decl = sema_find_operator(context, current_expr, OVERLOAD_ELEMENT_REF);
|
||||
if (!decl)
|
||||
if (!overload && eval_type == SUBSCRIPT_EVAL_REF)
|
||||
{
|
||||
decl = sema_find_operator(context, current_expr, OVERLOAD_ELEMENT_AT);
|
||||
if (decl && is_addr)
|
||||
// Maybe there is a [] overload?
|
||||
if (sema_expr_find_index_type_or_overload_for_subscript(context,
|
||||
subscripted,
|
||||
SUBSCRIPT_EVAL_VALUE,
|
||||
&index_type,
|
||||
&overload))
|
||||
{
|
||||
SEMA_ERROR(expr, "A function or macro with '@operator([])' is not defined for %s, so you need && to take the address of the temporary.",
|
||||
SEMA_ERROR(expr,
|
||||
"A function or macro with '@operator(&[])' is not defined for %s, so you need && to take the address of the temporary.",
|
||||
type_quoted_error_string(current_expr->type));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (decl)
|
||||
{
|
||||
Expr **args = NULL;
|
||||
vec_add(args, index);
|
||||
return sema_insert_method_call(context, expr, decl, current_expr, args);
|
||||
}
|
||||
}
|
||||
if (!inner_type)
|
||||
{
|
||||
SEMA_ERROR(subscripted, "Cannot index '%s'.", type_to_error_string(subscripted->type));
|
||||
return false;
|
||||
}
|
||||
if (overload)
|
||||
{
|
||||
if (eval_type == SUBSCRIPT_EVAL_ASSIGN)
|
||||
{
|
||||
expr->expr_kind = EXPR_SUBSCRIPT_ASSIGN;
|
||||
expr->subscript_assign_expr.expr = exprid(current_expr);
|
||||
expr->subscript_assign_expr.index = exprid(index);
|
||||
expr->subscript_assign_expr.method = declid(overload);
|
||||
return true;
|
||||
}
|
||||
Expr **args = NULL;
|
||||
vec_add(args, index);
|
||||
return sema_insert_method_call(context, expr, overload, current_expr, args);
|
||||
}
|
||||
|
||||
// Cast to an appropriate type for index.
|
||||
if (!cast_to_index(index)) return false;
|
||||
@@ -2306,9 +2412,9 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
(void)start_from_end;
|
||||
}
|
||||
|
||||
if (is_addr)
|
||||
if (eval_type == SUBSCRIPT_EVAL_REF)
|
||||
{
|
||||
inner_type = type_get_ptr(inner_type);
|
||||
index_type = type_get_ptr(index_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2318,7 +2424,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
}
|
||||
}
|
||||
expr->subscript_expr.expr = exprid(current_expr);
|
||||
expr->type = type_add_optional(inner_type, failable);
|
||||
expr->type = type_add_optional(index_type, failable);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2509,30 +2615,17 @@ RETRY:
|
||||
}
|
||||
case EXPR_CT_EVAL:
|
||||
{
|
||||
Expr *inner = child->inner_expr;
|
||||
TokenType type;
|
||||
// Only report missing if missing var is NULL
|
||||
Path *path = NULL;
|
||||
const char *ident = sema_ct_eval_expr(context, "$eval", inner, &type, &path, missing == NULL);
|
||||
if (!ident && missing)
|
||||
Expr *result = sema_ct_eval_expr(context, false, child->inner_expr, missing == NULL);
|
||||
if (!result)
|
||||
{
|
||||
*missing = true;
|
||||
if (missing) *missing = true;
|
||||
return NULL;
|
||||
}
|
||||
if (ident == ct_eval_error) return NULL;
|
||||
switch (type)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
child->expr_kind = EXPR_IDENTIFIER;
|
||||
child->identifier_expr.ident = ident;
|
||||
child->identifier_expr.path = path;
|
||||
child->identifier_expr.is_const = type == TOKEN_CONST_IDENT;
|
||||
goto RETRY;
|
||||
default:
|
||||
SEMA_ERROR(inner, "Only function, variable and constant names may be resolved with $eval.");
|
||||
return NULL;
|
||||
}
|
||||
expr_replace(child, result);
|
||||
goto RETRY;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
@@ -3693,9 +3786,16 @@ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *lef
|
||||
{
|
||||
return sema_expr_analyse_ct_type_identifier_assign(context, expr, left, right);
|
||||
}
|
||||
if (left->expr_kind == EXPR_SUBSCRIPT)
|
||||
{
|
||||
if (!sema_expr_analyse_subscript(context, left, SUBSCRIPT_EVAL_ASSIGN)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_expr_lvalue(context, left)) return false;
|
||||
}
|
||||
|
||||
if (!sema_analyse_expr_lvalue(context, left)) return false;
|
||||
|
||||
bool is_subscript_assign = left->expr_kind == EXPR_SUBSCRIPT_ASSIGN;
|
||||
|
||||
// 2. Check assignability
|
||||
if (!sema_expr_check_assign(context, left)) return false;
|
||||
@@ -3710,6 +3810,13 @@ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *lef
|
||||
sema_rewrap_var(context, left->identifier_expr.decl);
|
||||
return true;
|
||||
}
|
||||
if (left->expr_kind == EXPR_SUBSCRIPT_ASSIGN)
|
||||
{
|
||||
Expr **args = NULL;
|
||||
vec_add(args, exprptr(left->subscript_assign_expr.index));
|
||||
vec_add(args, right);
|
||||
return sema_insert_method_call(context, expr, declptr(left->subscript_assign_expr.method), exprptr(left->subscript_assign_expr.expr), args);
|
||||
}
|
||||
if (left->expr_kind == EXPR_BITACCESS)
|
||||
{
|
||||
if (!sema_bit_assignment_check(right, left->access_expr.ref)) return false;
|
||||
@@ -5523,6 +5630,28 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr *
|
||||
expr_rewrite_to_string(expr, context->compilation_unit->file->name);
|
||||
return true;
|
||||
}
|
||||
if (string == kw_FUNCPTR)
|
||||
{
|
||||
|
||||
switch (context->call_env.kind)
|
||||
{
|
||||
case CALL_ENV_GLOBAL_INIT:
|
||||
case CALL_ENV_CHECKS:
|
||||
case CALL_ENV_INITIALIZER:
|
||||
case CALL_ENV_FINALIZER:
|
||||
case CALL_ENV_ATTR:
|
||||
expr_rewrite_to_const_zero(expr, type_voidptr);
|
||||
return true;
|
||||
case CALL_ENV_FUNCTION:
|
||||
expr->expr_kind = EXPR_IDENTIFIER;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
expr->identifier_expr.decl = context->call_env.current_function;
|
||||
expr->type = expr->identifier_expr.decl->type;
|
||||
expr_insert_addr(expr);
|
||||
return true;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
if (string == kw_FUNC)
|
||||
{
|
||||
switch (context->call_env.kind)
|
||||
@@ -5932,25 +6061,15 @@ RETRY:
|
||||
case TYPE_INFO_EVALTYPE:
|
||||
{
|
||||
Expr *expr = type_info->unresolved_type_expr;
|
||||
TokenType type;
|
||||
Path *path = NULL;
|
||||
const char *ident = sema_ct_eval_expr(context, "$eval", expr, &type, &path, false);
|
||||
if (!ident) return NULL;
|
||||
if (ident == ct_eval_error) return poisoned_type;
|
||||
switch (type)
|
||||
expr = sema_ct_eval_expr(context, "$evaltype", expr, false);
|
||||
if (!expr) return NULL;
|
||||
if (expr->expr_kind != EXPR_TYPEINFO)
|
||||
{
|
||||
case TOKEN_TYPE_IDENT:
|
||||
type_info->unresolved.name = ident;
|
||||
type_info->span = expr->span;
|
||||
type_info->unresolved.path = path;
|
||||
type_info->kind = TYPE_INFO_IDENTIFIER;
|
||||
goto RETRY;
|
||||
case TYPE_TOKENS:
|
||||
return type_info->type = type_from_token(type);
|
||||
default:
|
||||
SEMA_ERROR(expr, "Only type names may be resolved with $evaltype.");
|
||||
return poisoned_type;
|
||||
SEMA_ERROR(expr, "Only type names may be resolved with $evaltype.");
|
||||
return poisoned_type;
|
||||
}
|
||||
type_info = expr->type_expr;
|
||||
goto RETRY;
|
||||
}
|
||||
case TYPE_INFO_SUBARRAY:
|
||||
{
|
||||
@@ -6055,28 +6174,9 @@ RETRY:
|
||||
if (!sema_expr_analyse_builtin(context, main_var, false)) goto NOT_DEFINED;
|
||||
break;
|
||||
case EXPR_CT_EVAL:
|
||||
{
|
||||
Expr *inner = main_var->inner_expr;
|
||||
TokenType token_type;
|
||||
Path *path = NULL;
|
||||
const char *ident = sema_ct_eval_expr(context, "$eval", inner, &token_type, &path, false);
|
||||
if (ident == ct_eval_error) return false;
|
||||
if (!ident) goto NOT_DEFINED;
|
||||
switch (token_type)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
main_var->expr_kind = EXPR_IDENTIFIER;
|
||||
main_var->resolve_status = RESOLVE_NOT_DONE;
|
||||
main_var->identifier_expr.ident = ident;
|
||||
main_var->identifier_expr.path = path;
|
||||
main_var->identifier_expr.is_const = token_type == TOKEN_CONST_IDENT;
|
||||
goto RETRY;
|
||||
default:
|
||||
SEMA_ERROR(inner, "Only function, variable and constant names may be resolved with $eval.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
main_var = sema_ct_eval_expr(context, "$eval", main_var->inner_expr, false);
|
||||
if (!main_var) goto NOT_DEFINED;
|
||||
goto RETRY;
|
||||
default:
|
||||
SEMA_ERROR(main_var, "Expected an identifier here.");
|
||||
return false;
|
||||
@@ -6245,24 +6345,17 @@ static inline bool sema_expr_analyse_ct_stringify(SemaContext *context, Expr *ex
|
||||
|
||||
static inline bool sema_expr_analyse_ct_eval(SemaContext *context, Expr *expr)
|
||||
{
|
||||
Expr *inner = expr->inner_expr;
|
||||
TokenType type;
|
||||
Path *path = NULL;
|
||||
const char *ident = sema_ct_eval_expr(context, "$eval", inner, &type, &path, true);
|
||||
if (ident == ct_eval_error) return false;
|
||||
switch (type)
|
||||
Expr *result = sema_ct_eval_expr(context, "$eval", expr->inner_expr, true);
|
||||
if (!result) return false;
|
||||
if (result->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
expr->expr_kind = EXPR_IDENTIFIER;
|
||||
expr->identifier_expr.ident = ident;
|
||||
expr->identifier_expr.path = path;
|
||||
expr->identifier_expr.is_const = type == TOKEN_CONST_IDENT;
|
||||
return sema_analyse_expr_dispatch(context, expr);
|
||||
default:
|
||||
SEMA_ERROR(inner, "Only function, variable and constant names may be resolved with $eval.");
|
||||
return false;
|
||||
SEMA_ERROR(result, "Evaluation to a type requires the use of '$evaltype' rather than '$eval'.");
|
||||
return false;
|
||||
}
|
||||
expr_replace(expr, result);
|
||||
return sema_analyse_expr_dispatch(context, expr);
|
||||
}
|
||||
|
||||
|
||||
@@ -6481,12 +6574,13 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
case EXPR_CALL:
|
||||
return sema_expr_analyse_call(context, expr);
|
||||
case EXPR_SUBSCRIPT:
|
||||
return sema_expr_analyse_subscript(context, expr, false);
|
||||
return sema_expr_analyse_subscript(context, expr, SUBSCRIPT_EVAL_VALUE);
|
||||
case EXPR_SUBSCRIPT_ADDR:
|
||||
return sema_expr_analyse_subscript(context, expr, true);
|
||||
return sema_expr_analyse_subscript(context, expr, SUBSCRIPT_EVAL_REF);
|
||||
case EXPR_GROUP:
|
||||
return sema_expr_analyse_group(context, expr);
|
||||
case EXPR_BITACCESS:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
UNREACHABLE
|
||||
case EXPR_ACCESS:
|
||||
return sema_expr_analyse_access(context, expr);
|
||||
@@ -6769,10 +6863,11 @@ bool sema_analyse_inferred_expr(SemaContext *context, Type *infer_type, Expr *ex
|
||||
return true;
|
||||
}
|
||||
|
||||
bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref, TokenType *type_ref)
|
||||
TokenType sema_splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref)
|
||||
{
|
||||
ArraySize path_end = 0;
|
||||
*path_ref = NULL;
|
||||
*ident_ref = NULL;
|
||||
for (ArraySize i = 0; i < len; i++)
|
||||
{
|
||||
char ch = string[i];
|
||||
@@ -6785,7 +6880,7 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
return TOKEN_INVALID_TOKEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6802,23 +6897,30 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char
|
||||
len--;
|
||||
string++;
|
||||
}
|
||||
if (len == 0) return false;
|
||||
if (len == 0) return TOKEN_INVALID_TOKEN;
|
||||
uint32_t hash = FNV1_SEED;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
char c = string[i];
|
||||
if (!char_is_alphanum_(c)) return false;
|
||||
if (!char_is_alphanum_(c)) return TOKEN_INVALID_TOKEN;
|
||||
hash = FNV1a(c, hash);
|
||||
}
|
||||
*ident_ref = symtab_find(string, len, hash, type_ref);
|
||||
if (!*ident_ref)
|
||||
TokenType type;
|
||||
*ident_ref = symtab_find(string, len, hash, &type);
|
||||
if (!*ident_ref) return TOKEN_IDENT;
|
||||
switch (type)
|
||||
{
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append_len(string, len);
|
||||
*ident_ref = scratch_buffer_to_string();
|
||||
*type_ref = TOKEN_INVALID_TOKEN;
|
||||
case TOKEN_TYPE_IDENT:
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
return type;
|
||||
case TYPE_TOKENS:
|
||||
if (!*path_ref) return type;
|
||||
FALLTHROUGH;
|
||||
default:
|
||||
*ident_ref = NULL;
|
||||
return TOKEN_INVALID_TOKEN;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments)
|
||||
|
||||
@@ -27,6 +27,17 @@
|
||||
#define POP_BREAKCONT() POP_CONTINUE(); POP_BREAK()
|
||||
#define IS_CONST(_x) ((_x)->expr_kind == EXPR_CONST)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPLIT_PATH_IDENT,
|
||||
SPLIT_PATH_CONST_IDENT,
|
||||
SPLIT_PATH_TYPE_IDENT,
|
||||
SPLIT_PATH_BUILTIN_TYPE_IDENT,
|
||||
SPLIT_PATH_UNKNOWN_IDENTIFIER,
|
||||
SPLIT_PATH_NOT_SINGLE_IDENTIFIER,
|
||||
SPLIT_PATH_NOT_AN_IDENTIFIER,
|
||||
} SplitPathResult;
|
||||
|
||||
extern const char *ct_eval_error;
|
||||
|
||||
Decl **global_context_acquire_locals_list(void);
|
||||
@@ -38,7 +49,8 @@ void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast);
|
||||
void context_change_scope_for_label(SemaContext *context, Decl *label);
|
||||
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags);
|
||||
SemaContext *context_transform_for_eval(SemaContext *context, SemaContext *temp_context, CompilationUnit *eval_unit);
|
||||
bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref, TokenType *type_ref);
|
||||
|
||||
TokenType sema_splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref);
|
||||
|
||||
void sema_context_init(SemaContext *context, CompilationUnit *unit);
|
||||
void sema_context_destroy(SemaContext *context);
|
||||
@@ -65,7 +77,7 @@ bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *meth
|
||||
bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr);
|
||||
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool failable);
|
||||
Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr);
|
||||
const char *sema_ct_eval_expr(SemaContext *c, const char *expr_type, Expr *inner, TokenType *type, Path **path_ref, bool report_missing);
|
||||
Expr *sema_ct_eval_expr(SemaContext *c, bool is_type, Expr *inner, bool report_missing);
|
||||
bool sema_analyse_asm(SemaContext *context, AsmInlineBlock *block, Ast *asm_stmt);
|
||||
bool sema_bit_assignment_check(Expr *right, Decl *member);
|
||||
int sema_check_comp_time_bool(SemaContext *context, Expr *expr);
|
||||
|
||||
@@ -273,7 +273,6 @@ bool sema_resolve_type_shallow(SemaContext *context, TypeInfo *type_info, bool a
|
||||
allow_inferred_type = false;
|
||||
in_shallow = true;
|
||||
}
|
||||
RETRY:
|
||||
switch (type_info->kind)
|
||||
{
|
||||
case TYPE_INFO_POISON:
|
||||
@@ -301,29 +300,18 @@ RETRY:
|
||||
{
|
||||
Expr *expr = type_info->unresolved_type_expr;
|
||||
TokenType type;
|
||||
Path *path = NULL;
|
||||
const char *ident = sema_ct_eval_expr(context, "$eval", expr, &type, &path, true);
|
||||
if (ident == ct_eval_error) return type_info_poison(type_info);
|
||||
switch (type)
|
||||
Expr *inner = sema_ct_eval_expr(context, "$evaltype", expr, true);
|
||||
if (!inner) return false;
|
||||
if (inner->expr_kind != EXPR_TYPEINFO)
|
||||
{
|
||||
case TOKEN_TYPE_IDENT:
|
||||
type_info->unresolved.name = ident;
|
||||
type_info->span = expr->span;
|
||||
type_info->unresolved.path = path;
|
||||
type_info->kind = TYPE_INFO_IDENTIFIER;
|
||||
goto RETRY;
|
||||
case TYPE_TOKENS:
|
||||
if (path)
|
||||
{
|
||||
SEMA_ERROR(path, "Built in types cannot have a path prefix.");
|
||||
return false;
|
||||
}
|
||||
type_info->type = type_from_token(type);
|
||||
goto APPEND_QUALIFIERS;
|
||||
default:
|
||||
SEMA_ERROR(expr, "Only type names may be resolved with $evaltype.");
|
||||
return type_info_poison(type_info);
|
||||
SEMA_ERROR(expr, "Only type names may be resolved with $evaltype.");
|
||||
return type_info_poison(type_info);
|
||||
}
|
||||
TypeInfo *inner_type = inner->type_expr;
|
||||
if (!sema_resolve_type_info(context, inner_type)) return false;
|
||||
type_info->type = inner_type->type;
|
||||
type_info->resolve_status = RESOLVE_DONE;
|
||||
goto APPEND_QUALIFIERS;
|
||||
}
|
||||
case TYPE_INFO_TYPEOF:
|
||||
{
|
||||
|
||||
@@ -285,7 +285,7 @@ void sema_analysis_run(void)
|
||||
Path *path;
|
||||
const char *ident;
|
||||
TokenType type;
|
||||
if (!splitpathref(panicfn, strlen(panicfn), &path, &ident, &type) || path == NULL)
|
||||
if (sema_splitpathref(panicfn, strlen(panicfn), &path, &ident) != TOKEN_IDENT || path == NULL || !ident)
|
||||
{
|
||||
error_exit("'%s' is not a valid panic function.", panicfn);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ const char *builtin_list[NUMBER_OF_BUILTINS];
|
||||
|
||||
const char *kw_FILE;
|
||||
const char *kw_FUNC;
|
||||
const char *kw_FUNCPTR;
|
||||
const char *kw_LINEREAL;
|
||||
const char *kw_LINE;
|
||||
const char *kw_align;
|
||||
@@ -131,6 +132,7 @@ void symtab_init(uint32_t capacity)
|
||||
kw_LINEREAL = KW_DEF("LINEREAL");
|
||||
kw_FILE = KW_DEF("FILE");
|
||||
kw_FUNC = KW_DEF("FUNC");
|
||||
kw_FUNCPTR = KW_DEF("FUNCPTR");
|
||||
|
||||
type = TOKEN_TYPE_IDENT;
|
||||
kw_typekind = KW_DEF("TypeKind");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.68"
|
||||
#define COMPILER_VERSION "0.3.69"
|
||||
69
test/test_suite/compile_time/ct_funcptr.c3t
Normal file
69
test/test_suite/compile_time/ct_funcptr.c3t
Normal file
@@ -0,0 +1,69 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std::io;
|
||||
|
||||
fn void test(int x)
|
||||
{
|
||||
$typeof($$FUNCPTR) ptr = $$FUNCPTR;
|
||||
io::printfln("%d", x);
|
||||
if (x > 0) ptr(x - 1);
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
test(10);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test_test(i32 %0) #0 {
|
||||
entry:
|
||||
%ptr = alloca void (i32)*, align 8
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
store void (i32)* @test_test, void (i32)** %ptr, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i64 2 }, %"char[]"* %taddr, align 8
|
||||
%1 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 0
|
||||
%lo = load i8*, i8** %2, align 8
|
||||
%3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 1
|
||||
%hi = load i64, i64* %3, align 8
|
||||
store i32 %0, i32* %taddr1, align 4
|
||||
%4 = bitcast i32* %taddr1 to i8*
|
||||
%5 = insertvalue %variant undef, i8* %4, 0
|
||||
%6 = insertvalue %variant %5, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%7 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0
|
||||
store %variant %6, %variant* %7, align 16
|
||||
%8 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1
|
||||
store i64 1, i64* %8, align 8
|
||||
%9 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0
|
||||
%10 = bitcast [1 x %variant]* %varargslots to %variant*
|
||||
store %variant* %10, %variant** %9, align 8
|
||||
%11 = bitcast %"variant[]"* %vararg to { i8*, i64 }*
|
||||
%12 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 0
|
||||
%lo2 = load i8*, i8** %12, align 8
|
||||
%13 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 1
|
||||
%hi3 = load i64, i64* %13, align 8
|
||||
%14 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %14, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
%gt = icmp sgt i32 %0, 0
|
||||
br i1 %gt, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %voiderr
|
||||
%15 = load void (i32)*, void (i32)** %ptr, align 8
|
||||
%sub = sub i32 %0, 1
|
||||
call void %15(i32 %sub)
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then, %voiderr
|
||||
ret void
|
||||
}
|
||||
@@ -16,5 +16,5 @@ fn void main3()
|
||||
|
||||
fn void main4()
|
||||
{
|
||||
$extnameof($evaltype("foo::int")); // #error: Built in types cannot have a path prefix.
|
||||
$extnameof($evaltype("foo::int")); // #error: Only valid types may be resolved with $evaltype.
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ fn void f()
|
||||
|
||||
fn void g()
|
||||
{
|
||||
int x = $evaltype("bar::").sizeof; // #error: A valid name was expected here.
|
||||
int x = $evaltype("bar::").sizeof; // #error: Only valid types may be resolved with $evaltype
|
||||
}
|
||||
|
||||
fn void k()
|
||||
|
||||
39
test/test_suite/overloading/set_overload.c3t
Normal file
39
test/test_suite/overloading/set_overload.c3t
Normal file
@@ -0,0 +1,39 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
import std::map;
|
||||
|
||||
define IntMap = HashMap<char[], int>;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
IntMap map;
|
||||
map.set("Hello", 4);
|
||||
map["Bye"] = 5;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test_main() #0 {
|
||||
entry:
|
||||
%map = alloca %HashMap, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%taddr1 = alloca %"char[]", align 8
|
||||
%0 = bitcast %HashMap* %map to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 40, i1 false)
|
||||
store %"char[]" { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 5 }, %"char[]"* %taddr, align 8
|
||||
%1 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 0
|
||||
%lo = load i8*, i8** %2, align 8
|
||||
%3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 1
|
||||
%hi = load i64, i64* %3, align 8
|
||||
%4 = call i8 @"std_map$$sa$char.int_HashMap_set"(%HashMap* %map, i8* %lo, i64 %hi, i32 4)
|
||||
store %"char[]" { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i64 3 }, %"char[]"* %taddr1, align 8
|
||||
%5 = bitcast %"char[]"* %taddr1 to { i8*, i64 }*
|
||||
%6 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %5, i32 0, i32 0
|
||||
%lo2 = load i8*, i8** %6, align 8
|
||||
%7 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %5, i32 0, i32 1
|
||||
%hi3 = load i64, i64* %7, align 8
|
||||
%8 = call i8 @"std_map$$sa$char.int_HashMap_set"(%HashMap* %map, i8* %lo2, i64 %hi3, i32 5)
|
||||
ret void
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
65
test/test_suite2/compile_time/ct_funcptr.c3t
Normal file
65
test/test_suite2/compile_time/ct_funcptr.c3t
Normal file
@@ -0,0 +1,65 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std::io;
|
||||
|
||||
fn void test(int x)
|
||||
{
|
||||
$typeof($$FUNCPTR) ptr = $$FUNCPTR;
|
||||
io::printfln("%d", x);
|
||||
if (x > 0) ptr(x - 1);
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
test(10);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test_test(i32 %0) #0 {
|
||||
entry:
|
||||
%ptr = alloca ptr, align 8
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
store ptr @test_test, ptr %ptr, align 8
|
||||
store %"char[]" { ptr @.str, i64 2 }, ptr %taddr, align 8
|
||||
%1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %1, align 8
|
||||
%2 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %2, align 8
|
||||
store i32 %0, ptr %taddr1, align 4
|
||||
%3 = insertvalue %variant undef, ptr %taddr1, 0
|
||||
%4 = insertvalue %variant %3, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%5 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0
|
||||
store %variant %4, ptr %5, align 16
|
||||
%6 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1
|
||||
store i64 1, ptr %6, align 8
|
||||
%7 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0
|
||||
store ptr %varargslots, ptr %7, align 8
|
||||
%8 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0
|
||||
%lo2 = load ptr, ptr %8, align 8
|
||||
%9 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1
|
||||
%hi3 = load i64, ptr %9, align 8
|
||||
%10 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %10, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
%gt = icmp sgt i32 %0, 0
|
||||
br i1 %gt, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %voiderr
|
||||
%11 = load ptr, ptr %ptr, align 8
|
||||
%sub = sub i32 %0, 1
|
||||
call void %11(i32 %sub)
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then, %voiderr
|
||||
ret void
|
||||
}
|
||||
@@ -16,5 +16,5 @@ fn void main3()
|
||||
|
||||
fn void main4()
|
||||
{
|
||||
$extnameof($evaltype("foo::int")); // #error: Built in types cannot have a path prefix.
|
||||
$extnameof($evaltype("foo::int")); // #error: Only valid types may be resolved with $evaltype.
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module foo;
|
||||
import bar;
|
||||
import bar::abc;
|
||||
|
||||
fn void a()
|
||||
{
|
||||
@@ -25,7 +24,7 @@ fn void f()
|
||||
|
||||
fn void g()
|
||||
{
|
||||
int x = $evaltype("bar::").sizeof; // #error: A valid name was expected here.
|
||||
int x = $evaltype("bar::").sizeof; // #error: Only valid types may be resolved with $evaltype
|
||||
}
|
||||
|
||||
fn void k()
|
||||
|
||||
36
test/test_suite2/overloading/set_overload.c3t
Normal file
36
test/test_suite2/overloading/set_overload.c3t
Normal file
@@ -0,0 +1,36 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
import std::map;
|
||||
|
||||
define IntMap = HashMap<char[], int>;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
IntMap map;
|
||||
map.set("Hello", 4);
|
||||
map["Bye"] = 5;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test_main() #0 {
|
||||
entry:
|
||||
%map = alloca %HashMap, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%taddr1 = alloca %"char[]", align 8
|
||||
call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 40, i1 false)
|
||||
store %"char[]" { ptr @.str, i64 5 }, ptr %taddr, align 8
|
||||
%0 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %0, align 8
|
||||
%1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %1, align 8
|
||||
%2 = call i8 @"std_map$$sa$char.int_HashMap_set"(ptr %map, ptr %lo, i64 %hi, i32 4)
|
||||
store %"char[]" { ptr @.str.1, i64 3 }, ptr %taddr1, align 8
|
||||
%3 = getelementptr inbounds { ptr, i64 }, ptr %taddr1, i32 0, i32 0
|
||||
%lo2 = load ptr, ptr %3, align 8
|
||||
%4 = getelementptr inbounds { ptr, i64 }, ptr %taddr1, i32 0, i32 1
|
||||
%hi3 = load i64, ptr %4, align 8
|
||||
%5 = call i8 @"std_map$$sa$char.int_HashMap_set"(ptr %map, ptr %lo2, i64 %hi3, i32 5)
|
||||
ret void
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user