Skip to content

Commit

Permalink
Old style enum declaration for params/type, but now the type is optio…
Browse files Browse the repository at this point in the history
…nal. "Inline" replaced by @inline(field name)
  • Loading branch information
lerno committed Mar 8, 2024
1 parent 56f1a34 commit 5c3f07e
Show file tree
Hide file tree
Showing 20 changed files with 156 additions and 124 deletions.
2 changes: 1 addition & 1 deletion lib/std/net/inetaddr.c3
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module std::net;
import std::io;
import std::ascii;

enum IpProtocol : { AIFamily ai_family} char
enum IpProtocol : char (AIFamily ai_family)
{
UNSPECIFIED = os::AF_UNSPEC,
IPV4 = os::AF_INET,
Expand Down
2 changes: 1 addition & 1 deletion lib/std/net/socket.c3
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ macro Socket new_socket(fd, ai)
return sock;
}

enum SocketOption : { CInt value } char
enum SocketOption : char (CInt value)
{
REUSEADDR = os::SO_REUSEADDR,
REUSEPORT @if(!env::WIN32) = os::SO_REUSEPORT,
Expand Down
2 changes: 1 addition & 1 deletion releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
- `any*` => `any`, same for interfaces.
- Private / local globals now have `internal` visibility in LLVM.
- Updated enum syntax.
- `inline` on function parameters for implicit conversions.
- 'rgba' also available for swizzling.
- The name "subarray" has been replaced by the more well known name "slice' across the codebase.
- Improved alignment handling.
- Add `--output-dir` to command line. #1155
- `@inline()` parameter attribute for extern functions.

### Fixes
- Fixed issue in safe mode when converting enums.
Expand Down
18 changes: 6 additions & 12 deletions resources/grammar/grammar.y
Original file line number Diff line number Diff line change
Expand Up @@ -493,9 +493,7 @@ identifier_list
;

enum_param_decl
: type
| type IDENT
| type IDENT '=' expr
: type IDENT
;

base_type
Expand Down Expand Up @@ -1016,10 +1014,6 @@ enum_params
| enum_params ',' enum_param_decl
;

enum_param_list
: '{' enum_params '}'
;

struct_member_decl
: type identifier_list opt_attributes ';'
| struct_or_union IDENT opt_attributes struct_body
Expand All @@ -1031,14 +1025,14 @@ struct_member_decl
;

enum_spec
: ':' enum_param_list opt_attributes
| ':' enum_param_list base_type opt_attributes
| ':' base_type opt_attributes
| opt_attributes
: ':' base_type '(' enum_params ')'
| ':' base_type
| ':' '(' enum_params ')'
;

enum_declaration
: ENUM TYPE_IDENT opt_interface_impl enum_spec '{' enum_list '}'
: ENUM TYPE_IDENT opt_interface_impl enum_spec opt_attributes '{' enum_list '}'
| ENUM TYPE_IDENT opt_interface_impl opt_attributes '{' enum_list '}'
;

faults
Expand Down
3 changes: 1 addition & 2 deletions src/compiler/compiler_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ typedef struct VarDecl_
bool is_threadlocal : 1;
bool no_init : 1;
bool bit_is_expr : 1;
bool is_inline : 1;
bool is_inline_fold : 1;
TypeInfoId type_info;
union
{
Expand Down Expand Up @@ -2403,7 +2403,6 @@ Type *type_find_largest_union_element(Type *type);
Type *type_find_max_type(Type *type, Type *other);
Type *type_find_max_type_may_fail(Type *type, Type *other);
Type *type_abi_find_single_struct_element(Type *type);
Type *type_inline_type(Type *type);
Module *type_base_module(Type *type);
bool type_is_valid_for_vector(Type *type);
bool type_is_valid_for_array(Type *type);
Expand Down
1 change: 0 additions & 1 deletion src/compiler/json_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ static inline void emit_func_data(FILE *file, Module *module, Decl *func)
if (!decl) continue;
fputs("\t\t\t\t{\n", file);
fprintf(file, "\t\t\t\t\t\"name\": \"%s\",\n", decl->name ? decl->name : "");
fprintf(file, "\t\t\t\t\t\"inline\": \"%s\",\n", decl->var.is_inline ? "false" : "true");
fprintf(file, "\t\t\t\t\t\"type\": \"");
if (decl->var.type_info)
{
Expand Down
31 changes: 10 additions & 21 deletions src/compiler/parse_global.c
Original file line number Diff line number Diff line change
Expand Up @@ -1133,21 +1133,20 @@ static inline Decl *parse_global_declaration(ParseContext *c)


/**
* enum_param_decl ::= type IDENT ('=' expr)?
* enum_param_decl ::= type IDENT attributes?
*/
static inline bool parse_enum_param_decl(ParseContext *c, Decl*** parameters)
{
bool is_inline = try_consume(c, TOKEN_INLINE);
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), false);
if (type->optional) RETURN_SEMA_ERROR(type, "Parameters may not be optional.");
Decl *param = decl_new_var_current(c, type, VARDECL_PARAM);
if (is_inline) param->var.is_inline = is_inline;
if (!try_consume(c, TOKEN_IDENT))
{
if (token_is_keyword_ident(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.");
}
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL)) return false;
vec_add(*parameters, param);
RANGE_EXTEND_PREV(param);
return true;
Expand Down Expand Up @@ -1226,7 +1225,6 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,

// Now we have the following possibilities: "foo", "Foo foo", "Foo... foo", "foo...", "Foo"
TypeInfo *type = NULL;
bool is_inline = try_consume(c, TOKEN_INLINE);
if (parse_next_is_typed_parameter(c, parse_kind))
{
// Parse the type,
Expand All @@ -1248,10 +1246,6 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params,
*variadic = VARIADIC_TYPED;
}
}
else
{
if (is_inline) RETURN_SEMA_ERROR_HERE("'inline' can only preceed a type.");
}
// We have parsed the optional type, next get the optional variable name
VarDeclKind param_kind;
const char *name = NULL;
Expand Down Expand Up @@ -1375,11 +1369,6 @@ 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 ? type_infoid(type) : 0;
if (is_inline)
{
assert(type);
param->var.is_inline = true;
}
if (!parse_attributes(c, &param->attributes, NULL, NULL, NULL)) return false;
if (!no_name)
{
Expand Down Expand Up @@ -2165,18 +2154,17 @@ static inline Decl *parse_fault_declaration(ParseContext *c)
static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref)
{
// If no left parenthesis we're done.
if (!try_consume(c, TOKEN_LBRACE)) 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_RBRACE))
while (!try_consume(c, TOKEN_RPAREN))
{
if (!parse_enum_param_decl(c, parameters_ref)) return false;
Decl *last_parameter = VECLAST(*parameters_ref);
assert(last_parameter);
last_parameter->var.index = vec_size(*parameters_ref) - 1;
if (!try_consume(c, TOKEN_COMMA))
{
EXPECT_OR_RET(TOKEN_RBRACE, false);
EXPECT_OR_RET(TOKEN_RPAREN, false);
}
}
return true;
Expand All @@ -2186,7 +2174,7 @@ static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref
/**
* Parse an enum declaration (after "enum")
*
* enum ::= ENUM TYPE_IDENT opt_interfaces (':' enum_param_list? type?)? opt_attributes '{' enum_body '}'
* enum ::= ENUM TYPE_IDENT opt_interfaces (':' type? enum_param_list?)? opt_attributes '{' enum_body '}'
* enum_body ::= enum_def (',' enum_def)* ','?
* enum_def ::= CONST_IDENT ('(' arg_list ')')?
*/
Expand All @@ -2199,11 +2187,10 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
if (!parse_interface_impls(c, &decl->interfaces)) return poisoned_decl;

TypeInfo *type = NULL;
// Parse the spec

if (try_consume(c, TOKEN_COLON))
{
if (!parse_enum_param_list(c, &decl->enums.parameters)) return poisoned_decl;
if (!decl->enums.parameters || !tok_is(c, TOKEN_LBRACE))
if (!tok_is(c, TOKEN_LPAREN) && !tok_is(c, TOKEN_LBRACE))
{
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), poisoned_decl);
if (type->optional)
Expand All @@ -2212,7 +2199,9 @@ static inline Decl *parse_enum_declaration(ParseContext *c)
return poisoned_decl;
}
}
if (!parse_enum_param_list(c, &decl->enums.parameters)) return poisoned_decl;
}

if (!parse_attributes_for_global(c, decl)) return poisoned_decl;
unsigned expected_parameters = vec_size(decl->enums.parameters);
Visibility visibility = decl->visibility;
Expand Down
122 changes: 90 additions & 32 deletions src/compiler/sema_decls.c
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,54 @@ static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase
return decl_poison(decl);
}

INLINE Decl *sema_member_decl_for_name(Type *type, const char *name)
{
RETRY:
switch (type->type_kind)
{
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
case TYPE_POISONED:
case TYPE_VOID:
case TYPE_BOOL:
case ALL_INTS:
case ALL_FLOATS:
case TYPE_ANYFAULT:
case TYPE_TYPEID:
case TYPE_POINTER:
case TYPE_FUNC:
case TYPE_FAULTTYPE:
case TYPE_ARRAY:
case TYPE_FLEXIBLE_ARRAY:
case TYPE_INFERRED_ARRAY:
case TYPE_VECTOR:
case TYPE_INFERRED_VECTOR:
case TYPE_UNTYPED_LIST:
case TYPE_OPTIONAL:
case TYPE_WILDCARD:
case TYPE_TYPEINFO:
case TYPE_MEMBER:
case TYPE_SLICE:
case TYPE_ANY:
case TYPE_INTERFACE:
case TYPE_ENUM:
{
FOREACH_BEGIN(Decl *param, type->decl->enums.parameters)
if (param->name == name) return param;
FOREACH_END();
return NULL;
}
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_DISTINCT:
case TYPE_BITSTRUCT:
return sema_decl_stack_find_decl_member(type->decl, name);
default:
UNREACHABLE
}
}


static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfoId type_parent)
{
Expand Down Expand Up @@ -1096,23 +1144,26 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,

if (!type_info)
{
if (param->var.is_inline) RETURN_SEMA_ERROR(param, "An 'inline' parameter must be typed.");
if (param->var.is_inline_fold) RETURN_SEMA_ERROR(param, "An '@inline' parameter must be typed.");
}
else
{
if (!sema_resolve_type_structure(context, type_info->type, type_info->span)) return false;
if (param->var.is_inline)
if (param->var.is_inline_fold)
{
if (param->var.kind != VARDECL_PARAM && param->var.kind != VARDECL_PARAM_CT)
{
RETURN_SEMA_ERROR(param, "Only regular and constant parameters may be 'inline'.");
}
Type *type = type_info->type->canonical;
if (!(type_is_user_defined(type) && type->decl && type->decl->is_substruct))
{
RETURN_SEMA_ERROR(param, "The type must either be an enum with 'inline', an distinct 'inline' or a substruct.");
RETURN_SEMA_ERROR(param, "Only regular and constant parameters may use '@inline'.");
}
param->type = type_inline_type(type);
Attr *attr = attr_find_kind(param->attributes, ATTRIBUTE_INLINE);
assert(attr);
Expr *ident_expr = attr->exprs[0];
const char *ident = ident_expr->identifier_expr.ident;
Decl *decl = sema_member_decl_for_name(type_info->type, ident);
if (!decl) RETURN_SEMA_ERROR(param, "Type %s does not have a member '%s', please check your '@inline' attribute.",
type_quoted_error_string(type_info->type), ident);
ident_expr->identifier_expr.decl = decl;
param->type = decl->type;
}
else
{
Expand Down Expand Up @@ -1322,11 +1373,6 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era
break;
}
if (!sema_analyse_enum_param(context, value)) goto ERR;
if (value->var.is_inline)
{
if (i != 0) RETURN_SEMA_ERROR(value, "Only the first parameter may be declared 'inline'.");
decl->is_substruct = true;
}
value->resolve_status = RESOLVE_DONE;
}
sema_decl_stack_restore(state);
Expand Down Expand Up @@ -1627,23 +1673,21 @@ INLINE void sema_set_method_ext_name(CompilationUnit *unit, const char *parent_n

bool sema_decl_if_cond(SemaContext *context, Decl *decl)
{
FOREACH_BEGIN(Attr *attr, decl->attributes)
if (attr->attr_kind != ATTRIBUTE_IF) continue;
if (vec_size(attr->exprs) != 1)
{
RETURN_SEMA_ERROR(attr, "Expected an argument to '@if'.");
}
Expr *expr = attr->exprs[0];
if (!sema_analyse_ct_expr(context, expr)) return false;
if (expr->type->canonical != type_bool)
{
RETURN_SEMA_ERROR(expr, "Expected a boolean value not %s.", type_quoted_error_string(expr->type));
}
if (expr->const_expr.b) return true;
decl->decl_kind = DECL_ERASED;
return false;
FOREACH_END();
UNREACHABLE
Attr *attr = attr_find_kind(decl->attributes, ATTRIBUTE_IF);
assert(attr);
if (vec_size(attr->exprs) != 1)
{
RETURN_SEMA_ERROR(attr, "Expected an argument to '@if'.");
}
Expr *expr = attr->exprs[0];
if (!sema_analyse_ct_expr(context, expr)) return false;
if (expr->type->canonical != type_bool)
{
RETURN_SEMA_ERROR(expr, "Expected a boolean value not %s.", type_quoted_error_string(expr->type));
}
if (expr->const_expr.b) return true;
decl->decl_kind = DECL_ERASED;
return false;
}

INLINE Attr* method_find_overload_attribute(Decl *method)
Expand Down Expand Up @@ -2239,7 +2283,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_FINALIZER] = ATTR_FUNC,
[ATTRIBUTE_IF] = (AttributeDomain)~(ATTR_CALL | ATTR_LOCAL | ATTR_PARAM),
[ATTRIBUTE_INIT] = ATTR_FUNC,
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL | ATTR_PARAM,
[ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT,
[ATTRIBUTE_LOCAL] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES | ATTR_DEF | ATTR_INTERFACE,
[ATTRIBUTE_MAYDISCARD] = CALLABLE_TYPE,
Expand Down Expand Up @@ -2487,6 +2531,13 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
decl->func_decl.signature.attrs.maydiscard = true;
break;
case ATTRIBUTE_INLINE:
if (decl->decl_kind == DECL_VAR)
{
decl->var.is_inline_fold = true;
if (!expr) RETURN_SEMA_ERROR(attr, "Expected an identifier argument, like '@inline(foo)'.");
if (expr->expr_kind != EXPR_IDENTIFIER) RETURN_SEMA_ERROR(expr, "Expected an identifier like '@inline(foo)'.");
return true;
}
decl->func_decl.attr_inline = true;
decl->func_decl.attr_noinline = false;
break;
Expand Down Expand Up @@ -2554,6 +2605,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,

}


// TODO consider doing this evaluation early, it should be possible.
static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr **attrs, AttributeDomain domain,
Decl *top, bool *erase_decl)
Expand Down Expand Up @@ -3282,6 +3334,12 @@ static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bo
case VARDECL_GLOBAL:
domain = ATTR_GLOBAL;
break;
case VARDECL_PARAM:
case VARDECL_PARAM_REF:
case VARDECL_PARAM_CT_TYPE:
case VARDECL_PARAM_CT:
domain = ATTR_PARAM;
break;
default:
domain = ATTR_LOCAL;
break;
Expand Down
Loading

0 comments on commit 5c3f07e

Please sign in to comment.