1 /*
2 * Copyright (c) 2021 Calvin Rose
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 
23 #ifndef JANET_AMALG
24 #include "features.h"
25 #include <janet.h>
26 #endif
27 
28 /* Run a string */
janet_dobytes(JanetTable * env,const uint8_t * bytes,int32_t len,const char * sourcePath,Janet * out)29 int janet_dobytes(JanetTable *env, const uint8_t *bytes, int32_t len, const char *sourcePath, Janet *out) {
30     JanetParser parser;
31     int errflags = 0, done = 0;
32     int32_t index = 0;
33     Janet ret = janet_wrap_nil();
34     const uint8_t *where = sourcePath ? janet_cstring(sourcePath) : NULL;
35 
36     if (where) janet_gcroot(janet_wrap_string(where));
37     if (NULL == sourcePath) sourcePath = "<unknown>";
38     janet_parser_init(&parser);
39 
40     /* While we haven't seen an error */
41     while (!done) {
42 
43         /* Evaluate parsed values */
44         while (janet_parser_has_more(&parser)) {
45             Janet form = janet_parser_produce(&parser);
46             JanetCompileResult cres = janet_compile(form, env, where);
47             if (cres.status == JANET_COMPILE_OK) {
48                 JanetFunction *f = janet_thunk(cres.funcdef);
49                 JanetFiber *fiber = janet_fiber(f, 64, 0, NULL);
50                 fiber->env = env;
51                 JanetSignal status = janet_continue(fiber, janet_wrap_nil(), &ret);
52                 if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
53                     janet_stacktrace_ext(fiber, ret, "");
54                     errflags |= 0x01;
55                     done = 1;
56                 }
57             } else {
58                 ret = janet_wrap_string(cres.error);
59                 if (cres.macrofiber) {
60                     janet_eprintf("compile error in %s: ", sourcePath);
61                     janet_stacktrace_ext(cres.macrofiber, ret, "");
62                 } else {
63                     janet_eprintf("compile error in %s: %s\n", sourcePath,
64                                   (const char *)cres.error);
65                 }
66                 errflags |= 0x02;
67                 done = 1;
68             }
69         }
70 
71         if (done) break;
72 
73         /* Dispatch based on parse state */
74         switch (janet_parser_status(&parser)) {
75             case JANET_PARSE_DEAD:
76                 done = 1;
77                 break;
78             case JANET_PARSE_ERROR: {
79                 const char *e = janet_parser_error(&parser);
80                 errflags |= 0x04;
81                 ret = janet_cstringv(e);
82                 size_t line = parser.line;
83                 size_t col = parser.column;
84                 janet_eprintf("%s:%lu:%lu: parse error: %s\n", sourcePath, line, col, e);
85                 done = 1;
86                 break;
87             }
88             case JANET_PARSE_ROOT:
89             case JANET_PARSE_PENDING:
90                 if (index >= len) {
91                     janet_parser_eof(&parser);
92                 } else {
93                     janet_parser_consume(&parser, bytes[index++]);
94                 }
95                 break;
96         }
97 
98     }
99 
100     /* Clean up and return errors */
101     janet_parser_deinit(&parser);
102     if (where) janet_gcunroot(janet_wrap_string(where));
103     if (out) *out = ret;
104     return errflags;
105 }
106 
janet_dostring(JanetTable * env,const char * str,const char * sourcePath,Janet * out)107 int janet_dostring(JanetTable *env, const char *str, const char *sourcePath, Janet *out) {
108     int32_t len = 0;
109     while (str[len]) ++len;
110     return janet_dobytes(env, (const uint8_t *)str, len, sourcePath, out);
111 }
112 
113 /* Run a fiber to completion (use event loop if enabled). Return the status. */
janet_loop_fiber(JanetFiber * fiber)114 int janet_loop_fiber(JanetFiber *fiber) {
115     int status;
116 #ifdef JANET_EV
117     janet_schedule(fiber, janet_wrap_nil());
118     janet_loop();
119     status = janet_fiber_status(fiber);
120 #else
121     Janet out;
122     status = janet_continue(fiber, janet_wrap_nil(), &out);
123     if (status != JANET_SIGNAL_OK && status != JANET_SIGNAL_EVENT) {
124         janet_stacktrace_ext(fiber, out, "");
125     }
126 #endif
127     return status;
128 }
129