main.c 8.93 KB
Newer Older
Damien's avatar
Damien committed
1
2
3
#include <stdint.h>
#include <stdio.h>
#include <string.h>
Edd Barrett's avatar
Edd Barrett committed
4
#include <stdlib.h>
Damien's avatar
Damien committed
5

6
#include "nlr.h"
Damien's avatar
Damien committed
7
#include "misc.h"
8
#include "mpconfig.h"
9
#include "qstr.h"
Damien's avatar
Damien committed
10
#include "lexer.h"
11
#include "lexerunix.h"
Damien's avatar
Damien committed
12
#include "parse.h"
13
#include "obj.h"
14
#include "compile.h"
15
16
#include "runtime0.h"
#include "runtime.h"
17
#include "repl.h"
Damien's avatar
Damien committed
18

19
#if MICROPY_USE_READLINE
Damien's avatar
Damien committed
20
#include <readline/readline.h>
21
#include <readline/history.h>
22
#endif
Damien's avatar
Damien committed
23

24
extern const mp_obj_fun_native_t mp_builtin_open_obj;
25
void file_init();
26
void rawsocket_init();
27
void time_init();
28
void ffi_init();
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
static void execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
    if (lex == NULL) {
        return;
    }

    if (0) {
        // just tokenise
        while (!mp_lexer_is_kind(lex, MP_TOKEN_END)) {
            mp_token_show(mp_lexer_cur(lex));
            mp_lexer_to_next(lex);
        }
        mp_lexer_free(lex);
        return;
    }

45
46
47
    qstr parse_exc_id;
    const char *parse_exc_msg;
    mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_exc_id, &parse_exc_msg);
48
49
50

    if (pn == MP_PARSE_NODE_NULL) {
        // parse error
51
52
53
        mp_lexer_show_error_pythonic_prefix(lex);
        printf("%s: %s\n", qstr_str(parse_exc_id), parse_exc_msg);
        mp_lexer_free(lex);
54
55
56
        return;
    }

57
    qstr source_name = mp_lexer_source_name(lex);
58
59
    mp_lexer_free(lex);

60
61
62
63
64
    /*
    printf("----------------\n");
    mp_parse_node_print(pn, 0);
    printf("----------------\n");
    */
65

66
    mp_obj_t module_fun = mp_compile(pn, source_name, is_repl);
67
68
69
70
71
72
73
74
75
76
77
78
79

    if (module_fun == mp_const_none) {
        // compile error
        return;
    }

    // execute it
    nlr_buf_t nlr;
    if (nlr_push(&nlr) == 0) {
        rt_call_function_0(module_fun);
        nlr_pop();
    } else {
        // uncaught exception
80
        mp_obj_print_exception((mp_obj_t)nlr.ret_val);
81
82
83
    }
}

84
static char *str_join(const char *s1, int sep_char, const char *s2) {
Damien's avatar
Damien committed
85
86
87
88
89
90
91
92
93
    int l1 = strlen(s1);
    int l2 = strlen(s2);
    char *s = m_new(char, l1 + l2 + 2);
    memcpy(s, s1, l1);
    if (sep_char != 0) {
        s[l1] = sep_char;
        l1 += 1;
    }
    memcpy(s + l1, s2, l2);
94
    s[l1 + l2] = 0;
Damien's avatar
Damien committed
95
96
97
    return s;
}

98
static char *prompt(char *p) {
99
#if MICROPY_USE_READLINE
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    char *line = readline(p);
    if (line) {
        add_history(line);
    }
#else
    static char buf[256];
    fputs(p, stdout);
    char *s = fgets(buf, sizeof(buf), stdin);
    if (!s) {
        return NULL;
    }
    int l = strlen(buf);
    if (buf[l - 1] == '\n') {
        buf[l - 1] = 0;
    } else {
        l++;
    }
Paul Sokolovsky's avatar
Paul Sokolovsky committed
117
    char *line = malloc(l);
118
119
120
121
122
    memcpy(line, buf, l);
#endif
    return line;
}

123
static void do_repl(void) {
Damien's avatar
Damien committed
124
    for (;;) {
125
        char *line = prompt(">>> ");
Damien's avatar
Damien committed
126
127
128
129
        if (line == NULL) {
            // EOF
            return;
        }
130
        if (mp_repl_is_compound_stmt(line)) {
Damien's avatar
Damien committed
131
            for (;;) {
132
                char *line2 = prompt("... ");
Damien's avatar
Damien committed
133
134
135
136
                if (line2 == NULL || strlen(line2) == 0) {
                    break;
                }
                char *line3 = str_join(line, '\n', line2);
137
138
                free(line);
                free(line2);
Damien's avatar
Damien committed
139
140
141
                line = line3;
            }
        }
142

143
        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
144
        execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true);
Paul Sokolovsky's avatar
Paul Sokolovsky committed
145
        free(line);
Damien's avatar
Damien committed
146
    }
Damien's avatar
Damien committed
147
148
}

149
static void do_file(const char *file) {
150
151
152
153
154
155
156
157
158
159
160
161
    // hack: set dir for import based on where this file is
    {
        const char * s = strrchr(file, '/');
        if (s != NULL) {
            int len = s - file;
            char *dir = m_new(char, len + 1);
            memcpy(dir, file, len);
            dir[len] = '\0';
            mp_import_set_directory(dir);
        }
    }

162
    mp_lexer_t *lex = mp_lexer_new_from_file(file);
163
164
    execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false);
}
Damien's avatar
Damien committed
165

166
static void do_str(const char *str) {
167
    mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, str, strlen(str), false);
168
    execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, false);
Damien's avatar
Damien committed
169
}
Damien's avatar
Damien committed
170

171
172
typedef struct _test_obj_t {
    mp_obj_base_t base;
173
    int value;
174
175
} test_obj_t;

176
static void test_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
177
178
    test_obj_t *self = self_in;
    print(env, "<test %d>", self->value);
Damien's avatar
Damien committed
179
180
}

181
182
183
static mp_obj_t test_get(mp_obj_t self_in) {
    test_obj_t *self = self_in;
    return mp_obj_new_int(self->value);
Damien's avatar
Damien committed
184
185
}

186
187
188
189
static mp_obj_t test_set(mp_obj_t self_in, mp_obj_t arg) {
    test_obj_t *self = self_in;
    self->value = mp_obj_get_int(arg);
    return mp_const_none;
Damien's avatar
Damien committed
190
191
}

192
193
194
static MP_DEFINE_CONST_FUN_OBJ_1(test_get_obj, test_get);
static MP_DEFINE_CONST_FUN_OBJ_2(test_set_obj, test_set);

195
196
197
198
199
200
static const mp_method_t test_methods[] = {
    { "get", &test_get_obj },
    { "set", &test_set_obj },
    { NULL, NULL },
};

201
202
static const mp_obj_type_t test_type = {
    { &mp_const_type },
Damien's avatar
Damien committed
203
    "Test",
204
    .print = test_print,
205
    .methods = test_methods,
Damien's avatar
Damien committed
206
207
};

208
209
210
211
212
213
214
mp_obj_t test_obj_new(int value) {
    test_obj_t *o = m_new_obj(test_obj_t);
    o->base.type = &test_type;
    o->value = value;
    return o;
}

215
216
217
218
219
int usage(void) {
    printf("usage: py [-c <command>] [<filename>]\n");
    return 1;
}

220
221
222
223
224
225
226
227
228
229
230
231
mp_obj_t mem_info(void) {
    printf("mem: total=%d, current=%d, peak=%d\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated());
    return mp_const_none;
}

mp_obj_t qstr_info(void) {
    uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
    qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
    printf("qstr pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
    return mp_const_none;
}

Damien's avatar
Damien committed
232
233
234
235
int main(int argc, char **argv) {
    qstr_init();
    rt_init();

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    char *home = getenv("HOME");
    char *path = getenv("MICROPYPATH");
    if (path == NULL) {
        path = "~/.micropython/lib:/usr/lib/micropython";
    }
    uint path_num = 0;
    for (char *p = path; p != NULL; p = strchr(p, ':')) {
        path_num++;
        if (p != NULL) {
            p++;
        }
    }
    sys_path = mp_obj_new_list(path_num, NULL);
    mp_obj_t *items;
    mp_obj_list_get(sys_path, &path_num, &items);
    char *p = path;
    for (int i = 0; i < path_num; i++) {
        char *p1 = strchr(p, ':');
        if (p1 == NULL) {
            p1 = p + strlen(p);
        }
        if (p[0] == '~' && p[1] == '/' && home != NULL) {
            // Expand standalone ~ to $HOME
            CHECKBUF(buf, PATH_MAX);
            CHECKBUF_APPEND(buf, home, strlen(home));
            CHECKBUF_APPEND(buf, p + 1, p1 - p - 1);
            items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(buf, CHECKBUF_LEN(buf)));
        } else {
            items[i] = MP_OBJ_NEW_QSTR(qstr_from_strn(p, p1 - p));
        }
        p = p1 + 1;
    }

269
    mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys);
270
    rt_store_attr(m_sys, MP_QSTR_path, sys_path);
Paul Sokolovsky's avatar
Paul Sokolovsky committed
271
    mp_obj_t py_argv = mp_obj_new_list(0, NULL);
272
    rt_store_attr(m_sys, MP_QSTR_argv, py_argv);
Paul Sokolovsky's avatar
Paul Sokolovsky committed
273

274
    rt_store_name(qstr_from_str("test"), test_obj_new(42));
275
276
    rt_store_name(qstr_from_str("mem_info"), rt_make_function_n(0, mem_info));
    rt_store_name(qstr_from_str("qstr_info"), rt_make_function_n(0, qstr_info));
Paul Sokolovsky's avatar
Paul Sokolovsky committed
277

278
    file_init();
279
    rawsocket_init();
280
281
282
#if MICROPY_MOD_TIME
    time_init();
#endif
283
#if MICROPY_MOD_FFI
284
    ffi_init();
285
#endif
Damien's avatar
Damien committed
286

287
288
289
290
291
292
293
294
    // Here is some example code to create a class and instance of that class.
    // First is the Python, then the C code.
    //
    // class TestClass:
    //     pass
    // test_obj = TestClass()
    // test_obj.attr = 42
    mp_obj_t test_class_type, test_class_instance;
295
    test_class_type = mp_obj_new_type("TestClass", mp_const_empty_tuple, mp_obj_new_dict(0));
296
297
    rt_store_name(QSTR_FROM_STR_STATIC("test_obj"), test_class_instance = rt_call_function_0(test_class_type));
    rt_store_attr(test_class_instance, QSTR_FROM_STR_STATIC("attr"), mp_obj_new_int(42));
298

299
300
301
302
303
304
305
    /*
    printf("bytes:\n");
    printf("    total %d\n", m_get_total_bytes_allocated());
    printf("    cur   %d\n", m_get_current_bytes_allocated());
    printf("    peak  %d\n", m_get_peak_bytes_allocated());
    */

Damien's avatar
Damien committed
306
307
308
    if (argc == 1) {
        do_repl();
    } else {
309
310
311
312
313
314
315
316
317
318
319
320
        for (int a = 1; a < argc; a++) {
            if (argv[a][0] == '-') {
                if (strcmp(argv[a], "-c") == 0) {
                    if (a + 1 >= argc) {
                        return usage();
                    }
                    do_str(argv[a + 1]);
                    a += 1;
                } else {
                    return usage();
                }
            } else {
Paul Sokolovsky's avatar
Paul Sokolovsky committed
321
                for (int i = a; i < argc; i++) {
322
                    rt_list_append(py_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i])));
Paul Sokolovsky's avatar
Paul Sokolovsky committed
323
                }
324
                do_file(argv[a]);
Paul Sokolovsky's avatar
Paul Sokolovsky committed
325
                break;
326
327
            }
        }
Damien's avatar
Damien committed
328
    }
329

Damien's avatar
Damien committed
330
331
332
333
334
    rt_deinit();

    //printf("total bytes = %d\n", m_get_total_bytes_allocated());
    return 0;
}
335
336
337
338
339
340

// for sqrt
#include <math.h>
machine_float_t machine_sqrt(machine_float_t x) {
    return sqrt(x);
}