Example #1
0
// Check whether the given entity has illegal parts
static ast_result_t syntax_entity(ast_t* ast, int entity_def_index)
{
  assert(ast != NULL);
  assert(entity_def_index >= 0 && entity_def_index < DEF_ENTITY_COUNT);
  ast_result_t r = AST_OK;

  const permission_def_t* def = &_entity_def[entity_def_index];
  AST_GET_CHILDREN(ast, id, typeparams, defcap, provides, members, c_api);

  // Check if we're called Main
  if(def->permissions[ENTITY_MAIN] == 'N' && ast_name(id) == stringtab("Main"))
  {
    ast_error(ast, "Main must be an actor");
    r = AST_ERROR;
  }

  if(!check_id_type(id, def->desc))
    r = AST_ERROR;

  if(!check_permission(def, ENTITY_CAP, defcap, "default capability", defcap))
    r = AST_ERROR;

  if(!check_permission(def, ENTITY_C_API, c_api, "C api", c_api))
    r = AST_ERROR;

  if(ast_id(c_api) == TK_AT)
  {
    if(ast_id(typeparams) != TK_NONE)
    {
      ast_error(typeparams, "generic actor cannot specify C api");
      r = AST_ERROR;
    }
  }

  if(entity_def_index != DEF_TYPEALIAS)
  {
    // Check referenced traits
    if(ast_id(provides) != TK_NONE &&
      !check_provides_type(provides, "provides"))
      r = AST_ERROR;
  }
  else
  {
    // Check for a type alias
    if(ast_id(provides) == TK_NONE)
    {
      ast_error(provides, "a type alias must specify a type");
      r = AST_ERROR;
    }
  }

  // Check for illegal members
  if(!check_members(members, entity_def_index))
    r = AST_ERROR;

  return r;
}
Example #2
0
// Check whether the given node is a valid provides type
static bool check_provides_type(pass_opt_t* opt, ast_t* type,
  const char* description)
{
  assert(type != NULL);
  assert(description != NULL);

  switch(ast_id(type))
  {
    case TK_NOMINAL:
    {
      AST_GET_CHILDREN(type, ignore0, ignore1, ignore2, cap, ephemeral);

      if(ast_id(cap) != TK_NONE)
      {
        ast_error(opt->check.errors, cap,
          "can't specify a capability in a provides type");
        return false;
      }

      if(ast_id(ephemeral) != TK_NONE)
      {
        ast_error(opt->check.errors, ephemeral,
          "can't specify ephemeral in a provides type");
        return false;
      }

      return true;
    }

    case TK_PROVIDES:
    case TK_ISECTTYPE:
      // Check all our children are also legal
      for(ast_t* p = ast_child(type); p != NULL; p = ast_sibling(p))
      {
        if(!check_provides_type(opt, p, description))
          return false;
      }

      return true;

    default:
      ast_error(opt->check.errors, type, "invalid %s type. Can only be "
        "interfaces, traits and intersects of those.", description);
      return false;
  }
}
Example #3
0
// Check whether the given entity members are legal in their entity
static bool check_members(pass_opt_t* opt, ast_t* members, int entity_def_index)
{
  assert(members != NULL);
  assert(entity_def_index >= 0 && entity_def_index < DEF_ENTITY_COUNT);
  bool r = true;

  const permission_def_t* def = &_entity_def[entity_def_index];
  ast_t* member = ast_child(members);

  while(member != NULL)
  {
    switch(ast_id(member))
    {
      case TK_FLET:
      case TK_FVAR:
      case TK_EMBED:
      {
        if(def->permissions[ENTITY_FIELD] == 'N')
        {
          ast_error(opt->check.errors, member,
            "Can't have fields in %s", def->desc);
          r = false;
        }

        if((ast_id(ast_parent(members)) == TK_OBJECT) && \
          (ast_id(ast_childidx(member, 2)) == TK_NONE))
        {
          ast_error(opt->check.errors, member,
            "object literal fields must be initialized");
          r = false;
        }

        if(!check_id_field(opt, ast_child(member)))
          r = false;

        ast_t* delegate_type = ast_childidx(member, 3);
        if(ast_id(delegate_type) != TK_NONE &&
          !check_provides_type(opt, delegate_type, "delegate"))
          r = false;
        break;
      }

      case TK_NEW:
        if(!check_method(opt, member, entity_def_index + DEF_NEW))
          r = false;
        break;

      case TK_BE:
      {
        if(!check_method(opt, member, entity_def_index + DEF_BE))
          r = false;
        break;
      }

      case TK_FUN:
      {
        if(!check_method(opt, member, entity_def_index + DEF_FUN))
          r = false;
        break;
      }

      default:
        ast_print(members);
        assert(0);
        return false;
    }

    member = ast_sibling(member);
  }

  return r;
}