예제 #1
0
파일: call.c 프로젝트: MochiKicks/ponyc
bool is_this_incomplete(typecheck_t* t, ast_t* ast)
{
  // If we're in a default argument, we're incomplete by definition.
  if(t->frame->method == NULL)
    return true;

  // If we're not in a constructor, we're complete by definition.
  if(ast_id(t->frame->method) != TK_NEW)
    return false;

  // Check if all fields have been marked as defined.
  ast_t* members = ast_childidx(t->frame->type, 4);
  ast_t* member = ast_child(members);

  while(member != NULL)
  {
    switch(ast_id(member))
    {
      case TK_FLET:
      case TK_FVAR:
      case TK_EMBED:
      {
        sym_status_t status;
        ast_t* id = ast_child(member);
        ast_get(ast, ast_name(id), &status);

        if(status != SYM_DEFINED)
          return true;

        break;
      }

      default: {}
    }

    member = ast_sibling(member);
  }

  return false;
}
예제 #2
0
static LLVMValueRef make_fieldptr(compile_t* c, LLVMValueRef l_value,
  ast_t* l_type, ast_t* right)
{
  switch(ast_id(l_type))
  {
    case TK_NOMINAL:
    {
      assert(ast_id(right) == TK_ID);

      ast_t* def = (ast_t*)ast_data(l_type);
      ast_t* field = ast_get(def, ast_name(right), NULL);
      int index = (int)ast_index(field);

      if(ast_id(def) != TK_STRUCT)
        index++;

      if(ast_id(def) == TK_ACTOR)
        index++;

      return LLVMBuildStructGEP(c->builder, l_value, index, "");
    }

    case TK_TUPLETYPE:
    {
      assert(ast_id(right) == TK_INT);
      int index = (int)ast_int(right)->low;

      return LLVMBuildExtractValue(c->builder, l_value, index, "");
    }

    case TK_ARROW:
      return make_fieldptr(c, l_value, ast_childidx(l_type, 1), right);

    default: {}
  }

  assert(0);
  return NULL;
}
예제 #3
0
파일: reference.c 프로젝트: Potpourri/ponyc
static bool check_fields_defined(ast_t* ast)
{
  assert(ast_id(ast) == TK_NEW);

  ast_t* members = ast_parent(ast);
  ast_t* member = ast_child(members);
  bool result = true;

  while(member != NULL)
  {
    switch(ast_id(member))
    {
      case TK_FVAR:
      case TK_FLET:
      {
        sym_status_t status;
        ast_t* id = ast_child(member);
        ast_t* def = ast_get(ast, ast_name(id), &status);

        if((def != member) || (status != SYM_DEFINED))
        {
          ast_error(def, "field left undefined in constructor");
          result = false;
        }

        break;
      }

      default: {}
    }

    member = ast_sibling(member);
  }

  if(!result)
    ast_error(ast, "constructor with undefined fields is here");

  return result;
}
예제 #4
0
파일: reify.c 프로젝트: Perelandric/ponyc
static void reify_reference(ast_t** astp, ast_t* typeparam, ast_t* typearg)
{
  ast_t* ast = *astp;
  pony_assert(ast_id(ast) == TK_REFERENCE);

  const char* name = ast_name(ast_child(ast));

  sym_status_t status;
  ast_t* ref_def = ast_get(ast, name, &status);

  if(ref_def == NULL)
    return;

  ast_t* param_def = (ast_t*)ast_data(typeparam);
  pony_assert(param_def != NULL);

  if(ref_def != param_def)
    return;

  ast_setid(ast, TK_TYPEREF);
  ast_add(ast, ast_from(ast, TK_NONE));    // 1st child: package reference
  ast_append(ast, ast_from(ast, TK_NONE)); // 3rd child: type args
  ast_settype(ast, typearg);
}
예제 #5
0
파일: names.c 프로젝트: dailypips/ponyc
bool names_nominal(pass_opt_t* opt, ast_t* scope, ast_t** astp)
{
  typecheck_t* t = &opt->check;
  ast_t* ast = *astp;

  if(ast_data(ast) != NULL)
    return true;

  AST_GET_CHILDREN(ast, package_id, type_id, typeparams, cap, eph);

  // Keep some stats.
  t->stats.names_count++;

  if(ast_id(cap) == TK_NONE)
    t->stats.default_caps_count++;

  ast_t* r_scope = get_package_scope(scope, ast);

  if(r_scope == NULL)
    return false;

  bool local_package =
    (r_scope == scope) || (r_scope == ast_nearest(ast, TK_PACKAGE));

  // Find our definition.
  const char* name = ast_name(type_id);
  ast_t* def = ast_get(r_scope, name, NULL);
  bool r = true;

  if(def == NULL)
  {
    ast_error(type_id, "can't find definition of '%s'", name);
    r = false;
  } else {
    // Check for a private type.
    if(!local_package && (name[0] == '_'))
    {
      ast_error(type_id, "can't access a private type from another package");
      r = false;
    }

    switch(ast_id(def))
    {
      case TK_TYPE:
        r = names_typealias(opt, astp, def);
        break;

      case TK_TYPEPARAM:
        r = names_typeparam(astp, def);
        break;

      case TK_INTERFACE:
      case TK_TRAIT:
      case TK_PRIMITIVE:
      case TK_CLASS:
      case TK_ACTOR:
        r = names_type(t, astp, def);
        break;

      default:
        ast_error(type_id, "definition of '%s' is not a type", name);
        r = false;
        break;
    }
  }

  return r;
}
예제 #6
0
파일: reference.c 프로젝트: tmmcguire/ponyc
bool expr_fieldref(pass_opt_t* opt, ast_t* ast, ast_t* find, token_id tid)
{
  AST_GET_CHILDREN(ast, left, right);
  ast_t* l_type = ast_type(left);

  if(is_typecheck_error(l_type))
    return false;

  AST_GET_CHILDREN(find, id, f_type, init);

  // Viewpoint adapted type of the field.
  ast_t* type = viewpoint_type(l_type, f_type);

  if(ast_id(type) == TK_ARROW)
  {
    ast_t* upper = viewpoint_upper(type);

    if(upper == NULL)
    {
      ast_error(opt->check.errors, ast, "can't read a field through %s",
        ast_print_type(l_type));
      return false;
    }

    ast_free_unattached(upper);
  }

  // In a recover expression, we can access obj.field if field is sendable
  // and not being assigned to, even if obj isn't sendable.

  typecheck_t* t = &opt->check;

  if(t->frame->recover != NULL)
  {
    if(!sendable(type))
    {
      if(!sendable(l_type))
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, ast, "can't access field of non-sendable "
          "object inside of a recover expression");
        ast_error_frame(&frame, find, "this would be possible if the field was "
          "sendable");
        errorframe_report(&frame, opt->check.errors);
        return false;
      }
    }
    else
    {
      ast_t* parent = ast_parent(ast);
      ast_t* current = ast;
      while(ast_id(parent) != TK_RECOVER && ast_id(parent) != TK_ASSIGN)
      {
        current = parent;
        parent = ast_parent(parent);
      }
      if(ast_id(parent) == TK_ASSIGN && ast_child(parent) != current)
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, ast, "can't access field of non-sendable "
          "object inside of a recover expression");
        ast_error_frame(&frame, parent, "this would be possible if the field "
          "wasn't assigned to");
        errorframe_report(&frame, opt->check.errors);
        return false;
      }
    }
  }

  // Set the unadapted field type.
  ast_settype(right, f_type);

  // Set the type so that it isn't free'd as unattached.
  ast_setid(ast, tid);
  ast_settype(ast, type);

  if(ast_id(left) == TK_THIS)
  {
    // Handle symbol status if the left side is 'this'.
    const char* name = ast_name(id);

    sym_status_t status;
    ast_get(ast, name, &status);

    if(!valid_reference(opt, ast, type, status))
      return false;
  }

  return true;
}
예제 #7
0
파일: traits.c 프로젝트: lzpfmh/ponyc
// Process all field delegations in the given type.
// Stage 3.
static bool field_delegations(ast_t* entity)
{
  assert(entity != NULL);

  ast_t* members = ast_childidx(entity, 4);
  assert(members != NULL);

  bool r = true;

  // Check all fields
  for(ast_t* f = ast_child(members); f != NULL; f = ast_sibling(f))
  {
    if(is_field(f))
    {
      AST_GET_CHILDREN(f, id, f_type, value, delegates);

      // Check all delegates for field
      for(ast_t* d = ast_child(delegates); d != NULL; d = ast_sibling(d))
      {
        if(!check_delegate(entity, f_type, d))
        {
          r = false;
          continue;
        }

        // Mark all methods in delegate trait as targets for this field
        ast_t* trait = (ast_t*)ast_data(d);
        assert(trait != NULL);
        ast_t* t_members = ast_childidx(trait, 4);

        for(ast_t* m = ast_child(t_members); m != NULL; m = ast_sibling(m))
        {
          if(is_method(m))
          {
            // Mark method as delegate target for this field
            const char* method_name = ast_name(ast_childidx(m, 1));
            assert(method_name != NULL);

            ast_t* local_method = ast_get(entity, method_name, NULL);
            assert(local_method != NULL);

            method_t* info = (method_t*)ast_data(local_method);
            assert(info != NULL);

            if(info->delegate_field_1 == NULL)
            {
              // First delegate field for this method
              info->delegate_field_1 = f;
              info->delegate_target_1 = d;
            }
            else if(info->delegate_field_2 == NULL &&
              info->delegate_field_1 != f)
            {
              // We already have one delegate field, record second
              info->delegate_field_2 = f;
              info->delegate_target_2 = d;
            }
          }
        }
      }
    }
  }

  return r;
}
예제 #8
0
파일: lookup.c 프로젝트: lzpfmh/ponyc
static ast_t* lookup_nominal(pass_opt_t* opt, ast_t* from, ast_t* orig,
                             ast_t* type, const char* name, bool errors)
{
    assert(ast_id(type) == TK_NOMINAL);
    typecheck_t* t = &opt->check;

    ast_t* def = (ast_t*)ast_data(type);
    AST_GET_CHILDREN(def, type_id, typeparams);
    const char* type_name = ast_name(type_id);

    if((type_name[0] == '_') && (from != NULL) && (opt != NULL))
    {
        if(ast_nearest(def, TK_PACKAGE) != t->frame->package)
        {
            if(errors)
            {
                ast_error(from,
                          "can't lookup fields or methods on private types from other packages"
                         );
            }

            return NULL;
        }
    }

    ast_t* find = ast_get(def, name, NULL);

    if(find != NULL)
    {
        switch(ast_id(find))
        {
        case TK_FVAR:
        case TK_FLET:
        case TK_EMBED:
            break;

        case TK_NEW:
        case TK_BE:
        case TK_FUN:
        {
            // Typecheck default args immediately.
            if(opt != NULL)
            {
                AST_GET_CHILDREN(find, cap, id, typeparams, params);
                ast_t* param = ast_child(params);

                while(param != NULL)
                {
                    AST_GET_CHILDREN(param, name, type, def_arg);

                    if((ast_id(def_arg) != TK_NONE) && (ast_type(def_arg) == NULL))
                    {
                        ast_settype(def_arg, ast_from(def_arg, TK_INFERTYPE));

                        if(ast_visit_scope(&def_arg, NULL, pass_expr, opt,
                                           PASS_EXPR) != AST_OK)
                            return false;

                        ast_visit_scope(&def_arg, NULL, pass_nodebug, opt, PASS_ALL);
                    }

                    param = ast_sibling(param);
                }
            }
            break;
        }

        default:
            find = NULL;
        }
    }

    if(find == NULL)
    {
        if(errors)
            ast_error(from, "couldn't find '%s' in '%s'", name, type_name);

        return NULL;
    }

    if((name[0] == '_') && (from != NULL) && (opt != NULL))
    {
        switch(ast_id(find))
        {
        case TK_FVAR:
        case TK_FLET:
        case TK_EMBED:
            if(t->frame->type != def)
            {
                if(errors)
                {
                    ast_error(from,
                              "can't lookup private fields from outside the type");
                }

                return NULL;
            }
            break;

        case TK_NEW:
        case TK_BE:
        case TK_FUN:
        {
            if(ast_nearest(def, TK_PACKAGE) != t->frame->package)
            {
                if(errors)
                {
                    ast_error(from,
                              "can't lookup private methods from outside the package");
                }

                return NULL;
            }
            break;
        }

        default:
            assert(0);
            return NULL;
        }

        if(!strcmp(name, "_final"))
        {
            switch(ast_id(find))
            {
            case TK_NEW:
            case TK_BE:
            case TK_FUN:
                if(errors)
                    ast_error(from, "can't lookup a _final function");

                return NULL;

            default:
            {}
            }
        }
    }

    ast_t* typeargs = ast_childidx(type, 2);
    ast_t* r_find = viewpoint_replacethis(find, orig);
    ast_t* rr_find = reify(r_find, typeparams, typeargs);
    ast_free_unattached(r_find);
    return rr_find;
}
예제 #9
0
파일: subtype.c 프로젝트: jersey99/ponyc
static bool is_nominal_sub_interface(ast_t* sub, ast_t* super,
  errorframe_t* errors)
{
  // implements(N, I)
  // k <: k'
  // ---
  // N k <: I k
  ast_t* sub_def = (ast_t*)ast_data(sub);
  ast_t* super_def = (ast_t*)ast_data(super);

  // Add an assumption: sub <: super
  if(push_assume(sub, super))
    return true;

  bool ret = true;

  // A struct has no descriptor, so can't be a subtype of an interface.
  if(ast_id(sub_def) == TK_STRUCT)
  {
    ret = false;

    if(errors != NULL)
    {
      ast_error_frame(errors, sub,
        "%s is not a subtype of %s: a struct can't be a subtype of an "
        "interface",
        ast_print_type(sub), ast_print_type(super));
    }
  }

  if(!is_sub_cap_and_eph(sub, super, errors))
    ret = false;

  ast_t* sub_typeargs = ast_childidx(sub, 2);
  ast_t* sub_typeparams = ast_childidx(sub_def, 1);

  ast_t* super_typeargs = ast_childidx(super, 2);
  ast_t* super_typeparams = ast_childidx(super_def, 1);

  ast_t* super_members = ast_childidx(super_def, 4);
  ast_t* super_member = ast_child(super_members);

  while(super_member != NULL)
  {
    ast_t* super_member_id = ast_childidx(super_member, 1);
    ast_t* sub_member = ast_get(sub_def, ast_name(super_member_id), NULL);

    // If we don't provide a method, we aren't a subtype.
    if(sub_member == NULL)
    {
      if(errors != NULL)
      {
        ast_error_frame(errors, sub,
          "%s is not a subtype of %s: it has no method %s",
          ast_print_type(sub), ast_print_type(super),
          ast_name(super_member_id));
      }

      ret = false;
      super_member = ast_sibling(super_member);
      continue;
    }

    // Reify the method on the subtype.
    ast_t* r_sub_member = reify(sub_member, sub_typeparams, sub_typeargs);
    assert(r_sub_member != NULL);

    // Reify the method on the supertype.
    ast_t* r_super_member = reify(super_member, super_typeparams,
      super_typeargs);
    assert(r_super_member != NULL);

    // Check the reified methods.
    bool ok = is_fun_sub_fun(r_sub_member, r_super_member, errors);
    ast_free_unattached(r_sub_member);
    ast_free_unattached(r_super_member);

    if(!ok)
    {
      ret = false;

      if(errors != NULL)
      {
        ast_error_frame(errors, sub_member,
          "%s is not a subtype of %s: method %s has an incompatible signature",
          ast_print_type(sub), ast_print_type(super),
          ast_name(super_member_id));
      }
    }

    super_member = ast_sibling(super_member);
  }

  pop_assume();
  return ret;
}
예제 #10
0
파일: genexe.c 프로젝트: enigma/ponyc
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;
}
예제 #11
0
파일: subtype.c 프로젝트: pengzj/ponyc
static bool is_fun_sub_fun(ast_t* sub, ast_t* super,
  ast_t* isub, ast_t* isuper)
{
  token_id tsub = ast_id(sub);
  token_id tsuper = ast_id(super);

  switch(tsub)
  {
    case TK_NEW:
    case TK_BE:
    case TK_FUN:
      break;

    default:
      return false;
  }

  switch(tsuper)
  {
    case TK_NEW:
    case TK_BE:
    case TK_FUN:
      break;

    default:
      return false;
  }

  // A constructor can only be a subtype of a constructor.
  if(((tsub == TK_NEW) || (tsuper == TK_NEW)) && (tsub != tsuper))
    return false;

  AST_GET_CHILDREN(sub, sub_cap, sub_id, sub_typeparams, sub_params);
  AST_GET_CHILDREN(super, super_cap, super_id, super_typeparams, super_params);

  // Must have the same name.
  if(ast_name(sub_id) != ast_name(super_id))
    return false;

  // Must have the same number of type parameters and parameters.
  if((ast_childcount(sub_typeparams) != ast_childcount(super_typeparams)) ||
    (ast_childcount(sub_params) != ast_childcount(super_params)))
    return false;

  ast_t* r_sub = sub;

  if(ast_id(super_typeparams) != TK_NONE)
  {
    // Reify sub with the type parameters of super.
    BUILD(typeargs, super_typeparams, NODE(TK_TYPEARGS));
    ast_t* super_typeparam = ast_child(super_typeparams);

    while(super_typeparam != NULL)
    {
      AST_GET_CHILDREN(super_typeparam, super_id, super_constraint);
      token_id cap = cap_from_constraint(super_constraint);

      BUILD(typearg, super_typeparam,
        NODE(TK_TYPEPARAMREF, TREE(super_id) NODE(cap) NONE));

      ast_t* def = ast_get(super_typeparam, ast_name(super_id), NULL);
      ast_setdata(typearg, def);
      ast_append(typeargs, typearg);

      super_typeparam = ast_sibling(super_typeparam);
    }

    r_sub = reify(sub, sub, sub_typeparams, typeargs);
    ast_free_unattached(typeargs);
  }

  bool ok = is_reified_fun_sub_fun(r_sub, super, isub, isuper);

  if(r_sub != sub)
    ast_free_unattached(r_sub);

  return ok;
}
예제 #12
0
파일: package.c 프로젝트: dipinhora/ponyc
ast_t* package_load(ast_t* from, const char* path, pass_opt_t* opt)
{
  pony_assert(from != NULL);

  magic_package_t* magic = find_magic_package(path, opt);
  const char* full_path = path;
  const char* qualified_name = path;
  ast_t* program = ast_nearest(from, TK_PROGRAM);

  if(magic == NULL)
  {
    // Lookup (and hence normalise) path
    bool is_relative = false;
    bool found_notdir = false;
    full_path = find_path(from, path, &is_relative, &found_notdir, opt);

    if(full_path == NULL)
    {
      errorf(opt->check.errors, path, "couldn't locate this path");

      if(found_notdir)
        errorf_continue(opt->check.errors, path, "note that a compiler "
          "invocation or a 'use' directive must refer to a directory");

      return NULL;
    }

    if((from != program) && is_relative)
    {
      // Package to load is relative to from, build the qualified name
      // The qualified name should be relative to the program being built
      package_t* from_pkg = (package_t*)ast_data(ast_child(program));

      if(from_pkg != NULL)
      {
        const char* base_name = from_pkg->qualified_name;
        size_t base_name_len = strlen(base_name);
        size_t path_len = strlen(path);
        size_t len = base_name_len + path_len + 2;
        char* q_name = (char*)ponyint_pool_alloc_size(len);
        memcpy(q_name, base_name, base_name_len);
        q_name[base_name_len] = '/';
        memcpy(q_name + base_name_len + 1, path, path_len);
        q_name[len - 1] = '\0';
        qualified_name = stringtab_consume(q_name, len);
      }
    }

    // we are loading the package specified as program dir
    if(from == program)
    {
      // construct the qualified name from the basename of the full path
      const char* basepath = strrchr(full_path, '/');
      if(basepath == NULL)
      {
        basepath = full_path;
      } else {
        basepath = basepath + 1;
      }
      qualified_name = basepath;
    }
  }

  ast_t* package = ast_get(program, full_path, NULL);

  // Package already loaded
  if(package != NULL)
    return package;

  package = create_package(program, full_path, qualified_name, opt);

  if(opt->verbosity >= VERBOSITY_INFO)
    fprintf(stderr, "Building %s -> %s\n", path, full_path);

  if(magic != NULL)
  {
    if(magic->src != NULL)
    {
      if(!parse_source_code(package, magic->src, opt))
        return NULL;
    } else if(magic->mapped_path != NULL) {
      if(!parse_files_in_dir(package, magic->mapped_path, opt))
        return NULL;
    } else {
      return NULL;
    }
  }
  else
  {
    if(!parse_files_in_dir(package, full_path, opt))
      return NULL;
  }

  if(ast_child(package) == NULL)
  {
    ast_error(opt->check.errors, package,
      "no source files in package '%s'", path);
    return NULL;
  }

  if(!ast_passes_subtree(&package, opt, opt->program_pass))
  {
    // If these passes failed, don't run future passes.
    ast_setflag(package, AST_FLAG_PRESERVE);
    return NULL;
  }

  return package;
}
예제 #13
0
파일: package.c 프로젝트: FedeOmoto/ponyc
ast_t* package_load(ast_t* from, const char* path, pass_opt_t* options)
{
  const char* magic = find_magic_package(path);
  const char* full_path = path;
  const char* qualified_name = path;
  ast_t* program = ast_nearest(from, TK_PROGRAM);

  if(magic == NULL)
  {
    // Lookup (and hence normalise) path
    bool is_relative = false;
    full_path = find_path(from, path, &is_relative);

    if(full_path == NULL)
      return NULL;

    if((from != NULL) && is_relative)
    {
      // Package to load is relative to from, build the qualified name
      // The qualified name should be relative to the program being built
      package_t* from_pkg = (package_t*)ast_data(ast_child(program));

      if(from_pkg != NULL)
      {
        const char* base_name = from_pkg->qualified_name;
        size_t base_name_len = strlen(base_name);
        size_t path_len = strlen(path);
        size_t len = base_name_len + path_len + 2;
        char* q_name = (char*)pool_alloc_size(len);
        memcpy(q_name, base_name, base_name_len);
        q_name[base_name_len] = '/';
        memcpy(q_name + base_name_len + 1, path, path_len);
        q_name[len - 1] = '\0';
        qualified_name = stringtab_consume(q_name, len);
      }
    }
  }

  ast_t* package = ast_get(program, full_path, NULL);

  // Package already loaded
  if(package != NULL)
    return package;

  package = create_package(program, full_path, qualified_name);

  if(report_build)
    printf("Building %s -> %s\n", path, full_path);

  if(magic != NULL)
  {
    if(!parse_source_code(package, magic, options))
      return NULL;
  }
  else
  {
    if(!parse_files_in_dir(package, full_path, options))
      return NULL;
  }

  if(ast_child(package) == NULL)
  {
    ast_error(package, "no source files in package '%s'", path);
    return NULL;
  }

  // We add new packages to the end of the program, so they will be reached by
  // the current pass processing. This means we need to catch up the new
  // package to the previous pass
  if(!ast_passes_subtree(&package, options,
    pass_prev(options->type_catchup_pass)))
    return NULL;

  return package;
}
예제 #14
0
파일: genexe.c 프로젝트: Praetonus/ponyc
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;
}
예제 #15
0
파일: operator.c 프로젝트: jonas-l/ponyc
static bool assign_id(typecheck_t* t, ast_t* ast, bool let, bool need_value)
{
  assert(ast_id(ast) == TK_ID);
  const char* name = ast_name(ast);

  sym_status_t status;
  ast_get(ast, name, &status);

  switch(status)
  {
    case SYM_UNDEFINED:
      if(need_value)
      {
        ast_error(ast, "the left side is undefined but its value is used");
        return false;
      }

      ast_setstatus(ast, name, SYM_DEFINED);
      return true;

    case SYM_DEFINED:
      if(let)
      {
        ast_error(ast,
          "can't assign to a let or embed definition more than once");
        return false;
      }

      return true;

    case SYM_CONSUMED:
    {
      bool ok = true;

      if(need_value)
      {
        ast_error(ast, "the left side is consumed but its value is used");
        ok = false;
      }

      if(let)
      {
        ast_error(ast,
          "can't assign to a let or embed definition more than once");
        ok = false;
      }

      if(t->frame->try_expr != NULL)
      {
        ast_error(ast,
          "can't reassign to a consumed identifier in a try expression");
        ok = false;
      }

      if(ok)
        ast_setstatus(ast, name, SYM_DEFINED);

      return ok;
    }

    default: {}
  }

  assert(0);
  return false;
}
예제 #16
0
파일: traits.c 프로젝트: awaidmann/ponyc
// Add a new method to the given entity, based on the specified method from
// the specified type.
// The trait_ref is the entry in the provides / delegates list that causes this
// method inclusion. Needed for error reporting.
// The basis_method is the reified method in the trait to add.
// The adjective parameter is used for error reporting and should be "provided"
// or similar.
// Return the newly added method or NULL on error.
static ast_t* add_method(ast_t* entity, ast_t* trait_ref, ast_t* basis_method,
  const char* adjective, pass_opt_t* opt)
{
  assert(entity != NULL);
  assert(trait_ref != NULL);
  assert(basis_method != NULL);
  assert(adjective != NULL);

  const char* name = ast_name(ast_childidx(basis_method, 1));

  // Check behaviour compatability.
  if(ast_id(basis_method) == TK_BE)
  {
    switch(ast_id(entity))
    {
      case TK_PRIMITIVE:
        ast_error(opt->check.errors, trait_ref,
          "cannot add a behaviour (%s) to a primitive", name);
        return NULL;

      case TK_STRUCT:
        ast_error(opt->check.errors, trait_ref,
          "cannot add a behaviour (%s) to a struct", name);
        return NULL;

      case TK_CLASS:
        ast_error(opt->check.errors, trait_ref,
          "cannot add a behaviour (%s) to a class", name);
        return NULL;

      default:
        break;
    }
  }

  // Check for existing method of the same name.
  ast_t* existing = ast_get(entity, name, NULL);

  if(existing != NULL)
  {
    assert(is_field(existing)); // Should already have checked for methods.

    ast_error(opt->check.errors, trait_ref,
      "%s method '%s' clashes with field", adjective, name);
    ast_error_continue(opt->check.errors, basis_method,
      "method is defined here");
    return NULL;
  }

  // Check for clash with existing method.
  ast_t* case_clash = ast_get_case(entity, name, NULL);

  if(case_clash != NULL)
  {
    const char* clash_name = "";

    switch(ast_id(case_clash))
    {
      case TK_FUN:
      case TK_BE:
      case TK_NEW:
        clash_name = ast_name(ast_childidx(case_clash, 1));
        break;

      case TK_LET:
      case TK_VAR:
      case TK_EMBED:
        clash_name = ast_name(ast_child(case_clash));
        break;

      default:
        assert(0);
        break;
    }

    ast_error(opt->check.errors, trait_ref,
      "%s method '%s' differs only in case from '%s'",
      adjective, name, clash_name);
    ast_error_continue(opt->check.errors, basis_method,
      "clashing method is defined here");
    return NULL;
  }

  AST_GET_CHILDREN(basis_method, cap, id, typeparams, params, result,
    can_error, body, doc);

  // Ignore docstring.
  if(ast_id(doc) == TK_STRING)
  {
    ast_set_name(doc, "");
    ast_setid(doc, TK_NONE);
  }

  ast_t* local = ast_append(ast_childidx(entity, 4), basis_method);
  ast_set(entity, name, local, SYM_DEFINED, false);
  ast_t* body_donor = (ast_t*)ast_data(basis_method);
  method_t* info = attach_method_t(local);
  info->trait_ref = trait_ref;

  if(ast_id(body) != TK_NONE)
    info->body_donor = body_donor;

  return local;
}
예제 #17
0
파일: lambda.c 프로젝트: Perelandric/ponyc
// Process the given capture and create the AST for the corresponding field.
// Returns the create field AST in out_field, which must be freed by the caller,
// or NULL if there is no field to create.
// Returns false on error.
static bool make_capture_field(pass_opt_t* opt, ast_t* capture,
  ast_t** out_field)
{
  pony_assert(capture != NULL);
  pony_assert(out_field != NULL);

  AST_GET_CHILDREN(capture, id_node, type, value);
  const char* name = ast_name(id_node);

  bool is_dontcare = is_name_dontcare(name);

  // There are 3 varieties of capture:
  // x -> capture variable x, type from defn of x
  // x = y -> capture expression y, type inferred from expression type
  // x: T = y -> capture expression y, type T

  if(ast_id(value) == TK_NONE)
  {
    // Variable capture
    pony_assert(ast_id(type) == TK_NONE);

    if(is_dontcare)
    {
      *out_field = NULL;
      return true;
    }

    ast_t* def = ast_get(capture, name, NULL);

    if(def == NULL)
    {
      ast_error(opt->check.errors, id_node,
        "cannot capture \"%s\", variable not defined", name);
      return false;
    }

    // lambda captures used before their declaration with their type
    // not defined are not legal
    if(!def_before_use(opt, def, capture, name))
      return false;

    switch(ast_id(def))
    {
      case TK_VAR:
      case TK_LET:
      case TK_PARAM:
      case TK_MATCH_CAPTURE:
      case TK_FVAR:
      case TK_FLET:
      case TK_EMBED:
        break;

      default:
        ast_error(opt->check.errors, id_node, "cannot capture \"%s\", can only "
          "capture fields, parameters and local variables", name);
        return false;
    }

    BUILD(capture_rhs, id_node, NODE(TK_REFERENCE, ID(name)));

    type = alias(ast_type(def));
    value = capture_rhs;
  } else if(ast_id(type) == TK_NONE) {
    // No type specified, use type of the captured expression
    if(ast_type(value) == NULL)
      return false;

    type = alias(ast_type(value));
  } else {
    // Type given, infer literals
    if(!coerce_literals(&value, type, opt))
      return false;

    // Check subtyping now if we're capturing into '_', since the field will be
    // discarded.
    if(is_dontcare)
    {
      ast_t* v_type = alias(ast_type(value));
      errorframe_t info = NULL;

      if(!is_subtype(v_type, type, &info, opt))
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, value, "argument not a subtype of parameter");
        errorframe_append(&frame, &info);
        errorframe_report(&frame, opt->check.errors);
        ast_free_unattached(v_type);
        return false;
      }

      ast_free_unattached(v_type);
    }
  }

  if(is_typecheck_error(type))
    return false;

  if(is_dontcare)
  {
    *out_field = NULL;
    return true;
  }

  type = sanitise_type(type);

  BUILD(field, id_node,
    NODE(TK_FVAR,
      TREE(id_node)
      TREE(type)
      TREE(value)));

  *out_field = field;
  return true;
}
예제 #18
0
파일: reference.c 프로젝트: tmmcguire/ponyc
bool expr_this(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

  if(t->frame->def_arg != NULL)
  {
    ast_error(opt->check.errors, ast,
      "can't reference 'this' in a default argument");
    return false;
  }

  sym_status_t status;
  ast_get(ast, stringtab("this"), &status);

  if(status == SYM_CONSUMED)
  {
    ast_error(opt->check.errors, ast,
      "can't use a consumed 'this' in an expression");
    return false;
  }

  assert(status == SYM_NONE);
  token_id cap = cap_for_this(t);

  if(!cap_sendable(cap) && (t->frame->recover != NULL))
  {
    ast_t* parent = ast_parent(ast);
    if(ast_id(parent) != TK_DOT)
      cap = TK_TAG;
  }

  bool make_arrow = false;

  if(cap == TK_BOX)
  {
    cap = TK_REF;
    make_arrow = true;
  }

  ast_t* type = type_for_this(opt, ast, cap, TK_NONE, false);

  if(make_arrow)
  {
    BUILD(arrow, ast, NODE(TK_ARROW, NODE(TK_THISTYPE) TREE(type)));
    type = arrow;
  }

  // Get the nominal type, which may be the right side of an arrow type.
  ast_t* nominal;
  bool arrow;

  if(ast_id(type) == TK_NOMINAL)
  {
    nominal = type;
    arrow = false;
  } else {
    nominal = ast_childidx(type, 1);
    arrow = true;
  }

  ast_t* typeargs = ast_childidx(nominal, 2);
  ast_t* typearg = ast_child(typeargs);

  while(typearg != NULL)
  {
    if(!expr_nominal(opt, &typearg))
    {
      ast_error(opt->check.errors, ast, "couldn't create a type for 'this'");
      ast_free(type);
      return false;
    }

    typearg = ast_sibling(typearg);
  }

  if(!expr_nominal(opt, &nominal))
  {
    ast_error(opt->check.errors, ast, "couldn't create a type for 'this'");
    ast_free(type);
    return false;
  }

  // Unless this is a field lookup, treat an incomplete `this` as a tag.
  ast_t* parent = ast_parent(ast);
  bool incomplete_ok = false;

  if((ast_id(parent) == TK_DOT) && (ast_child(parent) == ast))
  {
    ast_t* right = ast_sibling(ast);
    assert(ast_id(right) == TK_ID);
    ast_t* find = lookup_try(opt, ast, nominal, ast_name(right));

    if(find != NULL)
    {
      switch(ast_id(find))
      {
        case TK_FVAR:
        case TK_FLET:
        case TK_EMBED:
          incomplete_ok = true;
          break;

        default: {}
      }
    }
  }

  if(!incomplete_ok && is_this_incomplete(t, ast))
  {
    ast_t* tag_type = set_cap_and_ephemeral(nominal, TK_TAG, TK_NONE);
    ast_replace(&nominal, tag_type);
  }

  if(arrow)
    type = ast_parent(nominal);
  else
    type = nominal;

  ast_settype(ast, type);
  return true;
}
예제 #19
0
파일: reference.c 프로젝트: Preetam/ponyc
bool expr_this(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

  if(t->frame->def_arg != NULL)
  {
    ast_error(ast, "can't reference 'this' in a default argument");
    return false;
  }

  sym_status_t status;
  ast_get(ast, stringtab("this"), &status);

  if(status == SYM_CONSUMED)
  {
    ast_error(ast, "can't use a consumed 'this' in an expression");
    return false;
  }

  assert(status == SYM_NONE);
  token_id cap = cap_for_this(t);

  if(!cap_sendable(cap) && (t->frame->recover != NULL))
    cap = TK_TAG;

  bool make_arrow = false;

  if(cap == TK_BOX)
  {
    cap = TK_REF;
    make_arrow = true;
  }

  ast_t* type = type_for_this(opt, ast, cap, TK_NONE, false);

  if(make_arrow)
  {
    BUILD(arrow, ast, NODE(TK_ARROW, NODE(TK_THISTYPE) TREE(type)));
    type = arrow;
  }

  // Get the nominal type, which may be the right side of an arrow type.
  ast_t* nominal;
  bool arrow;

  if(ast_id(type) == TK_NOMINAL)
  {
    nominal = type;
    arrow = false;
  } else {
    nominal = ast_childidx(type, 1);
    arrow = true;
  }

  ast_t* typeargs = ast_childidx(nominal, 2);
  ast_t* typearg = ast_child(typeargs);

  while(typearg != NULL)
  {
    if(!expr_nominal(opt, &typearg))
    {
      ast_error(ast, "couldn't create a type for 'this'");
      ast_free(type);
      return false;
    }

    typearg = ast_sibling(typearg);
  }

  if(!expr_nominal(opt, &nominal))
  {
    ast_error(ast, "couldn't create a type for 'this'");
    ast_free(type);
    return false;
  }

  if(arrow)
    type = ast_parent(nominal);
  else
    type = nominal;

  ast_settype(ast, type);
  return true;
}
예제 #20
0
파일: lambda.c 프로젝트: Praetonus/ponyc
// Process the given capture and create the AST for the corresponding field.
// Returns the create field AST, which must be freed by the caller.
// Returns NULL on error.
static ast_t* make_capture_field(pass_opt_t* opt, ast_t* capture)
{
  assert(capture != NULL);

  AST_GET_CHILDREN(capture, id_node, type, value);
  const char* name = ast_name(id_node);

  // There are 3 varieties of capture:
  // x -> capture variable x, type from defn of x
  // x = y -> capture expression y, type inferred from expression type
  // x: T = y -> capture expression y, type T

  if(ast_id(value) == TK_NONE)
  {
    // Variable capture
    assert(ast_id(type) == TK_NONE);

    ast_t* def = ast_get(capture, name, NULL);

    if(def == NULL)
    {
      ast_error(opt->check.errors, id_node,
        "cannot capture \"%s\", variable not defined", name);
      return NULL;
    }

    token_id def_id = ast_id(def);

    if(def_id != TK_ID && def_id != TK_FVAR && def_id != TK_FLET &&
      def_id != TK_PARAM)
    {
      ast_error(opt->check.errors, id_node, "cannot capture \"%s\", can only "
        "capture fields, parameters and local variables", name);
      return NULL;
    }

    BUILD(capture_rhs, id_node, NODE(TK_REFERENCE, ID(name)));

    type = alias(ast_type(def));
    value = capture_rhs;
  } else if(ast_id(type) == TK_NONE) {
    // No type specified, use type of the captured expression
    type = alias(ast_type(value));
  } else {
    // Type given, infer literals
    if(!coerce_literals(&value, type, opt))
      return NULL;
  }

  if(is_typecheck_error(type))
    return NULL;

  type = sanitise_type(type);

  BUILD(field, id_node,
    NODE(TK_FVAR,
      TREE(id_node)
      TREE(type)
      TREE(value)
      NONE));  // Delegate type

  return field;
}
예제 #21
0
파일: lambda.c 프로젝트: Perelandric/ponyc
static bool capture_from_reference(pass_opt_t* opt, ast_t* ctx, ast_t* ast,
  ast_t* captures, ast_t** last_capture)
{
  const char* name = ast_name(ast_child(ast));

  if(is_name_dontcare(name))
    return true;

  ast_t* refdef = ast_get(ast, name, NULL);

  if(refdef != NULL)
    return true;

  refdef = ast_get(ctx, name, NULL);

  if(refdef == NULL)
  {
    ast_error(opt->check.errors, ast,
      "cannot capture \"%s\", variable not defined", name);
    return false;
  }

  if(!def_before_use(opt, refdef, ctx, name))
    return false;

  switch(ast_id(refdef))
  {
    case TK_VAR:
    case TK_LET:
    case TK_PARAM:
    case TK_MATCH_CAPTURE:
    case TK_FVAR:
    case TK_FLET:
    case TK_EMBED:
      break;

    default:
      ast_error(opt->check.errors, ast, "cannot capture \"%s\", can only "
        "capture fields, parameters and local variables", name);
      return NULL;
  }

  // Check if we've already captured it
  for(ast_t* p = ast_child(captures); p != NULL; p = ast_sibling(p))
  {
    AST_GET_CHILDREN(p, c_name, c_type);

    if(name == ast_name(c_name))
      return true;
  }

  ast_t* type = alias(ast_type(refdef));

  if(is_typecheck_error(type))
    return false;

  type = sanitise_type(type);

  BUILD(field, ast,
    NODE(TK_FVAR,
      ID(name)
      TREE(type)
      NODE(TK_REFERENCE, ID(name))));

  ast_list_append(captures, last_capture, field);
  return true;
}
예제 #22
0
파일: scope.c 프로젝트: jonas-l/ponyc
/**
 * Insert a name->AST mapping into the specified scope.
 */
static bool set_scope(typecheck_t* t, ast_t* scope, ast_t* name, ast_t* value)
{
  assert(ast_id(name) == TK_ID);
  const char* s = ast_name(name);

  sym_status_t status = SYM_NONE;

  switch(ast_id(value))
  {
    case TK_ID:
    {
      if((t != NULL) && (t->frame->pattern != NULL))
        status = SYM_DEFINED;
      else
        status = SYM_UNDEFINED;

      break;
    }

    case TK_FFIDECL:
    case TK_TYPE:
    case TK_INTERFACE:
    case TK_TRAIT:
    case TK_PRIMITIVE:
    case TK_CLASS:
    case TK_ACTOR:
    case TK_TYPEPARAM:
    case TK_PACKAGE:
    case TK_NEW:
    case TK_BE:
    case TK_FUN:
      break;

    case TK_FVAR:
    case TK_FLET:
    case TK_EMBED:
      status = SYM_DEFINED;
      break;

    case TK_PARAM:
      status = SYM_DEFINED;
      break;

    default:
      assert(0);
      return false;
  }

  if(!ast_set(scope, s, value, status))
  {
    ast_t* prev = ast_get(scope, s, NULL);
    ast_t* prev_nocase = ast_get_case(scope, s, NULL);

    ast_error(name, "can't reuse name '%s'", s);
    ast_error(prev_nocase, "previous use of '%s'%s",
      s, (prev == NULL) ? " differs only by case" : "");

    return false;
  }

  return true;
}
예제 #23
0
파일: genexe.c 프로젝트: jonas-l/ponyc
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);

  const char* create = stringtab("create");

  if(lookup(NULL, main_ast, main_ast, create) == NULL)
    return false;

  genprim_reachable_init(c, program);
  reach(c->reachable, main_ast, 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;
}
예제 #24
0
파일: reference.c 프로젝트: Preetam/ponyc
bool expr_reference(pass_opt_t* opt, ast_t** astp)
{
  typecheck_t* t = &opt->check;
  ast_t* ast = *astp;

  // Everything we reference must be in scope.
  const char* name = ast_name(ast_child(ast));

  sym_status_t status;
  ast_t* def = ast_get(ast, name, &status);

  if(def == NULL)
  {
    const char* alt_name = suggest_alt_name(ast, name);

    if(alt_name == NULL)
      ast_error(ast, "can't find declaration of '%s'", name);
    else
      ast_error(ast, "can't find declaration of '%s', did you mean '%s'?",
        name, alt_name);

    return false;
  }

  switch(ast_id(def))
  {
    case TK_PACKAGE:
    {
      // Only allowed if in a TK_DOT with a type.
      if(ast_id(ast_parent(ast)) != TK_DOT)
      {
        ast_error(ast, "a package can only appear as a prefix to a type");
        return false;
      }

      ast_setid(ast, TK_PACKAGEREF);
      return true;
    }

    case TK_INTERFACE:
    case TK_TRAIT:
    case TK_TYPE:
    case TK_TYPEPARAM:
    case TK_PRIMITIVE:
    case TK_STRUCT:
    case TK_CLASS:
    case TK_ACTOR:
    {
      // It's a type name. This may not be a valid type, since it may need
      // type arguments.
      ast_t* id = ast_child(def);
      const char* name = ast_name(id);
      ast_t* type = type_sugar(ast, NULL, name);
      ast_settype(ast, type);
      ast_setid(ast, TK_TYPEREF);

      return expr_typeref(opt, astp);
    }

    case TK_FVAR:
    case TK_FLET:
    case TK_EMBED:
    {
      // Transform to "this.f".
      if(!def_before_use(def, ast, name))
        return false;

      ast_t* dot = ast_from(ast, TK_DOT);
      ast_add(dot, ast_child(ast));

      ast_t* self = ast_from(ast, TK_THIS);
      ast_add(dot, self);

      ast_replace(astp, dot);

      if(!expr_this(opt, self))
        return false;

      return expr_dot(opt, astp);
    }

    case TK_PARAM:
    {
      if(t->frame->def_arg != NULL)
      {
        ast_error(ast, "can't reference a parameter in a default argument");
        return false;
      }

      if(!def_before_use(def, ast, name))
        return false;

      ast_t* type = ast_type(def);

      if(is_typecheck_error(type))
        return false;

      if(!valid_reference(opt, ast, type, status))
        return false;

      if(!sendable(type) && (t->frame->recover != NULL))
      {
        ast_error(ast,
          "can't access a non-sendable parameter from inside a recover "
          "expression");
        return false;
      }

      // Get the type of the parameter and attach it to our reference.
      // Automatically consume a parameter if the function is done.
      ast_t* r_type = type;

      if(is_method_return(t, ast))
        r_type = consume_type(type, TK_NONE);

      ast_settype(ast, r_type);
      ast_setid(ast, TK_PARAMREF);
      return true;
    }

    case TK_NEW:
    case TK_BE:
    case TK_FUN:
    {
      // Transform to "this.f".
      ast_t* dot = ast_from(ast, TK_DOT);
      ast_add(dot, ast_child(ast));

      ast_t* self = ast_from(ast, TK_THIS);
      ast_add(dot, self);

      ast_replace(astp, dot);

      if(!expr_this(opt, self))
        return false;

      return expr_dot(opt, astp);
    }

    case TK_ID:
    {
      if(!def_before_use(def, ast, name))
        return false;

      ast_t* type = ast_type(def);

      if(type != NULL && ast_id(type) == TK_INFERTYPE)
      {
        ast_error(ast, "cannot infer type of %s\n", ast_nice_name(def));
        ast_settype(def, ast_from(def, TK_ERRORTYPE));
        ast_settype(ast, ast_from(ast, TK_ERRORTYPE));
        return false;
      }

      if(is_typecheck_error(type))
        return false;

      if(!valid_reference(opt, ast, type, status))
        return false;

      ast_t* var = ast_parent(def);

      switch(ast_id(var))
      {
        case TK_VAR:
          ast_setid(ast, TK_VARREF);
          break;

        case TK_LET:
        case TK_MATCH_CAPTURE:
          ast_setid(ast, TK_LETREF);
          break;

        default:
          assert(0);
          return false;
      }

      if(!sendable(type))
      {
        if(t->frame->recover != NULL)
        {
          ast_t* def_recover = ast_nearest(def, TK_RECOVER);

          if(t->frame->recover != def_recover)
          {
            ast_error(ast, "can't access a non-sendable local defined outside "
              "of a recover expression from within that recover expression");
            return false;
          }
        }
      }

      // Get the type of the local and attach it to our reference.
      // Automatically consume a local if the function is done.
      ast_t* r_type = type;

      if(is_method_return(t, ast))
        r_type = consume_type(type, TK_NONE);

      ast_settype(ast, r_type);
      return true;
    }

    default: {}
  }

  assert(0);
  return false;
}
예제 #25
0
파일: lookup.c 프로젝트: Potpourri/ponyc
static ast_t* lookup_nominal(typecheck_t* t, ast_t* from, ast_t* orig,
  ast_t* type, const char* name, bool errors)
{
  assert(ast_id(type) == TK_NOMINAL);
  ast_t* def = (ast_t*)ast_data(type);
  ast_t* type_name = ast_child(def);
  ast_t* find = ast_get(def, name, NULL);

  if(find != NULL)
  {
    switch(ast_id(find))
    {
      case TK_FVAR:
      case TK_FLET:
      case TK_NEW:
      case TK_BE:
      case TK_FUN:
        break;

      default:
        find = NULL;
    }
  }

  if(find == NULL)
  {
    if(errors)
      ast_error(from, "couldn't find '%s' in '%s'", name, ast_name(type_name));

    return NULL;
  }

  if((name[0] == '_') && (from != NULL) && (t != NULL))
  {
    switch(ast_id(find))
    {
      case TK_FVAR:
      case TK_FLET:
        if(t->frame->type != def)
        {
          if(errors)
          {
            ast_error(from,
              "can't lookup private fields from outside the type");
          }

          return NULL;
        }
        break;

      case TK_NEW:
      case TK_BE:
      case TK_FUN:
      {
        if(ast_nearest(def, TK_PACKAGE) != t->frame->package)
        {
          if(errors)
          {
            ast_error(from,
              "can't lookup private methods from outside the package");
          }

          return NULL;
        }
        break;
      }

      default:
        assert(0);
        return NULL;
    }

    if(!strcmp(name, "_final"))
    {
      switch(ast_id(find))
      {
        case TK_NEW:
        case TK_BE:
        case TK_FUN:
          if(errors)
            ast_error(from, "can't lookup a _final function");

          return NULL;

        default: {}
      }
    }
  }

  ast_t* typeparams = ast_sibling(type_name);
  ast_t* typeargs = ast_childidx(type, 2);

  find = ast_dup(find);
  orig = ast_dup(orig);
  replace_thistype(&find, orig);
  ast_free_unattached(orig);

  ast_t* r_find = reify(from, find, typeparams, typeargs);

  if(r_find != find)
  {
    ast_free_unattached(find);
    find = r_find;
  }

  if((find != NULL) && !flatten_arrows(&find, errors))
  {
    if(errors)
      ast_error(from, "can't look this up on a tag");

    ast_free_unattached(find);
    return NULL;
  }

  return find;
}
예제 #26
0
파일: package.c 프로젝트: lzpfmh/ponyc
ast_t* package_load(ast_t* from, const char* path, pass_opt_t* options)
{
  assert(from != NULL);

  const char* magic = find_magic_package(path);
  const char* full_path = path;
  const char* qualified_name = path;
  ast_t* program = ast_nearest(from, TK_PROGRAM);

  if(magic == NULL)
  {
    // Lookup (and hence normalise) path
    bool is_relative = false;
    full_path = find_path(from, path, &is_relative);

    if(full_path == NULL)
      return NULL;

    if((from != program) && is_relative)
    {
      // Package to load is relative to from, build the qualified name
      // The qualified name should be relative to the program being built
      package_t* from_pkg = (package_t*)ast_data(ast_child(program));

      if(from_pkg != NULL)
      {
        const char* base_name = from_pkg->qualified_name;
        size_t base_name_len = strlen(base_name);
        size_t path_len = strlen(path);
        size_t len = base_name_len + path_len + 2;
        char* q_name = (char*)pool_alloc_size(len);
        memcpy(q_name, base_name, base_name_len);
        q_name[base_name_len] = '/';
        memcpy(q_name + base_name_len + 1, path, path_len);
        q_name[len - 1] = '\0';
        qualified_name = stringtab_consume(q_name, len);
      }
    }
  }

  ast_t* package = ast_get(program, full_path, NULL);

  // Package already loaded
  if(package != NULL)
    return package;

  package = create_package(program, full_path, qualified_name);

  if(report_build)
    printf("Building %s -> %s\n", path, full_path);

  if(magic != NULL)
  {
    if(!parse_source_code(package, magic, options))
      return NULL;
  }
  else
  {
    if(!parse_files_in_dir(package, full_path, options))
      return NULL;
  }

  if(ast_child(package) == NULL)
  {
    ast_error(package, "no source files in package '%s'", path);
    return NULL;
  }

  if(!ast_passes_subtree(&package, options, options->program_pass))
  {
    // If these passes failed, don't run future passes.
    ast_setflag(package, AST_FLAG_PRESERVE);
    return NULL;
  }

  return package;
}
예제 #27
0
파일: subtype.c 프로젝트: jersey99/ponyc
static bool is_fun_sub_fun(ast_t* sub, ast_t* super, errorframe_t* errors)
{
  token_id tsub = ast_id(sub);
  token_id tsuper = ast_id(super);

  switch(tsub)
  {
    case TK_NEW:
    case TK_BE:
    case TK_FUN:
      break;

    default:
      return false;
  }

  switch(tsuper)
  {
    case TK_NEW:
    case TK_BE:
    case TK_FUN:
      break;

    default:
      return false;
  }

  AST_GET_CHILDREN(sub, sub_cap, sub_id, sub_typeparams, sub_params);
  AST_GET_CHILDREN(super, super_cap, super_id, super_typeparams, super_params);

  // Must have the same name.
  if(ast_name(sub_id) != ast_name(super_id))
  {
    if(errors != NULL)
    {
      ast_error_frame(errors, sub,
        "method %s is not a subtype of method %s: they have different names",
        ast_name(sub_id), ast_name(super_id));
    }

    return false;
  }

  // A constructor can only be a subtype of a constructor.
  if(((tsub == TK_NEW) || (tsuper == TK_NEW)) && (tsub != tsuper))
  {
    if(errors != NULL)
      ast_error_frame(errors, sub,
        "only a constructor can be a subtype of a constructor");

    return false;
  }

  // Must have the same number of type parameters.
  if(ast_childcount(sub_typeparams) != ast_childcount(super_typeparams))
  {
    if(errors != NULL)
      ast_error_frame(errors, sub,
        "methods have a different number of type parameters");

    return false;
  }

  // Must have the same number of parameters.
  if(ast_childcount(sub_params) != ast_childcount(super_params))
  {
    if(errors != NULL)
      ast_error_frame(errors, sub,
        "methods have a different number of parameters");

    return false;
  }

  ast_t* r_sub = sub;

  if(ast_id(super_typeparams) != TK_NONE)
  {
    // Reify sub with the type parameters of super.
    BUILD(typeargs, super_typeparams, NODE(TK_TYPEARGS));
    ast_t* super_typeparam = ast_child(super_typeparams);

    while(super_typeparam != NULL)
    {
      AST_GET_CHILDREN(super_typeparam, super_id, super_constraint);

      BUILD(typearg, super_typeparam,
        NODE(TK_TYPEPARAMREF, TREE(super_id) NONE NONE));

      ast_t* def = ast_get(super_typeparam, ast_name(super_id), NULL);
      ast_setdata(typearg, def);
      typeparam_set_cap(typearg);
      ast_append(typeargs, typearg);

      super_typeparam = ast_sibling(super_typeparam);
    }

    r_sub = reify(sub, sub_typeparams, typeargs);
    ast_free_unattached(typeargs);
  }

  bool ok = is_reified_fun_sub_fun(r_sub, super, errors);

  if(r_sub != sub)
    ast_free_unattached(r_sub);

  return ok;
}