mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Grammar updates. Updated enum member parsing.
This commit is contained in:
@@ -28,7 +28,8 @@ void yyerror(char *s);
|
||||
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
|
||||
%token FN FAULT MACRO GENERIC CT_IF CT_ENDIF CT_ELSE CT_SWITCH CT_CASE CT_DEFAULT CT_FOR CT_FOREACH CT_ENDFOREACH
|
||||
%token CT_ENDFOR CT_ENDSWITCH BUILTIN IMPLIES INITIALIZE FINALIZE CT_ECHO CT_ASSERT CT_EVALTYPE CT_VATYPE
|
||||
%token TRY CATCH SCOPE PUBLIC DEFER ATTRIBUTE TRY_Q CATCH_Q LVEC RVEC OPTELSE CT_TYPEFROM CT_TYPEOF
|
||||
%token TRY CATCH SCOPE PUBLIC DEFER ATTRIBUTE TRY_Q CATCH_Q LVEC RVEC OPTELSE CT_TYPEFROM CT_TYPEOF TLOCAL
|
||||
%token CT_VASPLAT
|
||||
|
||||
%token FN_BLOCK_START FN_BLOCK_END
|
||||
|
||||
@@ -40,6 +41,7 @@ path
|
||||
| path IDENT SCOPE
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
import_path
|
||||
: IDENT
|
||||
| import_path SCOPE IDENT
|
||||
@@ -203,23 +205,44 @@ assignment_operator
|
||||
| SUB_MOD_ASSIGN
|
||||
;
|
||||
|
||||
constant_expression
|
||||
constant_expr
|
||||
: conditional_expression
|
||||
;
|
||||
|
||||
param_path_element
|
||||
: '[' expression ']'
|
||||
| '.' IDENT
|
||||
;
|
||||
|
||||
param_path
|
||||
: param_path_element
|
||||
| param_path param_path_element
|
||||
;
|
||||
|
||||
arg : param_path '=' expression
|
||||
| expression
|
||||
| CT_VASPLAT '(' constant_expr ')'
|
||||
| ELLIPSIS expression
|
||||
;
|
||||
|
||||
arg_list
|
||||
: arg
|
||||
| arg_list ',' arg
|
||||
;
|
||||
|
||||
enumerators
|
||||
: enumerator
|
||||
| enumerators ',' enumerator
|
||||
;
|
||||
enumerator_list
|
||||
|
||||
enum_list
|
||||
: enumerators
|
||||
| enumerators ','
|
||||
;
|
||||
|
||||
enumerator
|
||||
: CONST_IDENT
|
||||
| CONST_IDENT '=' constant_expression
|
||||
| CONST_IDENT '(' arg_list ')'
|
||||
;
|
||||
|
||||
identifier_list
|
||||
@@ -244,6 +267,12 @@ declaration
|
||||
| optional_type IDENT
|
||||
;
|
||||
|
||||
enum_param_decl
|
||||
: type
|
||||
| type IDENT
|
||||
| type IDENT '=' expression
|
||||
;
|
||||
|
||||
param_declaration
|
||||
: type
|
||||
| type IDENT
|
||||
@@ -266,6 +295,7 @@ parameter_list
|
||||
| parameter_list ',' param_declaration
|
||||
;
|
||||
|
||||
/* Updated for 0.5 */
|
||||
base_type
|
||||
: VOID
|
||||
| BOOL
|
||||
@@ -280,28 +310,30 @@ base_type
|
||||
| INT128
|
||||
| UINT128
|
||||
| FLOAT
|
||||
| DOUBLE
|
||||
| FLOAT16
|
||||
| FLOAT128
|
||||
| DOUBLE
|
||||
| TYPE_IDENT
|
||||
| path TYPE_IDENT
|
||||
| CT_TYPE_IDENT
|
||||
| CT_TYPEOF '(' expression ')'
|
||||
| CT_TYPEFROM '(' constant_expression ')'
|
||||
| CT_VATYPE '(' constant_expression ')'
|
||||
| CT_EVALTYPE '(' constant_expression ')'
|
||||
| CT_TYPEFROM '(' constant_expr ')'
|
||||
| CT_VATYPE '(' constant_expr ')'
|
||||
| CT_EVALTYPE '(' constant_expr ')'
|
||||
;
|
||||
|
||||
/* Updated for 0.5 */
|
||||
type
|
||||
: base_type
|
||||
| type '*'
|
||||
| type '[' constant_expression ']'
|
||||
| type '[' constant_expr ']'
|
||||
| type '[' ']'
|
||||
| type '[' '*' ']'
|
||||
| type LVEC constant_expression RVEC
|
||||
| type LVEC constant_expr RVEC
|
||||
| type LVEC '*' RVEC
|
||||
;
|
||||
|
||||
/* Updated for 0.5 */
|
||||
optional_type
|
||||
: type
|
||||
| type '!'
|
||||
@@ -312,6 +344,43 @@ initializer
|
||||
| initializer_list
|
||||
;
|
||||
|
||||
|
||||
/* Updated for 0.5 */
|
||||
local_decl_after_type
|
||||
: CT_IDENT
|
||||
| CT_IDENT '=' constant_expr
|
||||
| IDENT opt_attributes
|
||||
| IDENT opt_attributes '=' expression
|
||||
;
|
||||
|
||||
local_decl_storage
|
||||
: STATIC
|
||||
| TLOCAL
|
||||
|
|
||||
;
|
||||
|
||||
/* Updated for 0.5 */
|
||||
local_decl
|
||||
: const_declaration
|
||||
| local_decl_storage optional_type local_decl_after_type
|
||||
;
|
||||
|
||||
/* Updated for 0.5 */
|
||||
decl_or_expr
|
||||
: var_decl
|
||||
| optional_type local_decl_after_type
|
||||
| expression
|
||||
;
|
||||
|
||||
/* Updated for 0.5 */
|
||||
var_decl
|
||||
: VAR IDENT '=' expression
|
||||
| VAR CT_IDENT '=' expression
|
||||
| VAR CT_IDENT
|
||||
| VAR CT_TYPE_IDENT '=' expression
|
||||
| VAR CT_TYPE_IDENT
|
||||
;
|
||||
|
||||
initializer_values
|
||||
: initializer
|
||||
| initializer_values ',' initializer
|
||||
@@ -323,7 +392,7 @@ initializer_list
|
||||
;
|
||||
|
||||
ct_case_statement
|
||||
: CT_CASE expression ':' opt_stmt_list
|
||||
: CT_CASE constant_expr ':' opt_stmt_list
|
||||
| CT_DEFAULT ':' opt_stmt_list
|
||||
;
|
||||
|
||||
@@ -338,7 +407,7 @@ ct_for_stmt
|
||||
;
|
||||
|
||||
ct_foreach_stmt
|
||||
: CT_FOREACH '(' CT_IDENT ':' expression ')' opt_stmt_list CT_ENDFOREACH
|
||||
: CT_FOREACH '(' CT_IDENT ':' constant_expr ')' opt_stmt_list CT_ENDFOREACH
|
||||
|
||||
ct_statement
|
||||
: ct_if opt_stmt_list CT_ENDIF
|
||||
@@ -428,12 +497,12 @@ decl_expr_list
|
||||
;
|
||||
|
||||
ct_assert_stmt
|
||||
: CT_ASSERT '(' expression ',' expression ')' ';'
|
||||
| CT_ASSERT '(' expression ')' ';'
|
||||
: CT_ASSERT '(' constant_expr ',' constant_expr ')' ';'
|
||||
| CT_ASSERT '(' constant_expr ')' ';'
|
||||
;
|
||||
|
||||
ct_echo_stmt
|
||||
: CT_ECHO '(' expression ')' ';'
|
||||
: CT_ECHO '(' constant_expr ')' ';'
|
||||
|
||||
bitstruct_declaration
|
||||
: BITSTRUCT IDENT ':' type opt_attributes bitstruct_body
|
||||
@@ -449,8 +518,8 @@ bitstruct_defs
|
||||
;
|
||||
|
||||
bitstruct_def
|
||||
: type IDENT ':' constant_expression DOTDOT constant_expression ';'
|
||||
| type IDENT ':' constant_expression ';'
|
||||
: type IDENT ':' constant_expr DOTDOT constant_expr ';'
|
||||
| type IDENT ':' constant_expr ';'
|
||||
;
|
||||
|
||||
static_declaration
|
||||
@@ -482,53 +551,63 @@ jump_statement
|
||||
| RETURN expression ';'
|
||||
;
|
||||
|
||||
path_ident
|
||||
: IDENT
|
||||
| path IDENT
|
||||
/* Updated for 0.5 */
|
||||
attribute_name
|
||||
: AT_IDENT
|
||||
| AT_TYPE_IDENT
|
||||
| path AT_TYPE_IDENT
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
attribute_operator_expr
|
||||
: '&' '[' ']'
|
||||
| '[' ']' '='
|
||||
| '[' ']'
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
attr_param
|
||||
: attribute_operator_expr
|
||||
| constant_expr
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
attribute_param_list
|
||||
: attr_param
|
||||
| attribute_param_list ',' attr_param
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
attribute
|
||||
: '@' path_ident
|
||||
| '@' path_ident '(' constant_expression ')'
|
||||
: attribute_name
|
||||
| attribute_name '(' attribute_param_list ')'
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
attribute_list
|
||||
: attribute
|
||||
| attribute_list attribute
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
opt_attributes
|
||||
: attribute_list
|
||||
|
|
||||
;
|
||||
|
||||
func_name
|
||||
: path TYPE_IDENT '.' IDENT
|
||||
| TYPE_IDENT '.' IDENT
|
||||
| IDENT
|
||||
;
|
||||
|
||||
func_declaration
|
||||
: FN optional_type func_name opt_parameter_type_list opt_attributes
|
||||
;
|
||||
|
||||
func_definition
|
||||
: func_declaration compound_statement
|
||||
| func_declaration ';'
|
||||
| func_declaration IMPLIES expression ';'
|
||||
;
|
||||
|
||||
macro_declaration
|
||||
: MACRO type IDENT '(' macro_argument_list ')' compound_statement
|
||||
: MACRO IDENT '(' macro_argument_list ')' compound_statement
|
||||
;
|
||||
|
||||
|
||||
/* Checked for 0.5 */
|
||||
struct_or_union
|
||||
: STRUCT
|
||||
| UNION
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
struct_declaration
|
||||
: struct_or_union TYPE_IDENT opt_attributes struct_body
|
||||
;
|
||||
@@ -548,9 +627,23 @@ struct_member_declaration
|
||||
| struct_or_union opt_attributes struct_body
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
enum_params
|
||||
: enum_param_decl
|
||||
| enum_params ',' enum_param_decl
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
enum_spec
|
||||
: ':' type
|
||||
| ':' type '(' ')'
|
||||
| ':' type '(' enum_params ')'
|
||||
|
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
enum_declaration
|
||||
: ENUM TYPE_IDENT ':' type opt_attributes '{' enumerator_list '}'
|
||||
| ENUM TYPE_IDENT opt_attributes '{' enumerator_list '}'
|
||||
: ENUM TYPE_IDENT enum_spec opt_attributes '{' enum_list '}'
|
||||
;
|
||||
|
||||
faults
|
||||
@@ -563,9 +656,69 @@ fault_declaration
|
||||
| FAULT opt_attributes '{' faults ',' '}'
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
func_header
|
||||
: optional_type type '.' IDENT
|
||||
| optional_type IDENT
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
macro_name
|
||||
: IDENT
|
||||
| AT_IDENT
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
macro_header
|
||||
: optional_type type '.' macro_name
|
||||
| optional_type macro_name
|
||||
| type '.' macro_name
|
||||
| macro_name
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
fn_parameter_list
|
||||
: '(' parameters ')'
|
||||
| '(' ')'
|
||||
;
|
||||
|
||||
|
||||
/* Checked for 0.5 */
|
||||
parameters
|
||||
: parameter '=' expression
|
||||
| parameter
|
||||
| parameters ',' parameter
|
||||
| parameters ',' parameter '=' expression
|
||||
;
|
||||
|
||||
|
||||
/* Checked for 0.5 */
|
||||
parameter
|
||||
: type IDENT opt_attributes
|
||||
| ELLIPSIS
|
||||
| type ELLIPSIS IDENT opt_attributes
|
||||
| type ELLIPSIS CT_IDENT
|
||||
| IDENT ELLIPSIS
|
||||
| type '&' IDENT opt_attributes
|
||||
| '&' IDENT opt_attributes
|
||||
| type HASH_IDENT opt_attributes
|
||||
| HASH_IDENT opt_attributes
|
||||
| type CT_IDENT
|
||||
| CT_IDENT
|
||||
| CT_IDENT ELLIPSIS
|
||||
| type opt_attributes
|
||||
;
|
||||
|
||||
function_definition
|
||||
: FN func_header fn_parameter_list opt_attributes ';'
|
||||
| FN func_header fn_parameter_list opt_attributes IMPLIES expression ';'
|
||||
| FN func_header fn_parameter_list opt_attributes compound_statement
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
const_declaration
|
||||
: CONST CONST_IDENT opt_attributes '=' initializer ';'
|
||||
| CONST type CONST_IDENT opt_attributes '=' initializer ';'
|
||||
: CONST CONST_IDENT opt_attributes '=' expression
|
||||
| CONST type CONST_IDENT opt_attributes '=' expression
|
||||
;
|
||||
|
||||
func_typedef
|
||||
@@ -579,9 +732,24 @@ typedef_declaration
|
||||
;
|
||||
|
||||
|
||||
multi_declaration
|
||||
: ',' IDENT
|
||||
| multi_declaration ',' IDENT
|
||||
;
|
||||
|
||||
opt_multi_declaration
|
||||
: multi_declaration
|
||||
|
|
||||
;
|
||||
|
||||
global_storage
|
||||
: TLOCAL
|
||||
|
|
||||
;
|
||||
|
||||
global_declaration
|
||||
: type IDENT opt_attributes ';'
|
||||
| type IDENT opt_attributes '=' initializer ';'
|
||||
: global_storage optional_type IDENT opt_multi_declaration opt_attributes ';'
|
||||
| global_storage optional_type IDENT '=' constant_expr ';'
|
||||
;
|
||||
|
||||
ct_if
|
||||
@@ -620,22 +788,22 @@ conditional_compilation
|
||||
| ct_switch tl_ct_switch_body CT_ENDSWITCH
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
module_param
|
||||
: CT_IDENT
|
||||
| HASH_IDENT
|
||||
: CONST_IDENT
|
||||
| TYPE_IDENT
|
||||
| CT_TYPE_IDENT
|
||||
| IDENT
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
module_params
|
||||
: module_param
|
||||
| module_params ',' module_param
|
||||
;
|
||||
|
||||
/* Checked for 0.5 */
|
||||
module
|
||||
: MODULE import_path opt_attributes';'
|
||||
| MODULE import_path '<' module_params '>' ';'
|
||||
: MODULE import_path opt_attributes ';'
|
||||
| MODULE import_path '<' module_params '>' opt_attributes ';'
|
||||
;
|
||||
|
||||
import_decl
|
||||
@@ -654,14 +822,14 @@ top_level_statements
|
||||
|
||||
|
||||
top_level
|
||||
: func_definition
|
||||
: function_definition
|
||||
| module
|
||||
| import_decl
|
||||
| conditional_compilation
|
||||
| struct_declaration
|
||||
| enum_declaration
|
||||
| fault_declaration
|
||||
| const_declaration
|
||||
| const_declaration ';'
|
||||
| global_declaration
|
||||
| macro_declaration
|
||||
| typedef_declaration
|
||||
|
||||
@@ -1142,7 +1142,7 @@ struct Expr_
|
||||
ExprVariant variant_expr;
|
||||
ExprPointerOffset pointer_offset_expr;
|
||||
ExprAsmArg expr_asm_arg;
|
||||
OperatorOverload expr_operator_chars;
|
||||
OperatorOverload overload_expr;
|
||||
TypeInfo *type_expr; // 8
|
||||
ExprConst const_expr; // 32
|
||||
ExprArgv argv_expr; // 16
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
static bool context_next_is_path_prefix_start(ParseContext *c);
|
||||
static Decl *parse_const_declaration(ParseContext *c, bool is_global);
|
||||
static inline Decl *parse_func_definition(ParseContext *c, AstId docs, bool is_interface);
|
||||
static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool is_interface);
|
||||
static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl);
|
||||
static inline Decl *parse_static_top_level(ParseContext *c);
|
||||
static Decl *parse_include(ParseContext *c);
|
||||
@@ -502,9 +502,11 @@ bool parse_path_prefix(ParseContext *c, Path** path_ref)
|
||||
* | FLOAT16
|
||||
* | FLOAT128
|
||||
* | TYPE_IDENT
|
||||
* | ident_scope TYPE_IDENT
|
||||
* | path_prefix TYPE_IDENT
|
||||
* | CT_TYPE_IDENT
|
||||
* | CT_TYPEOF '(' expr ')'
|
||||
* | CT_TYPEFROM '(' expr ')'
|
||||
* | CT_VATYPE '(' expr ')'
|
||||
* | CT_EVALTYPE '(' expr ')'
|
||||
* ;
|
||||
*
|
||||
@@ -785,10 +787,7 @@ TypeInfo *parse_optional_type(ParseContext *c)
|
||||
// --- Decl parsing
|
||||
|
||||
/**
|
||||
* Parse ident ('=' expr)?
|
||||
* @param is_static
|
||||
* @param type
|
||||
* @return
|
||||
* after_type ::= (CT_IDENT | IDENT) attributes? ('=' decl_initializer)?
|
||||
*/
|
||||
Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type)
|
||||
{
|
||||
@@ -859,25 +858,30 @@ Decl *parse_local_decl(ParseContext *c)
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* decl_or_expr ::= var_decl | type local_decl_after_type | expression
|
||||
*/
|
||||
Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref)
|
||||
{
|
||||
// var-initialization is done separately.
|
||||
if (tok_is(c, TOKEN_VAR))
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(*decl_ref, parse_var_decl(c), poisoned_expr);
|
||||
return NULL;
|
||||
}
|
||||
TypeInfo *type_info;
|
||||
Expr *expr = parse_expr(c);
|
||||
|
||||
// If it's not a type info, we assume an expr.
|
||||
if (expr->expr_kind != EXPR_TYPEINFO) return expr;
|
||||
|
||||
// Otherwise we expect a declaration.
|
||||
ASSIGN_DECL_OR_RET(*decl_ref, parse_local_decl_after_type(c, expr->type_expr), poisoned_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* const_decl
|
||||
* : 'const' type? IDENT '=' const_expr
|
||||
* ;
|
||||
* const_decl ::= 'const' type? CONST_IDENT attributes? '=' const_expr
|
||||
*/
|
||||
static Decl *parse_const_declaration(ParseContext *c, bool is_global)
|
||||
{
|
||||
@@ -885,14 +889,19 @@ static Decl *parse_const_declaration(ParseContext *c, bool is_global)
|
||||
|
||||
TypeInfo *type_info = NULL;
|
||||
|
||||
// If not a const ident, assume we want the type
|
||||
if (c->tok != TOKEN_CONST_IDENT)
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(type_info, parse_type(c), poisoned_decl);
|
||||
}
|
||||
|
||||
// Create the decl
|
||||
Decl *decl = decl_new_var(symstr(c), c->span, type_info, VARDECL_CONST);
|
||||
|
||||
// Check the name
|
||||
if (!consume_const_name(c, "const")) return poisoned_decl;
|
||||
|
||||
// Differentiate between global and local attributes, global have visibility
|
||||
if (is_global)
|
||||
{
|
||||
if (!parse_attributes_for_global(c, decl)) return false;
|
||||
@@ -901,17 +910,22 @@ static Decl *parse_const_declaration(ParseContext *c, bool is_global)
|
||||
{
|
||||
if (!parse_attributes(c, &decl->attributes, NULL)) return poisoned_decl;
|
||||
}
|
||||
|
||||
// Required initializer
|
||||
CONSUME_OR_RET(TOKEN_EQ, poisoned_decl);
|
||||
|
||||
if (!parse_decl_initializer(c, decl)) return poisoned_decl;
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* var_decl ::= VAR (IDENT '=' expression) | (CT_IDENT ('=' expression)?) | (CT_TYPE_IDENT ('=' expression)?)
|
||||
*/
|
||||
Decl *parse_var_decl(ParseContext *c)
|
||||
{
|
||||
// CT variants will naturally be macro only, for runtime variables it is enforced in the semantic
|
||||
// analyser. The runtime variables must have an initializer unlike the CT ones.
|
||||
advance_and_verify(c, TOKEN_VAR);
|
||||
Decl *decl;
|
||||
switch (c->tok)
|
||||
@@ -957,34 +971,43 @@ Decl *parse_var_decl(ParseContext *c)
|
||||
|
||||
// --- Parse parameters & throws & attributes
|
||||
|
||||
/**
|
||||
* attribute ::= (AT_IDENT | path_prefix? AT_TYPE_IDENT) attr_params?
|
||||
* attr_params ::= '(' attr_param (',' attr_param)* ')'
|
||||
* attr_param ::= const_expr | '&' '[' ']' || '[' ']' '='?
|
||||
*/
|
||||
bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
||||
{
|
||||
bool had_error;
|
||||
Path *path;
|
||||
if (!parse_path_prefix(c, &path)) return false;
|
||||
|
||||
// Something not starting with `@` in attribute position:
|
||||
if (!tok_is(c, TOKEN_AT_IDENT) && !tok_is(c, TOKEN_AT_TYPE_IDENT))
|
||||
{
|
||||
if (path)
|
||||
{
|
||||
SEMA_ERROR_HERE("Expected an attribute name.");
|
||||
return false;
|
||||
}
|
||||
// Started a path? If so hard error
|
||||
if (path) RETURN_SEMA_ERROR_HERE("Expected an attribute name.");
|
||||
|
||||
// Otherwise assume no attributes
|
||||
*attribute_ref = NULL;
|
||||
return true;
|
||||
}
|
||||
Attr *attr = CALLOCS(Attr);
|
||||
|
||||
// Create an attribute
|
||||
Attr *attr = CALLOCS(Attr);
|
||||
attr->name = symstr(c);
|
||||
attr->span = c->span;
|
||||
attr->path = path;
|
||||
|
||||
// Pre-defined idents
|
||||
if (tok_is(c, TOKEN_AT_IDENT))
|
||||
{
|
||||
// Error for foo::bar::@inline
|
||||
if (path) RETURN_SEMA_ERROR_HERE("Only user-defined attribute names can have a module path prefix.");
|
||||
|
||||
// Check attribute it exists, theoretically we could defer this to semantic analysis
|
||||
AttributeType type = attribute_by_name(attr->name);
|
||||
if (type == ATTRIBUTE_NONE)
|
||||
{
|
||||
SEMA_ERROR_HERE("This is not a known valid attribute name.");
|
||||
return false;
|
||||
}
|
||||
if (type == ATTRIBUTE_NONE) RETURN_SEMA_ERROR_HERE("This is not a known valid attribute name.");
|
||||
attr->attr_kind = type;
|
||||
}
|
||||
else
|
||||
@@ -992,9 +1015,9 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
||||
attr->is_custom = true;
|
||||
}
|
||||
advance(c);
|
||||
|
||||
Expr **list = NULL;
|
||||
|
||||
// Consume the optional (expr | attr_param, ...)
|
||||
if (try_consume(c, TOKEN_LPAREN))
|
||||
{
|
||||
while (1)
|
||||
@@ -1009,16 +1032,16 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
||||
advance(c);
|
||||
CONSUME_OR_RET(TOKEN_LBRACKET, false);
|
||||
CONSUME_OR_RET(TOKEN_RBRACKET, false);
|
||||
expr->expr_operator_chars = OVERLOAD_ELEMENT_REF;
|
||||
expr->overload_expr = OVERLOAD_ELEMENT_REF;
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
break;
|
||||
case TOKEN_LBRACKET:
|
||||
// []
|
||||
// [] and []=
|
||||
expr = EXPR_NEW_TOKEN(EXPR_OPERATOR_CHARS);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
advance(c);
|
||||
CONSUME_OR_RET(TOKEN_RBRACKET, false);
|
||||
expr->expr_operator_chars = try_consume(c, TOKEN_EQ) ? OVERLOAD_ELEMENT_SET : OVERLOAD_ELEMENT_AT;
|
||||
expr->overload_expr = try_consume(c, TOKEN_EQ) ? OVERLOAD_ELEMENT_SET : OVERLOAD_ELEMENT_AT;
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
break;
|
||||
default:
|
||||
@@ -1033,11 +1056,13 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
||||
}
|
||||
|
||||
attr->exprs = list;
|
||||
|
||||
*attribute_ref = attr;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse global attributes, setting visibility defaults from the parent unit.
|
||||
*/
|
||||
static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
|
||||
{
|
||||
Visibility visibility = c->unit->default_visibility;
|
||||
@@ -1049,13 +1074,9 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
|
||||
}
|
||||
|
||||
/**
|
||||
* attribute_list
|
||||
* : attribute
|
||||
* | attribute_list attribute
|
||||
* ;
|
||||
* attribute_list ::= attribute*
|
||||
*
|
||||
* attribute
|
||||
* : path AT_IDENT | AT_TYPE_IDENT ('(' constant_expression ')')?
|
||||
* Patch visibility attributes immediately.
|
||||
*
|
||||
* @return true if parsing succeeded, false if recovery is needed
|
||||
*/
|
||||
@@ -1070,6 +1091,9 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib
|
||||
Visibility parsed_visibility = -1;
|
||||
if (!attr->is_custom)
|
||||
{
|
||||
// This is important: if we would allow user defined attributes,
|
||||
// ordering between visibility of attributes would be complex.
|
||||
// since there is little
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_PUBLIC:
|
||||
@@ -1086,27 +1110,15 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib
|
||||
}
|
||||
if (parsed_visibility != -1)
|
||||
{
|
||||
if (!visibility_ref)
|
||||
{
|
||||
SEMA_ERROR(attr, "'%s' cannot be used here.");
|
||||
return false;
|
||||
}
|
||||
if (visibility != -1)
|
||||
{
|
||||
SEMA_ERROR(attr, "Only a single visibility attribute may be added.");
|
||||
return false;
|
||||
}
|
||||
if (!visibility_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.");
|
||||
if (visibility != -1) RETURN_SEMA_ERROR(attr, "Only a single visibility attribute may be added.");
|
||||
*visibility_ref = visibility = parsed_visibility;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const char *name = attr->name;
|
||||
FOREACH_BEGIN(Attr *other_attr, *attributes_ref)
|
||||
if (other_attr->name == name)
|
||||
{
|
||||
SEMA_ERROR(attr, "Repeat of attribute '%s' here.", name);
|
||||
return false;
|
||||
}
|
||||
if (other_attr->name == name) RETURN_SEMA_ERROR(attr, "Repeat of attribute '%s' here.", name);
|
||||
FOREACH_END();
|
||||
vec_add(*attributes_ref, attr);
|
||||
}
|
||||
@@ -1115,13 +1127,8 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib
|
||||
|
||||
|
||||
/**
|
||||
* global_declaration
|
||||
* : global? optional_type IDENT ';'
|
||||
* | global? optional_type IDENT '=' expression ';'
|
||||
* | global? optional_type func_definition
|
||||
* ;
|
||||
* global_declaration ::= TLOCAL? optional_type IDENT (('=' expression)? | (',' IDENT)* opt_attributes) ';'
|
||||
*
|
||||
* @param visibility
|
||||
* @return true if parsing succeeded
|
||||
*/
|
||||
static inline Decl *parse_global_declaration(ParseContext *c)
|
||||
@@ -1130,7 +1137,6 @@ static inline Decl *parse_global_declaration(ParseContext *c)
|
||||
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl);
|
||||
|
||||
|
||||
if (tok_is(c, TOKEN_CONST_IDENT))
|
||||
{
|
||||
SEMA_ERROR_HERE("This looks like a constant variable, did you forget 'const'?");
|
||||
@@ -1139,9 +1145,11 @@ static inline Decl *parse_global_declaration(ParseContext *c)
|
||||
|
||||
Decl *decl;
|
||||
Decl **decls = NULL;
|
||||
// Parse IDENT (',' IDENT)*
|
||||
while (true)
|
||||
{
|
||||
decl = decl_new_var_current(c, type, VARDECL_GLOBAL);
|
||||
// Update threadlocal setting
|
||||
decl->var.is_threadlocal = threadlocal;
|
||||
if (!try_consume(c, TOKEN_IDENT))
|
||||
{
|
||||
@@ -1161,6 +1169,7 @@ static inline Decl *parse_global_declaration(ParseContext *c)
|
||||
|
||||
if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
|
||||
|
||||
// If we get '=' we can't have multiple idents.
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
{
|
||||
if (decls)
|
||||
@@ -1172,12 +1181,13 @@ static inline Decl *parse_global_declaration(ParseContext *c)
|
||||
}
|
||||
else if (!decl->attributes && tok_is(c, TOKEN_LPAREN) && !threadlocal)
|
||||
{
|
||||
// Guess we forgot `fn`?
|
||||
// Guess we forgot `fn`? -> improve error reporting.
|
||||
sema_error_at(type->span, "This looks like the beginning of a function declaration but it's missing the initial `fn`. Did you forget it?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
Attr **attributes = decl->attributes;
|
||||
// Copy the attributes to the other variables.
|
||||
if (attributes)
|
||||
{
|
||||
FOREACH_BEGIN(Decl *d, decls)
|
||||
@@ -1185,6 +1195,7 @@ static inline Decl *parse_global_declaration(ParseContext *c)
|
||||
d->attributes = copy_attributes_single(attributes);
|
||||
FOREACH_END();
|
||||
}
|
||||
// If we have multiple decls, then we return that as a bundled decl_globals
|
||||
if (decls)
|
||||
{
|
||||
decl = decl_calloc();
|
||||
@@ -1198,46 +1209,23 @@ static inline Decl *parse_global_declaration(ParseContext *c)
|
||||
|
||||
|
||||
/**
|
||||
* param_declaration ::= type_expression '...'?) (IDENT ('=' initializer)?)?
|
||||
* ;
|
||||
* enum_param_decl ::= type IDENT ('=' expr)?
|
||||
*/
|
||||
static inline bool parse_param_decl(ParseContext *c, Decl*** parameters, bool require_name)
|
||||
static inline bool parse_enum_param_decl(ParseContext *c, Decl*** parameters)
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), false);
|
||||
if (type->optional)
|
||||
{
|
||||
SEMA_ERROR(type, "Parameters may not be optional.");
|
||||
return false;
|
||||
}
|
||||
bool vararg = try_consume(c, TOKEN_ELLIPSIS);
|
||||
if (type->optional) RETURN_SEMA_ERROR(type, "Parameters may not be optional.");
|
||||
Decl *param = decl_new_var_current(c, type, VARDECL_PARAM);
|
||||
param->var.vararg = vararg;
|
||||
if (!try_consume(c, TOKEN_IDENT))
|
||||
{
|
||||
param->name = NULL;
|
||||
if (token_is_keyword(c->tok)) RETURN_SEMA_ERROR_HERE("Keywords cannot be used as member names.");
|
||||
if (token_is_some_ident(c->tok)) RETURN_SEMA_ERROR_HERE("Expected a name starting with a lower-case letter.");
|
||||
RETURN_SEMA_ERROR_HERE("Expected a member name here.");
|
||||
}
|
||||
const char *name = param->name;
|
||||
|
||||
if (!name && require_name)
|
||||
{
|
||||
if (!tok_is(c, TOKEN_COMMA) && !tok_is(c, TOKEN_RPAREN))
|
||||
{
|
||||
if (tok_is(c, TOKEN_CT_IDENT))
|
||||
{
|
||||
SEMA_ERROR_HERE("Compile time identifiers are only allowed as macro parameters.");
|
||||
return false;
|
||||
}
|
||||
sema_error_at_after(type->span, "Unexpected end of the parameter list, did you forget an ')'?");
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR(type, "The parameter must be named.");
|
||||
return false;
|
||||
}
|
||||
if (name && try_consume(c, TOKEN_EQ))
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
{
|
||||
if (!parse_decl_initializer(c, param)) return poisoned_decl;
|
||||
}
|
||||
|
||||
vec_add(*parameters, param);
|
||||
RANGE_EXTEND_PREV(param);
|
||||
return true;
|
||||
@@ -1463,6 +1451,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,
|
||||
}
|
||||
Decl *param = decl_new_var(name, span, type, param_kind);
|
||||
param->var.type_info = type;
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL)) return false;
|
||||
if (!no_name)
|
||||
{
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
@@ -1470,7 +1459,6 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,
|
||||
if (!parse_decl_initializer(c, param)) return poisoned_decl;
|
||||
}
|
||||
}
|
||||
if (!parse_attributes(c, ¶m->attributes, NULL)) return false;
|
||||
if (ellipsis)
|
||||
{
|
||||
var_arg_found = true;
|
||||
@@ -1486,8 +1474,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* parameter_type_list ::= '(' parameters ')'
|
||||
* fn_parameter_list ::= '(' parameters ')'
|
||||
*/
|
||||
static inline bool parse_fn_parameter_list(ParseContext *c, Signature *signature, bool is_interface)
|
||||
{
|
||||
@@ -2081,8 +2068,8 @@ static inline bool parse_is_macro_name(ParseContext *c)
|
||||
}
|
||||
|
||||
/**
|
||||
* func_header ::= type '!'? (type '.')? (IDENT | MACRO_IDENT)
|
||||
* macro_header ::= (type '!'?)? (type '.')? (IDENT | MACRO_IDENT)
|
||||
* func_header ::= optional_type (type '.')? IDENT
|
||||
* macro_header ::= optional_type? (type '.')? (IDENT | MACRO_IDENT)
|
||||
*/
|
||||
static inline bool parse_func_macro_header(ParseContext *c, Decl *decl)
|
||||
{
|
||||
@@ -2229,31 +2216,25 @@ static inline Decl *parse_fault_declaration(ParseContext *c)
|
||||
}
|
||||
|
||||
/**
|
||||
* enum_spec
|
||||
* : type
|
||||
* | type '(' opt_parameter_type_list ')'
|
||||
* ;
|
||||
* enum_spec ::= type ('(' enum_params ')')?
|
||||
*/
|
||||
static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl*** parameters_ref)
|
||||
{
|
||||
|
||||
ASSIGN_TYPE_OR_RET(*type_ref, parse_optional_type(c), false);
|
||||
if ((*type_ref)->optional)
|
||||
{
|
||||
SEMA_ERROR(*type_ref, "An enum can't have an optional type.");
|
||||
return false;
|
||||
}
|
||||
// If no left parenthesis we're done.
|
||||
if (!try_consume(c, TOKEN_LPAREN)) return true;
|
||||
|
||||
// We allow (), but we might consider making it an error later on.
|
||||
while (!try_consume(c, TOKEN_RPAREN))
|
||||
{
|
||||
if (!parse_param_decl(c, parameters_ref, true)) return false;
|
||||
if (!parse_enum_param_decl(c, parameters_ref)) return false;
|
||||
Decl *last_parameter = VECLAST(*parameters_ref);
|
||||
assert(last_parameter);
|
||||
if (last_parameter->var.vararg)
|
||||
{
|
||||
SEMA_ERROR_LAST("Vararg parameters are not allowed as enum parameters.");
|
||||
return false;
|
||||
}
|
||||
last_parameter->var.index = vec_size(*parameters_ref) - 1;
|
||||
if (!try_consume(c, TOKEN_COMMA))
|
||||
{
|
||||
@@ -2263,25 +2244,13 @@ static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl***
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expect current at enum name.
|
||||
*
|
||||
* enum
|
||||
* : ENUM type_ident '{' enum_body '}'
|
||||
* | ENUM type_ident ':' enum_spec '{' enum_body '}'
|
||||
* ;
|
||||
*
|
||||
* enum_body
|
||||
* : enum_def
|
||||
* | enum_def ',' enum_body
|
||||
* | enum_body ','
|
||||
* ;
|
||||
*
|
||||
* enum_def
|
||||
* : CAPS_IDENT
|
||||
* | CAPS_IDENT '(' expr_list ')'
|
||||
* ;
|
||||
* Parse an enum declaration (after "enum")
|
||||
*
|
||||
* enum ::= ENUM TYPE_IDENT enum_spec? opt_attributes '{' enum_body '}'
|
||||
* enum_body ::= enum_def (',' enum_def)* ','?
|
||||
* enum_def ::= CONST_IDENT ('(' arg_list ')')?
|
||||
*/
|
||||
static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
{
|
||||
@@ -2291,6 +2260,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
if (!consume_type_name(c, "enum")) return poisoned_decl;
|
||||
|
||||
TypeInfo *type = NULL;
|
||||
// Parse the spec
|
||||
if (try_consume(c, TOKEN_COLON))
|
||||
{
|
||||
if (!parse_enum_spec(c, &type, &decl->enums.parameters)) return poisoned_decl;
|
||||
@@ -2302,7 +2272,6 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl);
|
||||
|
||||
decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span);
|
||||
|
||||
while (!try_consume(c, TOKEN_RBRACE))
|
||||
{
|
||||
Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, symstr(c), c->span);
|
||||
@@ -2342,8 +2311,6 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
|
||||
// --- Parse function
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Starts after 'fn'
|
||||
*
|
||||
@@ -2365,12 +2332,12 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
* @param visibility
|
||||
* @return Decl*
|
||||
*/
|
||||
static inline Decl *parse_func_definition(ParseContext *c, AstId docs, bool is_interface)
|
||||
static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool is_interface)
|
||||
{
|
||||
advance_and_verify(c, TOKEN_FN);
|
||||
Decl *func = decl_calloc();
|
||||
func->decl_kind = DECL_FUNC;
|
||||
func->func_decl.docs = docs;
|
||||
func->func_decl.docs = contracts;
|
||||
if (!parse_func_macro_header(c, func)) return poisoned_decl;
|
||||
if (func->name[0] == '@')
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ Ast* parse_compound_stmt(ParseContext *c);
|
||||
Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool require_eos);
|
||||
Ast *parse_jump_stmt_no_eos(ParseContext *c);
|
||||
bool parse_attribute(ParseContext *c, Attr **attribute_ref);
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility);
|
||||
bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref);
|
||||
|
||||
bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type);
|
||||
Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl);
|
||||
|
||||
@@ -1605,7 +1605,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
decl->operator = OVERLOAD_LEN;
|
||||
break;
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
decl->operator = expr->expr_operator_chars;
|
||||
decl->operator = expr->overload_expr;
|
||||
break;
|
||||
default:
|
||||
goto FAILED_OP_TYPE;
|
||||
|
||||
4
test/test_suite/attributes/attribute_path.c3
Normal file
4
test/test_suite/attributes/attribute_path.c3
Normal file
@@ -0,0 +1,4 @@
|
||||
fn void test() abc::@inline // #error: Only user-defined attribute names
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
|
||||
enum EnumWithErrorWithMissingName : int (int) // #error: The parameter must be named
|
||||
enum EnumWithErrorWithMissingName : int (int) // #error: Expected a member name here
|
||||
{
|
||||
TEST
|
||||
}
|
||||
|
||||
enum EnumWithErrorData : int (int // #error: end of the parameter list
|
||||
{
|
||||
enum EnumWithErrorData : int (int
|
||||
{ // #error: Expected a member name here
|
||||
TEST
|
||||
}
|
||||
|
||||
enum EnumWithErrorData2 : int (int, int bar) // #error: The parameter must be named
|
||||
enum EnumWithErrorData2 : int (int, int bar) // #error: Expected a member name here
|
||||
{
|
||||
TEST
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user