1/*
2Copyright (C) 2011-2014, Parrot Foundation.
3
4=head1 NAME
5
6src/pmc/imccompiler.pmc - IMCCompiler PMC
7
8=head1 DESCRIPTION
9
10A compiler object to wrap IMCC, the internal PIR and PASM compiler.
11
12=head2 Functions
13
14=cut
15
16*/
17
18#include "imcc/embed.h"
19#include "imcc/yyscanner.h"
20#include "pmc/pmc_sub.h"
21
22/* HEADERIZER BEGIN: static */
23/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
24
25/* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
26/* HEADERIZER END: static */
27
28#define BEGIN_IMCC_COMPILE(i) \
29    do { \
30        UINTVAL __regs_used[4] = {3, 3, 3, 3}; \
31        PMC * const __newcontext = Parrot_push_context((i), __regs_used); \
32        PackFile_ByteCode * const __old_bc = (i)->code; \
33        Parrot_block_GC_mark((i)); \
34        Parrot_pcc_set_HLL((i), __newcontext, 0); \
35        Parrot_pcc_set_sub((i), __newcontext, 0); \
36
37#define END_IMCC_COMPILE(i) \
38        Parrot_pop_context((i)); \
39        Parrot_unblock_GC_mark((i)); \
40        (i)->code = __old_bc; \
41    } while (0)
42
43#define ERROR_IMCC_COMPILE(i) \
44    Parrot_pop_context((i)); \
45    Parrot_unblock_GC_mark((i)); \
46    (i)->code = __old_bc; \
47
48/* HEADERIZER HFILE: none */
49
50pmclass IMCCompiler auto_attrs provides HLLCompiler provide invokable {
51    ATTR void *imcc_info;
52    ATTR INTVAL is_pasm; /* 0 = PIR, 1 = PASM */
53    ATTR INTVAL current_eval;
54
55    VTABLE void init() :no_wb {
56        UNUSED(SELF)
57        Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
58            "IMCCompiler: Must initialize with an integer argument 0 (PIR) or 1 (PASM)");
59    }
60
61    VTABLE void init_pmc(PMC *init) :manual_wb {
62        const INTVAL type = VTABLE_get_integer(INTERP, init);
63        VTABLE_init_int(INTERP, SELF, type);
64    }
65
66    VTABLE void init_int(INTVAL is_pasm) {
67        Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
68        if (is_pasm != 0 && is_pasm != 1)
69            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
70                "IMCCompiler: Must have type 0 (PIR) or 1 (PASM)");
71        attrs->is_pasm = is_pasm;
72        attrs->imcc_info = (void*) imcc_new(INTERP);
73        attrs->current_eval = 0;
74    }
75
76    /* provided to emulate the current NCI compreg */
77    /* DEPRECATED. See TT #1967 */
78    VTABLE opcode_t* invoke(void* next) :no_wb {
79        Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
80        imc_info_t * const imcc = (imc_info_t*) attrs->imcc_info;
81        PMC * const ctx = CURRENT_CONTEXT(INTERP);
82        PMC * cont = INTERP->current_cont;
83        PMC * const call_object = Parrot_pcc_get_signature(interp, ctx);
84        PackFile_ByteCode * const cur_code = interp->code;
85        STRING * code = STRINGNULL;
86        PMC * result = PMCNULL;
87        const UINTVAL regs_used[4] = {3, 3, 3, 3};
88        PMC * const newcontext = Parrot_push_context(interp, regs_used);
89
90        Parrot_block_GC_mark(interp);
91        Parrot_pcc_set_sub(interp, newcontext, 0);
92
93        Parrot_pcc_fill_params_from_c_args(INTERP, call_object, "S", &code);
94        imcc_reset(imcc);
95        result = imcc_compile_string(imcc, code, attrs->is_pasm);
96        if (PMC_IS_NULL(result)) {
97            STRING * const msg   = imcc_last_error_message(imcc);
98            const INTVAL errcode = imcc_last_error_code(imcc);
99            Parrot_unblock_GC_mark(interp);
100            Parrot_ex_throw_from_c_args(INTERP, NULL, errcode, "%Ss", msg);
101        }
102
103        Parrot_pop_context(interp);
104        Parrot_unblock_GC_mark(interp);
105
106        /* Handle the case where we we've been tailcalled into. See NCI.invoke
107           for more details */
108        if (!PMC_IS_NULL(cont)
109        && (PObj_get_FLAGS(cont) & SUB_FLAG_TAILCALL)) {
110            cont = Parrot_pcc_get_continuation(interp, CURRENT_CONTEXT(interp));
111            next = VTABLE_invoke(INTERP, cont, next);
112        }
113
114        Parrot_pcc_set_call_from_c_args(INTERP, call_object, "P", result);
115        interp->code = cur_code;
116        return (opcode_t*)next;
117    }
118
119    VTABLE void *get_pointer() :no_wb {
120        const Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
121        UNUSED(INTERP)
122        return attrs->imcc_info;
123    }
124
125    VTABLE INTVAL get_integer() :no_wb {
126        const Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
127        UNUSED(INTERP)
128        return attrs->is_pasm;
129    }
130
131    VTABLE STRING *get_string() :no_wb {
132        const Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
133        if (attrs->is_pasm)
134            return CONST_STRING(INTERP, "PASM");
135        else
136            return CONST_STRING(INTERP, "PIR");
137    }
138
139    VTABLE void destroy() :no_wb {
140        Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
141        UNUSED(INTERP)
142        imcc_destroy((imc_info_t*)(attrs->imcc_info));
143        attrs->imcc_info = NULL;
144    }
145
146    METHOD compile(STRING *source,
147            STRING *path   :optional, INTVAL has_path   :opt_flag,
148            STRING *target :named("target")    :optional, INTVAL has_target :opt_flag,
149            PMC *outer_ctx :named("outer_ctx") :optional, INTVAL has_ctx    :opt_flag) :no_wb
150    {
151        Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
152        PMC * pf;
153        imc_info_t * const imcc = (imc_info_t*)attrs->imcc_info;
154
155        if (has_target)
156            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
157                "IMCCompiler: compiler does not support the target option");
158
159        BEGIN_IMCC_COMPILE(interp);
160
161        /* TODO: Handle outer_ctx */
162        pf = imcc_compile_string(imcc, source, attrs->is_pasm);
163        if (PMC_IS_NULL(pf)) {
164            STRING * const msg = imcc_last_error_message(imcc);
165            INTVAL code = imcc_last_error_code(imcc);
166            ERROR_IMCC_COMPILE(interp);
167            Parrot_ex_throw_from_c_args(INTERP, NULL, code, "%Ss", msg);
168        }
169        if (has_path)
170            VTABLE_set_string_native(INTERP, pf, path);
171
172        END_IMCC_COMPILE(interp);
173
174        RETURN(PMC *pf);
175    }
176
177    METHOD compile_file(STRING *filename,
178            STRING *path   :optional, INTVAL has_path   :opt_flag,
179            STRING *target :named("target")    :optional, INTVAL has_target :opt_flag,
180            PMC *outer_ctx :named("outer_ctx") :optional, INTVAL has_ctx    :opt_flag) :no_wb
181    {
182        Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
183        PMC * pf = PMCNULL;
184        imc_info_t * const imcc = (imc_info_t*)attrs->imcc_info;
185
186        if (has_target)
187            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
188                "IMCCompiler: compiler does not support the target option");
189
190        BEGIN_IMCC_COMPILE(interp);
191
192        /* TODO: Handle outer_ctx */
193        pf = imcc_compile_file(imcc, filename, attrs->is_pasm);
194        if (PMC_IS_NULL(pf)) {
195            STRING * const msg = imcc_last_error_message(imcc);
196            const INTVAL code = imcc_last_error_code(imcc);
197            ERROR_IMCC_COMPILE(interp);
198            Parrot_ex_throw_from_c_args(INTERP, NULL, code, "%Ss", msg);
199        }
200
201        if (has_path)
202            VTABLE_set_string_native(INTERP, pf, path);
203
204        END_IMCC_COMPILE(interp);
205
206        RETURN(PMC *pf);
207    }
208
209    /*METHOD eval(STRING *source,
210            STRING *target :named("target") :optional, INTVAL has_target :opt_flag,
211            PMC *outer_ctx :named("outer_ctx") :optional, INTVAL has_ctx :opt_flag) :no_wb
212    {
213        Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
214        PMC * pf = PMCNULL;
215        imc_info_t * const imcc = (imc_info_t*)attrs->imcc_info;
216        if (has_target)
217            Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_INVALID_OPERATION,
218                "IMCCompiler: compiler does not support the target option");
219        pf = imcc_compile_string(imcc, source, attrs->is_pasm);
220    }*/
221
222    METHOD preprocess(STRING *code) :no_wb {
223        const Parrot_IMCCompiler_attributes * const attrs = PARROT_IMCCOMPILER(SELF);
224        imc_info_t * const imcc = (imc_info_t*)attrs->imcc_info;
225        imcc_preprocess(imcc, code);
226    }
227
228    /*METHOD parse_name(STRING *name) :no_wb {
229        Parrot_ex_throw_from_c_noargs(INTERP, EXCEPTION_UNIMPLEMENTED,
230                "IMCCompiler: parse_name is not supported");
231    }*/
232
233    /* TODO: This */
234    /*METHOD load_module(STRING *name) :no_wb {
235
236    }*/
237
238    /* TODO: This */
239    /*METHOD get_module(STRING *name) :no_wb {
240
241    }*/
242
243    /* TODO: This */
244    /*METHOD get_exports(PMC *module) :no_wb {
245
246    }*/
247}
248
249/*
250 * Local variables:
251 *   c-file-style: "parrot"
252 * End:
253 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
254 */
255