Exemple #1
0
bool genexe(compile_t* c, ast_t* program)
{
  // The first package is the main package. It has to have a Main actor.
  const char* main_actor = stringtab("Main");
  const char* env_class = stringtab("Env");

  ast_t* package = ast_child(program);
  ast_t* main_def = ast_get(package, main_actor, NULL);

  if(main_def == NULL)
  {
    errorf(NULL, "no Main actor found in package '%s'", c->filename);
    return false;
  }

  // Generate the Main actor and the Env class.
  ast_t* main_ast = type_builtin(c->opt, main_def, main_actor);
  ast_t* env_ast = type_builtin(c->opt, main_def, env_class);

  genprim_reachable_init(c, program);
  reach(c->reachable, main_ast, stringtab("create"), NULL);
  reach(c->reachable, env_ast, stringtab("_create"), NULL);
  paint(c->reachable);

  gentype_t main_g;
  gentype_t env_g;

  bool ok = gentype(c, main_ast, &main_g) && gentype(c, env_ast, &env_g);

  if(ok)
    gen_main(c, &main_g, &env_g);

  ast_free_unattached(main_ast);
  ast_free_unattached(env_ast);

  if(!ok)
    return false;

  if(!genopt(c))
    return false;

  const char* file_o = genobj(c);

  if(file_o == NULL)
    return false;

  if(c->opt->limit < PASS_ALL)
    return true;

  if(!link_exe(c, program, file_o))
    return false;

#ifdef PLATFORM_IS_WINDOWS
  _unlink(file_o);
#else
  unlink(file_o);
#endif

  return true;
}
Exemple #2
0
bool codegen_gen_test(compile_t* c, ast_t* program, pass_opt_t* opt,
  pass_id last_pass)
{
  if(last_pass < PASS_REACH)
  {
    memset(c, 0, sizeof(compile_t));

    genned_strings_init(&c->strings, 64);
    ffi_decls_init(&c->ffi_decls, 64);

    if(!init_module(c, program, opt))
      return false;

    init_runtime(c);
    genprim_reachable_init(c, program);

    const char* main_actor = c->str_Main;
    const char* env_class = c->str_Env;

    ast_t* package = ast_child(program);
    ast_t* main_def = ast_get(package, main_actor, NULL);

    if(main_def == NULL)
      return false;

    ast_t* main_ast = type_builtin(opt, main_def, main_actor);
    ast_t* env_ast = type_builtin(opt, main_def, env_class);

    if(lookup(opt, main_ast, main_ast, c->str_create) == NULL)
      return false;

    reach(c->reach, main_ast, c->str_create, NULL, opt);
    reach(c->reach, env_ast, c->str__create, NULL, opt);
    reach_done(c->reach, c->opt);
  }

  if(opt->limit == PASS_REACH)
    return true;

  if(last_pass < PASS_PAINT)
    paint(&c->reach->types);

  if(opt->limit == PASS_PAINT)
    return true;

  if(!gentypes(c))
    return false;

  return true;
}
Exemple #3
0
static bool reachable_methods(compile_t* c, ast_t* ast)
{
  ast_t* id = ast_child(ast);
  ast_t* type = type_builtin(c->opt, ast, ast_name(id));

  ast_t* def = (ast_t*)ast_data(type);
  ast_t* members = ast_childidx(def, 4);
  ast_t* member = ast_child(members);

  while(member != NULL)
  {
    switch(ast_id(member))
    {
      case TK_NEW:
      case TK_BE:
      case TK_FUN:
      {
        AST_GET_CHILDREN(member, cap, m_id, typeparams);

        // Mark all non-polymorphic methods as reachable.
        if(ast_id(typeparams) == TK_NONE)
          reach(c->reach, type, ast_name(m_id), NULL, c->opt);
        break;
      }

      default: {}
    }

    member = ast_sibling(member);
  }

  ast_free_unattached(type);
  return true;
}
Exemple #4
0
bool expr_digestof(pass_opt_t* opt, ast_t* ast)
{
  ast_t* expr = ast_child(ast);

  switch(ast_id(expr))
  {
    case TK_FVARREF:
    case TK_FLETREF:
    case TK_EMBEDREF:
    case TK_VARREF:
    case TK_LETREF:
    case TK_PARAMREF:
    case TK_THIS:
      break;

    default:
      ast_error(opt->check.errors, ast,
        "can only get the digest of a field, local, parameter or this");
      return false;
  }

  // Set the type to U64.
  ast_t* type = type_builtin(opt, expr, "U64");
  ast_settype(ast, type);
  return true;
}
Exemple #5
0
bool expr_identityof(pass_opt_t* opt, ast_t* ast)
{
  ast_t* expr = ast_child(ast);

  switch(ast_id(expr))
  {
    case TK_FVARREF:
    case TK_FLETREF:
    case TK_EMBEDREF:
    case TK_VARREF:
    case TK_LETREF:
    case TK_PARAMREF:
    case TK_THIS:
      break;

    default:
      ast_error(ast, "identity must be for a field, local, parameter or this");
      return false;
  }

  // Set the type to U64.
  ast_t* type = type_builtin(opt, expr, "U64");
  ast_settype(ast, type);
  return true;
}
Exemple #6
0
// Fill the given UIF type cache
static bool uif_type(pass_opt_t* opt, ast_t* literal, ast_t* type,
  lit_chain_t* chain_head, bool report_errors)
{
  pony_assert(chain_head != NULL);
  pony_assert(chain_head->cardinality == CHAIN_CARD_BASE);

  chain_head->formal = NULL;
  int r = uifset(opt, type, chain_head->next);

  if(r == UIF_ERROR)
    return false;

  if(r == UIF_NO_TYPES)
  {
    if(report_errors)
      ast_error(opt->check.errors, literal,
        "could not infer literal type, no valid types found");

    return false;
  }

  pony_assert(type != NULL);

  if((r & UIF_CONSTRAINED) != 0)
  {
    // Type is a formal parameter
    pony_assert(chain_head->formal != NULL);
    pony_assert(chain_head->name != NULL);
    pony_assert(chain_head->cached_uif_index < 0);

    BUILD(uif_type, type,
      NODE(TK_TYPEPARAMREF, DATA(chain_head->formal)
      ID(chain_head->name) NODE(TK_VAL) NONE));

    chain_head->cached_type = uif_type;
    chain_head->valid_for_float = ((r & UIF_INT_MASK) == 0);
    return true;
  }

  // Type is one or more UIFs
  for(int i = 0; i < UIF_COUNT; i++)
  {
    if(r == (1 << i))
    {
      chain_head->valid_for_float = (((1 << i) & UIF_INT_MASK) == 0);
      chain_head->cached_type =
        type_builtin(opt, type, _str_uif_types[i].name);
      //ast_setid(ast_childidx(chain_head->cached_type, 4), TK_EPHEMERAL);
      chain_head->name = _str_uif_types[i].name;
      chain_head->cached_uif_index = i;
      return true;
    }
  }

  ast_error(opt->check.errors, literal, "Multiple possible types for literal");
  return false;
}
Exemple #7
0
bool expr_literal(pass_opt_t* opt, ast_t* ast, const char* name)
{
  ast_t* type = type_builtin(opt, ast, name);

  if(is_typecheck_error(type))
    return false;

  ast_settype(ast, type);
  return true;
}
Exemple #8
0
void genprim_reachable_init(compile_t* c, ast_t* program)
{
  // Look for primitives in all packages that have _init or _final methods.
  // Mark them as reachable.
  ast_t* package = ast_child(program);

  while(package != NULL)
  {
    ast_t* module = ast_child(package);

    while(module != NULL)
    {
      ast_t* entity = ast_child(module);

      while(entity != NULL)
      {
        if(ast_id(entity) == TK_PRIMITIVE)
        {
          AST_GET_CHILDREN(entity, id, typeparams);

          if(ast_id(typeparams) == TK_NONE)
          {
            ast_t* type = type_builtin(c->opt, entity, ast_name(id));
            ast_t* finit = ast_get(entity, c->str__init, NULL);
            ast_t* ffinal = ast_get(entity, c->str__final, NULL);

            if(finit != NULL)
            {
              reach(c->reach, type, c->str__init, NULL, c->opt);
              ast_free_unattached(finit);
            }

            if(ffinal != NULL)
            {
              reach(c->reach, type, c->str__final, NULL, c->opt);
              ast_free_unattached(ffinal);
            }

            ast_free_unattached(type);
          }
        }

        entity = ast_sibling(entity);
      }

      module = ast_sibling(module);
    }

    package = ast_sibling(package);
  }
}
Exemple #9
0
static bool generate_actor(compile_t* c, ast_t* ast)
{
  ast_t* id = ast_child(ast);
  ast_t* type = type_builtin(c->opt, ast, ast_name(id));

  if(type == NULL)
    return false;

  gentype_t g;
  bool ok = gentype(c, type, &g);
  ast_free_unattached(type);

  return ok;
}
Exemple #10
0
bool is_signed(pass_opt_t* opt, ast_t* type)
{
  if(type == NULL)
    return false;

  ast_t* builtin = type_builtin(opt, type, "Signed");

  if(builtin == NULL)
    return false;

  bool ok = is_subtype(type, builtin);
  ast_free_unattached(builtin);
  return ok;
}
Exemple #11
0
// Determine the UIF types that satisfy the given "simple" type.
// Here a simple type is defined as a non-tuple type that does not depend on
// any formal parameters.
static int uifset_simple_type(pass_opt_t* opt, ast_t* type)
{
  assert(type != NULL);

  int set = 0;

  for(int i = 0; i < UIF_COUNT; i++)
  {
    ast_t* uif = type_builtin(opt, type, _str_uif_types[i].name);
    ast_setid(ast_childidx(uif, 3), TK_VAL);
    ast_setid(ast_childidx(uif, 4), TK_EPHEMERAL);

    if(is_subtype(uif, type))
      set |= (1 << i);

    ast_free(uif);
  }

  return set;
}
Exemple #12
0
bool expr_addressof(pass_opt_t* opt, ast_t* ast)
{
  // Check if we're in an FFI call.
  ast_t* parent = ast_parent(ast);

  if(ast_id(parent) == TK_SEQ)
  {
    parent = ast_parent(parent);

    if(ast_id(parent) == TK_POSITIONALARGS)
    {
      parent = ast_parent(parent);

      if(ast_id(parent) == TK_FFICALL)
        return expr_addressof_ffi(opt, ast);
    }
  }

  ast_t* expr = ast_child(ast);

  switch(ast_id(expr))
  {
    case TK_FVARREF:
    case TK_VARREF:
    case TK_FLETREF:
    case TK_LETREF:
    case TK_PARAMREF:
      break;

    default:
      ast_error(ast, "identity must be for a field, local or parameter");
      return false;
  }

  // Turn this into an identity operation. Set the type to U64.
  ast_t* type = type_builtin(opt, expr, "U64");
  ast_settype(ast, type);
  ast_setid(ast, TK_IDENTITY);
  return true;
}
Exemple #13
0
// Determine the UIF types that the given formal parameter may be
static int uifset_formal_param(pass_opt_t* opt, ast_t* type_param_ref,
  lit_chain_t* chain)
{
  assert(type_param_ref != NULL);
  assert(ast_id(type_param_ref) == TK_TYPEPARAMREF);

  ast_t* type_param = (ast_t*)ast_data(type_param_ref);

  assert(type_param != NULL);
  assert(ast_id(type_param) == TK_TYPEPARAM);
  assert(chain != NULL);

  ast_t* constraint = ast_childidx(type_param, 1);
  assert(constraint != NULL);

  // If the constraint is not a subtype of (Real[A] & Number) then there are no
  // legal types in the set
  ast_t* number = type_builtin(opt, type_param, "Number");
  ast_t* real = type_builtin(opt, type_param, "Real");
  ast_setid(ast_childidx(real, 3), TK_BOX);

  ast_t* p_ref = ast_childidx(real, 2);
  REPLACE(&p_ref,
    NODE(TK_TYPEARGS,
      NODE(TK_TYPEPARAMREF, DATA(type_param)
        ID(ast_name(ast_child(type_param))) NODE(TK_VAL) NONE)));

  bool is_real = is_subtype(constraint, real);
  bool is_number = is_subtype(constraint, number);
  ast_free(number);
  ast_free(real);

  if(!is_real || !is_number)
    // The formal param is not a subset of (Real[A] & Number)
    return UIF_NO_TYPES;

  int uif_set = 0;

  for(int i = 0; i < UIF_COUNT; i++)
  {
    ast_t* uif = type_builtin(opt, type_param, _str_uif_types[i].name);

    BUILD(params, type_param, NODE(TK_TYPEPARAMS, TREE(ast_dup(type_param))));
    BUILD(args, type_param, NODE(TK_TYPEARGS, TREE(uif)));

    if(check_constraints(params, args, false))
      uif_set |= (1 << i);

    ast_free(args);
    ast_free(params);
  }

  if(uif_set == 0)  // No legal types
    return UIF_NO_TYPES;

  // Given formal parameter is legal to coerce to
  if(chain->formal != NULL && chain->formal != type_param)
  {
    ast_error(type_param_ref,
      "Cannot infer a literal type with multiple formal parameters");
    return UIF_ERROR;
  }

  chain->formal = type_param;
  chain->name = ast_name(ast_child(type_param));
  return uif_set | UIF_CONSTRAINED;
}
Exemple #14
0
bool expr_location(pass_opt_t* opt, ast_t* ast)
{
  ast_settype(ast, type_builtin(opt, ast, "SourceLoc"));
  return true;
}
Exemple #15
0
bool expr_addressof(pass_opt_t* opt, ast_t* ast)
{
  // Check if we're in an FFI call.
  ast_t* parent = ast_parent(ast);
  bool ok = false;

  if(ast_id(parent) == TK_SEQ)
  {
    parent = ast_parent(parent);

    if(ast_id(parent) == TK_POSITIONALARGS)
    {
      parent = ast_parent(parent);

      if(ast_id(parent) == TK_FFICALL)
        ok = true;
    }
  }

  if(!ok)
  {
    ast_error(ast, "the & operator can only be used for FFI arguments");
    return false;
  }

  ast_t* expr = ast_child(ast);

  switch(ast_id(expr))
  {
    case TK_FVARREF:
    case TK_VARREF:
    case TK_FUNREF:
    case TK_BEREF:
      break;

    case TK_FLETREF:
      ast_error(ast, "can't take the address of a let field");
      return false;

    case TK_EMBEDREF:
      ast_error(ast, "can't take the address of an embed field");
      return false;

    case TK_LETREF:
      ast_error(ast, "can't take the address of a let local");
      return false;

    case TK_PARAMREF:
      ast_error(ast, "can't take the address of a function parameter");
      return false;

    default:
      ast_error(ast, "can only take the address of a local, field or method");
      return false;
  }

  // Set the type to Pointer[ast_type(expr)]. Set to Pointer[None] for function
  // pointers.
  ast_t* expr_type = ast_type(expr);

  if(is_typecheck_error(expr_type))
    return false;

  switch(ast_id(expr))
  {
    case TK_FUNREF:
    case TK_BEREF:
      expr_type = type_builtin(opt, ast, "None");
      break;

    default: {}
  }

  ast_t* type = type_pointer_to(opt, expr_type);
  ast_settype(ast, type);
  return true;
}
Exemple #16
0
bool expr_identity(pass_opt_t* opt, ast_t* ast)
{
  ast_settype(ast, type_builtin(opt, ast, "Bool"));
  return literal_is(ast, opt);
}
Exemple #17
0
bool expr_identity(pass_opt_t* opt, ast_t* ast)
{
  ast_settype(ast, type_builtin(opt, ast, "Bool"));
  ast_inheritflags(ast);
  return true;
}
Exemple #18
0
bool genexe(compile_t* c, ast_t* program)
{
  errors_t* errors = c->opt->check.errors;

  // The first package is the main package. It has to have a Main actor.
  const char* main_actor = c->str_Main;
  const char* env_class = c->str_Env;

  ast_t* package = ast_child(program);
  ast_t* main_def = ast_get(package, main_actor, NULL);

  if(main_def == NULL)
  {
    errorf(errors, NULL, "no Main actor found in package '%s'", c->filename);
    return false;
  }

  // Generate the Main actor and the Env class.
  ast_t* main_ast = type_builtin(c->opt, main_def, main_actor);
  ast_t* env_ast = type_builtin(c->opt, main_def, env_class);

  if(lookup(NULL, main_ast, main_ast, c->str_create) == NULL)
    return false;

  if(c->opt->verbosity >= VERBOSITY_INFO)
    fprintf(stderr, " Reachability\n");
  reach(c->reach, main_ast, c->str_create, NULL, c->opt);
  reach(c->reach, env_ast, c->str__create, NULL, c->opt);

  if(c->opt->limit == PASS_REACH)
    return true;

  if(c->opt->verbosity >= VERBOSITY_INFO)
    fprintf(stderr, " Selector painting\n");
  paint(&c->reach->types);

  if(c->opt->limit == PASS_PAINT)
    return true;

  if(!gentypes(c))
    return false;

  if(c->opt->verbosity >= VERBOSITY_ALL)
    reach_dump(c->reach);

  reach_type_t* t_main = reach_type(c->reach, main_ast);
  reach_type_t* t_env = reach_type(c->reach, env_ast);

  if((t_main == NULL) || (t_env == NULL))
    return false;

  gen_main(c, t_main, t_env);

  if(!genopt(c))
    return false;

  const char* file_o = genobj(c);

  if(file_o == NULL)
    return false;

  if(c->opt->limit < PASS_ALL)
    return true;

  if(!link_exe(c, program, file_o))
    return false;

#ifdef PLATFORM_IS_WINDOWS
  _unlink(file_o);
#else
  unlink(file_o);
#endif

  return true;
}
Exemple #19
0
bool genexe(compile_t* c, ast_t* program)
{
  errors_t* errors = c->opt->check.errors;

  // The first package is the main package. It has to have a Main actor.
  const char* main_actor = c->str_Main;
  const char* env_class = c->str_Env;

  ast_t* package = ast_child(program);
  ast_t* main_def = ast_get(package, main_actor, NULL);

  if(main_def == NULL)
  {
    errorf(errors, NULL, "no Main actor found in package '%s'", c->filename);
    return false;
  }

  // Generate the Main actor and the Env class.
  ast_t* main_ast = type_builtin(c->opt, main_def, main_actor);
  ast_t* env_ast = type_builtin(c->opt, main_def, env_class);

  if(lookup(c->opt, main_ast, main_ast, c->str_create) == NULL)
    return false;

  if(c->opt->verbosity >= VERBOSITY_INFO)
    fprintf(stderr, " Reachability\n");
  reach(c->reach, main_ast, c->str_create, NULL, c->opt);
  reach(c->reach, env_ast, c->str__create, NULL, c->opt);

  if(c->opt->limit == PASS_REACH)
    return true;

  if(c->opt->verbosity >= VERBOSITY_INFO)
    fprintf(stderr, " Selector painting\n");
  paint(&c->reach->types);

  if(c->opt->limit == PASS_PAINT)
    return true;

  if(!gentypes(c))
    return false;

  if(c->opt->verbosity >= VERBOSITY_ALL)
    reach_dump(c->reach);

  reach_type_t* t_main = reach_type(c->reach, main_ast);
  reach_type_t* t_env = reach_type(c->reach, env_ast);

  if((t_main == NULL) || (t_env == NULL))
    return false;

  gen_main(c, t_main, t_env);

  if(!genopt(c, true))
    return false;

  if(c->opt->runtimebc)
  {
    if(!codegen_merge_runtime_bitcode(c))
      return false;

    // Rerun the optimiser without the Pony-specific optimisation passes.
    // Inlining runtime functions can screw up these passes so we can't
    // run the optimiser only once after merging.
    if(!genopt(c, false))
      return false;
  }

  const char* file_o = genobj(c);

  if(file_o == NULL)
    return false;

  if(c->opt->limit < PASS_ALL)
    return true;

  if(!link_exe(c, program, file_o))
    return false;

#ifdef PLATFORM_IS_WINDOWS
  _unlink(file_o);
#else
  unlink(file_o);
#endif

  return true;
}