示例#1
0
文件: ifdef.c 项目: Theodus/ponyc
// Evaluate the given ifdef condition for the given config, or our target build
// if no config is given.
static bool cond_eval(ast_t* ast, buildflagset_t* config, bool release,
  pass_opt_t* opt)
{
  pony_assert(ast != NULL);

  switch(ast_id(ast))
  {
    case TK_NONE:
      // No condition to evaluate
      return true;

    case TK_IFDEFAND:
    {
      AST_GET_CHILDREN(ast, left, right);
      return cond_eval(left, config, release, opt) &&
        cond_eval(right, config, release, opt);
    }

    case TK_IFDEFOR:
    {
      AST_GET_CHILDREN(ast, left, right);
      return cond_eval(left, config, release, opt) ||
        cond_eval(right, config, release, opt);
    }

    case TK_IFDEFNOT:
      return !cond_eval(ast_child(ast), config, release, opt);

    case TK_IFDEFFLAG:
    {
      const char* name = ast_name(ast_child(ast));

      if(config != NULL)
        // Lookup flag in given config.
        return buildflagset_get(config, name);

      // No config given, lookup platform flag for current build.
      bool val;
      if(os_is_target(name, release, &val, opt))
      {
        return val;
      }

      // Not a platform flag, must be a user flag.
      return is_build_flag_defined(name);
    }

    default:
      pony_assert(0);
      return false;
  }
}
示例#2
0
文件: ifdef.c 项目: Theodus/ponyc
bool ifdef_cond_normalise(ast_t** astp, pass_opt_t* opt)
{
  pony_assert(astp != NULL);
  pony_assert(*astp != NULL);

  if(ast_id(*astp) == TK_NONE)  // No condition to normalise.
    return true;

  cond_normalise(astp);

  // Check whether condition can ever be true.
  buildflagset_t* config = buildflagset_create();
  find_flags_in_cond(*astp, config);
  check_config_count(config, *astp);
  buildflagset_startenum(config);

  while(buildflagset_next(config))
  {
    if(cond_eval(*astp, config, false, opt))
    {
      // Condition is true for this config.
      buildflagset_free(config);
      return true;
    }
  }

  // Condition isn't true for any configs.
  buildflagset_free(config);
  return false;
}
示例#3
0
文件: ifdef.c 项目: Theodus/ponyc
bool ifdef_cond_eval(ast_t* ast, pass_opt_t* opt)
{
  pony_assert(ast != NULL);

  if(ast_id(ast) == TK_NONE)  // No condition to evaluate
    return true;

  return cond_eval(ast, NULL, opt->release, opt);
}
示例#4
0
文件: ifdef.c 项目: Theodus/ponyc
// Find the declaration for the given FFI call that is valid for the given
// build config, within the specified ifdef condition (NULL for none).
// Returns: true on success, false on failure.
static bool find_ffi_decl(ast_t* ast, ast_t* package, ast_t* ifdef_cond,
  ast_t** out_decl, pass_opt_t* opt)
{
  pony_assert(ast != NULL);
  pony_assert(package != NULL);
  pony_assert(out_decl != NULL);

  const char* ffi_name = ast_name(ast_child(ast));
  buildflagset_t* config = buildflagset_create();

  // Find all the relevant build flags.
  if(ifdef_cond != NULL)
    find_flags_in_cond(ifdef_cond, config);

  if(!find_decl_flags(package, ffi_name, config))
  {
    // There are no declarations for this FFI.
    buildflagset_free(config);
    *out_decl = NULL;
    return true;
  }

  check_config_count(config, ast);
  ffi_decl_t decl_info = { NULL, NULL };
  buildflagset_startenum(config);

  while(buildflagset_next(config))
  {
    if(ifdef_cond == NULL || cond_eval(ifdef_cond, config, false, opt))
    {
      // ifdef condition true, or not in an ifdef.
      // Look for valid FFI declaration.
      if(!find_decl_for_config(ast, package, ffi_name, config, &decl_info, opt))
      {
        // Config has failed.
        buildflagset_free(config);
        return false;
      }

      pony_assert(decl_info.decl != NULL);
    }
  }

  buildflagset_free(config);
  pony_assert(decl_info.decl != NULL);
  *out_decl = decl_info.decl;
  return true;
}
示例#5
0
文件: ifdef.c 项目: Theodus/ponyc
// Find the declaration for the specified FFI name that is valid for the given
// build config.
// The declaration found is stored in the given decl info argument.
// There must be exactly one valid declaration.
// If a declaration is already specified in the given decl info this must be
// the same as the one found.
// All other cases are errors, which will be reported by this function.
// Returns: true on success, false on failure.
static bool find_decl_for_config(ast_t* call, ast_t* package,
  const char* ffi_name, buildflagset_t* config, ffi_decl_t* decl_info,
  pass_opt_t* opt)
{
  pony_assert(call != NULL);
  pony_assert(package != NULL);
  pony_assert(ffi_name != NULL);
  pony_assert(config != NULL);
  pony_assert(decl_info != NULL);

  bool had_valid_decl = false;

  // FFI declarations are package wide, so check all modules in package.
  for(ast_t* m = ast_child(package); m != NULL; m = ast_sibling(m))
  {
    // Find all the FFI declarations in this module.
    for(ast_t* use = ast_child(m); use != NULL; use = ast_sibling(use))
    {
      if(ast_id(use) == TK_USE)
      {
        AST_GET_CHILDREN(use, alias, decl, guard);

        if(ast_id(decl) == TK_FFIDECL && ffi_name == ast_name(ast_child(decl)))
        {
          // We have an FFI declaration for the specified name.
          if(cond_eval(guard, config, false, opt))
          {
            // This declaration is valid for this config.
            had_valid_decl = true;

            if(decl_info->decl != NULL)
            {
              // We already have a decalaration, is it the same one?
              if(decl_info->decl != decl)
              {
                ast_error(opt->check.errors, call,
                  "Multiple possible declarations for FFI call");
                ast_error_continue(opt->check.errors, decl_info->decl,
                  "This declaration valid for config: %s", decl_info->config);
                ast_error_continue(opt->check.errors, decl,
                  "This declaration valid for config: %s",
                  buildflagset_print(config));
                return false;
              }
            }
            else
            {
              // Store the declaration found.
              // We store the config string incase we need it for error
              // messages later. We stringtab it because the version we are
              // given is in a temporary buffer.
              decl_info->decl = decl;
              decl_info->config = stringtab(buildflagset_print(config));
            }
          }
        }
      }
    }
  }

  if(!had_valid_decl)
  {
    ast_error(opt->check.errors, call,
      "No FFI declaration found for '%s' in config: %s", ffi_name,
      buildflagset_print(config));
    return false;
  }

  return true;
}
示例#6
0
文件: cond.c 项目: B1gSmoke/autotools
int mdb_cond_evaluate(mdb_table_t *tbl, mqi_cond_entry_t **cond_ptr,void *data)
{
    static int precedence[mqi_operator_max] = {
        [ mqi_done  ] = 0,
        [ mqi_begin ] = 1,
        [ mqi_and   ] = 2,
        [ mqi_or    ] = 3,
        [ mqi_less  ] = 4,
        [ mqi_leq   ] = 4,
        [ mqi_eq    ] = 4,
        [ mqi_geq   ] = 4,
        [ mqi_gt    ] = 4,
        [ mqi_not   ] = 5
    };

    mqi_cond_entry_t *cond       = *cond_ptr;
    cond_stack_t      stack[256] = {
        [0] = { precedence[mqi_begin], { .operator = mqi_begin } }
    };
    cond_stack_t     *sp         = stack + 1;
    cond_stack_t     *lastop     = stack;
    int               result;
    int               pr;

    MDB_CHECKARG(cond && data, -1);

    for (;;) {
        switch (cond->type) {

        case mqi_operator:
            pr  = precedence[cond->u.operator];
            sp += cond_eval(sp, lastop, pr);

            switch (cond->u.operator) {

            case mqi_begin:
                cond++;
                result = mdb_cond_evaluate(tbl, &cond, data);
                cond++;

                sp->data.v.integer = result >= 0 ? result : 0;
                sp->precedence   = PRECEDENCE_DATA;
                sp->data.type    = mqi_integer;
                sp++;
                break;

            case mqi_end:
                *cond_ptr = cond+1;
                sp--;
                if (sp->precedence < PRECEDENCE_DATA ||
                    sp->data.type != mqi_integer)
                {
                    errno = ENOENT;
                    return -1;
                }
                return sp->data.v.integer ? 1 : 0;

            case mqi_and:
            case mqi_or:
            case mqi_less:
            case mqi_leq:
            case mqi_eq:
            case mqi_geq:
            case mqi_gt:
            case mqi_not:
                lastop = sp++;
                lastop->precedence = pr;
                lastop->operator = cond->u.operator;
                cond++;
                break;

            default:
                break;
            }
            break;

        case mqi_variable:
        case mqi_column:
            sp += cond_get_data(sp, cond, tbl->columns, data);
            cond++;
            break;

        default:
            errno = EINVAL;
            return -1;
        }

    } /* for ;; */
}