SPVM

 view release on metacpan or  search on metacpan

lib/SPVM/Builder/src/spvm_op.c  view on Meta::CPAN

          break;
        }
        default: {
          SPVM_COMPILER_error(compiler, "Invalid method attribute \"%s\".\n  at %s line %d", SPVM_ATTRIBUTE_get_name(compiler, attribute->id), op_attributes->file, op_attributes->line);
        }
      }
    }
    
    if (method->is_native && method->is_precompile) {
      SPVM_COMPILER_error(compiler, "Only one of method attributes \"native\" and \"precompile\" can be specified.\n  at %s line %d", op_attributes->file, op_attributes->line);
    }
    if (access_control_attributes_count > 1) {
      SPVM_COMPILER_error(compiler, "Only one of method attributes \"private\", \"protected\" or \"public\" can be specified.\n  at %s line %d", op_method->file, op_method->line);
    }
  }
  
  // The default of the access controll of the method is publice.
  if (method->access_control_type == SPVM_ATTRIBUTE_C_ID_UNKNOWN) {
    method->access_control_type = SPVM_ATTRIBUTE_C_ID_PUBLIC;
  }
  
  // Native method cannnot have block
  if ((method->is_native) && op_block) {
    SPVM_COMPILER_error(compiler, "A native method cannnot have its block.\n  at %s line %d", op_block->file, op_block->line);
  }
  
  // method args
  if (!op_args) {
    op_args = SPVM_OP_new_op_list(compiler, op_method->file, op_method->line);
  }
  
  // Add $self : self before the first argument
  if (!method->is_class_method) {
    SPVM_OP* op_arg_var_name_self = SPVM_OP_new_op_name(compiler, "$self", op_method->file, op_method->line);
    SPVM_OP* op_arg_var_self = SPVM_OP_new_op_var(compiler, op_arg_var_name_self);
    SPVM_OP* op_self_type = SPVM_OP_new_op_unresolved_type(compiler, NULL, 0, 0, op_method->file, op_method->line);
    SPVM_TYPE* self_type = op_self_type->uv.type;
    SPVM_OP* op_arg_self = SPVM_OP_build_arg(compiler, op_arg_var_self, op_self_type, NULL, NULL);
    SPVM_OP_insert_child(compiler, op_args, op_args->first, op_arg_self);
  }
  
  // Add method arguments
  {
    int32_t found_optional_arg = 0;
    int32_t required_args_length = 0;
    int32_t args_length = 0;
    SPVM_OP* op_arg = op_args->first;
    while ((op_arg = SPVM_OP_sibling(compiler, op_arg))) {
      SPVM_VAR_DECL* arg_var_decl = op_arg->uv.var->var_decl;
      if (!found_optional_arg) {
        if (arg_var_decl->op_arg_default) {
          found_optional_arg = 1;
        }
        else {
          required_args_length++;
        }
      }
      args_length++;
    }
    method->args_length = args_length;
    method->required_args_length = required_args_length;
  }
  
  // Variable declarations of arguments
  SPVM_OP* op_arg = op_args->first;
  while ((op_arg = SPVM_OP_sibling(compiler, op_arg))) {
    SPVM_LIST_push(method->var_decls, op_arg->uv.var->var_decl);
  }
  
  // return type
  method->return_type = op_return_type->uv.type;
  
  if (strcmp(method->op_name->uv.name, "DESTROY") == 0) {
    method->is_destroy_method = 1;
    
    // DESTROY return type must be void
    if (!(method->return_type->dimension == 0 && method->return_type->basic_type->id == SPVM_NATIVE_C_BASIC_TYPE_ID_VOID)) {
      SPVM_COMPILER_error(compiler, "The return type of DESTROY method must be the void type.\n  at %s line %d", op_method->file, op_method->line);
    }
    
    // DESTROY is instance method
    if (method->is_class_method) {
      SPVM_COMPILER_error(compiler, "DESTROY method must be an instance method.\n  at %s line %d", op_method->file, op_method->line);
    }
    
    // DESTROY doesn't have arguments without invocant
    if (method->args_length != 1) {
      SPVM_COMPILER_error(compiler, "DESTROY method cannnot have arguments.\n  at %s line %d", op_method->file, op_method->line);
    }
  }
  
  SPVM_OP* op_anon_method_field_var_decl_start = NULL;
  if (op_block) {
    
    SPVM_OP* op_list_statement = op_block->first;
    
    op_anon_method_field_var_decl_start = SPVM_OP_new_op(compiler, SPVM_OP_C_ID_DO_NOTHING, op_list_statement->file, op_list_statement->last->line + 1);
    
    SPVM_OP_insert_child(compiler, op_list_statement, op_list_statement->first, op_anon_method_field_var_decl_start);
    
    method->op_anon_method_field_var_decl_start = op_anon_method_field_var_decl_start;
    
    // Add variable declarations before the first of the statements
    for (int32_t i = method->args_length - 1; i >= 0; i--) {
      SPVM_VAR_DECL* arg_var_decl = SPVM_LIST_get(method->var_decls, i);
      assert(arg_var_decl);
      SPVM_OP* op_name_var = SPVM_OP_new_op_name(compiler, arg_var_decl->var->name, arg_var_decl->op_var_decl->file, arg_var_decl->op_var_decl->line);
      SPVM_OP* op_var = SPVM_OP_new_op_var(compiler, op_name_var);
      op_var->uv.var->var_decl = arg_var_decl;
      op_var->uv.var->is_declaration = 1;
      op_var->uv.var->var_decl = arg_var_decl;
      
      SPVM_OP_insert_child(compiler, op_list_statement, op_list_statement->first, op_var);
    }
    
    // Add condition_flag variable to first of block
    {
      SPVM_OP* op_var = SPVM_OP_new_op_var_condition_flag(compiler, op_list_statement->file, op_list_statement->last->line + 1);
      SPVM_OP* op_var_decl = SPVM_OP_new_op_var_decl(compiler, op_list_statement->file, op_list_statement->last->line + 1);
      SPVM_OP* op_type = SPVM_OP_new_op_int_type(compiler, op_list_statement->file, op_list_statement->line);
      op_var = SPVM_OP_build_var_decl(compiler, op_var_decl, op_var, op_type, NULL);



( run in 3.344 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )