Exemple #1
0
// Add the given case method into the given match method wrapper and check the
// are compatible.
// Returns: match case for worker method or NULL on error.
static ast_t* add_case_method(ast_t* match_method, ast_t* case_method)
{
  assert(match_method != NULL);
  assert(case_method != NULL);

  // We need default capabality and return value if not provided explicitly.
  if(ast_id(case_method) == TK_FUN)
    fun_defaults(case_method);

  AST_GET_CHILDREN(match_method, match_cap, match_id, match_t_params,
    match_params, match_ret_type, match_question);

  AST_GET_CHILDREN(case_method, case_cap, case_id, case_t_params, case_params,
    case_ret_type, case_question, case_body, case_docstring, case_guard);

  bool ok = true;

  if(ast_id(case_method) != ast_id(match_method))
  {
    ast_error(case_method,
      "cannot mix fun and be cases in a single match method");
    ast_error(match_method, "clashing method here");
    ok = false;
  }

  if(ast_id(case_method) == TK_FUN)
  {
    if(ast_id(case_cap) != ast_id(match_cap))
    {
      ast_error(case_cap, "differing receiver capabilities on case methods");
      ast_error(match_cap, "clashing capability here");
      ok = false;
    }

    if(ast_id(match_ret_type) == TK_NONE)
    {
      // Use case method return type.
      ast_replace(&match_ret_type, case_ret_type);
    }
    else
    {
      // Union this case method's return type with the existing match one.
      REPLACE(&match_ret_type,
        NODE(TK_UNIONTYPE,
        TREE(match_ret_type)
        TREE(case_ret_type)));
    }
  }

  if(ast_id(case_question) == TK_QUESTION)
    // If any case throws the match does too.
    ast_setid(match_question, TK_QUESTION);

  if(!process_t_params(match_t_params, case_t_params))
    ok = false;

  ast_t* pattern = process_params(match_params, case_params);

  if(!ok || pattern == NULL)
  {
    ast_free(pattern);
    return NULL;
  }

  // Extract case body and guard condition (if any) to avoid copying.
  ast_t* body = ast_from(case_body, TK_NONE);
  ast_swap(case_body, body);
  ast_t* guard = ast_from(case_guard, TK_NONE);
  ast_swap(case_guard, guard);

  // Make match case.
  BUILD(match_case, pattern,
    NODE(TK_CASE, AST_SCOPE
      TREE(pattern)
      TREE(case_guard)
      TREE(case_body)));

  return match_case;
}
Exemple #2
0
// Make a skeleton wrapper method based on the given case method.
// Returns: created method, NULL on error.
static ast_t* make_match_wrapper(ast_t* case_method)
{
  assert(case_method != NULL);

  if(ast_id(case_method) == TK_FUN)
    fun_defaults(case_method);

  AST_GET_CHILDREN(case_method, cap, id, t_params, params, ret_type, question,
    body, docstring);

  if(ast_child(params) == NULL)
  {
    ast_error(params, "case method must have at least one parameter");
    return NULL;
  }

  ast_t* new_params = ast_from(params, TK_PARAMS);
  ast_t* param_list_end = NULL;

  for(ast_t* p = ast_child(params); p != NULL; p = ast_sibling(p))
  {
    // Set all parameter info to none now and fill it in later.
    BUILD(new_param, p, NODE(TK_PARAM, NONE NONE NONE));
    ast_list_append(new_params, &param_list_end, new_param);
  }

  ast_t* new_t_params = ast_from(params, TK_NONE);
  ast_t* t_param_list_end = NULL;

  for(ast_t* p = ast_child(t_params); p != NULL; p = ast_sibling(p))
  {
    // Set all type parameter info to none now and fill it in later.
    BUILD(new_t_param, p, NODE(TK_TYPEPARAM, NONE NONE NONE));
    ast_list_append(new_t_params, &t_param_list_end, new_t_param);
    ast_setid(new_t_params, TK_TYPEPARAMS);
  }

  if(ast_id(case_method) == TK_FUN)
  {
    // Function case.

    // TODO: For now always need a `None |` in the return type to allow for
    // match else clause. We won't need that once exhaustive matching is done.
    BUILD(wrapper, case_method,
      NODE(ast_id(case_method), AST_SCOPE
        TREE(cap)
        TREE(id)
        TREE(new_t_params)
        TREE(new_params)
        NODE(TK_NOMINAL, NONE ID("None") NONE NONE NONE)  // Return value.
        NONE    // Error.
        NODE(TK_SEQ)  // Body.
        NONE    // Doc string.
        NONE)); // Guard.

    return wrapper;
  }
  else
  {
    // Behaviour case.
    BUILD(wrapper, case_method,
      NODE(ast_id(case_method), AST_SCOPE
      NONE    // Capability.
      TREE(id)
      TREE(new_t_params)
      TREE(new_params)
      NONE    // Return value.
      NONE    // Error.
      NODE(TK_SEQ)  // Body.
      NONE    // Doc string.
      NONE)); // Guard.

    return wrapper;
  }
}
Exemple #3
0
static ast_result_t sugar_fun(ast_t* ast)
{
  fun_defaults(ast);
  sugar_docstring(ast);
  return check_method(ast);
}