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