mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Only rudimentary parsing of "private" in prefix location. Make contract handling more correct.
This commit is contained in:
@@ -21,14 +21,14 @@ void yyerror(char *s);
|
||||
%token XOR_ASSIGN OR_ASSIGN VAR NIL ELVIS NEXTCASE
|
||||
%token TYPEDEF MODULE IMPORT DEFINE
|
||||
%token CHAR SHORT INT LONG FLOAT DOUBLE CONST VOID
|
||||
%token BYTE USHORT UINT ULONG BOOL
|
||||
%token TYPEID
|
||||
%token ICHAR USHORT UINT ULONG BOOL INT128 UINT128 FLOAT16 FLOAT128
|
||||
%token TYPEID BITSTRUCT STATIC
|
||||
%token STRUCT UNION ENUM ELLIPSIS DOTDOT
|
||||
|
||||
%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
|
||||
%token TRY CATCH SCOPE PUBLIC DEFER ATTRIBUTE TRY_Q CATCH_Q LVEC RVEC OPTELSE
|
||||
%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 FN_BLOCK_START FN_BLOCK_END
|
||||
|
||||
@@ -270,18 +270,26 @@ base_type
|
||||
: VOID
|
||||
| BOOL
|
||||
| CHAR
|
||||
| BYTE
|
||||
| ICHAR
|
||||
| SHORT
|
||||
| USHORT
|
||||
| INT
|
||||
| UINT
|
||||
| LONG
|
||||
| ULONG
|
||||
| INT128
|
||||
| UINT128
|
||||
| FLOAT
|
||||
| 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 ')'
|
||||
;
|
||||
|
||||
type
|
||||
@@ -419,6 +427,37 @@ decl_expr_list
|
||||
| decl_expr_list ',' declaration
|
||||
;
|
||||
|
||||
ct_assert_stmt
|
||||
: CT_ASSERT '(' expression ',' expression ')' ';'
|
||||
| CT_ASSERT '(' expression ')' ';'
|
||||
;
|
||||
|
||||
ct_echo_stmt
|
||||
: CT_ECHO '(' expression ')' ';'
|
||||
|
||||
bitstruct_declaration
|
||||
: BITSTRUCT IDENT ':' type opt_attributes bitstruct_body
|
||||
|
||||
bitstruct_body
|
||||
: '{' '}'
|
||||
| '{' bitstruct_defs '}'
|
||||
;
|
||||
|
||||
bitstruct_defs
|
||||
: bitstruct_def
|
||||
| bitstruct_defs bitstruct_def
|
||||
;
|
||||
|
||||
bitstruct_def
|
||||
: type IDENT ':' constant_expression DOTDOT constant_expression ';'
|
||||
| type IDENT ':' constant_expression ';'
|
||||
;
|
||||
|
||||
static_declaration
|
||||
: STATIC INITIALIZE opt_attributes compound_statement
|
||||
| STATIC FINALIZE opt_attributes compound_statement
|
||||
;
|
||||
|
||||
for_statement
|
||||
: FOR '(' decl_expr_list ';' expression_statement ')' statement
|
||||
| FOR '(' decl_expr_list ';' expression_statement expression_list ')' statement
|
||||
@@ -627,6 +666,10 @@ top_level
|
||||
| macro_declaration
|
||||
| typedef_declaration
|
||||
| define_declaration
|
||||
| static_declaration
|
||||
| ct_assert_stmt
|
||||
| ct_echo_stmt
|
||||
| bitstruct_declaration
|
||||
;
|
||||
|
||||
|
||||
|
||||
@@ -487,20 +487,23 @@ bool parse_path_prefix(ParseContext *c, Path** path_ref)
|
||||
* base_type
|
||||
* : VOID
|
||||
* | BOOL
|
||||
* | ICHAR
|
||||
* | CHAR
|
||||
* | BYTE
|
||||
* | SHORT
|
||||
* | USHORT
|
||||
* | INT
|
||||
* | UINT
|
||||
* | LONG
|
||||
* | ULONG
|
||||
* | INT128
|
||||
* | UINT128
|
||||
* | FLOAT
|
||||
* | DOUBLE
|
||||
* | FLOAT16
|
||||
* | FLOAT128
|
||||
* | TYPE_IDENT
|
||||
* | ident_scope TYPE_IDENT
|
||||
* | CT_TYPE_IDENT
|
||||
* | VIRTUAL (ident_scope TYPE_IDENT)?
|
||||
* | CT_TYPEOF '(' expr ')'
|
||||
* | CT_EVALTYPE '(' expr ')'
|
||||
* ;
|
||||
@@ -2179,13 +2182,12 @@ static inline Decl *parse_macro_declaration(ParseContext *c, AstId docs)
|
||||
* | FAULT TYPE_IDENT '{' error_data '}'
|
||||
* ;
|
||||
*/
|
||||
static inline Decl *parse_fault_declaration(ParseContext *c, bool is_private)
|
||||
static inline Decl *parse_fault_declaration(ParseContext *c)
|
||||
{
|
||||
advance(c);
|
||||
// advance_and_verify(context, TOKEN_ERRTYPE);
|
||||
|
||||
Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_FAULT);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (!consume_type_name(c, "fault")) return poisoned_decl;
|
||||
|
||||
TypeInfo *type = NULL;
|
||||
@@ -2197,7 +2199,6 @@ static inline Decl *parse_fault_declaration(ParseContext *c, bool is_private)
|
||||
while (!try_consume(c, TOKEN_RBRACE))
|
||||
{
|
||||
Decl *fault_const = decl_new(DECL_FAULTVALUE, symstr(c), c->span);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (!consume_const_name(c, "fault value"))
|
||||
{
|
||||
return poisoned_decl;
|
||||
@@ -2282,12 +2283,11 @@ static inline bool parse_enum_spec(ParseContext *c, TypeInfo **type_ref, Decl***
|
||||
* ;
|
||||
*
|
||||
*/
|
||||
static inline Decl *parse_enum_declaration(ParseContext *c, bool is_private)
|
||||
static inline Decl *parse_enum_declaration(ParseContext *c)
|
||||
{
|
||||
advance_and_verify(c, TOKEN_ENUM);
|
||||
|
||||
Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_ENUM);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (!consume_type_name(c, "enum")) return poisoned_decl;
|
||||
|
||||
TypeInfo *type = NULL;
|
||||
@@ -2821,88 +2821,60 @@ END:
|
||||
}
|
||||
|
||||
/**
|
||||
* top_level_statement ::= visibility? top_level
|
||||
* top_level_statement ::= struct_declaration | enum_declaration | fault_declaration | const_declaration
|
||||
* | global_declaration | macro_declaration | func_definition | typedef_declaration
|
||||
* | conditional_compilation | define_declaration | import_declaration | module_declaration
|
||||
* | static_declaration | ct_assert_declaration | ct_echo_declaration | bitstruct_declaration
|
||||
*
|
||||
* top_level
|
||||
* : struct_declaration
|
||||
* | enum_declaration
|
||||
* | error_declaration
|
||||
* | const_declaration
|
||||
* | global_declaration
|
||||
* | macro_declaration
|
||||
* | func_definition
|
||||
* | generics_declaration
|
||||
* | typedef_declaration
|
||||
* | conditional_compilation
|
||||
* | attribute_declaration
|
||||
* ;
|
||||
* @param visibility
|
||||
* @return Decl* or a poison value if parsing failed
|
||||
*/
|
||||
Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref)
|
||||
{
|
||||
AstId docs = 0;
|
||||
if (!parse_contracts(c, &docs)) return poisoned_decl;
|
||||
AstId contracts = 0;
|
||||
if (!parse_contracts(c, &contracts)) return poisoned_decl;
|
||||
Decl *decl;
|
||||
bool is_private = try_consume(c, TOKEN_PRIVATE); // TODO remove
|
||||
if (is_private)
|
||||
{
|
||||
sema_warning_at(c->prev_span, "The use of 'private' is deprecated. Use '@private' instead.");
|
||||
}
|
||||
|
||||
TokenType tok = c->tok;
|
||||
if (tok != TOKEN_MODULE && !c->unit->module)
|
||||
{
|
||||
if (!context_set_module_from_filename(c)) return poisoned_decl;
|
||||
// Pass the docs to the next thing.
|
||||
}
|
||||
bool is_private = false;
|
||||
AFTER_VISIBILITY:
|
||||
|
||||
switch (tok)
|
||||
{
|
||||
case TOKEN_PRIVATE:
|
||||
if (is_private)
|
||||
{
|
||||
SEMA_ERROR_HERE("Two 'private' modifiers cannot be used in a row.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
sema_warning_at(c->span, "The use of 'private' is deprecated. Use '@private' instead.");
|
||||
is_private = true;
|
||||
advance(c);
|
||||
tok = c->tok;
|
||||
goto AFTER_VISIBILITY;
|
||||
case TOKEN_EXTERN:
|
||||
if (is_private)
|
||||
{
|
||||
SEMA_ERROR_HERE("'private' cannot be combined with 'extern'.");
|
||||
}
|
||||
// Extern declarations
|
||||
advance(c);
|
||||
tok = c->tok;
|
||||
switch (tok)
|
||||
{
|
||||
case TOKEN_FN:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_func_definition(c, docs, false), poisoned_decl);
|
||||
decl = parse_func_definition(c, contracts, false);
|
||||
break;
|
||||
}
|
||||
case TOKEN_CONST:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_top_level_const_declaration(c), poisoned_decl);
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_top_level_const_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_TLOCAL:
|
||||
case TYPELIKE_TOKENS:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_global_declaration(c), poisoned_decl);
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_global_declaration(c);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SEMA_ERROR_HERE("Expected 'extern' to be followed by a function, constant or global variable.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!decl_ok(decl)) return decl;
|
||||
decl->is_extern = true;
|
||||
break;
|
||||
case TOKEN_MODULE:
|
||||
if (is_private)
|
||||
{
|
||||
SEMA_ERROR_HERE("Did not expect 'private' before 'module'.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!c_ref)
|
||||
{
|
||||
SEMA_ERROR_HERE("'module' cannot appear inside of conditional compilation.");
|
||||
@@ -2911,167 +2883,101 @@ AFTER_VISIBILITY:
|
||||
advance(c);
|
||||
if (c->unit->module)
|
||||
{
|
||||
// We might run into another module declaration. If so, create a new unit.
|
||||
ParseContext *new_context = CALLOCS(ParseContext);
|
||||
*new_context = *c;
|
||||
new_context->unit = unit_create(c->unit->file);
|
||||
*c_ref = c = new_context;
|
||||
}
|
||||
if (!parse_module(c, docs)) return poisoned_decl;
|
||||
if (!parse_module(c, contracts)) return poisoned_decl;
|
||||
return NULL;
|
||||
case TOKEN_DOCS_START:
|
||||
if (is_private)
|
||||
{
|
||||
SEMA_ERROR_HERE("Did not expect doc comments after 'private'.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
SEMA_ERROR_HERE("There are more than one doc comment in a row, that is not allowed.");
|
||||
return poisoned_decl;
|
||||
case TOKEN_TYPEDEF:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_define_type(c), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_define_type(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_DEFINE:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_define(c), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_define(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_FN:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_func_definition(c, docs, false), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
decl = parse_func_definition(c, contracts, false);
|
||||
break;
|
||||
}
|
||||
case TOKEN_STATIC:
|
||||
{
|
||||
if (!check_no_visibility_before(c, is_private)) return poisoned_decl;
|
||||
ASSIGN_DECL_OR_RET(decl, parse_static_top_level(c), poisoned_decl);
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before 'static', did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_static_top_level(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_CT_ASSERT:
|
||||
if (!check_no_visibility_before(c, is_private)) return poisoned_decl;
|
||||
{
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
ASSIGN_AST_OR_RET(Ast *ast, parse_ct_assert_stmt(c), poisoned_decl);
|
||||
decl = decl_new_ct(DECL_CT_ASSERT, ast->span);
|
||||
decl->ct_assert_decl = ast;
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before $assert, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
case TOKEN_CT_ECHO:
|
||||
if (!check_no_visibility_before(c, is_private)) return poisoned_decl;
|
||||
{
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
ASSIGN_AST_OR_RET(Ast *ast, parse_ct_echo_stmt(c), poisoned_decl);
|
||||
decl = decl_new_ct(DECL_CT_ECHO, ast->span);
|
||||
decl->ct_echo_decl = ast;
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before $echo, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
return decl;
|
||||
break;
|
||||
}
|
||||
case TOKEN_CT_IF:
|
||||
{
|
||||
if (!check_no_visibility_before(c, is_private)) return poisoned_decl;
|
||||
ASSIGN_DECL_OR_RET(decl, parse_ct_if_top_level(c), poisoned_decl);
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before $if, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_ct_if_top_level(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_IMPORT:
|
||||
if (!check_no_visibility_before(c, is_private)) return poisoned_decl;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
if (!c_ref)
|
||||
{
|
||||
SEMA_ERROR_HERE("'import' may not appear inside a compile time statement.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!parse_import(c)) return poisoned_decl;
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before import, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
return NULL;
|
||||
case TOKEN_CT_SWITCH:
|
||||
{
|
||||
if (!check_no_visibility_before(c, is_private)) return poisoned_decl;
|
||||
ASSIGN_DECL_OR_RET(decl, parse_ct_switch_top_level(c), poisoned_decl);
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before $switch, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_ct_switch_top_level(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_CT_INCLUDE:
|
||||
if (!check_no_visibility_before(c, is_private)) return poisoned_decl;
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before $include, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
ASSIGN_DECL_OR_RET(decl, parse_include(c), poisoned_decl);
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_include(c);
|
||||
break;
|
||||
case TOKEN_BITSTRUCT:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_bitstruct_declaration(c), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_bitstruct_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_CONST:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_top_level_const_declaration(c), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_top_level_const_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_STRUCT:
|
||||
case TOKEN_UNION:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_struct_declaration(c), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_struct_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_MACRO:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_macro_declaration(c, docs), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
decl = parse_macro_declaration(c, contracts);
|
||||
break;
|
||||
}
|
||||
case TOKEN_ENUM:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_enum_declaration(c, is_private), poisoned_decl);
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_enum_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_FAULT:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_fault_declaration(c, is_private), poisoned_decl);
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_fault_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_IDENT:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_global_declaration(c), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_global_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_EOF:
|
||||
SEMA_ERROR_LAST("Expected a top level declaration");
|
||||
SEMA_ERROR_LAST("Expected a top level declaration.");
|
||||
return poisoned_decl;
|
||||
case TOKEN_CT_CONST_IDENT:
|
||||
{
|
||||
if (peek(c) == TOKEN_EQ)
|
||||
{
|
||||
SEMA_ERROR_HERE("Did you forget a 'const' before the name of this compile time constant?");
|
||||
@@ -3080,15 +2986,12 @@ AFTER_VISIBILITY:
|
||||
{
|
||||
SEMA_ERROR_HERE("Compile time constant unexpectedly found.");
|
||||
}
|
||||
}
|
||||
return poisoned_decl;
|
||||
case TOKEN_TLOCAL:
|
||||
case TYPELIKE_TOKENS:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_global_declaration(c), poisoned_decl);
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE;
|
||||
if (contracts) goto CONTRACT_NOT_ALLOWED;
|
||||
decl = parse_global_declaration(c);
|
||||
break;
|
||||
}
|
||||
case TOKEN_EOS:
|
||||
SEMA_ERROR_HERE("';' wasn't expected here, try removing it.");
|
||||
return poisoned_decl;
|
||||
@@ -3096,8 +2999,13 @@ AFTER_VISIBILITY:
|
||||
SEMA_ERROR_HERE("Expected the start of a global declaration here.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!decl_ok(decl)) return decl;
|
||||
if (is_private) decl->visibility = VISIBLE_PRIVATE; // TODO remove
|
||||
assert(decl);
|
||||
return decl;
|
||||
CONTRACT_NOT_ALLOWED:
|
||||
SEMA_ERROR(astptr(contracts), "Contracts are only used for modules, functions and macros.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
void consume_deprecated_symbol(ParseContext *c, TokenType type)
|
||||
|
||||
Reference in New Issue
Block a user