Fix constant typeid comparisons. Allow methods to use & and * and constants. Improved error messages. Updated String type with generic append.

This commit is contained in:
Christoffer Lerno
2022-07-23 23:08:27 +02:00
committed by Christoffer Lerno
parent c1de3f059e
commit 7e0a29ef40
11 changed files with 117 additions and 50 deletions

View File

@@ -41,14 +41,12 @@ fn String new(char[] c)
return (String)data;
}
fn ZString String.zstr(String* str)
fn ZString String.zstr(String str)
{
if (!str) return (ZString)"";
StringData* data = str.data();
if (!data) return (ZString)"";
if (data.capacity == data.len)
{
libc::printf("feofk\n");
str.reserve(1);
data.chars[data.len] = 0;
}
@@ -59,24 +57,24 @@ fn ZString String.zstr(String* str)
return (ZString)&data.chars[0];
}
fn usize String.len(String* this)
fn usize String.len(String this)
{
if (!*this) return 0;
if (!this) return 0;
return this.data().len;
}
/**
* @require new_size <= this.len()
*/
fn void String.chop(String* this, usize new_size)
fn void String.chop(String this, usize new_size)
{
if (!*this) return;
if (!this) return;
this.data().len = new_size;
}
fn char[] String.str(String* str)
fn char[] String.str(String str)
{
StringData* data = (StringData*)*str;
StringData* data = (StringData*)str;
return data.chars[0..data.len - 1];
}
@@ -92,7 +90,7 @@ fn void String.append_utf32(String* str, Char32[] chars)
/**
* @require index < str.len()
**/
fn void String.set(String* str, usize index, char c)
fn void String.set(String str, usize index, char c)
{
str.data().chars[index] = c;
}
@@ -147,7 +145,7 @@ fn void String.append_char32(String* str, Char32 c)
fn String String.copy(String* str, Allocator allocator = { null, null })
{
if (!*str)
if (!str)
{
if (allocator.function) return new_with_capacity(0, allocator);
return (String)null;
@@ -175,7 +173,7 @@ fn ZString String.copy_zstr(String* str, Allocator allocator = { null, null })
return (ZString)zstr;
}
fn bool String.equals(String* str, String other_string)
fn bool String.equals(String str, String other_string)
{
StringData *str1 = str.data();
StringData *str2 = other_string.data();
@@ -200,7 +198,7 @@ fn void String.destroy(String* str)
*str = (String)null;
}
fn bool String.less(String* str, String other_string)
fn bool String.less(String str, String other_string)
{
StringData* str1 = str.data();
StringData* str2 = other_string.data();
@@ -217,7 +215,7 @@ fn bool String.less(String* str, String other_string)
return true;
}
fn void String.append(String* this, char[] str)
fn void String.append_chars(String* this, char[] str)
{
usize other_len = str.len;
if (!other_len) return;
@@ -255,29 +253,50 @@ fn void String.append_char(String* str, char c)
data.chars[data.len++] = c;
}
macro void String.@append(String &str, value)
macro bool is_pointer_char_array($Type)
{
$switch ($typeof(value)):
var $Type2 = $Type;
$if ($Type.typeid.kind != TypeKind.POINTER):
return false;
$elif ($Type.typeid.inner.kind != TypeKind.ARRAY):
return false;
$elif ($Type.typeid.inner.inner != char.typeid):
return false;
$else:
return true;
$endif;
}
macro void String.append(String* str, value)
{
var $Type = $typeof(value);
$switch ($Type):
$case char:
$case ichar:
str.append_char(value);
$case String:
str.append_string(value);
$case char[]:
str.append(value);
$case char32:
str.append_chars(value);
$case Char32:
str.append_char32(value);
$default:
$assert("Unsupported type for appending");
$if ($Type.typeid.kind == TypeKind.SIGNED_INT || $Type.typeid.kind == TypeKind.UNSIGNED_INT):
str.append_char32((Char32)value);
$elif (is_pointer_char_array($Type)):
str.append_chars(value);
$else:
$assert("Unsupported type for appending");
$endif;
$endswitch;
}
private fn StringData* String.data(String* str) @inline
private fn StringData* String.data(String str) @inline
{
return (StringData*)*str;
return (StringData*)str;
}
private fn void String.reserve(String* str, usize addition)
{
StringData* data = str.data();

View File

@@ -1,4 +1,4 @@
module std::math;
module std::math::matrix;
fault MatrixError {
MATRIX_INVERSE_DOESNT_EXIST,
@@ -360,7 +360,7 @@ fn Matrix4x4 Matrix4x4.scale(Matrix4x4* m, float[<3>] v) {
}
fn Matrix4x4 Matrix4x4.ortho(float left, float right, float top, float bottom, float near, float far) {
fn Matrix4x4 ortho(float left, float right, float top, float bottom, float near, float far) {
float width = right - left;
float height = top - bottom;
float depth = far - near;
@@ -375,7 +375,7 @@ fn Matrix4x4 Matrix4x4.ortho(float left, float right, float top, float bottom, f
}
// fov in radians
fn Matrix4x4 Matrix4x4.perspective(float fov, float aspect_ratio, float near, float far) {
fn Matrix4x4 perspective(float fov, float aspect_ratio, float near, float far) {
float top = ((float)math::sin(fov / 2) / (float)math::cos(fov / 2)) * near;
float right = top * aspect_ratio;
float depth = far - near;

View File

@@ -1913,6 +1913,7 @@ void expr_const_set_float(ExprConst *expr, Real d, TypeKind kind);
void expr_const_set_bool(ExprConst *expr, bool b);
void expr_const_set_null(ExprConst *expr);
bool expr_const_in_range(const ExprConst *left, const ExprConst *right, const ExprConst *right_to);
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);

View File

@@ -102,7 +102,8 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
is_eq = !strncmp(left->string.chars, right->string.chars, left->string.len);
break;
case CONST_TYPEID:
return left->typeid == right->typeid;
is_eq = left->typeid == right->typeid;
break;
case CONST_ERR:
case CONST_ENUM:
{
@@ -151,6 +152,15 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp
return (op == BINARYOP_EQ) && is_eq;
}
bool expr_const_in_range(const ExprConst *left, const ExprConst *right, const ExprConst *right_to)
{
if (right == right_to)
{
return expr_const_compare(left, right, BINARYOP_EQ);
}
return expr_const_compare(left, right, BINARYOP_GE) && expr_const_compare(left, right_to, BINARYOP_LE);
}
bool float_const_fits_type(const ExprConst *expr_const, TypeKind kind)
{
Real hi_limit;

View File

@@ -585,7 +585,7 @@ static inline Ast* parse_ct_else_stmt(ParseContext *c)
{
Ast *ast = new_ast(AST_CT_ELSE_STMT, c->span);
advance_and_verify(c, TOKEN_CT_ELSE);
TRY_CONSUME(TOKEN_COLON, "$else needs a ':', did you forget it?");
TRY_CONSUME_AFTER(TOKEN_COLON, "$else needs a ':', did you forget it?", poisoned_ast);
if (!parse_ct_compound_stmt(c, &ast->ct_else_stmt)) return poisoned_ast;
return ast;
}
@@ -604,11 +604,11 @@ static inline Ast* parse_ct_if_stmt(ParseContext *c, bool is_elif)
ASSIGN_EXPR_OR_RET(ast->ct_if_stmt.expr, parse_const_paren_expr(c), poisoned_ast);
if (is_elif)
{
TRY_CONSUME(TOKEN_COLON, "$elif needs a ':' after the expression, did you forget it?");
TRY_CONSUME_AFTER(TOKEN_COLON, "$elif needs a ':' after the expression, did you forget it?", poisoned_ast);
}
else
{
TRY_CONSUME(TOKEN_COLON, "$if needs a ':' after the expression, did you forget it?");
TRY_CONSUME_AFTER(TOKEN_COLON, "$if needs a ':' after the expression, did you forget it?", poisoned_ast);
}
if (!parse_ct_compound_stmt(c, &ast->ct_if_stmt.then)) return poisoned_ast;

View File

@@ -13,6 +13,7 @@
#define TRY_EXPECT_OR_RET(_tok, _message, _type) do { if (!tok_is(c, _tok)) { SEMA_ERROR_HERE(_message); return _type; } } while(0)
#define TRY_CONSUME_OR_RET(_tok, _message, _type) do { if (!consume(c, _tok, _message)) return _type; } while(0)
#define TRY_CONSUME(_tok, _message) TRY_CONSUME_OR_RET(_tok, _message, poisoned_ast)
#define TRY_CONSUME_AFTER(_tok, _message, _type) do { if (!try_consume(c, _tok)) { sema_error_at_after(c->prev_span, _message); return _type; } } while(0)
#define CHECK_EXPR_OR_RET(_expr) do { if (!expr_ok(_expr)) return _expr; } while(0)
Decl *parse_top_level_statement(ParseContext *c);

View File

@@ -5,6 +5,7 @@
#include "sema_internal.h"
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type);
static bool sema_analyse_struct_union(SemaContext *context, Decl *decl);
static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr** attrs, AttributeDomain domain);
static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl);
@@ -1116,6 +1117,14 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
type_to_error_string(parent_type->type));
return false;
}
Decl **params = decl->func_decl.function_signature.params;
if (!vec_size(params))
{
SEMA_ERROR(decl, "A method must start with a parameter of type %s or %s.",
type_quoted_error_string(parent_type->type), type_quoted_error_string(type_get_ptr(parent_type->type)));
return false;
}
if (!sema_is_valid_method_param(context, params[0], type)) return false;
return unit_add_method_like(context->unit, type, decl);
}
@@ -1755,6 +1764,24 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
return true;
}
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type)
{
assert(parent_type->canonical == parent_type && "Expected already the canonical version.");
Type *param_type = param->type;
if (!param_type) goto ERROR;
param_type = param_type->canonical;
// 1. Same type ok!
if (param_type == parent_type) return true;
// 2. A pointer is ok!
if (param_type->type_kind == TYPE_POINTER && param_type->pointer == parent_type) return true;
ERROR:
SEMA_ERROR(param, "The first parameter must be of type %s or %s.", type_quoted_error_string(parent_type),
type_quoted_error_string(type_get_ptr(parent_type)));
return false;
}
static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
{
TypeInfo *parent_type_info = type_infoptr(decl->macro_decl.type_parent);
@@ -1769,18 +1796,16 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
}
if (!vec_size(decl->macro_decl.parameters))
{
SEMA_ERROR(decl, "Expected at least one parameter - of type &%s.", type_to_error_string(parent_type));
SEMA_ERROR(decl, "Expected at least one parameter - of type %s.", type_to_error_string(parent_type));
return false;
}
Decl *first_param = decl->macro_decl.parameters[0];
if (!first_param->type || first_param->type->canonical != parent_type->canonical)
if (!sema_is_valid_method_param(context, first_param, parent_type->canonical)) return false;
if (first_param->var.kind != VARDECL_PARAM_REF && first_param->var.kind != VARDECL_PARAM)
{
SEMA_ERROR(first_param, "The first parameter must be &%s.", type_to_error_string(parent_type));
return false;
}
if (first_param->var.kind != VARDECL_PARAM_REF)
{
SEMA_ERROR(first_param, "The first parameter must be a ref (&) parameter.");
SEMA_ERROR(first_param, "The first parameter must be a regular or ref (&) type.");
return false;
}
return unit_add_method_like(context->unit, parent_type, decl);

View File

@@ -2488,10 +2488,24 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
break;
case EXPR_ACCESS:
decl = func_expr->access_expr.ref;
if (decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO)
switch (decl->decl_kind)
{
if (decl->decl_kind != DECL_MACRO) expr_insert_addr(func_expr->access_expr.parent);
struct_var = func_expr->access_expr.parent;
case DECL_MACRO:
if (decl->macro_decl.parameters[0]->type->type_kind == TYPE_POINTER)
{
expr_insert_addr(func_expr->access_expr.parent);
}
struct_var = func_expr->access_expr.parent;
break;
case DECL_FUNC:
if (decl->func_decl.function_signature.params[0]->type->type_kind == TYPE_POINTER)
{
expr_insert_addr(func_expr->access_expr.parent);
}
struct_var = func_expr->access_expr.parent;
break;
default:
break;
}
break;
case EXPR_TYPEINFO:

View File

@@ -242,16 +242,14 @@ static inline bool sema_analyse_top_level_switch(SemaContext *context, Decl *ct_
ExprConst *other_const = &other_case->ct_case_decl.expr->const_expr;
ExprConst *other_const_to = other_case->ct_case_decl.to_expr
? &other_case->ct_case_decl.to_expr->const_expr : other_const;
if (expr_const_compare(const_expr, other_const_to, BINARYOP_LE) &&
expr_const_compare(const_to_expr, other_const, BINARYOP_GE))
if (expr_const_in_range(const_expr, other_const, other_const_to))
{
SEMA_ERROR(kase, "'%s' appears more than once.", expr_const_to_error_string(const_expr));
SEMA_PREV(cases[j]->ct_case_decl.expr, "The previous $case was here.");
return false;
}
}
if (expr_const_compare(switch_expr_const, const_expr, BINARYOP_GE) &&
expr_const_compare(switch_expr_const, const_to_expr, BINARYOP_LE))
if (expr_const_in_range(switch_expr_const, const_expr, const_to_expr))
{
matched_case = (int)i;
}

View File

@@ -1531,8 +1531,7 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement)
}
ExprConst *const_expr = &case_stmt->case_stmt.expr->const_expr;
ExprConst *to_const_expr = case_stmt->case_stmt.to_expr ? &case_stmt->case_stmt.to_expr->const_expr : const_expr;
if (expr_const_compare(&target->const_expr, const_expr, BINARYOP_GE) &&
expr_const_compare(&target->const_expr, to_const_expr, BINARYOP_LE))
if (expr_const_in_range(&target->const_expr, const_expr, to_const_expr))
{
statement->nextcase_stmt.case_switch_stmt = astid(case_stmt);
return true;
@@ -1753,7 +1752,7 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type
if (other->ast_kind != AST_CASE_STMT) continue;
ExprConst *other_const = &other->case_stmt.expr->const_expr;
ExprConst *other_to_const = other->case_stmt.to_expr ? &other->case_stmt.to_expr->const_expr : other_const;
if (expr_const_compare(const_expr, other_to_const, BINARYOP_LE) && expr_const_compare(to_const_expr, other_const, BINARYOP_GE))
if (expr_const_in_range(const_expr, other_const, other_to_const))
{
SEMA_ERROR(case_stmt, "The same case value appears more than once.");
SEMA_PREV(other, "Here is the previous use of that value.");
@@ -1937,14 +1936,14 @@ static bool sema_analyse_ct_switch_body(SemaContext *context, Ast *statement)
if (other_stmt->ast_kind == AST_DEFAULT_STMT) continue;
ExprConst *other_const = &other_stmt->case_stmt.expr->const_expr;
ExprConst *other_const_to = other_stmt->case_stmt.to_expr ? &other_stmt->case_stmt.to_expr->const_expr : other_const;
if (expr_const_compare(const_expr, other_const_to, BINARYOP_LE) && expr_const_compare(const_to_expr, other_const, BINARYOP_GE))
if (expr_const_in_range(const_expr, other_const, other_const_to))
{
SEMA_ERROR(stmt, "'%s' appears more than once.", expr_const_to_error_string(const_expr));
SEMA_PREV(cases[j]->case_stmt.expr, "The previous $case was here.");
return false;
}
}
if (expr_const_compare(switch_expr_const, const_expr, BINARYOP_GE) && expr_const_compare(switch_expr_const, const_to_expr, BINARYOP_LE))
if (expr_const_in_range(switch_expr_const, const_expr, const_to_expr))
{
matched_case = (int) i;
}

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.2.21"
#define COMPILER_VERSION "0.2.22"