Пример #1
0
// Check the extra information. This includes:
// * legal data pointer
// * legal scope symbol table
// * no extra children
static check_res_t check_extras(ast_t* ast, check_state_t* state)
{
  assert(ast != NULL);
  assert(state != NULL);

  if(state->child != NULL)
  {
    printf("Internal error: AST node id %d, child %ld (id %d) unexpected\n",
      ast_id(ast), state->child_index, ast_id(state->child));
    return CHK_ERROR;
  }

  if(ast_data(ast) != NULL && !state->has_data)
  {
    printf("Internal error: AST node id %d, unexpected data %p\n",
      ast_id(ast), ast_data(ast));
    return CHK_ERROR;
  }

  if(ast_has_scope(ast) && !state->is_scope)
  {
    printf("Internal error: AST node id %d unexpectedly has scope\n",
      ast_id(ast));
    return CHK_ERROR;
  }

  return CHK_OK;
}
Пример #2
0
// Sort out symbol table for copied method body
static ast_result_t rescope(ast_t** astp, pass_opt_t* options)
{
  (void)options;
  ast_t* ast = *astp;

  if(ast_has_scope(ast))
    ast_clear_local(ast);

  switch(ast_id(ast))
  {
    case TK_FVAR:
    case TK_FLET:
    case TK_PARAM:
    case TK_TYPEPARAM:
      assert(ast_child(ast) != NULL);
      ast_set(ast, ast_name(ast_child(ast)), ast, SYM_DEFINED);
      break;

    case TK_LET:
    case TK_VAR:
    {
      ast_t* scope = ast_parent(ast);
      ast_t* id = ast_child(ast);
      ast_set(scope, ast_name(id), id, SYM_DEFINED);
      break;
    }

    default: {}
  }

  return AST_OK;
}
Пример #3
0
// Sort out symbol table for copied method body.
static ast_result_t rescope(ast_t** astp, pass_opt_t* options)
{
  (void)options;
  ast_t* ast = *astp;

  if(ast_has_scope(ast))
    ast_clear_local(ast);

  switch(ast_id(ast))
  {
    case TK_FVAR:
    case TK_FLET:
    case TK_EMBED:
    case TK_PARAM:
    case TK_TYPEPARAM:
    {
      assert(ast_child(ast) != NULL);
      ast_set(ast, ast_name(ast_child(ast)), ast, SYM_DEFINED, true);
      break;
    }

    case TK_LET:
    case TK_VAR:
    {
      ast_t* scope = ast_parent(ast);
      ast_t* id = ast_child(ast);
      ast_set(scope, ast_name(id), id, SYM_UNDEFINED, true);
      break;
    }

    case TK_MATCH_CAPTURE:
    {
      ast_t* scope = ast_parent(ast);
      ast_t* id = ast_child(ast);
      ast_set(scope, ast_name(id), id, SYM_DEFINED, true);
      break;
    }

    case TK_TYPEPARAMREF:
    {
      assert(ast_child(ast) != NULL);
      ast_t* def = ast_get(ast, ast_name(ast_child(ast)), NULL);
      ast_setdata(ast, def);
      break;
    }

    default: {}
  }

  return AST_OK;
}
Пример #4
0
LLVMValueRef gen_expr(compile_t* c, ast_t* ast)
{
  LLVMValueRef ret;
  bool has_scope = ast_has_scope(ast);
  bool has_source = codegen_hassource(c);

  if(has_scope)
  {
    codegen_pushscope(c);

    // Dwarf a new lexical scope, if necessary.
    if(has_source)
      dwarf_lexicalscope(&c->dwarf, ast);
  }

  switch(ast_id(ast))
  {
    case TK_SEQ:
      ret = gen_seq(c, ast);
      break;

    case TK_FVARREF:
    case TK_FLETREF:
      ret = gen_fieldload(c, ast);
      break;

    case TK_PARAMREF:
      ret = gen_param(c, ast);
      break;

    case TK_VAR:
    case TK_LET:
      ret = gen_localdecl(c, ast);
      break;

    case TK_VARREF:
    case TK_LETREF:
      ret = gen_localload(c, ast);
      break;

    case TK_IF:
      ret = gen_if(c, ast);
      break;

    case TK_WHILE:
      ret = gen_while(c, ast);
      break;

    case TK_REPEAT:
      ret = gen_repeat(c, ast);
      break;

    case TK_TRY:
    case TK_TRY_NO_CHECK:
      ret = gen_try(c, ast);
      break;

    case TK_MATCH:
      ret = gen_match(c, ast);
      break;

    case TK_CALL:
      ret = gen_call(c, ast);
      break;

    case TK_CONSUME:
      ret = gen_expr(c, ast_childidx(ast, 1));
      break;

    case TK_RECOVER:
      ret = gen_expr(c, ast_childidx(ast, 1));
      break;

    case TK_BREAK:
      ret = gen_break(c, ast);
      break;

    case TK_CONTINUE:
      ret = gen_continue(c, ast);
      break;

    case TK_RETURN:
      ret = gen_return(c, ast);
      break;

    case TK_ERROR:
      ret = gen_error(c, ast);
      break;

    case TK_IS:
      ret = gen_is(c, ast);
      break;

    case TK_ISNT:
      ret = gen_isnt(c, ast);
      break;

    case TK_ASSIGN:
      ret = gen_assign(c, ast);
      break;

    case TK_THIS:
      ret = gen_this(c, ast);
      break;

    case TK_TRUE:
      ret = LLVMConstInt(c->i1, 1, false);
      break;

    case TK_FALSE:
      ret = LLVMConstInt(c->i1, 0, false);
      break;

    case TK_INT:
      ret = gen_int(c, ast);
      break;

    case TK_FLOAT:
      ret = gen_float(c, ast);
      break;

    case TK_STRING:
      ret = gen_string(c, ast);
      break;

    case TK_TUPLE:
      ret = gen_tuple(c, ast);
      break;

    case TK_FFICALL:
      ret = gen_ffi(c, ast);
      break;

    case TK_AMP:
      ret = gen_addressof(c, ast);
      break;

    case TK_IDENTITY:
      ret = gen_identity(c, ast);
      break;

    case TK_DONTCARE:
      ret = GEN_NOVALUE;
      break;

    case TK_COMPILER_INTRINSIC:
      ast_error(ast, "unimplemented compiler intrinsic");
      LLVMBuildUnreachable(c->builder);
      ret = GEN_NOVALUE;
      break;

    default:
      ast_error(ast, "not implemented (codegen unknown)");
      return NULL;
  }

  if(has_scope)
  {
    codegen_popscope(c);

    if(has_source)
      dwarf_finish(&c->dwarf);
  }

  return ret;
}
Пример #5
0
LLVMValueRef gen_expr(compile_t* c, ast_t* ast)
{
  LLVMValueRef ret;
  bool has_scope = ast_has_scope(ast);

  if(has_scope)
    codegen_pushscope(c, ast);

  switch(ast_id(ast))
  {
    case TK_SEQ:
      ret = gen_seq(c, ast);
      break;

    case TK_FVARREF:
    case TK_FLETREF:
      ret = gen_fieldload(c, ast);
      break;

    case TK_EMBEDREF:
      ret = gen_fieldptr(c, ast);
      break;

    case TK_PARAMREF:
      ret = gen_param(c, ast);
      break;

    case TK_VAR:
    case TK_LET:
    case TK_MATCH_CAPTURE:
      ret = gen_localdecl(c, ast);
      break;

    case TK_VARREF:
    case TK_LETREF:
      ret = gen_localload(c, ast);
      break;

    case TK_IF:
      ret = gen_if(c, ast);
      break;

    case TK_WHILE:
      ret = gen_while(c, ast);
      break;

    case TK_REPEAT:
      ret = gen_repeat(c, ast);
      break;

    case TK_TRY:
    case TK_TRY_NO_CHECK:
      ret = gen_try(c, ast);
      break;

    case TK_MATCH:
      ret = gen_match(c, ast);
      break;

    case TK_CALL:
      ret = gen_call(c, ast);
      break;

    case TK_CONSUME:
      ret = gen_expr(c, ast_childidx(ast, 1));
      break;

    case TK_RECOVER:
      ret = gen_expr(c, ast_childidx(ast, 1));
      break;

    case TK_BREAK:
      ret = gen_break(c, ast);
      break;

    case TK_CONTINUE:
      ret = gen_continue(c, ast);
      break;

    case TK_RETURN:
      ret = gen_return(c, ast);
      break;

    case TK_ERROR:
      ret = gen_error(c, ast);
      break;

    case TK_IS:
      ret = gen_is(c, ast);
      break;

    case TK_ISNT:
      ret = gen_isnt(c, ast);
      break;

    case TK_ASSIGN:
      ret = gen_assign(c, ast);
      break;

    case TK_THIS:
      ret = gen_this(c, ast);
      break;

    case TK_TRUE:
      ret = LLVMConstInt(c->i1, 1, false);
      break;

    case TK_FALSE:
      ret = LLVMConstInt(c->i1, 0, false);
      break;

    case TK_INT:
      ret = gen_int(c, ast);
      break;

    case TK_FLOAT:
      ret = gen_float(c, ast);
      break;

    case TK_STRING:
      ret = gen_string(c, ast);
      break;

    case TK_TUPLE:
      ret = gen_tuple(c, ast);
      break;

    case TK_FFICALL:
      ret = gen_ffi(c, ast);
      break;

    case TK_ADDRESS:
      ret = gen_addressof(c, ast);
      break;

    case TK_DIGESTOF:
      ret = gen_digestof(c, ast);
      break;

    case TK_DONTCARE:
      ret = GEN_NOVALUE;
      break;

    case TK_COMPILE_INTRINSIC:
      ast_error(c->opt->check.errors, ast, "unimplemented compile intrinsic");
      return NULL;

    case TK_COMPILE_ERROR:
    {
      ast_t* reason_seq = ast_child(ast);
      ast_t* reason = ast_child(reason_seq);
      ast_error(c->opt->check.errors, ast, "compile error: %s",
        ast_name(reason));
      return NULL;
    }

    default:
      ast_error(c->opt->check.errors, ast, "not implemented (codegen unknown)");
      return NULL;
  }

  if(has_scope)
    codegen_popscope(c);

  return ret;
}
Пример #6
0
static bool compare_asts(ast_t* prev, ast_t* expected, ast_t* actual,
  bool check_siblings)
{
  assert(prev != NULL);

  if(expected == NULL && actual == NULL)
    return true;

  if(actual == NULL)
  {
    ast_error(expected, "Expected AST %s not found", ast_get_print(expected));
    return false;
  }

  if(expected == NULL)
  {
    ast_error(prev, "Unexpected AST node found, %s", ast_get_print(actual));
    return false;
  }

  token_id expected_id = ast_id(expected);
  token_id actual_id = ast_id(actual);

  if(expected_id != actual_id)
  {
    ast_error(expected, "AST ID mismatch, got %d (%s), expected %d (%s)",
      ast_id(actual), ast_get_print(actual),
      ast_id(expected), ast_get_print(expected));
    return false;
  }

  if(ast_id(expected) == TK_ID && ast_name(actual)[0] == '$' &&
    strcmp(ast_name(expected), "hygid") == 0)
  {
    // Allow expected "hygid" to match any hygenic ID
  }
  else if(strcmp(ast_get_print(expected), ast_get_print(actual)) != 0)
  {
    ast_error(expected, "AST text mismatch, got %s, expected %s",
      ast_get_print(actual), ast_get_print(expected));
    return false;
  }

  if(ast_has_scope(expected) && !ast_has_scope(actual))
  {
    ast_error(expected, "AST missing scope");
    return false;
  }

  if(!ast_has_scope(expected) && ast_has_scope(actual))
  {
    ast_error(actual, "Unexpected AST scope");
    return false;
  }

  if(!compare_asts(expected, ast_child(expected), ast_child(actual), true) ||
    !compare_asts(expected, ast_type(expected), ast_type(actual), true))
    return false;

  return !check_siblings ||
    compare_asts(expected, ast_sibling(expected), ast_sibling(actual), true);
}
Пример #7
0
bool expr_seq(pass_opt_t* opt, ast_t* ast)
{
    bool ok = true;

    // Any expression other than the last that is still literal is an error
    for(ast_t* p = ast_child(ast); ast_sibling(p) != NULL; p = ast_sibling(p))
    {
        ast_t* p_type = ast_type(p);

        if(is_typecheck_error(p_type))
        {
            ok = false;
        } else if(is_type_literal(p_type)) {
            ast_error(p, "Cannot infer type of unused literal");
            ok = false;
        }
    }

    // We might already have a type due to a return expression.
    ast_t* type = ast_type(ast);
    ast_t* last = ast_childlast(ast);

    if((type != NULL) && !coerce_literals(&last, type, opt))
        return false;

    // Type is unioned with the type of the last child.
    type = control_type_add_branch(type, last);
    ast_settype(ast, type);
    ast_inheritflags(ast);

    if(!ast_has_scope(ast))
        return ok;

    ast_t* parent = ast_parent(ast);

    switch(ast_id(parent))
    {
    case TK_TRY:
    case TK_TRY_NO_CHECK:
    {
        // Propagate consumes forward in a try expression.
        AST_GET_CHILDREN(parent, body, else_clause, then_clause);

        if(body == ast)
        {
            // Push our consumes, but not defines, to the else clause.
            ast_inheritbranch(else_clause, body);
            ast_consolidate_branches(else_clause, 2);
        } else if(else_clause == ast) {
            // Push our consumes, but not defines, to the then clause. This
            // includes the consumes from the body.
            ast_inheritbranch(then_clause, else_clause);
            ast_consolidate_branches(then_clause, 2);
        }
    }

    default:
    {}
    }

    return ok;
}
Пример #8
0
// Check the extra information. This includes:
// * legal data pointer
// * legal scope symbol table
// * no extra children
static check_res_t check_extras(ast_t* ast, check_state_t* state,
  errors_t* errors)
{
  assert(ast != NULL);
  assert(state != NULL);


  ast_t* type_field = ast_type(ast);

  if(type_field != NULL)
  {
    if(state->type == NULL)
    {
      error_preamble(ast);
      printf("unexpected type\n");
      ast_error(state->errors, ast, "Here");
      ast_print(ast);
#ifdef IMMEDIATE_FAIL
      assert(false);
#endif
      return CHK_ERROR;
    }

    check_res_t r = state->type(type_field, errors);

    if(r == CHK_ERROR)  // Propogate error
      return CHK_ERROR;

    if(r == CHK_NOT_FOUND)
    {
      error_preamble(ast);
      printf("type field has invalid id %d\n", ast_id(type_field));
      ast_error(state->errors, ast, "Here");
      ast_print(ast);
#ifdef IMMEDIATE_FAIL
      assert(false);
#endif
      return CHK_ERROR;
    }
  }

  if(state->child != NULL)
  {
    error_preamble(ast);
    printf("child " __zu " (id %d, %s) unexpected\n", state->child_index,
      ast_id(state->child), ast_get_print(state->child));
    ast_error(state->errors, ast, "Here");
    ast_print(ast);
#ifdef IMMEDIATE_FAIL
    assert(false);
#endif
    return CHK_ERROR;
  }

  if(ast_data(ast) != NULL && !state->has_data)
  {
    error_preamble(ast);
    printf("unexpected data %p\n", ast_data(ast));
    ast_error(state->errors, ast, "Here");
    ast_print(ast);
#ifdef IMMEDIATE_FAIL
    assert(false);
#endif
    return CHK_ERROR;
  }

  if(ast_has_scope(ast) && !state->is_scope)
  {
    error_preamble(ast);
    printf("unexpected scope\n");
    ast_error(state->errors, ast, "Here");
    ast_print(ast);
#ifdef IMMEDIATE_FAIL
    assert(false);
#endif
    return CHK_ERROR;
  }

  if(!ast_has_scope(ast) && state->is_scope)
  {
    error_preamble(ast);
    printf("expected scope not found\n");
    ast_error(state->errors, ast, "Here");
    ast_print(ast);
#ifdef IMMEDIATE_FAIL
    assert(false);
#endif
    return CHK_ERROR;
  }

  return CHK_OK;
}