struct ast* rlength(struct ast* a) {
  switch (a->node_type) {
    case N_STRING_1: {
                           return new_integer_node(strlen(string_value(a)));
                           break;
    };
    case N_STRING_2: {
                           return new_integer_node(strlen(string_value(a)));
                           break;
    };
    case N_IDENTIFIER: {
                           return rlength(eval_ast(a));
                           break;
    };
    case N_ARRAY: {
                           return new_integer_node(array_tree_size(a->left));
                           break;
    };
    case N_ARRAY_CONTENT: {
                           return rlength(eval_ast(a->left));
                           break;
    };
     default: {
                          no_method_error("length", a);
		                      break;
		 };
  };
  return new_nil_node();
};
struct ast* eval_instance_native_method(struct ast* m) {
	if (m != NULL){
    char* method_name;

    if (m->node_type == N_METHOD_CALL_1) {
      method_name = strdup(((struct method_call_node*)m)->method_name);
    };

		if (!strcmp(method_name, LENGTH)) {
      struct method_call_node* mc = (struct method_call_node*)m;
      return rlength(eval_ast(mc->left_ast));

    } else if (!strcmp(method_name, EACH_ITERATOR)) {
      struct method_call_node* mc = (struct method_call_node*)m;
      return reach(eval_ast(mc->left_ast), mc->opt_block);

    } else if (!strcmp(method_name, RESPOND_TO)) {
      struct method_call_node* mc = (struct method_call_node*)m;
      struct list_node* arg_node = mc->args;
      if (list_length(arg_node) != 1){
        wrong_arguments_error(list_length(arg_node), 1);
      }
      return rrespond_to(eval_ast(mc->left_ast), strdup(string_value(eval_ast(arg_node->arg))));

    } else if (!strcmp(method_name, NIL_METHOD)) {
      return rnil((struct method_call_node*)m);

    } else if (!strcmp(method_name, OBJECT_ID)) {
      return robject_id((struct method_call_node*)m);
    };
	};
  return new_nil_node();
};
struct ast* rrespond_to(struct ast* a, char* method_name){
  switch (a->node_type) {
    case N_STRING_1: {
                            return new_bool_node(string_is_in_array((void*)string_methods_array, method_name));
    };
    case N_STRING_2: {
                            return new_bool_node(string_is_in_array((void*)string_methods_array, method_name));
    };
    case N_ARRAY: {
                            return new_bool_node(string_is_in_array((void*)array_methods_array, method_name));
    };
    case N_INTEGER : {
                            return new_bool_node(string_is_in_array((void*)integer_methods_array, method_name));
    };
    case N_BOOL : {
                            return new_bool_node(string_is_in_array((void*)bool_methods_array, method_name));
    };
    case N_OBJECT : {
                            struct object_node* o = (struct object_node*) a;
                            return new_bool_node(NULL != find_method_for_class(o->class_ptr->name, strdup(method_name)));
    };
    case N_IDENTIFIER: {
                            return rrespond_to(eval_ast(a), strdup(method_name));
    };
    case N_ARRAY_CONTENT: {
                            return rrespond_to(eval_ast(a->left), strdup(method_name));
    };
    default: {
                            no_method_error("respond_to?", a);
                            break;
              };
  }
}
Esempio n. 4
0
MalVal *EVAL(MalVal *ast, GHashTable *env) {
    if (!ast || mal_error) return NULL;
    //g_print("EVAL: %s\n", _pr_str(ast,1));
    if (ast->type != MAL_LIST) {
        return eval_ast(ast, env);
    }
    if (!ast || mal_error) return NULL;

    // apply list
    //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
    if (_count(ast) == 0) { return ast; }
    MalVal *a0 = _nth(ast, 0);
    assert_type(a0, MAL_SYMBOL, "Cannot invoke %s", _pr_str(a0,1));
    MalVal *el = eval_ast(ast, env);
    if (!el || mal_error) { return NULL; }
    MalVal *(*f)(void *, void*) = (MalVal *(*)(void*, void*))_first(el);
    //g_print("eval_invoke el: %s\n", _pr_str(el,1));
    return f(_nth(el, 1), _nth(el, 2));
}
struct ast* reach(struct ast* a, struct ast* block) {

  if (a->node_type == N_ARRAY) {

    if (block != NULL) {

      struct ast* arr = (struct ast*) a->left;
      struct opt_block_node* b = (struct opt_block_node*) block;

      // obtengo arreglo a partir de Array
      int arr_size = array_tree_size(arr);

      struct ast* result[arr_size];

      struct ast* ptr = arr;
      int i;
      for (i = (arr_size - 1); i > -1; i--) {
        result[i] = ptr->left;
        ptr = ptr->right;
      };

      // itero sobre array
      for (i = 0; i < arr_size; i++) {
        push_scope();

        // put first arg to scope
        if (b->opt_ids != NULL) {
          put_sym(SYM_VAR, string_value(b->opt_ids->arg), result[i], NULL);
        };

        // eval block stmts
        eval_ast(b->stmts);

        pop_scope();
      }; 

      return a;

    } else {
      block_is_required_error(EACH_ITERATOR);
    };

  } else {
    no_method_error(EACH_ITERATOR, a);
  };  

};
struct ast* eval_class_native_method(struct method_call_node* m){
  if (m != NULL) {

  	// new
    if (!strcmp(m->method_name, NEW)) {
      //creo objeto
      struct class* class_ptr = find_class(string_value(m->left_ast));	
      struct sym* sym_list = copy_instance_variables_for_class(class_ptr);
      struct ast* new_object = new_object_node(class_ptr, sym_list);

      struct sym* s = find_method_for_class(string_value(m->left_ast), "initialize");

      // initialize está definido
        if (s != NULL) {           
          // llamo a initialize sobre el objeto 
          eval_and_push_args_and_object_info(s->args, m->args, new_object);
          struct ast* eval = eval_ast(s->ast); //eval initialize
          update_instance(new_object); //Antes de hacer pop, salvo en la instancia los cambios en sus variables de instancia
          pop_scope(); // pop del scope pusheado
        };
        return new_object;
      };
  };
};
Esempio n. 7
0
///////////////////////////////
// FIXME - make it loop over 
//   - eval_ast
//   - apply
// 
ast
EVAL (ast tree, environment::ptr a_env)
{
  for (;;)
  {
    if (!tree)
      return tree;

    if (tree->type () != node_type_enum::LIST)
      return eval_ast (tree, a_env);

    // not as_or_throw - we know the type
    auto root_list = tree->as<ast_node_list> ();
    if (root_list->empty ())
      return tree;

    //
    auto fn_handle_def = [root_list, &a_env]()
    {
      if (root_list->size () != 3)
        raise<mal_exception_eval_invalid_arg> (root_list->to_string ());

      const auto& key = (*root_list)[1]->as_or_throw<ast_node_symbol, mal_exception_eval_invalid_arg> ()->symbol ();

      ast_node::ptr value = EVAL ((*root_list)[2], a_env);
      a_env->set (key, value);
      return value;
    };

    // tco
    auto fn_handle_let_tco = [root_list, &a_env]() -> tco
    {
      if (root_list->size () != 3)
        raise<mal_exception_eval_invalid_arg> (root_list->to_string ());

      const ast_node_container_base* let_bindings = nullptr;
      const auto root_list_arg_1 = (*root_list)[1];
      switch (root_list_arg_1->type ())
      {
      case node_type_enum::LIST:
      case node_type_enum::VECTOR:
        let_bindings = root_list_arg_1->as<ast_node_container_base> ();
        break;
      default:
        raise<mal_exception_eval_invalid_arg> (root_list_arg_1->to_string ());
      };

      //
      auto let_env = environment::make (a_env);

      if (let_bindings->size () % 2 != 0)
        raise<mal_exception_eval_invalid_arg> (let_bindings->to_string ());
      
      for (size_t i = 0, e = let_bindings->size(); i < e; i += 2)
      {
        const auto& key = (*let_bindings)[i]->as_or_throw<ast_node_symbol, mal_exception_eval_invalid_arg> ()->symbol ();
        ast_node::ptr value = EVAL ((*let_bindings)[i + 1], let_env);

        let_env->set (key, value);
      }

      return {(*root_list)[2], let_env};
    };

    // tco
    auto fn_handle_apply_tco= [&tree, &a_env]() -> tco
    {
      ast_node::ptr new_node = eval_ast (tree, a_env);
      auto callable_list = new_node->as_or_throw<ast_node_list, mal_exception_eval_not_list> ();

      const size_t list_size = callable_list->size ();
      if (list_size == 0)
        raise<mal_exception_eval_not_callable> (callable_list->to_string ());

      auto && callable_node = (*callable_list)[0]->as_or_throw<ast_node_callable, mal_exception_eval_not_callable> ();

      return callable_node->call_tco (call_arguments (callable_list, 1, list_size - 1));
    };

    // tco
    auto fn_handle_do_tco = [root_list, &a_env]() -> tco
    {
      const size_t list_size = root_list->size ();
      if (list_size < 2)
        raise<mal_exception_eval_invalid_arg> (root_list->to_string ());

      for (size_t i = 1, e = list_size - 1; i < e; ++i)
      {
        /*retVal = */EVAL ((*root_list)[i], a_env);
      }

      return {(*root_list)[list_size - 1], a_env};
    };

    // tco
    auto fn_handle_if_tco = [root_list, &a_env] () -> tco
    {
      const size_t list_size = root_list->size ();
      if (list_size < 3 || list_size > 4)
        raise<mal_exception_eval_invalid_arg> (root_list->to_string ());

      ast_node::ptr condNode = EVAL ((*root_list)[1], a_env);
      const bool cond = !(condNode == ast_node::nil_node) && !(condNode == ast_node::false_node);

      if (cond)
        return {(*root_list)[2], a_env};
      else if (list_size == 4)
        return {(*root_list)[3], a_env};

      return tco {nullptr, nullptr, ast_node::nil_node};
    };

    auto fn_handle_fn = [root_list, &a_env] () -> ast
    {
      const size_t list_size = root_list->size ();
      if (list_size != 3)
        raise<mal_exception_eval_invalid_arg> (root_list->to_string ());

      auto&& bindsNode = (*root_list)[1];
      auto&& astNode = (*root_list)[2];

      ast_node::ptr retVal = std::make_shared<ast_node_callable_lambda> (bindsNode, astNode, a_env);
      return retVal;
    };

    auto first = (*root_list)[0];
    if (first->type () == node_type_enum::SYMBOL)
    {
      // apply special symbols
      // not as_or_throw - we know the type
      const auto first_symbol = first->as<ast_node_symbol> ();
      const auto& symbol = first_symbol->symbol ();

      if (symbol == "def!")
      {
        return fn_handle_def ();
      }
      else if (symbol == "let*")
      {
        std::tie (tree, a_env, std::ignore) = fn_handle_let_tco ();
        continue;
      }
      else if (symbol == "do")
      {
        std::tie (tree, a_env, std::ignore) = fn_handle_do_tco ();
        continue;
      }
      else if (symbol == "if")
      {
        ast retVal;
        std::tie (tree, a_env, retVal) = fn_handle_if_tco ();
        if (retVal)
          return retVal;
        continue;
      }
      else if (symbol == "fn*")
      {
        return fn_handle_fn ();
      }
    }

    // apply
    {
      ast retVal;
      std::tie (tree, a_env, retVal) = fn_handle_apply_tco ();
      if (retVal)
        return retVal;
      continue;
    }

  }
}
Esempio n. 8
0
long lispy_eval_result(lispy_result* result)
{
  return eval_ast(result->mpc_result->output);
}
Esempio n. 9
0
static long eval_ast_root(mpc_ast_t* ast)
{
  // Root has three children. Regex + expression + Regex
  assert(ast->children_num == 3);
  return eval_ast(ast->children[1]);
}
struct ast* rputs(struct ast* a){

  if (a->node_type == N_METHOD_CALL_0 || a->node_type == N_METHOD_CALL_1 || a->node_type == N_METHOD_CALL_2) {
    struct method_call_node* m = (struct method_call_node*)a;
    struct list_node* arg_node = m->args;

    // caso especial: puts() sin parámetros imprime salto de línea
    if (arg_node == NULL) {
      printf("\n");

    // comportamiento normal
    } else {  
      while(arg_node != NULL){
        struct ast* evaluated = eval_ast(arg_node->arg);
        rputs(evaluated);
        arg_node = arg_node->next;
      };
    };

  } else if (a->node_type == N_ARRAY) {
    int arr_size = array_tree_size(a->left);
    struct ast* result[arr_size];
    struct ast* ptr = a->left;
    int i;
    for (i = 0; i < arr_size; i++) {
      result[i] = ptr;
      ptr = ptr->right;
    };

    ptr = result[arr_size-1];
    for (i = arr_size-1; i >= 0; i--) {
      rputs(eval_ast(result[i]));
    };

  } else if (a->node_type == N_ARRAY_CONTENT) {
    rputs(eval_ast(a->left));

  } else if (a->node_type == N_STRING_1) {
    printf("%s\n", string_value(a));

  } else if (a->node_type == N_STRING_2) {

    char * str = malloc(sizeof( strlen(string_value(a)) ));
    strcpy(str, string_value(a));
    str = build_end_of_lines(str);
    printf("%s\n", str);

  } else if (a->node_type == N_INTEGER) {
    printf("%d\n", int_value(a));

  } else if (a->node_type == N_DOUBLE) {
    double d = double_value(a);
    if ( d - floor(d) == 0.0 ) {
      printf( "%g.0\n", d );
    } else {
      printf( "%g\n", d );
    };

  } else if (a->node_type == N_BOOL) {
    printf("%s\n", bool_value(a) ? "true" : "false");

  } else if (a->node_type == N_NIL) {
    printf("\n");

  } else if (a->node_type == N_OBJECT) {
    struct object_node * object = (struct object_node *) a;
    printf("<#%s:%p>\n", object->class_ptr->name, (void *)object);

  } else {
    printf("Puts doesn't support %s type, sorry :D\n", type_name(a->node_type));
  };
  return new_nil_node();
};
struct ast* robject_id(struct method_call_node* m) {
  struct ast* evaluated = eval_ast(m->left_ast);
  return new_integer_node((long)evaluated);
};
struct ast* rnil(struct method_call_node* m) {
  struct ast* evaluated = eval_ast(m->left_ast);
  return new_bool_node(evaluated->node_type == N_NIL);
};