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-1301 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
31static mrb_value
32eval_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
85void
86grn_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