medit/moo/mooutils/mooscript/mooscript-node.c

1345 lines
28 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
*
* as-script-node.c
*
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#include "mooscript-node.h"
#include "mooscript-func.h"
#include "mooscript-context.h"
#include "mooutils/moopython.h"
#include <string.h>
MSValue *
_ms_node_eval (MSNode *node,
MSContext *ctx)
{
g_return_val_if_fail (node != NULL, NULL);
g_return_val_if_fail (MS_IS_CONTEXT (ctx), NULL);
g_return_val_if_fail (node->eval != NULL, NULL);
return node->eval (node, ctx);
}
MSValue *
ms_top_node_eval (MSNode *node,
MSContext *ctx)
{
MSValue *ret;
g_return_val_if_fail (node != NULL, NULL);
g_return_val_if_fail (MS_IS_CONTEXT (ctx), NULL);
g_return_val_if_fail (node->eval != NULL, NULL);
ret = _ms_node_eval (node, ctx);
if (ctx->return_set)
ms_context_unset_return (ctx);
if (ctx->break_set)
ms_context_unset_break (ctx);
if (ctx->continue_set)
ms_context_unset_continue (ctx);
return ret;
}
static MSNode *
ms_node_new (gsize node_size,
MSNodeType type,
MSNodeEval eval,
MSNodeDestroy destroy)
{
MSNode *node;
g_assert (node_size >= sizeof (MSNode));
g_assert (eval != NULL);
g_assert (type && type < MS_TYPE_NODE_LAST);
node = g_malloc0 (node_size);
node->ref_count = 1;
node->type = type;
node->eval = eval;
node->destroy = destroy;
return node;
}
#define NODE_NEW(Type_,type_,eval_,destroy_) \
((Type_*) ms_node_new (sizeof (Type_), type_, eval_, destroy_))
gpointer
ms_node_ref (gpointer node)
{
if (node)
MS_NODE(node)->ref_count++;
return node;
}
void
ms_node_unref (gpointer node)
{
if (node && !--MS_NODE(node)->ref_count)
{
if (MS_NODE(node)->destroy)
MS_NODE(node)->destroy (node);
g_free (node);
}
}
/****************************************************************************/
/* MSNodeList
*/
static MSValue*
ms_node_list_eval (MSNode *node,
MSContext *ctx)
{
guint i;
MSValue *ret = NULL;
MSNodeList *list = MS_NODE_LIST (node);
if (!list->n_nodes)
return ms_value_none ();
for (i = 0; i < list->n_nodes; ++i)
{
ret = _ms_node_eval (list->nodes[i], ctx);
if (!ret)
return NULL;
if (ctx->return_set)
{
ms_value_unref (ret);
ret = ms_value_ref (ctx->return_val);
break;
}
if (ctx->break_set || ctx->continue_set)
break;
if (i + 1 < list->n_nodes)
ms_value_unref (ret);
}
return ret;
}
static void
ms_node_list_destroy (MSNode *node)
{
guint i;
MSNodeList *list = MS_NODE_LIST (node);
for (i = 0; i < list->n_nodes; ++i)
ms_node_unref (list->nodes[i]);
g_free (list->nodes);
}
MSNodeList *
ms_node_list_new (void)
{
return NODE_NEW (MSNodeList,
MS_TYPE_NODE_LIST,
ms_node_list_eval,
ms_node_list_destroy);
}
void
ms_node_list_add (MSNodeList *list,
MSNode *node)
{
g_return_if_fail (list != NULL && node != NULL);
g_return_if_fail (MS_NODE_TYPE (list) == MS_TYPE_NODE_LIST);
if (list->n_nodes_allocd__ == list->n_nodes)
{
MSNode **tmp;
list->n_nodes_allocd__ = MAX (list->n_nodes_allocd__ + 2,
1.2 * list->n_nodes_allocd__);
tmp = g_new0 (MSNode*, list->n_nodes_allocd__);
if (list->n_nodes)
memcpy (tmp, list->nodes, list->n_nodes * sizeof(MSNode*));
g_free (list->nodes);
list->nodes = tmp;
}
list->nodes[list->n_nodes++] = ms_node_ref (node);
}
/****************************************************************************/
/* MSNodeVar
*/
static void
ms_node_var_destroy (MSNode *node)
{
MSNodeVar *var = MS_NODE_VAR (node);
g_free (var->name);
}
static MSValue *
ms_node_var_eval (MSNode *node,
MSContext *ctx)
{
MSNodeVar *var = MS_NODE_VAR (node);
return ms_context_eval_variable (ctx, var->name);
}
MSNodeVar *
ms_node_var_new (const char *name)
{
MSNodeVar *var;
g_return_val_if_fail (name && name[0], NULL);
var = NODE_NEW (MSNodeVar,
MS_TYPE_NODE_VAR,
ms_node_var_eval,
ms_node_var_destroy);
var->name = g_strdup (name);
return var;
}
/****************************************************************************/
/* MSNodeCommand
*/
static void
ms_node_command_destroy (MSNode *node)
{
MSNodeCommand *cmd = MS_NODE_COMMAND (node);
g_free (cmd->name);
if (cmd->args)
ms_node_unref (MS_NODE (cmd->args));
}
static MSValue *
ms_node_command_eval (MSNode *node,
MSContext *ctx)
{
guint i, n_args;
MSValue **args;
MSValue *ret;
MSNodeCommand *cmd = MS_NODE_COMMAND (node);
MSFunc *func;
g_return_val_if_fail (cmd->name != NULL, NULL);
func = ms_context_lookup_func (ctx, cmd->name);
if (!func)
return ms_context_format_error (ctx, MS_ERROR_NAME,
"unknown command '%s'",
cmd->name);
g_object_ref (func);
n_args = cmd->args ? cmd->args->n_nodes : 0;
args = NULL;
ret = NULL;
if (n_args)
{
args = g_new0 (MSValue*, n_args);
for (i = 0; i < n_args; ++i)
{
args[i] = _ms_node_eval (cmd->args->nodes[i], ctx);
if (!args[i])
goto out;
}
}
ret = ms_func_call (func, args, n_args, ctx);
out:
for (i = 0; i < n_args; ++i)
if (args[i])
ms_value_unref (args[i]);
g_free (args);
g_object_unref (func);
return ret;
}
MSNodeCommand *
ms_node_command_new (const char *name,
MSNodeList *args)
{
MSNodeCommand *cmd;
g_return_val_if_fail (name && name[0], NULL);
g_return_val_if_fail (!args || MS_NODE_TYPE (args) == MS_TYPE_NODE_LIST, NULL);
if (args && !args->n_nodes)
args = NULL;
cmd = NODE_NEW (MSNodeCommand,
MS_TYPE_NODE_COMMAND,
ms_node_command_eval,
ms_node_command_destroy);
cmd->name = g_strdup (name);
cmd->args = args ? ms_node_ref (args) : NULL;
return cmd;
}
MSNodeCommand *
ms_node_binary_op_new (MSBinaryOp op,
MSNode *lval,
MSNode *rval)
{
MSNodeCommand *cmd;
MSNodeList *args;
const char *name;
g_return_val_if_fail (lval && rval, NULL);
name = ms_binary_op_name (op);
g_return_val_if_fail (name != NULL, NULL);
args = ms_node_list_new ();
ms_node_list_add (args, lval);
ms_node_list_add (args, rval);
cmd = ms_node_command_new (name, args);
ms_node_unref (args);
return cmd;
}
MSNodeCommand *
ms_node_unary_op_new (MSUnaryOp op,
MSNode *val)
{
MSNodeCommand *cmd;
MSNodeList *args;
const char *name;
g_return_val_if_fail (val != NULL, NULL);
name = ms_unary_op_name (op);
g_return_val_if_fail (name != NULL, NULL);
args = ms_node_list_new ();
ms_node_list_add (args, val);
cmd = ms_node_command_new (name, args);
ms_node_unref (args);
return cmd;
}
/****************************************************************************/
/* MSNodeIfElse
*/
static void
ms_node_if_else_destroy (MSNode *node_)
{
MSNodeIfElse *node = MS_NODE_IF_ELSE (node_);
ms_node_unref (node->condition);
ms_node_unref (node->then_);
ms_node_unref (node->else_);
}
static MSValue *
ms_node_if_else_eval (MSNode *node_,
MSContext *ctx)
{
MSValue *ret = NULL, *cond;
MSNodeIfElse *node = MS_NODE_IF_ELSE (node_);
g_return_val_if_fail (node->condition != NULL, NULL);
g_return_val_if_fail (node->then_ != NULL, NULL);
cond = _ms_node_eval (node->condition, ctx);
if (!cond)
return NULL;
if (ms_value_get_bool (cond))
ret = _ms_node_eval (node->then_, ctx);
else if (node->else_)
ret = _ms_node_eval (node->else_, ctx);
else
ret = ms_value_none ();
if (ctx->return_set)
{
ms_value_unref (ret);
ret = ms_value_ref (ctx->return_val);
}
ms_value_unref (cond);
return ret;
}
MSNodeIfElse *
ms_node_if_else_new (MSNode *condition,
MSNode *then_,
MSNode *else_)
{
MSNodeIfElse *node;
g_return_val_if_fail (condition && then_, NULL);
node = NODE_NEW (MSNodeIfElse,
MS_TYPE_NODE_IF_ELSE,
ms_node_if_else_eval,
ms_node_if_else_destroy);
node->condition = ms_node_ref (condition);
node->then_ = ms_node_ref (then_);
node->else_ = else_ ? ms_node_ref (else_) : NULL;
return node;
}
/****************************************************************************/
/* MSNodeWhile
*/
static void
ms_node_while_destroy (MSNode *node)
{
MSNodeWhile *wh = MS_NODE_WHILE (node);
ms_node_unref (wh->condition);
ms_node_unref (wh->what);
}
static MSValue *
ms_loop_while (MSContext *ctx,
MSNode *condition,
MSNode *what)
{
MSValue *ret;
g_return_val_if_fail (condition != NULL, NULL);
ret = NULL;
while (TRUE)
{
MSValue *cond = _ms_node_eval (condition, ctx);
gboolean doit;
if (!cond)
return NULL;
doit = ms_value_get_bool (cond);
ms_value_unref (cond);
if (doit)
{
if (ret)
ms_value_unref (ret);
if (what)
ret = _ms_node_eval (what, ctx);
else
ret = ms_value_none ();
if (!ret)
return NULL;
if (ctx->return_set)
{
ms_value_unref (ret);
ret = ms_value_ref (ctx->return_val);
break;
}
if (ctx->break_set)
{
ms_context_unset_break (ctx);
break;
}
if (ctx->continue_set)
ms_context_unset_continue (ctx);
}
else
{
break;
}
}
return ret ? ret : ms_value_none ();
}
static MSValue *
ms_loop_do_while (MSContext *ctx,
MSNode *condition,
MSNode *what)
{
MSValue *ret;
g_return_val_if_fail (condition != NULL, NULL);
ret = NULL;
while (TRUE)
{
MSValue *cond;
gboolean stop;
if (ret)
ms_value_unref (ret);
if (what)
ret = _ms_node_eval (what, ctx);
else
ret = ms_value_none ();
if (!ret)
return NULL;
if (ctx->return_set)
{
ms_value_unref (ret);
ret = ms_value_ref (ctx->return_val);
break;
}
if (ctx->break_set)
{
ms_context_unset_break (ctx);
break;
}
if (ctx->continue_set)
ms_context_unset_continue (ctx);
cond = _ms_node_eval (condition, ctx);
if (!cond)
return NULL;
stop = !ms_value_get_bool (cond);
ms_value_unref (cond);
if (stop)
break;
}
return ret ? ret : ms_value_none ();
}
static MSValue *
ms_node_while_eval (MSNode *node,
MSContext *ctx)
{
MSNodeWhile *wh = MS_NODE_WHILE (node);
g_return_val_if_fail (wh->condition != NULL, NULL);
switch (wh->type)
{
case MS_COND_BEFORE:
return ms_loop_while (ctx, wh->condition, wh->what);
case MS_COND_AFTER:
return ms_loop_do_while (ctx, wh->condition, wh->what);
}
g_return_val_if_reached (NULL);
}
MSNodeWhile*
ms_node_while_new (MSCondType type,
MSNode *cond,
MSNode *what)
{
MSNodeWhile *wh;
g_return_val_if_fail (cond != NULL, NULL);
wh = NODE_NEW (MSNodeWhile,
MS_TYPE_NODE_WHILE,
ms_node_while_eval,
ms_node_while_destroy);
wh->type = type;
wh->condition = ms_node_ref (cond);
wh->what = what ? ms_node_ref (what) : NULL;
return wh;
}
/****************************************************************************/
/* MSNodeFor
*/
static void
ms_node_for_destroy (MSNode *node)
{
MSNodeFor *loop = MS_NODE_FOR (node);
ms_node_unref (loop->variable);
ms_node_unref (loop->list);
ms_node_unref (loop->what);
}
static MSValue *
ms_node_for_eval (MSNode *node,
MSContext *ctx)
{
MSNodeVar *var;
MSNodeFor *loop = MS_NODE_FOR (node);
MSValue *vallist = NULL;
MSValue *ret = NULL;
guint i;
g_return_val_if_fail (loop->variable != NULL, NULL);
g_return_val_if_fail (loop->list != NULL, NULL);
if (!MS_IS_NODE_VAR (loop->variable))
return ms_context_format_error (ctx, MS_ERROR_TYPE,
"illegal loop variable");
if (!MS_IS_NODE_VAL_LIST (loop->list))
if (!MS_IS_NODE_VALUE (loop->list) ||
MS_NODE_VALUE(loop->list)->value->type != MS_VALUE_LIST)
return ms_context_format_error (ctx, MS_ERROR_TYPE,
"illegal loop list");
var = MS_NODE_VAR (loop->variable);
if (MS_IS_NODE_VAL_LIST (loop->list))
vallist = _ms_node_eval (loop->list, ctx);
else
vallist = ms_value_ref (MS_NODE_VALUE(loop->list)->value);
if (!vallist)
return NULL;
g_return_val_if_fail (vallist->type == MS_VALUE_LIST, NULL);
for (i = 0; i < vallist->list.n_elms; ++i)
{
if (!ms_context_assign_variable (ctx, var->name, vallist->list.elms[i]))
goto error;
if (ret)
ms_value_unref (ret);
if (loop->what)
ret = _ms_node_eval (loop->what, ctx);
else
ret = ms_value_none ();
if (!ret)
goto error;
if (ctx->return_set)
{
ms_value_unref (ret);
ret = ms_value_ref (ctx->return_val);
break;
}
if (ctx->break_set)
{
ms_context_unset_break (ctx);
break;
}
if (ctx->continue_set)
ms_context_unset_continue (ctx);
}
if (!ret)
ret = ms_value_none ();
ms_value_unref (vallist);
return ret;
error:
if (ret)
ms_value_unref (ret);
ms_value_unref (vallist);
return NULL;
}
MSNodeFor*
ms_node_for_new (MSNode *var,
MSNode *list,
MSNode *what)
{
MSNodeFor *loop;
g_return_val_if_fail (var && list, NULL);
loop = NODE_NEW (MSNodeFor,
MS_TYPE_NODE_FOR,
ms_node_for_eval,
ms_node_for_destroy);
loop->variable = ms_node_ref (var);
loop->list = ms_node_ref (list);
loop->what = what ? ms_node_ref (what) : NULL;
return loop;
}
/****************************************************************************/
/* MSNodeAssign
*/
static void
ms_node_assign_destroy (MSNode *node_)
{
MSNodeAssign *node = MS_NODE_ASSIGN (node_);
ms_node_unref (node->var);
ms_node_unref (node->val);
}
static MSValue *
ms_node_assign_eval (MSNode *node_,
MSContext *ctx)
{
MSValue *value;
MSNodeAssign *node = MS_NODE_ASSIGN (node_);
g_return_val_if_fail (node->var != NULL, NULL);
g_return_val_if_fail (node->val != NULL, NULL);
value = _ms_node_eval (node->val, ctx);
if (!value)
return NULL;
if (!ms_context_assign_variable (ctx, node->var->name, value))
{
ms_value_unref (value);
return NULL;
}
return value;
}
MSNodeAssign *
ms_node_assign_new (MSNodeVar *var,
MSNode *val)
{
MSNodeAssign *node;
g_return_val_if_fail (MS_IS_NODE_VAR (var), NULL);
g_return_val_if_fail (val != NULL, NULL);
node = NODE_NEW (MSNodeAssign,
MS_TYPE_NODE_ASSIGN,
ms_node_assign_eval,
ms_node_assign_destroy);
node->var = ms_node_ref (var);
node->val = ms_node_ref (val);
return node;
}
/****************************************************************************/
/* MSNodeValue
*/
static void
ms_node_value_destroy (MSNode *node)
{
MSNodeValue *val = MS_NODE_VALUE (node);
ms_value_unref (val->value);
}
static MSValue *
ms_node_value_eval (MSNode *node,
G_GNUC_UNUSED MSContext *ctx)
{
return ms_value_ref (MS_NODE_VALUE(node)->value);
}
MSNodeValue *
ms_node_value_new (MSValue *value)
{
MSNodeValue *node;
g_return_val_if_fail (value != NULL, NULL);
node = NODE_NEW (MSNodeValue,
MS_TYPE_NODE_VALUE,
ms_node_value_eval,
ms_node_value_destroy);
node->value = ms_value_ref (value);
return node;
}
/****************************************************************************/
/* MSNodeValList
*/
static void
ms_node_val_list_destroy (MSNode *node_)
{
MSNodeValList *node = MS_NODE_VAL_LIST (node_);
ms_node_unref (node->elms);
ms_node_unref (node->first);
ms_node_unref (node->last);
}
static MSValue *
ms_node_val_range_eval (MSNodeValList *node,
MSContext *ctx)
{
MSValue *ret;
guint n_elms, i;
MSValue *vfirst, *vlast;
int first, last;
g_assert (node->type == MS_VAL_RANGE);
vfirst = _ms_node_eval (node->first, ctx);
if (!vfirst)
return NULL;
vlast = _ms_node_eval (node->last, ctx);
if (!vlast)
{
ms_value_unref (vfirst);
return NULL;
}
if (!ms_value_get_int (vfirst, &first) || !ms_value_get_int (vlast, &last))
{
ms_value_unref (vfirst);
ms_value_unref (vlast);
return ms_context_format_error (ctx, MS_ERROR_TYPE,
"illegal list bounds");
}
ms_value_unref (vfirst);
ms_value_unref (vlast);
if (first > last)
return ms_value_list (0);
n_elms = last - first + 1;
ret = ms_value_list (n_elms);
for (i = 0; i < n_elms; ++i)
{
MSValue *val = ms_value_int (first + i);
ms_value_list_set_elm (ret, i, val);
ms_value_unref (val);
}
return ret;
}
static MSValue *
ms_node_val_list_eval (MSNode *node_,
MSContext *ctx)
{
MSValue *ret;
guint n_elms, i;
MSNodeValList *node = MS_NODE_VAL_LIST (node_);
switch (node->type)
{
case MS_VAL_LIST:
n_elms = node->elms ? node->elms->n_nodes : 0;
ret = ms_value_list (n_elms);
for (i = 0; i < n_elms; ++i)
{
MSValue *elm = _ms_node_eval (node->elms->nodes[i], ctx);
if (!elm)
{
ms_value_unref (ret);
return NULL;
}
ms_value_list_set_elm (ret, i, elm);
ms_value_unref (elm);
}
return ret;
case MS_VAL_RANGE:
return ms_node_val_range_eval (node, ctx);
}
g_return_val_if_reached (NULL);
}
static MSNodeValList *
ms_node_val_list_new_ (void)
{
return NODE_NEW (MSNodeValList,
MS_TYPE_NODE_VAL_LIST,
ms_node_val_list_eval,
ms_node_val_list_destroy);
}
MSNodeValList *
ms_node_val_list_new (MSNodeList *list)
{
MSNodeValList *node;
g_return_val_if_fail (!list || MS_IS_NODE_LIST (list), NULL);
if (list && !list->n_nodes)
list = NULL;
node = ms_node_val_list_new_ ();
node->type = MS_VAL_LIST;
node->elms = list ? ms_node_ref (list) : NULL;
return node;
}
MSNodeValList *
ms_node_val_range_new (MSNode *first,
MSNode *last)
{
MSNodeValList *node;
g_return_val_if_fail (first && last, NULL);
node = ms_node_val_list_new_ ();
node->type = MS_VAL_RANGE;
node->first = ms_node_ref (first);
node->last = ms_node_ref (last);
return node;
}
/****************************************************************************/
/* MSNodePython
*/
static void
ms_node_python_destroy (MSNode *node)
{
g_free (MS_NODE_PYTHON(node)->script);
}
static MSValue *
ms_node_python_eval (MSNode *node_,
MSContext *ctx)
{
MSNodePython *node = MS_NODE_PYTHON (node_);
MooPyObject *ret;
if (!moo_python_running())
return ms_context_format_error (ctx, MS_ERROR_RUNTIME,
"Python support not available");
ret = moo_python_run_string (node->script);
if (ret)
{
moo_Py_DECREF (ret);
return ms_value_none ();
}
else
{
moo_PyErr_Print ();
return ms_context_format_error (ctx, MS_ERROR_RUNTIME,
"python script raised exception");
}
}
MSNodePython *
ms_node_python_new (const char *script)
{
MSNodePython *node;
g_return_val_if_fail (script != NULL, NULL);
node = NODE_NEW (MSNodePython,
MS_TYPE_NODE_PYTHON,
ms_node_python_eval,
ms_node_python_destroy);
node->script = g_strdup (script);
return node;
}
/****************************************************************************/
/* MSNodeListElm
*/
static void
ms_node_list_elm_destroy (MSNode *node)
{
ms_node_unref (MS_NODE_LIST_ELM(node)->list);
ms_node_unref (MS_NODE_LIST_ELM(node)->ind);
}
static MSValue *
ms_node_list_elm_eval (MSNode *node_,
MSContext *ctx)
{
MSNodeListElm *node = MS_NODE_LIST_ELM (node_);
MSValue *list = NULL, *ind = NULL, *ret;
guint len;
int index;
list = _ms_node_eval (node->list, ctx);
if (!list)
goto error;
ind = _ms_node_eval (node->ind, ctx);
if (!ind)
goto error;
if (!ms_value_get_int (ind, &index))
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"invalid list index");
goto error;
}
if (index < 0)
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"index out of range");
goto error;
}
switch (list->type)
{
case MS_VALUE_STRING:
len = g_utf8_strlen (list->str, -1);
break;
case MS_VALUE_LIST:
len = list->list.n_elms;
break;
default:
ms_context_format_error (ctx, MS_ERROR_VALUE,
"invalid subscript");
goto error;
}
if ((guint) index >= len)
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"index out of range");
goto error;
}
switch (list->type)
{
case MS_VALUE_STRING:
ret = ms_value_string_len (g_utf8_offset_to_pointer (list->str, index), 1);
break;
case MS_VALUE_LIST:
ret = ms_value_ref (list->list.elms[index]);
break;
default:
g_assert_not_reached ();
}
ms_node_unref (list);
ms_node_unref (ind);
return ret;
error:
ms_node_unref (list);
ms_node_unref (ind);
return NULL;
}
MSNodeListElm *
ms_node_list_elm_new (MSNode *list,
MSNode *ind)
{
MSNodeListElm *node;
g_return_val_if_fail (list && ind, NULL);
node = NODE_NEW (MSNodeListElm,
MS_TYPE_NODE_LIST_ELM,
ms_node_list_elm_eval,
ms_node_list_elm_destroy);
node->list = ms_node_ref (list);
node->ind = ms_node_ref (ind);
return node;
}
/****************************************************************************/
/* MSNodeListAssign
*/
static void
ms_node_list_assign_destroy (MSNode *node)
{
ms_node_unref (MS_NODE_LIST_ASSIGN(node)->list);
ms_node_unref (MS_NODE_LIST_ASSIGN(node)->ind);
ms_node_unref (MS_NODE_LIST_ASSIGN(node)->val);
}
static MSValue *
ms_node_list_assign_eval (MSNode *node_,
MSContext *ctx)
{
MSNodeListAssign *node = MS_NODE_LIST_ASSIGN (node_);
MSValue *list = NULL, *ind = NULL, *val = NULL;
guint len;
int index;
list = _ms_node_eval (node->list, ctx);
if (!list)
goto error;
ind = _ms_node_eval (node->ind, ctx);
if (!ind)
goto error;
if (!ms_value_get_int (ind, &index))
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"invalid list index");
goto error;
}
if (index < 0)
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"index out of range");
goto error;
}
switch (list->type)
{
case MS_VALUE_LIST:
len = list->list.n_elms;
break;
default:
ms_context_format_error (ctx, MS_ERROR_VALUE,
"invalid list assignment");
goto error;
}
if ((guint) index >= len)
{
ms_context_format_error (ctx, MS_ERROR_VALUE,
"index out of range");
goto error;
}
val = _ms_node_eval (node->val, ctx);
if (!val)
goto error;
switch (node->list->type)
{
case MS_VALUE_LIST:
ms_value_list_set_elm (list, index, val);
break;
default:
g_assert_not_reached ();
}
ms_value_unref (list);
ms_value_unref (ind);
return val;
error:
if (list) ms_value_unref (list);
if (ind) ms_node_unref (ind);
if (val) ms_value_unref (val);
return NULL;
}
MSNodeListAssign *
ms_node_list_assign_new (MSNode *list,
MSNode *ind,
MSNode *val)
{
MSNodeListAssign *node;
g_return_val_if_fail (list && ind && val, NULL);
node = NODE_NEW (MSNodeListAssign,
MS_TYPE_NODE_LIST_ASSIGN,
ms_node_list_assign_eval,
ms_node_list_assign_destroy);
node->list = ms_node_ref (list);
node->ind = ms_node_ref (ind);
node->val = ms_node_ref (val);
return node;
}
/****************************************************************************/
/* MSNodeReturn
*/
static void
ms_node_return_destroy (MSNode *node)
{
ms_node_unref (MS_NODE_RETURN(node)->val);
}
static MSValue *
ms_node_return_eval (MSNode *node_,
MSContext *ctx)
{
MSNodeReturn *node = MS_NODE_RETURN (node_);
MSValue *ret;
if (node->val)
{
ret = _ms_node_eval (node->val, ctx);
if (!ret)
return NULL;
}
else
{
ret = ms_value_none ();
}
ms_context_set_return (ctx, ret);
return ret;
}
MSNodeReturn *
ms_node_return_new (MSNode *val)
{
MSNodeReturn *node;
node = NODE_NEW (MSNodeReturn,
MS_TYPE_NODE_RETURN,
ms_node_return_eval,
ms_node_return_destroy);
node->val = ms_node_ref (val);
return node;
}
/****************************************************************************/
/* MSNodeBreak
*/
static MSValue *
ms_node_break_eval (MSNode *node_,
MSContext *ctx)
{
MSNodeBreak *node = MS_NODE_BREAK (node_);
switch (node->type)
{
case MS_BREAK_BREAK:
ms_context_set_break (ctx);
break;
case MS_BREAK_CONTINUE:
ms_context_set_continue (ctx);
break;
default:
g_assert_not_reached ();
}
return ms_value_none ();
}
MSNodeBreak *
ms_node_break_new (MSBreakType type)
{
MSNodeBreak *node;
node = NODE_NEW (MSNodeBreak,
MS_TYPE_NODE_BREAK,
ms_node_break_eval,
NULL);
node->type = type;
return node;
}