1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2016 Brazil
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License version 2.1 as published by the Free Software Foundation.
8 
9   This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
17 */
18 
19 #include "../grn_ctx_impl.h"
20 
21 #ifdef GRN_WITH_MRUBY
22 #include <mruby.h>
23 #include <mruby/proc.h>
24 #include <mruby/compile.h>
25 #include <mruby/opcode.h>
26 
27 #include "../grn_mrb.h"
28 #include "mrb_ctx.h"
29 #include "mrb_eval_context.h"
30 
31 static mrb_value
32 eval_context_compile(mrb_state *mrb, mrb_value self)
33 {
34   char *script;
35   mrb_int script_length;
36   mrbc_context* compile_ctx;
37   struct mrb_parser_state *parser;
38   struct RProc *proc;
39 
40   mrb_get_args(mrb, "s", &script, &script_length);
41 
42   compile_ctx = mrbc_context_new(mrb);
43   if (!compile_ctx) {
44     mrb_raise(mrb, E_RUNTIME_ERROR,
45               "[mruby][eval][compile] failed to allocate context");
46   }
47   compile_ctx->capture_errors = TRUE;
48 
49   parser = mrb_parse_nstring(mrb, script, script_length, compile_ctx);
50   if (!parser) {
51     mrbc_context_free(mrb, compile_ctx);
52     mrb_raise(mrb, E_RUNTIME_ERROR,
53               "[mruby][eval][compile] failed to allocate parser");
54   }
55   if (parser->nerr > 0) {
56     struct mrb_parser_message *error = &(parser->error_buffer[0]);
57     mrb_value new_args[1];
58     mrb_value exception;
59 
60     new_args[0] = mrb_format(mrb,
61                              "line %S:%S: %S",
62                              mrb_fixnum_value(error->lineno),
63                              mrb_fixnum_value(error->column),
64                              mrb_str_new_cstr(mrb, error->message));
65     exception = mrb_obj_new(mrb, E_SYNTAX_ERROR, 1, new_args);
66     mrb_parser_free(parser);
67     mrbc_context_free(mrb, compile_ctx);
68 
69     mrb_exc_raise(mrb, exception);
70   }
71 
72   proc = mrb_generate_code(mrb, parser);
73   {
74     mrb_code *iseq = proc->body.irep->iseq;
75     while (GET_OPCODE(*iseq) != OP_STOP) {
76       iseq++;
77     }
78     *iseq = MKOP_AB(OP_RETURN, 1, OP_R_NORMAL);
79   }
80   mrb_parser_free(parser);
81   mrbc_context_free(mrb, compile_ctx);
82   return mrb_obj_value(proc);
83 }
84 
85 void
86 grn_mrb_eval_context_init(grn_ctx *ctx)
87 {
88   grn_mrb_data *data = &(ctx->impl->mrb);
89   mrb_state *mrb = data->state;
90   struct RClass *module = data->module;
91   struct RClass *klass;
92 
93   klass = mrb_define_class_under(mrb, module, "EvalContext", mrb->object_class);
94 
95   mrb_define_method(mrb, klass, "compile", eval_context_compile,
96                     MRB_ARGS_REQ(1));
97 }
98 #endif
99