Grammar updates. Updated enum member parsing.

This commit is contained in:
Christoffer Lerno
2023-03-22 21:46:47 +01:00
parent 0f80d985fa
commit ad7ee06635
7 changed files with 335 additions and 196 deletions

View File

@@ -28,7 +28,8 @@ void yyerror(char *s);
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN %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 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 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 %token FN_BLOCK_START FN_BLOCK_END
@@ -40,6 +41,7 @@ path
| path IDENT SCOPE | path IDENT SCOPE
; ;
/* Checked for 0.5 */
import_path import_path
: IDENT : IDENT
| import_path SCOPE IDENT | import_path SCOPE IDENT
@@ -203,23 +205,44 @@ assignment_operator
| SUB_MOD_ASSIGN | SUB_MOD_ASSIGN
; ;
constant_expression constant_expr
: conditional_expression : 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 enumerators
: enumerator : enumerator
| enumerators ',' enumerator | enumerators ',' enumerator
; ;
enumerator_list
enum_list
: enumerators : enumerators
| enumerators ',' | enumerators ','
; ;
enumerator enumerator
: CONST_IDENT : CONST_IDENT
| CONST_IDENT '=' constant_expression | CONST_IDENT '(' arg_list ')'
; ;
identifier_list identifier_list
@@ -244,6 +267,12 @@ declaration
| optional_type IDENT | optional_type IDENT
; ;
enum_param_decl
: type
| type IDENT
| type IDENT '=' expression
;
param_declaration param_declaration
: type : type
| type IDENT | type IDENT
@@ -266,6 +295,7 @@ parameter_list
| parameter_list ',' param_declaration | parameter_list ',' param_declaration
; ;
/* Updated for 0.5 */
base_type base_type
: VOID : VOID
| BOOL | BOOL
@@ -280,28 +310,30 @@ base_type
| INT128 | INT128
| UINT128 | UINT128
| FLOAT | FLOAT
| DOUBLE
| FLOAT16 | FLOAT16
| FLOAT128 | FLOAT128
| DOUBLE
| TYPE_IDENT | TYPE_IDENT
| path TYPE_IDENT | path TYPE_IDENT
| CT_TYPE_IDENT | CT_TYPE_IDENT
| CT_TYPEOF '(' expression ')' | CT_TYPEOF '(' expression ')'
| CT_TYPEFROM '(' constant_expression ')' | CT_TYPEFROM '(' constant_expr ')'
| CT_VATYPE '(' constant_expression ')' | CT_VATYPE '(' constant_expr ')'
| CT_EVALTYPE '(' constant_expression ')' | CT_EVALTYPE '(' constant_expr ')'
; ;
/* Updated for 0.5 */
type type
: base_type : base_type
| type '*' | type '*'
| type '[' constant_expression ']' | type '[' constant_expr ']'
| type '[' ']' | type '[' ']'
| type '[' '*' ']' | type '[' '*' ']'
| type LVEC constant_expression RVEC | type LVEC constant_expr RVEC
| type LVEC '*' RVEC | type LVEC '*' RVEC
; ;
/* Updated for 0.5 */
optional_type optional_type
: type : type
| type '!' | type '!'
@@ -312,6 +344,43 @@ initializer
| initializer_list | 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_values
: initializer : initializer
| initializer_values ',' initializer | initializer_values ',' initializer
@@ -319,11 +388,11 @@ initializer_values
initializer_list initializer_list
: '{' initializer_values '}' : '{' initializer_values '}'
| '{' initializer_values ',' '}' | '{' initializer_values ',' '}'
; ;
ct_case_statement ct_case_statement
: CT_CASE expression ':' opt_stmt_list : CT_CASE constant_expr ':' opt_stmt_list
| CT_DEFAULT ':' opt_stmt_list | CT_DEFAULT ':' opt_stmt_list
; ;
@@ -338,7 +407,7 @@ ct_for_stmt
; ;
ct_foreach_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_statement
: ct_if opt_stmt_list CT_ENDIF : ct_if opt_stmt_list CT_ENDIF
@@ -428,12 +497,12 @@ decl_expr_list
; ;
ct_assert_stmt ct_assert_stmt
: CT_ASSERT '(' expression ',' expression ')' ';' : CT_ASSERT '(' constant_expr ',' constant_expr ')' ';'
| CT_ASSERT '(' expression ')' ';' | CT_ASSERT '(' constant_expr ')' ';'
; ;
ct_echo_stmt ct_echo_stmt
: CT_ECHO '(' expression ')' ';' : CT_ECHO '(' constant_expr ')' ';'
bitstruct_declaration bitstruct_declaration
: BITSTRUCT IDENT ':' type opt_attributes bitstruct_body : BITSTRUCT IDENT ':' type opt_attributes bitstruct_body
@@ -449,8 +518,8 @@ bitstruct_defs
; ;
bitstruct_def bitstruct_def
: type IDENT ':' constant_expression DOTDOT constant_expression ';' : type IDENT ':' constant_expr DOTDOT constant_expr ';'
| type IDENT ':' constant_expression ';' | type IDENT ':' constant_expr ';'
; ;
static_declaration static_declaration
@@ -482,41 +551,49 @@ jump_statement
| RETURN expression ';' | RETURN expression ';'
; ;
path_ident /* Updated for 0.5 */
: IDENT attribute_name
| path IDENT : 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 attribute
: '@' path_ident : attribute_name
| '@' path_ident '(' constant_expression ')' | attribute_name '(' attribute_param_list ')'
; ;
/* Checked for 0.5 */
attribute_list attribute_list
: attribute : attribute
| attribute_list attribute | attribute_list attribute
; ;
/* Checked for 0.5 */
opt_attributes opt_attributes
: attribute_list : 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_declaration
: MACRO type IDENT '(' macro_argument_list ')' compound_statement : MACRO type IDENT '(' macro_argument_list ')' compound_statement
@@ -524,14 +601,16 @@ macro_declaration
; ;
/* Checked for 0.5 */
struct_or_union struct_or_union
: STRUCT : STRUCT
| UNION | UNION
; ;
/* Checked for 0.5 */
struct_declaration struct_declaration
: struct_or_union TYPE_IDENT opt_attributes struct_body : struct_or_union TYPE_IDENT opt_attributes struct_body
; ;
struct_body struct_body
: '{' struct_declaration_list '}' : '{' struct_declaration_list '}'
@@ -548,10 +627,24 @@ struct_member_declaration
| struct_or_union opt_attributes struct_body | 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_declaration
: ENUM TYPE_IDENT ':' type opt_attributes '{' enumerator_list '}' : ENUM TYPE_IDENT enum_spec opt_attributes '{' enum_list '}'
| ENUM TYPE_IDENT opt_attributes '{' enumerator_list '}' ;
;
faults faults
: CONST_IDENT : CONST_IDENT
@@ -563,10 +656,70 @@ fault_declaration
| FAULT opt_attributes '{' faults ',' '}' | 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_declaration
: CONST CONST_IDENT opt_attributes '=' initializer ';' : CONST CONST_IDENT opt_attributes '=' expression
| CONST type CONST_IDENT opt_attributes '=' initializer ';' | CONST type CONST_IDENT opt_attributes '=' expression
; ;
func_typedef func_typedef
: FN optional_type opt_parameter_type_list : FN optional_type opt_parameter_type_list
@@ -579,9 +732,24 @@ typedef_declaration
; ;
multi_declaration
: ',' IDENT
| multi_declaration ',' IDENT
;
opt_multi_declaration
: multi_declaration
|
;
global_storage
: TLOCAL
|
;
global_declaration global_declaration
: type IDENT opt_attributes ';' : global_storage optional_type IDENT opt_multi_declaration opt_attributes ';'
| type IDENT opt_attributes '=' initializer ';' | global_storage optional_type IDENT '=' constant_expr ';'
; ;
ct_if ct_if
@@ -620,22 +788,22 @@ conditional_compilation
| ct_switch tl_ct_switch_body CT_ENDSWITCH | ct_switch tl_ct_switch_body CT_ENDSWITCH
; ;
/* Checked for 0.5 */
module_param module_param
: CT_IDENT : CONST_IDENT
| HASH_IDENT
| TYPE_IDENT | TYPE_IDENT
| CT_TYPE_IDENT
| IDENT
; ;
/* Checked for 0.5 */
module_params module_params
: module_param : module_param
| module_params ',' module_param | module_params ',' module_param
; ;
/* Checked for 0.5 */
module module
: MODULE import_path opt_attributes';' : MODULE import_path opt_attributes ';'
| MODULE import_path '<' module_params '>' ';' | MODULE import_path '<' module_params '>' opt_attributes ';'
; ;
import_decl import_decl
@@ -654,14 +822,14 @@ top_level_statements
top_level top_level
: func_definition : function_definition
| module | module
| import_decl | import_decl
| conditional_compilation | conditional_compilation
| struct_declaration | struct_declaration
| enum_declaration | enum_declaration
| fault_declaration | fault_declaration
| const_declaration | const_declaration ';'
| global_declaration | global_declaration
| macro_declaration | macro_declaration
| typedef_declaration | typedef_declaration

View File

@@ -1142,7 +1142,7 @@ struct Expr_
ExprVariant variant_expr; ExprVariant variant_expr;
ExprPointerOffset pointer_offset_expr; ExprPointerOffset pointer_offset_expr;
ExprAsmArg expr_asm_arg; ExprAsmArg expr_asm_arg;
OperatorOverload expr_operator_chars; OperatorOverload overload_expr;
TypeInfo *type_expr; // 8 TypeInfo *type_expr; // 8
ExprConst const_expr; // 32 ExprConst const_expr; // 32
ExprArgv argv_expr; // 16 ExprArgv argv_expr; // 16

View File

@@ -7,7 +7,7 @@
static bool context_next_is_path_prefix_start(ParseContext *c); static bool context_next_is_path_prefix_start(ParseContext *c);
static Decl *parse_const_declaration(ParseContext *c, bool is_global); 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 bool parse_bitstruct_body(ParseContext *c, Decl *decl);
static inline Decl *parse_static_top_level(ParseContext *c); static inline Decl *parse_static_top_level(ParseContext *c);
static Decl *parse_include(ParseContext *c); static Decl *parse_include(ParseContext *c);
@@ -502,9 +502,11 @@ bool parse_path_prefix(ParseContext *c, Path** path_ref)
* | FLOAT16 * | FLOAT16
* | FLOAT128 * | FLOAT128
* | TYPE_IDENT * | TYPE_IDENT
* | ident_scope TYPE_IDENT * | path_prefix TYPE_IDENT
* | CT_TYPE_IDENT * | CT_TYPE_IDENT
* | CT_TYPEOF '(' expr ')' * | CT_TYPEOF '(' expr ')'
* | CT_TYPEFROM '(' expr ')'
* | CT_VATYPE '(' expr ')'
* | CT_EVALTYPE '(' expr ')' * | CT_EVALTYPE '(' expr ')'
* ; * ;
* *
@@ -785,10 +787,7 @@ TypeInfo *parse_optional_type(ParseContext *c)
// --- Decl parsing // --- Decl parsing
/** /**
* Parse ident ('=' expr)? * after_type ::= (CT_IDENT | IDENT) attributes? ('=' decl_initializer)?
* @param is_static
* @param type
* @return
*/ */
Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type) Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type)
{ {
@@ -859,25 +858,30 @@ Decl *parse_local_decl(ParseContext *c)
return decl; return decl;
} }
/**
* decl_or_expr ::= var_decl | type local_decl_after_type | expression
*/
Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref) Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref)
{ {
// var-initialization is done separately.
if (tok_is(c, TOKEN_VAR)) if (tok_is(c, TOKEN_VAR))
{ {
ASSIGN_DECL_OR_RET(*decl_ref, parse_var_decl(c), poisoned_expr); ASSIGN_DECL_OR_RET(*decl_ref, parse_var_decl(c), poisoned_expr);
return NULL; return NULL;
} }
TypeInfo *type_info;
Expr *expr = parse_expr(c); Expr *expr = parse_expr(c);
// If it's not a type info, we assume an expr.
if (expr->expr_kind != EXPR_TYPEINFO) return 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); ASSIGN_DECL_OR_RET(*decl_ref, parse_local_decl_after_type(c, expr->type_expr), poisoned_expr);
return NULL; return NULL;
} }
/** /**
* const_decl * const_decl ::= 'const' type? CONST_IDENT attributes? '=' const_expr
* : 'const' type? IDENT '=' const_expr
* ;
*/ */
static Decl *parse_const_declaration(ParseContext *c, bool is_global) 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; TypeInfo *type_info = NULL;
// If not a const ident, assume we want the type
if (c->tok != TOKEN_CONST_IDENT) if (c->tok != TOKEN_CONST_IDENT)
{ {
ASSIGN_TYPE_OR_RET(type_info, parse_type(c), poisoned_decl); 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); 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; if (!consume_const_name(c, "const")) return poisoned_decl;
// Differentiate between global and local attributes, global have visibility
if (is_global) if (is_global)
{ {
if (!parse_attributes_for_global(c, decl)) return false; 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; if (!parse_attributes(c, &decl->attributes, NULL)) return poisoned_decl;
} }
// Required initializer
CONSUME_OR_RET(TOKEN_EQ, poisoned_decl); CONSUME_OR_RET(TOKEN_EQ, poisoned_decl);
if (!parse_decl_initializer(c, decl)) return poisoned_decl; if (!parse_decl_initializer(c, decl)) return poisoned_decl;
RANGE_EXTEND_PREV(decl); RANGE_EXTEND_PREV(decl);
return decl; return decl;
} }
/**
* var_decl ::= VAR (IDENT '=' expression) | (CT_IDENT ('=' expression)?) | (CT_TYPE_IDENT ('=' expression)?)
*/
Decl *parse_var_decl(ParseContext *c) 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); advance_and_verify(c, TOKEN_VAR);
Decl *decl; Decl *decl;
switch (c->tok) switch (c->tok)
@@ -957,34 +971,43 @@ Decl *parse_var_decl(ParseContext *c)
// --- Parse parameters & throws & attributes // --- 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 parse_attribute(ParseContext *c, Attr **attribute_ref)
{ {
bool had_error; bool had_error;
Path *path; Path *path;
if (!parse_path_prefix(c, &path)) return false; 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 (!tok_is(c, TOKEN_AT_IDENT) && !tok_is(c, TOKEN_AT_TYPE_IDENT))
{ {
if (path) // Started a path? If so hard error
{ if (path) RETURN_SEMA_ERROR_HERE("Expected an attribute name.");
SEMA_ERROR_HERE("Expected an attribute name.");
return false; // Otherwise assume no attributes
}
*attribute_ref = NULL; *attribute_ref = NULL;
return true; return true;
} }
Attr *attr = CALLOCS(Attr);
// Create an attribute
Attr *attr = CALLOCS(Attr);
attr->name = symstr(c); attr->name = symstr(c);
attr->span = c->span; attr->span = c->span;
attr->path = path; attr->path = path;
// Pre-defined idents
if (tok_is(c, TOKEN_AT_IDENT)) 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); AttributeType type = attribute_by_name(attr->name);
if (type == ATTRIBUTE_NONE) if (type == ATTRIBUTE_NONE) RETURN_SEMA_ERROR_HERE("This is not a known valid attribute name.");
{
SEMA_ERROR_HERE("This is not a known valid attribute name.");
return false;
}
attr->attr_kind = type; attr->attr_kind = type;
} }
else else
@@ -992,9 +1015,9 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
attr->is_custom = true; attr->is_custom = true;
} }
advance(c); advance(c);
Expr **list = NULL; Expr **list = NULL;
// Consume the optional (expr | attr_param, ...)
if (try_consume(c, TOKEN_LPAREN)) if (try_consume(c, TOKEN_LPAREN))
{ {
while (1) while (1)
@@ -1009,16 +1032,16 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
advance(c); advance(c);
CONSUME_OR_RET(TOKEN_LBRACKET, false); CONSUME_OR_RET(TOKEN_LBRACKET, false);
CONSUME_OR_RET(TOKEN_RBRACKET, false); CONSUME_OR_RET(TOKEN_RBRACKET, false);
expr->expr_operator_chars = OVERLOAD_ELEMENT_REF; expr->overload_expr = OVERLOAD_ELEMENT_REF;
RANGE_EXTEND_PREV(expr); RANGE_EXTEND_PREV(expr);
break; break;
case TOKEN_LBRACKET: case TOKEN_LBRACKET:
// [] // [] and []=
expr = EXPR_NEW_TOKEN(EXPR_OPERATOR_CHARS); expr = EXPR_NEW_TOKEN(EXPR_OPERATOR_CHARS);
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
advance(c); advance(c);
CONSUME_OR_RET(TOKEN_RBRACKET, false); 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); RANGE_EXTEND_PREV(expr);
break; break;
default: default:
@@ -1033,11 +1056,13 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
} }
attr->exprs = list; attr->exprs = list;
*attribute_ref = attr; *attribute_ref = attr;
return true; return true;
} }
/**
* Parse global attributes, setting visibility defaults from the parent unit.
*/
static bool parse_attributes_for_global(ParseContext *c, Decl *decl) static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
{ {
Visibility visibility = c->unit->default_visibility; Visibility visibility = c->unit->default_visibility;
@@ -1049,13 +1074,9 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
} }
/** /**
* attribute_list * attribute_list ::= attribute*
* : attribute
* | attribute_list attribute
* ;
* *
* attribute * Patch visibility attributes immediately.
* : path AT_IDENT | AT_TYPE_IDENT ('(' constant_expression ')')?
* *
* @return true if parsing succeeded, false if recovery is needed * @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; Visibility parsed_visibility = -1;
if (!attr->is_custom) 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) switch (attr->attr_kind)
{ {
case ATTRIBUTE_PUBLIC: case ATTRIBUTE_PUBLIC:
@@ -1086,27 +1110,15 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib
} }
if (parsed_visibility != -1) if (parsed_visibility != -1)
{ {
if (!visibility_ref) 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.");
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;
}
*visibility_ref = visibility = parsed_visibility; *visibility_ref = visibility = parsed_visibility;
continue; continue;
} }
} }
const char *name = attr->name; const char *name = attr->name;
FOREACH_BEGIN(Attr *other_attr, *attributes_ref) FOREACH_BEGIN(Attr *other_attr, *attributes_ref)
if (other_attr->name == name) if (other_attr->name == name) RETURN_SEMA_ERROR(attr, "Repeat of attribute '%s' here.", name);
{
SEMA_ERROR(attr, "Repeat of attribute '%s' here.", name);
return false;
}
FOREACH_END(); FOREACH_END();
vec_add(*attributes_ref, attr); vec_add(*attributes_ref, attr);
} }
@@ -1115,13 +1127,8 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib
/** /**
* global_declaration * global_declaration ::= TLOCAL? optional_type IDENT (('=' expression)? | (',' IDENT)* opt_attributes) ';'
* : global? optional_type IDENT ';'
* | global? optional_type IDENT '=' expression ';'
* | global? optional_type func_definition
* ;
* *
* @param visibility
* @return true if parsing succeeded * @return true if parsing succeeded
*/ */
static inline Decl *parse_global_declaration(ParseContext *c) 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); ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl);
if (tok_is(c, TOKEN_CONST_IDENT)) if (tok_is(c, TOKEN_CONST_IDENT))
{ {
SEMA_ERROR_HERE("This looks like a constant variable, did you forget 'const'?"); 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 *decl;
Decl **decls = NULL; Decl **decls = NULL;
// Parse IDENT (',' IDENT)*
while (true) while (true)
{ {
decl = decl_new_var_current(c, type, VARDECL_GLOBAL); decl = decl_new_var_current(c, type, VARDECL_GLOBAL);
// Update threadlocal setting
decl->var.is_threadlocal = threadlocal; decl->var.is_threadlocal = threadlocal;
if (!try_consume(c, TOKEN_IDENT)) 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 (!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 (try_consume(c, TOKEN_EQ))
{ {
if (decls) if (decls)
@@ -1172,12 +1181,13 @@ static inline Decl *parse_global_declaration(ParseContext *c)
} }
else if (!decl->attributes && tok_is(c, TOKEN_LPAREN) && !threadlocal) 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?"); 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; return poisoned_decl;
} }
CONSUME_EOS_OR_RET(poisoned_decl); CONSUME_EOS_OR_RET(poisoned_decl);
Attr **attributes = decl->attributes; Attr **attributes = decl->attributes;
// Copy the attributes to the other variables.
if (attributes) if (attributes)
{ {
FOREACH_BEGIN(Decl *d, decls) FOREACH_BEGIN(Decl *d, decls)
@@ -1185,6 +1195,7 @@ static inline Decl *parse_global_declaration(ParseContext *c)
d->attributes = copy_attributes_single(attributes); d->attributes = copy_attributes_single(attributes);
FOREACH_END(); FOREACH_END();
} }
// If we have multiple decls, then we return that as a bundled decl_globals
if (decls) if (decls)
{ {
decl = decl_calloc(); 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); ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), false);
if (type->optional) if (type->optional) RETURN_SEMA_ERROR(type, "Parameters may not be optional.");
{
SEMA_ERROR(type, "Parameters may not be optional.");
return false;
}
bool vararg = try_consume(c, TOKEN_ELLIPSIS);
Decl *param = decl_new_var_current(c, type, VARDECL_PARAM); Decl *param = decl_new_var_current(c, type, VARDECL_PARAM);
param->var.vararg = vararg;
if (!try_consume(c, TOKEN_IDENT)) 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 (try_consume(c, TOKEN_EQ))
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 (!parse_decl_initializer(c, param)) return poisoned_decl; if (!parse_decl_initializer(c, param)) return poisoned_decl;
} }
vec_add(*parameters, param); vec_add(*parameters, param);
RANGE_EXTEND_PREV(param); RANGE_EXTEND_PREV(param);
return true; 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); Decl *param = decl_new_var(name, span, type, param_kind);
param->var.type_info = type; param->var.type_info = type;
if (!parse_attributes(c, &param->attributes, NULL)) return false;
if (!no_name) if (!no_name)
{ {
if (try_consume(c, TOKEN_EQ)) 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_decl_initializer(c, param)) return poisoned_decl;
} }
} }
if (!parse_attributes(c, &param->attributes, NULL)) return false;
if (ellipsis) if (ellipsis)
{ {
var_arg_found = true; var_arg_found = true;
@@ -1486,8 +1474,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,
/** /**
* * fn_parameter_list ::= '(' parameters ')'
* parameter_type_list ::= '(' parameters ')'
*/ */
static inline bool parse_fn_parameter_list(ParseContext *c, Signature *signature, bool is_interface) 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) * func_header ::= optional_type (type '.')? IDENT
* macro_header ::= (type '!'?)? (type '.')? (IDENT | MACRO_IDENT) * macro_header ::= optional_type? (type '.')? (IDENT | MACRO_IDENT)
*/ */
static inline bool parse_func_macro_header(ParseContext *c, Decl *decl) 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 * enum_spec ::= type ('(' enum_params ')')?
* : type
* | type '(' opt_parameter_type_list ')'
* ;
*/ */
static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl*** parameters_ref) 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); ASSIGN_TYPE_OR_RET(*type_ref, parse_optional_type(c), false);
if ((*type_ref)->optional) if ((*type_ref)->optional)
{ {
SEMA_ERROR(*type_ref, "An enum can't have an optional type."); SEMA_ERROR(*type_ref, "An enum can't have an optional type.");
return false; return false;
} }
// If no left parenthesis we're done.
if (!try_consume(c, TOKEN_LPAREN)) return true; 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)) 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); Decl *last_parameter = VECLAST(*parameters_ref);
assert(last_parameter); 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; last_parameter->var.index = vec_size(*parameters_ref) - 1;
if (!try_consume(c, TOKEN_COMMA)) if (!try_consume(c, TOKEN_COMMA))
{ {
@@ -2263,25 +2244,13 @@ static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl***
return true; return true;
} }
/** /**
* Expect current at enum name. * Parse an enum declaration (after "enum")
*
* 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 ')'
* ;
* *
* 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) 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; if (!consume_type_name(c, "enum")) return poisoned_decl;
TypeInfo *type = NULL; TypeInfo *type = NULL;
// Parse the spec
if (try_consume(c, TOKEN_COLON)) if (try_consume(c, TOKEN_COLON))
{ {
if (!parse_enum_spec(c, &type, &decl->enums.parameters)) return poisoned_decl; 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); CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl);
decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span); decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span);
while (!try_consume(c, TOKEN_RBRACE)) while (!try_consume(c, TOKEN_RBRACE))
{ {
Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, symstr(c), c->span); 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 // --- Parse function
/** /**
* Starts after 'fn' * Starts after 'fn'
* *
@@ -2365,12 +2332,12 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
* @param visibility * @param visibility
* @return Decl* * @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); advance_and_verify(c, TOKEN_FN);
Decl *func = decl_calloc(); Decl *func = decl_calloc();
func->decl_kind = DECL_FUNC; 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 (!parse_func_macro_header(c, func)) return poisoned_decl;
if (func->name[0] == '@') if (func->name[0] == '@')
{ {

View File

@@ -47,7 +47,7 @@ Ast* parse_compound_stmt(ParseContext *c);
Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool require_eos); Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool require_eos);
Ast *parse_jump_stmt_no_eos(ParseContext *c); Ast *parse_jump_stmt_no_eos(ParseContext *c);
bool parse_attribute(ParseContext *c, Attr **attribute_ref); 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); bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type);
Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl); Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl);

View File

@@ -1605,7 +1605,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
decl->operator = OVERLOAD_LEN; decl->operator = OVERLOAD_LEN;
break; break;
case EXPR_OPERATOR_CHARS: case EXPR_OPERATOR_CHARS:
decl->operator = expr->expr_operator_chars; decl->operator = expr->overload_expr;
break; break;
default: default:
goto FAILED_OP_TYPE; goto FAILED_OP_TYPE;

View File

@@ -0,0 +1,4 @@
fn void test() abc::@inline // #error: Only user-defined attribute names
{
}

View File

@@ -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 TEST
} }
enum EnumWithErrorData : int (int // #error: end of the parameter list enum EnumWithErrorData : int (int
{ { // #error: Expected a member name here
TEST 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 TEST
} }