mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
New generic syntax and ad hoc invocation.
This commit is contained in:
committed by
Christoffer Lerno
parent
276281c3f9
commit
4f7b42cdc4
@@ -79,13 +79,13 @@ import stack;
|
||||
|
||||
// Define our new types, the first will implicitly create
|
||||
// a complete copy of the entire Stack module with "Type" set to "int"
|
||||
def IntStack = Stack<int>;
|
||||
def IntStack = Stack(<int>);
|
||||
// The second creates another copy with "Type" set to "double"
|
||||
def DoubleStack = Stack<double>;
|
||||
def DoubleStack = Stack(<double>);
|
||||
|
||||
// If we had added "define IntStack2 = Stack<int>"
|
||||
// If we had added "define IntStack2 = Stack(<int>)"
|
||||
// no additional copy would have been made (since we already
|
||||
// have an parameterization of Stack<int>) so it would
|
||||
// have an parameterization of Stack(<int>)) so it would
|
||||
// be same as declaring IntStack2 an alias of IntStack
|
||||
|
||||
// Importing an external C function is straightforward
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::collections::enummap<Enum, ValueType>;
|
||||
module std::collections::enummap(<Enum, ValueType>);
|
||||
|
||||
struct EnumMap
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/**
|
||||
* @require Enum.kindof == TypeKind.ENUM : "Only enums maybe be used with an enumset"
|
||||
**/
|
||||
module std::collections::enumset<Enum>;
|
||||
module std::collections::enumset(<Enum>);
|
||||
|
||||
def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @private ;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::linkedlist<Type>;
|
||||
module std::collections::linkedlist(<Type>);
|
||||
|
||||
struct Node @private
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::list<Type>;
|
||||
module std::collections::list(<Type>);
|
||||
import std::math;
|
||||
|
||||
def ElementPredicate = fn bool(Type *type);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2023 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::collections::map<Key, Value>;
|
||||
module std::collections::map(<Key, Value>);
|
||||
import std::math;
|
||||
|
||||
const uint DEFAULT_INITIAL_CAPACITY = 16;
|
||||
|
||||
@@ -465,7 +465,7 @@ fn Object* Object.get_or_create_obj(&self, String key)
|
||||
return container;
|
||||
}
|
||||
|
||||
def ObjectInternalMap = HashMap<String, Object*> @private;
|
||||
def ObjectInternalList = List<Object*> @private;
|
||||
def ObjectInternalMapEntry = Entry<String, Object*> @private;
|
||||
def ObjectInternalMap = HashMap(<String, Object*>) @private;
|
||||
def ObjectInternalList = List(<Object*>) @private;
|
||||
def ObjectInternalMapEntry = Entry(<String, Object*>) @private;
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
module std::collections::priorityqueue<Type>;
|
||||
module std::collections::priorityqueue(<Type>);
|
||||
import std::collections::list;
|
||||
|
||||
def Heap = List<Type>;
|
||||
def Heap = List(<Type>);
|
||||
|
||||
struct PriorityQueue
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @checked Type{} < Type{} : "The type must be comparable"
|
||||
* @checked Type{} + (Type)1 : "The type must be possible to add to"
|
||||
**/
|
||||
module std::collections::range<Type>;
|
||||
module std::collections::range(<Type>);
|
||||
|
||||
struct Range
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
module std::core::mem::allocator;
|
||||
import std::collections::map;
|
||||
|
||||
def PtrMap = HashMap<uptr, usz>;
|
||||
def PtrMap = HashMap(<uptr, usz>);
|
||||
|
||||
// A simple tracking allocator.
|
||||
// It tracks allocations using a hash map but
|
||||
|
||||
@@ -6,7 +6,7 @@ const char PREFERRED_SEPARATOR_WIN32 = '\\';
|
||||
const char PREFERRED_SEPARATOR_POSIX = '/';
|
||||
const char PREFERRED_SEPARATOR = env::WIN32 ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX;
|
||||
|
||||
def PathList = List<Path>;
|
||||
def PathList = List(<Path>);
|
||||
|
||||
fault PathResult
|
||||
{
|
||||
|
||||
@@ -85,33 +85,33 @@ fault MatrixError
|
||||
MATRIX_INVERSE_DOESNT_EXIST,
|
||||
}
|
||||
|
||||
def Complexf = Complex<float>;
|
||||
def Complex = Complex<double>;
|
||||
def complexf_identity = complex::identity<float>;
|
||||
def complex_identity = complex::identity<double>;
|
||||
def Complexf = Complex(<float>);
|
||||
def Complex = Complex(<double>);
|
||||
def complexf_identity = complex::identity(<float>);
|
||||
def complex_identity = complex::identity(<double>);
|
||||
|
||||
def Quaternionf = Quaternion<float>;
|
||||
def Quaternion = Quaternion<double>;
|
||||
def quaternionf_identity = quaternion::identity<float>;
|
||||
def quaternion_identity = quaternion::identity<double>;
|
||||
def Quaternionf = Quaternion(<float>);
|
||||
def Quaternion = Quaternion(<double>);
|
||||
def quaternionf_identity = quaternion::identity(<float>);
|
||||
def quaternion_identity = quaternion::identity(<double>);
|
||||
|
||||
def Matrix2f = Matrix2x2<float>;
|
||||
def Matrix2 = Matrix2x2<double>;
|
||||
def Matrix3f = Matrix3x3<float>;
|
||||
def Matrix3 = Matrix3x3<double>;
|
||||
def Matrix4f = Matrix4x4<float>;
|
||||
def Matrix4 = Matrix4x4<double>;
|
||||
def matrix4_ortho = matrix::ortho<double>;
|
||||
def matrix4_perspective = matrix::perspective<double>;
|
||||
def matrix4f_ortho = matrix::ortho<float>;
|
||||
def matrix4f_perspective = matrix::perspective<float>;
|
||||
def Matrix2f = Matrix2x2(<float>);
|
||||
def Matrix2 = Matrix2x2(<double>);
|
||||
def Matrix3f = Matrix3x3(<float>);
|
||||
def Matrix3 = Matrix3x3(<double>);
|
||||
def Matrix4f = Matrix4x4(<float>);
|
||||
def Matrix4 = Matrix4x4(<double>);
|
||||
def matrix4_ortho = matrix::ortho(<double>);
|
||||
def matrix4_perspective = matrix::perspective(<double>);
|
||||
def matrix4f_ortho = matrix::ortho(<float>);
|
||||
def matrix4f_perspective = matrix::perspective(<float>);
|
||||
|
||||
def MATRIX2_IDENTITY = matrix::IDENTITY2<double>;
|
||||
def MATRIX2F_IDENTITY = matrix::IDENTITY2<float>;
|
||||
def MATRIX3_IDENTITY = matrix::IDENTITY3<double>;
|
||||
def MATRIX3F_IDENTITY = matrix::IDENTITY3<float>;
|
||||
def MATRIX4_IDENTITY = matrix::IDENTITY4<double>;
|
||||
def MATRIX4F_IDENTITY = matrix::IDENTITY4<float>;
|
||||
def MATRIX2_IDENTITY = matrix::IDENTITY2(<double>);
|
||||
def MATRIX2F_IDENTITY = matrix::IDENTITY2(<float>);
|
||||
def MATRIX3_IDENTITY = matrix::IDENTITY3(<double>);
|
||||
def MATRIX3F_IDENTITY = matrix::IDENTITY3(<float>);
|
||||
def MATRIX4_IDENTITY = matrix::IDENTITY4(<double>);
|
||||
def MATRIX4F_IDENTITY = matrix::IDENTITY4(<float>);
|
||||
|
||||
/**
|
||||
* @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::complex<Real>;
|
||||
module std::math::complex(<Real>);
|
||||
|
||||
union Complex
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::matrix<Real>;
|
||||
module std::math::matrix(<Real>);
|
||||
|
||||
struct Matrix2x2
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::math::quaternion<Real>;
|
||||
module std::math::quaternion(<Real>);
|
||||
import std::math::vector;
|
||||
union Quaternion
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::sort::quicksort<Type>;
|
||||
module std::sort::quicksort(<Type>);
|
||||
import std::sort;
|
||||
|
||||
def ElementType = $typeof(Type{}[0]);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
## 0.5.0 Change List
|
||||
|
||||
### Changes / improvements
|
||||
- New generic syntax.
|
||||
- Ad hoc generics are now allowed.
|
||||
- Allow inferred type on method first argument.
|
||||
- Fix to void expression blocks
|
||||
- Temporary objects may now invoke methods using ref parameters.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::container::map <Key, Type>;
|
||||
module std::container::map(<Key, Type>);
|
||||
import std::core::builtin;
|
||||
import std::io;
|
||||
fault MapResult
|
||||
|
||||
@@ -751,7 +751,7 @@ fn u32 addKind(u32 value, NodeKind k) @(inline) {
|
||||
}
|
||||
|
||||
fn NodeKind getKind(u32 value) @(inline) {
|
||||
return cast<NodeKind>(value >> NodeKindOffset);
|
||||
return cast(<NodeKind>)(value >> NodeKindOffset);
|
||||
}
|
||||
|
||||
fn u32 getValue(u32 value) @(inline) {
|
||||
|
||||
@@ -216,6 +216,8 @@ b64\`{B64}+\` { count(); return(BYTES); }
|
||||
"=>" { count(); return(IMPLIES); }
|
||||
"[<" { count(); return(LVEC); }
|
||||
">]" { count(); return(RVEC); }
|
||||
"(<" { count(); return(LGENPAR); }
|
||||
">)" { count(); return(RGENPAR); }
|
||||
"$$" { count(); return(BUILTIN); }
|
||||
";" { count(); return(';'); }
|
||||
("{") { count(); return('{'); }
|
||||
|
||||
@@ -15,6 +15,7 @@ void yyerror(char *s);
|
||||
%token STRING_LITERAL INTEGER
|
||||
%token INC_OP DEC_OP SHL_OP SHR_OP LE_OP GE_OP EQ_OP NE_OP
|
||||
%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
|
||||
%token LGENPAR RGENPAR
|
||||
%token SUB_ASSIGN SHL_ASSIGN SHR_ASSIGN AND_ASSIGN
|
||||
%token XOR_ASSIGN OR_ASSIGN VAR NUL ELVIS NEXTCASE ANYFAULT
|
||||
%token MODULE IMPORT DEF EXTERN
|
||||
@@ -187,6 +188,7 @@ call_trailing
|
||||
| call_invocation
|
||||
| call_invocation compound_statement
|
||||
| '.' access_ident
|
||||
| generic_expr
|
||||
| INC_OP
|
||||
| DEC_OP
|
||||
| '!'
|
||||
@@ -1104,9 +1106,9 @@ opt_distinct_inline
|
||||
;
|
||||
|
||||
generic_parameters
|
||||
: additive_expr
|
||||
: expr
|
||||
| type
|
||||
| generic_parameters ',' bit_expr
|
||||
| generic_parameters ',' expr
|
||||
| generic_parameters ',' type
|
||||
;
|
||||
|
||||
@@ -1154,8 +1156,12 @@ define_attribute
|
||||
| AT_TYPE_IDENT opt_attributes '=' '{' opt_attributes '}'
|
||||
;
|
||||
|
||||
generic_expr
|
||||
: LGENPAR generic_parameters RGENPAR
|
||||
;
|
||||
|
||||
opt_generic_parameters
|
||||
: '<' generic_parameters '>'
|
||||
: generic_expr
|
||||
| empty
|
||||
;
|
||||
|
||||
@@ -1194,7 +1200,7 @@ module_params
|
||||
|
||||
module
|
||||
: MODULE path_ident opt_attributes ';'
|
||||
| MODULE path_ident '<' module_params '>' opt_attributes ';'
|
||||
| MODULE path_ident LGENPAR module_params RGENPAR opt_attributes ';'
|
||||
;
|
||||
|
||||
import_paths
|
||||
|
||||
@@ -377,6 +377,11 @@ struct TypeInfo_
|
||||
Expr *len;
|
||||
} array;
|
||||
TypeInfo *pointer;
|
||||
struct
|
||||
{
|
||||
TypeInfo *base;
|
||||
Expr **params;
|
||||
} generic;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -840,6 +845,13 @@ typedef struct
|
||||
BuiltinAccessKind kind : 8;
|
||||
ExprId inner;
|
||||
} ExprBuiltinAccess;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ExprId parent;
|
||||
Expr **parmeters;
|
||||
} ExprGenericIdent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *parent;
|
||||
@@ -1135,6 +1147,7 @@ struct Expr_
|
||||
ExprCall call_expr; // 32
|
||||
Expr *inner_expr; // 8
|
||||
ExprBuiltinAccess builtin_access_expr;
|
||||
ExprGenericIdent generic_ident_expr;
|
||||
ExprCatchUnwrap catch_unwrap_expr; // 24
|
||||
ExprSubscript subscript_expr; // 12
|
||||
ExprSubscriptAssign subscript_assign_expr;
|
||||
@@ -1482,6 +1495,7 @@ typedef struct Module_
|
||||
Module **sub_modules;
|
||||
Decl **tests;
|
||||
Decl **lambdas_to_evaluate;
|
||||
const char *generic_suffix;
|
||||
} Module;
|
||||
|
||||
|
||||
@@ -2548,6 +2562,11 @@ INLINE bool type_is_integer_unsigned(Type *type)
|
||||
|
||||
INLINE bool type_info_poison(TypeInfo *type)
|
||||
{
|
||||
if (global_context.suppress_errors)
|
||||
{
|
||||
type->resolve_status = RESOLVE_NOT_DONE;
|
||||
return false;
|
||||
}
|
||||
type->type = poisoned_type;
|
||||
type->resolve_status = RESOLVE_DONE;
|
||||
return false;
|
||||
|
||||
@@ -296,6 +296,10 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
{
|
||||
case EXPR_ANYSWITCH:
|
||||
UNREACHABLE
|
||||
case EXPR_GENERIC_IDENT:
|
||||
MACRO_COPY_EXPRID(expr->generic_ident_expr.parent);
|
||||
MACRO_COPY_EXPR_LIST(expr->generic_ident_expr.parmeters);
|
||||
return expr;
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
MACRO_COPY_EXPR_LIST(expr->body_expansion_expr.values);
|
||||
MACRO_COPY_DECL_LIST(expr->body_expansion_expr.declarations);
|
||||
@@ -797,6 +801,10 @@ TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source)
|
||||
case TYPE_INFO_CT_IDENTIFIER:
|
||||
case TYPE_INFO_IDENTIFIER:
|
||||
return copy;
|
||||
case TYPE_INFO_GENERIC:
|
||||
copy->generic.base = copy_type_info(c, copy->generic.base);
|
||||
copy->generic.params = copy_expr_list(c, copy->generic.params);
|
||||
return copy;
|
||||
case TYPE_INFO_TYPEFROM:
|
||||
case TYPE_INFO_EVALTYPE:
|
||||
case TYPE_INFO_TYPEOF:
|
||||
|
||||
@@ -228,6 +228,7 @@ typedef enum
|
||||
EXPR_EXPR_BLOCK,
|
||||
EXPR_OPTIONAL,
|
||||
EXPR_FORCE_UNWRAP,
|
||||
EXPR_GENERIC_IDENT,
|
||||
EXPR_GROUP,
|
||||
EXPR_HASH_IDENT,
|
||||
EXPR_IDENTIFIER,
|
||||
@@ -375,6 +376,7 @@ typedef enum
|
||||
TYPE_INFO_INFERRED_VECTOR,
|
||||
TYPE_INFO_SUBARRAY,
|
||||
TYPE_INFO_POINTER,
|
||||
TYPE_INFO_GENERIC,
|
||||
} TypeInfoKind;
|
||||
|
||||
typedef enum
|
||||
@@ -427,6 +429,7 @@ typedef enum
|
||||
TOKEN_IMPLIES, // =>
|
||||
TOKEN_LESS_EQ, // <=
|
||||
TOKEN_LBRAPIPE, // {|
|
||||
TOKEN_LGENPAR, // (<
|
||||
TOKEN_LVEC, // [<
|
||||
TOKEN_MINUS_ASSIGN, // -=
|
||||
TOKEN_MINUSMINUS, // --
|
||||
@@ -437,6 +440,7 @@ typedef enum
|
||||
TOKEN_PLUS_ASSIGN, // +=
|
||||
TOKEN_PLUSPLUS, // ++
|
||||
TOKEN_RBRAPIPE, // |}
|
||||
TOKEN_RGENPAR, // >)
|
||||
TOKEN_RVEC, // >]
|
||||
TOKEN_QUESTQUEST, // ??
|
||||
TOKEN_SCOPE, // ::
|
||||
@@ -812,7 +816,8 @@ typedef enum
|
||||
ANALYSIS_CT_ECHO,
|
||||
ANALYSIS_CT_ASSERT,
|
||||
ANALYSIS_FUNCTIONS,
|
||||
ANALYSIS_LAST = ANALYSIS_FUNCTIONS
|
||||
ANALYSIS_FINALIZE,
|
||||
ANALYSIS_LAST = ANALYSIS_FINALIZE
|
||||
} AnalysisStage;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -133,6 +133,7 @@ bool expr_may_addr(Expr *expr)
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_SWIZZLE:
|
||||
case EXPR_LAMBDA:
|
||||
case EXPR_GENERIC_IDENT:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -325,6 +326,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_ASM:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
case EXPR_GENERIC_IDENT:
|
||||
UNREACHABLE
|
||||
case EXPR_NOP:
|
||||
return true;
|
||||
@@ -689,6 +691,8 @@ bool expr_is_pure(Expr *expr)
|
||||
return expr_is_pure(expr->unary_expr.expr);
|
||||
}
|
||||
UNREACHABLE
|
||||
case EXPR_GENERIC_IDENT:
|
||||
return exprid_is_pure(expr->generic_ident_expr.parent);
|
||||
case EXPR_BITACCESS:
|
||||
case EXPR_ACCESS:
|
||||
// All access is pure if the parent is pure.
|
||||
|
||||
@@ -1312,7 +1312,7 @@ static bool lexer_scan_token_inner(Lexer *lexer)
|
||||
case '}':
|
||||
return return_token(lexer, TOKEN_RBRACE, "}");
|
||||
case '(':
|
||||
return return_token(lexer, TOKEN_LPAREN, "(");
|
||||
return match(lexer, '<') ? return_token(lexer, TOKEN_LGENPAR, "(<") : return_token(lexer, TOKEN_LPAREN, "(");
|
||||
case ')':
|
||||
return return_token(lexer, TOKEN_RPAREN, ")");
|
||||
case '[':
|
||||
@@ -1368,6 +1368,7 @@ static bool lexer_scan_token_inner(Lexer *lexer)
|
||||
if (match(lexer, '=')) return return_token(lexer, TOKEN_SHR_ASSIGN, ">>=");
|
||||
return return_token(lexer, TOKEN_SHR, ">>");
|
||||
}
|
||||
if (match(lexer, ')')) return return_token(lexer, TOKEN_RGENPAR, ">)");
|
||||
if (match(lexer, ']')) return return_token(lexer, TOKEN_RVEC, ">]");
|
||||
return match(lexer, '=') ? return_token(lexer, TOKEN_GREATER_EQ, ">=") : return_token(lexer,
|
||||
TOKEN_GREATER,
|
||||
|
||||
@@ -6543,6 +6543,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
case EXPR_COND:
|
||||
case EXPR_ASM:
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_GENERIC_IDENT:
|
||||
UNREACHABLE
|
||||
case EXPR_LAMBDA:
|
||||
llvm_emit_lambda(c, value, expr);
|
||||
|
||||
@@ -525,7 +525,7 @@ Expr *parse_expression_list(ParseContext *c, bool allow_decl)
|
||||
while (1)
|
||||
{
|
||||
Decl *decl;
|
||||
ASSIGN_EXPR_OR_RET(Expr * expr, parse_decl_or_expr(c, &decl), poisoned_expr);
|
||||
ASSIGN_EXPR_OR_RET(Expr *expr, parse_decl_or_expr(c, &decl), poisoned_expr);
|
||||
if (!expr)
|
||||
{
|
||||
if (!allow_decl)
|
||||
@@ -969,6 +969,28 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left)
|
||||
return subs_expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_expr ::= '(<' generic_parameters '>)'
|
||||
*/
|
||||
static Expr *parse_generic_expr(ParseContext *c, Expr *left)
|
||||
{
|
||||
assert(left && expr_ok(left));
|
||||
advance_and_verify(c, TOKEN_LGENPAR);
|
||||
|
||||
Expr *subs_expr = expr_new_expr(EXPR_GENERIC_IDENT, left);
|
||||
subs_expr->generic_ident_expr.parent = exprid(left);
|
||||
Expr **exprs = NULL;
|
||||
do
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(Expr *param, parse_expr(c), poisoned_expr);
|
||||
vec_add(exprs, param);
|
||||
} while (try_consume(c, TOKEN_COMMA));
|
||||
CONSUME_OR_RET(TOKEN_RGENPAR, poisoned_expr);
|
||||
subs_expr->generic_ident_expr.parmeters = exprs;
|
||||
RANGE_EXTEND_PREV(subs_expr);
|
||||
return subs_expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* access_expr ::= '.' primary_expr
|
||||
*/
|
||||
@@ -1809,6 +1831,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_LBRAPIPE] = { parse_expr_block, NULL, PREC_NONE },
|
||||
[TOKEN_BANGBANG] = { NULL, parse_force_unwrap_expr, PREC_CALL },
|
||||
[TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL },
|
||||
[TOKEN_LGENPAR] = { NULL, parse_generic_expr, PREC_CALL },
|
||||
[TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
|
||||
[TOKEN_PLUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
|
||||
[TOKEN_DIV] = { NULL, parse_binary, PREC_MULTIPLICATIVE },
|
||||
|
||||
@@ -144,9 +144,13 @@ static inline bool parse_optional_module_params(ParseContext *c, const char ***t
|
||||
|
||||
*tokens_ref = NULL;
|
||||
|
||||
if (!try_consume(c, TOKEN_LESS)) return true;
|
||||
SourceSpan span = c->span;
|
||||
bool is_old_style = try_consume(c, TOKEN_LESS);
|
||||
if (!is_old_style && !try_consume(c, TOKEN_LGENPAR)) return true;
|
||||
|
||||
if (try_consume(c, TOKEN_GREATER)) RETURN_SEMA_ERROR_HERE("Generic parameter list cannot be empty.");
|
||||
// TODO remove after deprecation time
|
||||
TokenType end_token = is_old_style ? TOKEN_GREATER : TOKEN_RGENPAR;
|
||||
if (try_consume(c, end_token)) RETURN_SEMA_ERROR_HERE("Generic parameter list cannot be empty.");
|
||||
|
||||
// No params
|
||||
while (1)
|
||||
@@ -170,13 +174,18 @@ static inline bool parse_optional_module_params(ParseContext *c, const char ***t
|
||||
advance(c);
|
||||
if (!try_consume(c, TOKEN_COMMA))
|
||||
{
|
||||
return consume(c, TOKEN_GREATER, "Expected '>'.");
|
||||
if (!consume(c, end_token, "Expected '>)'.")) return false;
|
||||
if (is_old_style)
|
||||
{
|
||||
span = extend_span_with_token(span, c->prev_span);
|
||||
sema_warning_at(span, "Generics with <...> syntax is deprecated, use (<...>) instead.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* module ::= MODULE module_path ('<' module_params '>')? (@public|@private|@local|@test|@export|@extern) EOS
|
||||
* module ::= MODULE module_path ('(<' module_params '>)')? (@public|@private|@local|@test|@export|@extern) EOS
|
||||
*/
|
||||
bool parse_module(ParseContext *c, AstId contracts)
|
||||
{
|
||||
@@ -487,6 +496,24 @@ static inline TypeInfo *parse_base_type(ParseContext *c)
|
||||
return type_info;
|
||||
}
|
||||
|
||||
static inline TypeInfo *parse_generic_type(ParseContext *c, TypeInfo *type)
|
||||
{
|
||||
assert(type_info_ok(type));
|
||||
|
||||
advance_and_verify(c, TOKEN_LGENPAR);
|
||||
Expr **exprs = NULL;
|
||||
do
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(Expr *param, parse_expr(c), poisoned_type_info);
|
||||
vec_add(exprs, param);
|
||||
} while (try_consume(c, TOKEN_COMMA));
|
||||
CONSUME_OR_RET(TOKEN_RGENPAR, poisoned_type_info);
|
||||
TypeInfo *generic_type = type_info_new(TYPE_INFO_GENERIC, type->span);
|
||||
generic_type->generic.params = exprs;
|
||||
generic_type->generic.base = type;
|
||||
return generic_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* array_type_index
|
||||
* : '[' constant_expression ']'
|
||||
@@ -597,6 +624,9 @@ TypeInfo *parse_type_with_base(ParseContext *c, TypeInfo *type_info)
|
||||
case TOKEN_LBRACKET:
|
||||
type_info = parse_array_type_index(c, type_info);
|
||||
break;
|
||||
case TOKEN_LGENPAR:
|
||||
type_info = parse_generic_type(c, type_info);
|
||||
break;
|
||||
case TOKEN_STAR:
|
||||
advance(c);
|
||||
{
|
||||
@@ -1629,21 +1659,23 @@ static bool parse_macro_params(ParseContext *c, Decl *macro)
|
||||
}
|
||||
|
||||
/**
|
||||
* define_parameters ::= expr (',' expr)* '>'
|
||||
* define_parameters ::= expr (<',' expr)* '>)'
|
||||
*
|
||||
* @return NULL if parsing failed, otherwise a list of Type*
|
||||
*/
|
||||
static inline Expr **parse_generic_parameters(ParseContext *c)
|
||||
static inline Expr **parse_generic_parameters(ParseContext *c, bool old_style)
|
||||
{
|
||||
Expr **params = NULL;
|
||||
while (!try_consume(c, TOKEN_GREATER))
|
||||
// TODO remove deprecation
|
||||
TokenType end_token = old_style ? TOKEN_GREATER : TOKEN_RGENPAR;
|
||||
while (!try_consume(c, end_token))
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg, parse_generic_parameter(c), NULL);
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg, old_style ? parse_generic_parameter(c) : parse_expr(c), NULL);
|
||||
vec_add(params, arg);
|
||||
TokenType tok = c->tok;
|
||||
if (tok != TOKEN_RPAREN && tok != TOKEN_GREATER)
|
||||
if (tok != end_token)
|
||||
{
|
||||
TRY_CONSUME_OR_RET(TOKEN_COMMA, "Expected ',' after argument.", NULL);
|
||||
TRY_CONSUME_OR_RET(TOKEN_COMMA, "Expected ',' after the argument.", NULL);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
@@ -1723,10 +1755,12 @@ static inline Decl *parse_def_type(ParseContext *c)
|
||||
// 2. Now parse the type which we know is here.
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_type(c), poisoned_decl);
|
||||
|
||||
// 3. Do we have '<' if so it's a parameterized type e.g. foo::bar::Type<int, double>.
|
||||
if (try_consume(c, TOKEN_LESS))
|
||||
bool old_style_encountered = try_consume(c, TOKEN_LESS);
|
||||
|
||||
// 3. Do we have '(<' if so it's a parameterized type e.g. foo::bar::Type(<int, double>).
|
||||
if (old_style_encountered || try_consume(c, TOKEN_LGENPAR))
|
||||
{
|
||||
Expr **params = parse_generic_parameters(c);
|
||||
Expr **params = parse_generic_parameters(c, old_style_encountered);
|
||||
if (!params) return poisoned_decl;
|
||||
decl->decl_kind = DECL_DEFINE;
|
||||
decl_add_type(decl, TYPE_TYPEDEF);
|
||||
@@ -1736,6 +1770,10 @@ static inline Decl *parse_def_type(ParseContext *c)
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
if (old_style_encountered)
|
||||
{
|
||||
sema_warning_at(decl->span, "Use of <...> for generics is deprecated, please use (<...>) instead.");
|
||||
}
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
@@ -1849,16 +1887,22 @@ static inline Decl *parse_def_ident(ParseContext *c)
|
||||
decl->define_decl.span = c->span;
|
||||
advance(c);
|
||||
|
||||
if (try_consume(c, TOKEN_LESS))
|
||||
bool old_style_encountered = try_consume(c, TOKEN_LESS);
|
||||
|
||||
if (old_style_encountered || try_consume(c, TOKEN_LGENPAR) )
|
||||
{
|
||||
decl->define_decl.define_kind = DEFINE_IDENT_GENERIC;
|
||||
Expr **params = parse_generic_parameters(c);
|
||||
Expr **params = parse_generic_parameters(c, old_style_encountered);
|
||||
if (!params) return poisoned_decl;
|
||||
decl->define_decl.generic_params = params;
|
||||
}
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
if (old_style_encountered)
|
||||
{
|
||||
sema_warning_at(decl->span, "Use of <...> for generics is deprecated, please use (<...>) instead.");
|
||||
}
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -1316,6 +1316,7 @@ Ast *parse_stmt(ParseContext *c)
|
||||
case TOKEN_INLINE:
|
||||
case TOKEN_DISTINCT:
|
||||
case TOKEN_CT_INCLUDE:
|
||||
case TOKEN_LGENPAR:
|
||||
SEMA_ERROR_HERE("Unexpected '%s' found when expecting a statement.",
|
||||
token_type_to_string(c->tok));
|
||||
advance(c);
|
||||
@@ -1323,6 +1324,7 @@ Ast *parse_stmt(ParseContext *c)
|
||||
case TOKEN_RPAREN:
|
||||
case TOKEN_RBRACE:
|
||||
case TOKEN_RBRACKET:
|
||||
case TOKEN_RGENPAR:
|
||||
SEMA_ERROR_HERE("Mismatched '%s' found.", token_type_to_string(c->tok));
|
||||
advance(c);
|
||||
return poisoned_ast;
|
||||
|
||||
@@ -79,11 +79,12 @@ INLINE void add_decl_to_list(Decl ***list, Decl *decl)
|
||||
}
|
||||
|
||||
bool parse_module(ParseContext *c, AstId contracts);
|
||||
Expr *parse_generic_parameter(ParseContext *c);
|
||||
|
||||
bool try_consume(ParseContext *c, TokenType type);
|
||||
bool consume(ParseContext *c, TokenType type, const char *message, ...);
|
||||
bool consume_const_name(ParseContext *c, const char* type);
|
||||
Expr *parse_precedence_with_left_side(ParseContext *c, Expr *left_side, Precedence precedence);
|
||||
Expr *parse_generic_parameter(ParseContext *c);
|
||||
|
||||
INLINE const char *symstr(ParseContext *c)
|
||||
{
|
||||
|
||||
@@ -139,7 +139,7 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
|
||||
{
|
||||
RETURN_SEMA_ERROR(decl, "Circular dependency resolving member.");
|
||||
}
|
||||
assert(!decl->unit || decl->unit->module->is_generic);
|
||||
assert(!decl->unit || decl->unit->module->is_generic || decl->unit == parent->unit);
|
||||
decl->unit = parent->unit;
|
||||
|
||||
AttributeDomain domain = ATTR_MEMBER;
|
||||
@@ -319,6 +319,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl *
|
||||
bool is_packed = decl->is_packed;
|
||||
unsigned member_count = vec_size(members);
|
||||
Decl **struct_members = decl->strukt.members;
|
||||
|
||||
for (unsigned i = 0; i < member_count; i++)
|
||||
{
|
||||
AGAIN:;
|
||||
@@ -331,12 +332,8 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl *
|
||||
bool erase_decl = false;
|
||||
if (!sema_analyse_struct_member(context, decl, member, &erase_decl))
|
||||
{
|
||||
if (decl_ok(decl))
|
||||
{
|
||||
decl_poison(decl);
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
decl_poison(member);
|
||||
return decl_poison(decl);
|
||||
}
|
||||
if (erase_decl)
|
||||
{
|
||||
@@ -2988,20 +2985,8 @@ static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit)
|
||||
static Module *module_instantiate_generic(SemaContext *context, Module *module, Path *path, Expr **params,
|
||||
SourceSpan from)
|
||||
{
|
||||
Module *new_module = compiler_find_or_create_module(path, NULL);
|
||||
new_module->is_generic = false;
|
||||
CompilationUnit **units = module->units;
|
||||
VECEACH(units, i)
|
||||
{
|
||||
vec_add(new_module->units, unit_copy(new_module, units[i]));
|
||||
}
|
||||
CompilationUnit *first_context = new_module->units[0];
|
||||
if (module->contracts)
|
||||
{
|
||||
copy_begin();
|
||||
new_module->contracts = astid(copy_ast_macro(astptr(module->contracts)));
|
||||
copy_end();
|
||||
}
|
||||
unsigned decls = 0;
|
||||
Decl* params_decls[MAX_PARAMS];
|
||||
VECEACH(module->parameters, i)
|
||||
{
|
||||
const char *param_name = module->parameters[i];
|
||||
@@ -3018,7 +3003,7 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module,
|
||||
decl->var.init_expr = param;
|
||||
decl->type = param->type;
|
||||
decl->resolve_status = RESOLVE_NOT_DONE;
|
||||
vec_add(first_context->global_decls, decl);
|
||||
params_decls[decls++] = decl;
|
||||
continue;
|
||||
}
|
||||
if (is_value)
|
||||
@@ -3033,12 +3018,34 @@ static Module *module_instantiate_generic(SemaContext *context, Module *module,
|
||||
decl->typedef_decl.type_info = type_info;
|
||||
decl->type->name = decl->name;
|
||||
decl->type->canonical = type_info->type->canonical;
|
||||
vec_add(first_context->global_decls, decl);
|
||||
params_decls[decls++] = decl;
|
||||
}
|
||||
|
||||
|
||||
Module *new_module = compiler_find_or_create_module(path, NULL);
|
||||
new_module->is_generic = false;
|
||||
CompilationUnit **units = module->units;
|
||||
VECEACH(units, i)
|
||||
{
|
||||
vec_add(new_module->units, unit_copy(new_module, units[i]));
|
||||
}
|
||||
CompilationUnit *first_context = new_module->units[0];
|
||||
for (unsigned i = 0; i < decls; i++)
|
||||
{
|
||||
vec_add(first_context->global_decls, params_decls[i]);
|
||||
}
|
||||
|
||||
if (module->contracts)
|
||||
{
|
||||
copy_begin();
|
||||
new_module->contracts = astid(copy_ast_macro(astptr(module->contracts)));
|
||||
copy_end();
|
||||
}
|
||||
|
||||
return new_module;
|
||||
}
|
||||
|
||||
static bool sema_append_generate_parameterized_name(SemaContext *c, Module *module, Decl *decl, bool mangled)
|
||||
static bool sema_append_generate_parameterized_name(SemaContext *c, Module *module, Expr **params, bool mangled)
|
||||
{
|
||||
if (mangled)
|
||||
{
|
||||
@@ -3047,9 +3054,9 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
|
||||
}
|
||||
else
|
||||
{
|
||||
scratch_buffer_append_char('<');
|
||||
scratch_buffer_append("(<");
|
||||
}
|
||||
FOREACH_BEGIN_IDX(i, Expr *param, decl->define_decl.generic_params)
|
||||
FOREACH_BEGIN_IDX(i, Expr *param, params)
|
||||
if (i != 0)
|
||||
{
|
||||
scratch_buffer_append(mangled ? "$" : ", ");
|
||||
@@ -3057,23 +3064,11 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
|
||||
if (param->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
TypeInfo *type_info = param->type_expr;
|
||||
if (!sema_resolve_type_info(c, type_info)) return decl_poison(decl);
|
||||
if (!sema_resolve_type_info(c, type_info)) return false;
|
||||
Type *type = type_info->type->canonical;
|
||||
if (type->type_kind == TYPE_OPTIONAL)
|
||||
{
|
||||
SEMA_ERROR(type_info, "Expected a non-optional type.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (type == type_void)
|
||||
{
|
||||
SEMA_ERROR(type_info, "A 'void' type cannot be used as a parameter type.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (type_is_invalid_storage_type(type))
|
||||
{
|
||||
SEMA_ERROR(type_info, "Expected a runtime type.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (type->type_kind == TYPE_OPTIONAL) RETURN_SEMA_ERROR(type_info, "Expected a non-optional type.");
|
||||
if (type == type_void) RETURN_SEMA_ERROR(type_info, "A 'void' type cannot be used as a parameter type.");
|
||||
if (type_is_invalid_storage_type(type)) RETURN_SEMA_ERROR(type_info, "Expected a runtime type.");
|
||||
if (mangled)
|
||||
{
|
||||
type_mangle_introspect_name_to_buffer(type);
|
||||
@@ -3085,7 +3080,7 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_ct_expr(c, param)) return decl_poison(decl);
|
||||
if (!sema_analyse_ct_expr(c, param)) return false;
|
||||
Type *type = param->type->canonical;
|
||||
if (!type_is_integer_or_bool_kind(type))
|
||||
{
|
||||
@@ -3110,7 +3105,6 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
|
||||
if (type->type_kind == TYPE_I128 || type->type_kind == TYPE_U128)
|
||||
{
|
||||
char *str = int_to_str(param->const_expr.ixx, 10);
|
||||
|
||||
scratch_buffer_append(str);
|
||||
}
|
||||
else
|
||||
@@ -3121,7 +3115,7 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
|
||||
}
|
||||
else
|
||||
{
|
||||
scratch_buffer_append_unsigned_int(param->const_expr.ixx.i.high);
|
||||
scratch_buffer_append_unsigned_int(param->const_expr.ixx.i.low);
|
||||
}
|
||||
}
|
||||
if (mangled)
|
||||
@@ -3132,7 +3126,7 @@ static bool sema_append_generate_parameterized_name(SemaContext *c, Module *modu
|
||||
}
|
||||
}
|
||||
FOREACH_END();
|
||||
scratch_buffer_append_char(mangled ? '$' : '>');
|
||||
scratch_buffer_append(mangled ? "$" : ">)");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3176,6 +3170,8 @@ static bool sema_analyse_generic_module_contracts(SemaContext *c, Module *module
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
{
|
||||
Path *decl_path;
|
||||
@@ -3204,19 +3200,40 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
Expr **params = decl->define_decl.generic_params;
|
||||
Decl *symbol = sema_analyse_parameterized_identifier(c, decl_path, name, span, params);
|
||||
if (!decl_ok(symbol)) return decl_poison(decl);
|
||||
switch (decl->define_decl.define_kind)
|
||||
{
|
||||
case DEFINE_IDENT_GENERIC:
|
||||
decl->define_decl.alias = symbol;
|
||||
decl->type = symbol->type;
|
||||
return true;
|
||||
case DEFINE_TYPE_GENERIC:
|
||||
{
|
||||
Type *type = type_new(TYPE_TYPEDEF, decl->name);
|
||||
decl->type = type;
|
||||
type->decl = symbol;
|
||||
decl->decl_kind = DECL_TYPEDEF;
|
||||
type->canonical = symbol->type->canonical;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span, Expr **params)
|
||||
{
|
||||
NameResolve name_resolve = {
|
||||
.path = decl_path,
|
||||
.span = span,
|
||||
.symbol = name
|
||||
};
|
||||
Decl *alias = unit_resolve_parameterized_symbol(c->unit, &name_resolve);
|
||||
if (!decl_ok(alias))
|
||||
{
|
||||
return decl_poison(decl);
|
||||
}
|
||||
if (!decl_ok(alias)) return poisoned_decl;
|
||||
|
||||
Module *module = alias->unit->module;
|
||||
Expr **params = decl->define_decl.generic_params;
|
||||
unsigned parameter_count = vec_size(module->parameters);
|
||||
assert(parameter_count > 0);
|
||||
if (parameter_count != vec_size(params))
|
||||
@@ -3225,11 +3242,11 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
sema_error_at(extend_span_with_token(params[0]->span, vectail(params)->span),
|
||||
"The generic module expected %d arguments, but you supplied %d, did you make a mistake?",
|
||||
parameter_count,
|
||||
vec_size(decl->define_decl.generic_params));
|
||||
return decl_poison(decl);
|
||||
vec_size(params));
|
||||
return poisoned_decl;
|
||||
}
|
||||
scratch_buffer_clear();
|
||||
if (!sema_append_generate_parameterized_name(c, module, decl, true)) return decl_poison(decl);
|
||||
if (!sema_append_generate_parameterized_name(c, module, params, true)) return poisoned_decl;
|
||||
TokenType ident_type = TOKEN_IDENT;
|
||||
const char *path_string = scratch_buffer_interned();
|
||||
Module *instantiated_module = global_context_find_module(path_string);
|
||||
@@ -3242,50 +3259,31 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
path->module = path_string;
|
||||
path->span = module->name->span;
|
||||
path->len = scratch_buffer.len;
|
||||
instantiated_module = module_instantiate_generic(c, module, path,
|
||||
decl->define_decl.generic_params, decl->span);
|
||||
if (!instantiated_module) return decl_poison(decl);
|
||||
instantiated_module = module_instantiate_generic(c, module, path, params, span);
|
||||
scratch_buffer_clear();
|
||||
if (!sema_append_generate_parameterized_name(c, module, params, false)) return poisoned_decl;
|
||||
if (!instantiated_module) return poisoned_decl;
|
||||
instantiated_module->generic_suffix = scratch_buffer_copy();
|
||||
sema_analyze_stage(instantiated_module, c->unit->module->stage - 1);
|
||||
}
|
||||
if (global_context.errors_found) return decl_poison(decl);
|
||||
if (global_context.errors_found) return poisoned_decl;
|
||||
Decl *symbol = module_find_symbol(instantiated_module, name);
|
||||
if (!symbol)
|
||||
{
|
||||
SEMA_ERROR(decl, "The generic module '%s' does not have '%s' for this parameterization.", module->name->module, name);
|
||||
return decl_poison(decl);
|
||||
sema_error_at(span, "The generic module '%s' does not have '%s' for this parameterization.", module->name->module, name);
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (was_initiated && instantiated_module->contracts)
|
||||
{
|
||||
SourceSpan error_span = extend_span_with_token(params[0]->span, params[parameter_count - 1]->span);
|
||||
if (!sema_analyse_generic_module_contracts(c, instantiated_module, error_span))
|
||||
{
|
||||
return decl_poison(decl);
|
||||
return poisoned_decl;
|
||||
}
|
||||
}
|
||||
if (!sema_analyse_decl(c, symbol)) return false;
|
||||
if (!sema_analyse_decl(c, symbol)) return poisoned_decl;
|
||||
unit_register_external_symbol(c->compilation_unit, symbol);
|
||||
switch (decl->define_decl.define_kind)
|
||||
{
|
||||
case DEFINE_IDENT_GENERIC:
|
||||
decl->define_decl.alias = symbol;
|
||||
decl->type = symbol->type;
|
||||
return true;
|
||||
case DEFINE_TYPE_GENERIC:
|
||||
{
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(symbol->name);
|
||||
sema_append_generate_parameterized_name(c, module, decl, false);
|
||||
symbol->type->name = scratch_buffer_interned();
|
||||
Type *type = type_new(TYPE_TYPEDEF, decl->name);
|
||||
decl->type = type;
|
||||
type->decl = symbol;
|
||||
decl->decl_kind = DECL_TYPEDEF;
|
||||
type->canonical = symbol->type->canonical;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl)
|
||||
|
||||
@@ -507,6 +507,7 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr)
|
||||
case EXPR_ANYSWITCH:
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_TEST_HOOK:
|
||||
case EXPR_GENERIC_IDENT:
|
||||
goto ERR;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -616,6 +617,7 @@ static bool expr_may_ref(Expr *expr)
|
||||
case EXPR_ANYSWITCH:
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_TEST_HOOK:
|
||||
case EXPR_GENERIC_IDENT:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -6764,6 +6766,8 @@ RETRY:
|
||||
{
|
||||
case TYPE_INFO_POISON:
|
||||
return poisoned_type;
|
||||
case TYPE_INFO_GENERIC:
|
||||
TODO
|
||||
case TYPE_INFO_VECTOR:
|
||||
{
|
||||
ArraySize size;
|
||||
@@ -6968,6 +6972,23 @@ static inline Decl *sema_find_cached_lambda(SemaContext *context, Type *func_typ
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_generic_ident(SemaContext *context, Expr *expr)
|
||||
{
|
||||
Expr *parent = exprptr(expr->generic_ident_expr.parent);
|
||||
if (parent->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(parent, "Expected an identifier to parameterize.");
|
||||
return false;
|
||||
}
|
||||
Decl *symbol = sema_analyse_parameterized_identifier(context, parent->identifier_expr.path, parent->identifier_expr.ident, parent->span, expr->generic_ident_expr.parmeters);
|
||||
if (!decl_ok(symbol)) return false;
|
||||
expr->expr_kind = EXPR_IDENTIFIER;
|
||||
expr->identifier_expr.decl = symbol;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
expr->type = symbol->type;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_lambda(SemaContext *context, Type *func_type, Expr *expr)
|
||||
{
|
||||
Decl *decl = expr->lambda_expr;
|
||||
@@ -7447,6 +7468,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
case EXPR_VASPLAT:
|
||||
SEMA_ERROR(expr, "'$vasplat' can only be used inside of macros.");
|
||||
return false;
|
||||
case EXPR_GENERIC_IDENT:
|
||||
return sema_expr_analyse_generic_ident(context, expr);
|
||||
case EXPR_LAMBDA:
|
||||
return sema_expr_analyse_lambda(context, NULL, expr);
|
||||
case EXPR_CT_CHECKS:
|
||||
|
||||
@@ -87,6 +87,7 @@ Type *cast_numeric_arithmetic_promotion(Type *type);
|
||||
void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type);
|
||||
bool sema_decl_if_cond(SemaContext *context, Decl *decl);
|
||||
bool sema_flattened_expr_is_const(SemaContext *context, Expr *expr);
|
||||
Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span, Expr **params);
|
||||
|
||||
bool sema_analyse_checked(SemaContext *context, Ast *directive, SourceSpan span);
|
||||
|
||||
|
||||
@@ -249,6 +249,7 @@ RETRY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_CT_IDENT:
|
||||
case EXPR_ANYSWITCH:
|
||||
case EXPR_GENERIC_IDENT:
|
||||
UNREACHABLE
|
||||
case EXPR_DESIGNATOR:
|
||||
sema_trace_expr_liveness(expr->designator_expr.value);
|
||||
|
||||
@@ -311,6 +311,23 @@ INLINE bool sema_resolve_vatype(SemaContext *context, TypeInfo *type_info)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Foo(<...>)
|
||||
INLINE bool sema_resolve_generic_type(SemaContext *context, TypeInfo *type_info)
|
||||
{
|
||||
TypeInfo *inner = type_info->generic.base;
|
||||
if (inner->kind != TYPE_INFO_IDENTIFIER && inner->subtype != TYPE_COMPRESSED_NONE && !inner->optional)
|
||||
{
|
||||
SEMA_ERROR(inner, "Parameterization required a concrete type name here.");
|
||||
return false;
|
||||
}
|
||||
assert(inner->resolve_status == RESOLVE_NOT_DONE);
|
||||
|
||||
Decl *type = sema_analyse_parameterized_identifier(context, inner->unresolved.path, inner->unresolved.name, inner->span, type_info->generic.params);
|
||||
if (!decl_ok(type)) return false;
|
||||
type_info->type = type->type;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_resolve_type(SemaContext *context, TypeInfo *type_info, bool allow_inferred_type, bool is_pointee)
|
||||
{
|
||||
// Ok, already resolved.
|
||||
@@ -338,6 +355,9 @@ static inline bool sema_resolve_type(SemaContext *context, TypeInfo *type_info,
|
||||
{
|
||||
case TYPE_INFO_POISON:
|
||||
UNREACHABLE
|
||||
case TYPE_INFO_GENERIC:
|
||||
if (!sema_resolve_generic_type(context, type_info)) return type_info_poison(type_info);
|
||||
goto APPEND_QUALIFIERS;
|
||||
case TYPE_INFO_VATYPE:
|
||||
if (!sema_resolve_vatype(context, type_info)) return type_info_poison(type_info);
|
||||
goto APPEND_QUALIFIERS;
|
||||
|
||||
@@ -159,6 +159,8 @@ void sema_analyze_stage(Module *module, AnalysisStage stage)
|
||||
case ANALYSIS_FUNCTIONS:
|
||||
sema_analysis_pass_functions(module);
|
||||
break;
|
||||
case ANALYSIS_FINALIZE:
|
||||
break;
|
||||
}
|
||||
if (global_context.errors_found) return;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ const char *token_type_to_string(TokenType type)
|
||||
return "<=";
|
||||
case TOKEN_LBRAPIPE:
|
||||
return "{|";
|
||||
case TOKEN_LGENPAR:
|
||||
return "(<";
|
||||
case TOKEN_LVEC:
|
||||
return "[<";
|
||||
case TOKEN_MINUS_ASSIGN:
|
||||
@@ -120,6 +122,8 @@ const char *token_type_to_string(TokenType type)
|
||||
return "??";
|
||||
case TOKEN_RBRAPIPE:
|
||||
return "|}";
|
||||
case TOKEN_RGENPAR:
|
||||
return ">)";
|
||||
case TOKEN_RVEC:
|
||||
return ">]";
|
||||
case TOKEN_SCOPE:
|
||||
|
||||
@@ -201,27 +201,36 @@ const char *type_to_error_string(Type *type)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
return "poisoned";
|
||||
case TYPE_ENUM:
|
||||
case TYPE_FAULTTYPE:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOL:
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_UNION:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_ANYFAULT:
|
||||
case TYPE_UNTYPED_LIST:
|
||||
case TYPE_ANY:
|
||||
case TYPE_MEMBER:
|
||||
case TYPE_WILDCARD:
|
||||
return type->name;
|
||||
case TYPE_ENUM:
|
||||
case TYPE_FAULTTYPE:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
{
|
||||
Decl *decl = type->decl;
|
||||
if (!decl || !decl->unit || !decl->unit->module->generic_suffix) return type->name;
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(decl->name);
|
||||
scratch_buffer_append(decl->unit->module->generic_suffix);
|
||||
return scratch_buffer_copy();
|
||||
}
|
||||
case TYPE_FUNC:
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append("fn ");
|
||||
type_append_func_to_scratch(type->function.prototype);
|
||||
return str_printf("fn %s", scratch_buffer_to_string());
|
||||
return scratch_buffer_copy();
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
return str_printf("%s[<*>]", type_to_error_string(type->array.base));
|
||||
case TYPE_VECTOR:
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.554"
|
||||
#define COMPILER_VERSION "0.4.555"
|
||||
@@ -2,11 +2,11 @@ module foo;
|
||||
|
||||
// def <name> = <name>
|
||||
def standard_foo = __stdin;
|
||||
def someFunctionIntBool = someFunction<int, bool>;
|
||||
def FooInt = Foo<int>;
|
||||
def A_CONST_INT = A_CONST<int>;
|
||||
def someFunctionIntBool = someFunction(<int, bool>);
|
||||
def FooInt = Foo(<int>);
|
||||
def A_CONST_INT = A_CONST(<int>);
|
||||
|
||||
def standard_foo<int> = ofke; // #error: Expected '='
|
||||
def standard_foo(<int>) = ofke; // #error: Expected '='
|
||||
def fn foo = fef; // #error: A type, variable, constant or attribute name was expected here
|
||||
def feokfe = fn void(int); // #error: Expected a function or variable name here
|
||||
def AOFKE = ofek; // #error: Expected a constant name here
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module foo<Type>;
|
||||
module foo(<Type>);
|
||||
import std::io;
|
||||
|
||||
macro @hello(Type thing) {
|
||||
@@ -9,8 +9,8 @@ module bar;
|
||||
|
||||
import foo @public;
|
||||
|
||||
def intHello = foo::@hello<int>; // #error: cannot be aliased
|
||||
def @intHello = foo::hello<int>; // #error: cannot use
|
||||
def intHello = foo::@hello(<int>); // #error: cannot be aliased
|
||||
def @intHello = foo::hello(<int>); // #error: cannot use
|
||||
|
||||
fn void main(String[] args) {
|
||||
@intHello(42);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module foo<Type>;
|
||||
module foo(<Type>);
|
||||
import std::io;
|
||||
|
||||
macro @hello(Type thing) {
|
||||
@@ -9,7 +9,7 @@ module bar;
|
||||
|
||||
import foo @public;
|
||||
|
||||
def @intHello = foo::@hello<int>;
|
||||
def @intHello = foo::@hello(<int>);
|
||||
|
||||
fn void main(String[] args) {
|
||||
@intHello(42);
|
||||
|
||||
@@ -65,8 +65,8 @@ fn int Foo2.mutate(Foo2 *foo)
|
||||
return ++foo.x;
|
||||
}
|
||||
|
||||
def oopsInt = test2::argh<int>;
|
||||
def oopsDouble = test2::argh<int>;
|
||||
def oopsInt = test2::argh(<int>);
|
||||
def oopsDouble = test2::argh(<int>);
|
||||
def Argh = fn int(double, Bobo);
|
||||
def Argh2 = fn int(double, Bobo);
|
||||
|
||||
@@ -95,15 +95,15 @@ struct Foo
|
||||
int b;
|
||||
}
|
||||
|
||||
def getValueInt = test2::getValue<int>;
|
||||
def getValueDouble = test2::getValue<double>;
|
||||
def IntBlob = test2::Blob<int>;
|
||||
def DoubleBlob = Blob<double>;
|
||||
def getMultInt = test2::getMult<int>;
|
||||
def getMultDouble = test2::getMult<double>;
|
||||
def getValueInt = test2::getValue(<int>);
|
||||
def getValueDouble = test2::getValue(<double>);
|
||||
def IntBlob = test2::Blob(<int>);
|
||||
def DoubleBlob = Blob(<double>);
|
||||
def getMultInt = test2::getMult(<int>);
|
||||
def getMultDouble = test2::getMult(<double>);
|
||||
|
||||
def IntArray = List<int>;
|
||||
def IntList = LinkedList<int>;
|
||||
def IntArray = List(<int>);
|
||||
def IntList = LinkedList(<int>);
|
||||
|
||||
enum MyEnum : int
|
||||
{
|
||||
@@ -173,7 +173,7 @@ module hello_world;
|
||||
import foo;
|
||||
|
||||
extern fn int printf(char *, ...);
|
||||
def doubleMult = foo::check<double>;
|
||||
def doubleMult = foo::check(<double>);
|
||||
|
||||
fn void hello()
|
||||
{
|
||||
@@ -181,14 +181,14 @@ fn void hello()
|
||||
printf("Mult %f\n", doubleMult(11.1));
|
||||
}
|
||||
|
||||
module foo <Type>;
|
||||
module foo(<Type>);
|
||||
|
||||
fn Type check(Type i)
|
||||
{
|
||||
return i * i;
|
||||
}
|
||||
|
||||
module test2 <Type>;
|
||||
module test2(<Type>);
|
||||
|
||||
struct Blob
|
||||
{
|
||||
|
||||
@@ -67,8 +67,8 @@ fn int Foo2.mutate(Foo2 *foo)
|
||||
|
||||
|
||||
|
||||
def oopsInt = test2::argh<int>;
|
||||
def oopsDouble = test2::argh<int>;
|
||||
def oopsInt = test2::argh(<int>);
|
||||
def oopsDouble = test2::argh(<int>);
|
||||
def Argh = fn int(double, Bobo);
|
||||
def Argh2 = fn int(double, Bobo);
|
||||
|
||||
@@ -97,15 +97,15 @@ struct Foo
|
||||
int b;
|
||||
}
|
||||
|
||||
def getValueInt = test2::getValue<int>;
|
||||
def getValueDouble = test2::getValue<double>;
|
||||
def IntBlob = test2::Blob<int>;
|
||||
def DoubleBlob = Blob<double>;
|
||||
def getMultInt = test2::getMult<int>;
|
||||
def getMultDouble = test2::getMult<double>;
|
||||
def getValueInt = test2::getValue(<int>);
|
||||
def getValueDouble = test2::getValue(<double>);
|
||||
def IntBlob = test2::Blob(<int>);
|
||||
def DoubleBlob = Blob(<double>);
|
||||
def getMultInt = test2::getMult(<int>);
|
||||
def getMultDouble = test2::getMult(<double>);
|
||||
|
||||
def IntArray = List<int>;
|
||||
def IntList = LinkedList<int>;
|
||||
def IntArray = List(<int>);
|
||||
def IntList = LinkedList(<int>);
|
||||
|
||||
enum MyEnum : int
|
||||
{
|
||||
@@ -175,7 +175,7 @@ module hello_world;
|
||||
import foo;
|
||||
|
||||
extern fn int printf(char *, ...);
|
||||
def doubleMult = foo::check<double>;
|
||||
def doubleMult = foo::check(<double>);
|
||||
|
||||
fn void hello()
|
||||
{
|
||||
@@ -183,14 +183,14 @@ fn void hello()
|
||||
printf("Mult %f\n", doubleMult(11.1));
|
||||
}
|
||||
|
||||
module foo <Type>;
|
||||
module foo(<Type>);
|
||||
|
||||
fn Type check(Type i)
|
||||
{
|
||||
return i * i;
|
||||
}
|
||||
|
||||
module test2 <Type>;
|
||||
module test2(<Type>);
|
||||
|
||||
struct Blob
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ module test;
|
||||
import std::io;
|
||||
import std::collections::enumset;
|
||||
|
||||
def AbcEnumSet = EnumSet<Abc>;
|
||||
def AbcEnumSet = EnumSet(<Abc>);
|
||||
|
||||
enum Abc
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module foo<Type>;
|
||||
module foo(<Type>);
|
||||
|
||||
fn void abc()
|
||||
{
|
||||
@@ -9,4 +9,4 @@ fn void abc()
|
||||
module tester;
|
||||
import foo;
|
||||
|
||||
def abc_my = foo::abc<int>;
|
||||
def abc_my = foo::abc(<int>);
|
||||
@@ -2,14 +2,14 @@
|
||||
module test;
|
||||
import bar;
|
||||
|
||||
def BazTest = Baz<Test>;
|
||||
def BazTest = Baz(<Test>); // #error: Recursive definition of 'BazTest'
|
||||
|
||||
struct Test // #error: Recursive definition of 'Test'
|
||||
struct Test
|
||||
{
|
||||
BazTest t;
|
||||
}
|
||||
|
||||
module bar<Test>;
|
||||
module bar(<Test>);
|
||||
|
||||
struct Baz
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module gen <Type>;
|
||||
module gen(<Type>);
|
||||
|
||||
fn Type mult(Type x)
|
||||
{
|
||||
@@ -13,8 +13,8 @@ fn Type addMult(Type x, Type a, Type b)
|
||||
module test;
|
||||
import gen;
|
||||
|
||||
def intMult = gen::mult<int>;
|
||||
def doubleAddMult = gen::addMult<double>;
|
||||
def intMult = gen::mult(<int>);
|
||||
def doubleAddMult = gen::addMult(<double>);
|
||||
|
||||
fn int getIt(int i)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// #target: macos-x64
|
||||
module hello<Type, FOO>;
|
||||
module hello(<Type, FOO>);
|
||||
|
||||
fn Type x(Type t)
|
||||
{
|
||||
@@ -8,7 +8,7 @@ fn Type x(Type t)
|
||||
|
||||
module test;
|
||||
import hello;
|
||||
def xint = hello::x<int, -123>;
|
||||
def xint = hello::x(<int, -123>);
|
||||
|
||||
import std::io;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ module test;
|
||||
import std::io;
|
||||
import std::collections::list;
|
||||
|
||||
def TreeNodeList = List<TreeNode>;
|
||||
def TreeNodeList = List(<TreeNode>);
|
||||
|
||||
struct TreeNode
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module foo<Type, SIZE>;
|
||||
module foo(<Type, SIZE>);
|
||||
|
||||
struct Foo
|
||||
{
|
||||
@@ -7,5 +7,5 @@ struct Foo
|
||||
module bar;
|
||||
import foo;
|
||||
|
||||
def Bar = Foo<int, int>; // #error: Expected a value, not a type
|
||||
def Baz = Foo<5, 4>; // #error: Expected a type, not a value
|
||||
def Bar = Foo(<int, int>); // #error: Expected a value, not a type
|
||||
def Baz = Foo(<5, 4>); // #error: Expected a type, not a value
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module compiler_c3;
|
||||
import std::collections::list;
|
||||
|
||||
def IntArray = List<int>;
|
||||
def IntArray = List(<int>);
|
||||
|
||||
extern fn void printf(char*, ...);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
module test;
|
||||
import std::collections::map;
|
||||
|
||||
def IntMap = HashMap<char[], int>;
|
||||
def IntMap = HashMap(<char[], int>);
|
||||
|
||||
fn void main()
|
||||
{
|
||||
|
||||
@@ -6,8 +6,8 @@ import std::collections::map;
|
||||
|
||||
struct Foo { int x; void* bar; }
|
||||
|
||||
def IntFooMap = HashMap<int, Foo>;
|
||||
def IntDoubleMap = HashMap<int, double>;
|
||||
def IntFooMap = HashMap(<int, Foo>);
|
||||
def IntDoubleMap = HashMap(<int, double>);
|
||||
|
||||
fn String Foo.to_string(Foo* foo, Allocator* allocator = mem::heap()) @dynamic
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ import std::io;
|
||||
import std::math;
|
||||
import std::collections::priorityqueue;
|
||||
|
||||
def FooPriorityQueue = PriorityQueue<Foo>;
|
||||
def FooPriorityQueue = PriorityQueue(<Foo>);
|
||||
|
||||
fn void main()
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ enum FooEnum
|
||||
THREE,
|
||||
}
|
||||
|
||||
def FooEnumMap = EnumMap<FooEnum, uint>;
|
||||
def FooEnumMap = EnumMap(<FooEnum, uint>);
|
||||
|
||||
fn void! enums()
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module linkedlist_test @test;
|
||||
import std::collections::linkedlist;
|
||||
|
||||
def IntList = LinkedList<int>;
|
||||
def IntList = LinkedList(<int>);
|
||||
|
||||
fn void! test_push()
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
module listtests @test;
|
||||
import std::collections::list;
|
||||
|
||||
def IntList = List<int>;
|
||||
def PtrList = List<void*>;
|
||||
def IntList = List(<int>);
|
||||
def PtrList = List(<void*>);
|
||||
|
||||
fn void! test_delete_contains_index()
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
module range_test @test;
|
||||
import std::collections::range;
|
||||
|
||||
def IntRange = Range<int>;
|
||||
def IntExRange = ExclusiveRange<int>;
|
||||
def IntRange = Range(<int>);
|
||||
def IntExRange = ExclusiveRange(<int>);
|
||||
|
||||
fn void! test_exrange()
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ module sort_test @test;
|
||||
import std::sort;
|
||||
import std::sort::quicksort;
|
||||
|
||||
def qs_int = quicksort::sort<int[]>;
|
||||
def qs_int = quicksort::sort(<int[]>);
|
||||
|
||||
fn void quicksort()
|
||||
{
|
||||
@@ -22,7 +22,8 @@ fn void quicksort()
|
||||
}
|
||||
|
||||
def Cmp = fn int(int*, int*);
|
||||
def qs_int_ref = quicksort::sort_ref_fn<int[]>;
|
||||
|
||||
def qs_int_ref = quicksort::sort_ref_fn(<int[]>);
|
||||
|
||||
fn void quicksort_with()
|
||||
{
|
||||
@@ -41,7 +42,7 @@ fn void quicksort_with()
|
||||
}
|
||||
}
|
||||
|
||||
def qs_int_fn = quicksort::sort_fn<int[]>;
|
||||
def qs_int_fn = quicksort::sort_fn(<int[]>);
|
||||
|
||||
fn void quicksort_with2()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user