Commit c41c7d31 authored by Chris Müller's avatar Chris Müller
Browse files

start implementing repl

parent 33a0cdbf
set(CORE_SOURCES
read.c
eval.c
value.c
unicode.c
tables.c)
set(INTERPRETER_SOURCES
......@@ -9,5 +11,4 @@ set(INTERPRETER_SOURCES
add_library(cherry-core ${CORE_SOURCES})
add_executable(cherry ${INTERPRETER_SOURCES})
target_link_libraries(cherry readline crystal cherry-core)
target_link_libraries(cherry readline crystal cherry-core gc)
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include "cherry.h"
int main(int argc, char** argv)
{
printf("Cherry Interpreter 0.1\n\n");
char* line = readline("> ");
org_cherry_initialize(0);
printf("written: %s\n", line);
struct org_cherry_symbollist* env = org_cherry_symbollist();
while(1) {
byte_t* line = (byte_t*) readline("> ");
struct org_cherry_context* context = org_cherry_context_repl(line);
struct org_cherry_value* exp = org_cherry_read(context);
org_cherry_print(stdout, org_cherry_eval(env, exp));
printf("\n");
free(line);
}
printf("Goodbye\n");
return EXIT_SUCCESS;
}
......@@ -16,59 +16,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <crystal/standard.h>
#include "cherry/runtime.h"
#include <stdlib.h>
#include <stdint.h>
struct CyArray;
struct CyFile {
const char* filename;
const byte_t* begin;
};
struct CyContext {
struct CyFile* file;
byte_t* src;
struct CryArray* buffer;
};
struct CyContext* cy_context_new(const byte_t* source, const char* filename);
struct CyContext* cy_context_repl_new(const byte_t* source);
void cy_context_free(struct CyContext* context);
void cy_error(struct CyContext* context, const char* format, ...);
enum CyTOK {
TOK_EOF,
TOK_ROUNDLEFTBRACE,
TOK_ROUNDRIGHTBRACE,
TOK_SQUARELEFTBRACE,
TOK_SQUARERIGHTBRACE,
TOK_COMMENT,
TOK_DOT,
TOK_STRING,
TOK_CHAR,
TOK_HEX,
TOK_DEC,
TOK_OCT,
TOK_BIN,
TOK_FLOAT,
TOK_SYMBOL,
TOK_TRUE,
TOK_FALSE,
TOK_QUOTE
};
const byte_t* cy_tok_to_string(enum CyTOK token);
enum CyTOK cy_lex(struct CyContext* context);
byte_t* cy_token_string(struct CyContext* context);
size_t cy_token_length(struct CyContext* context);
struct org_cherry_value*
org_cherry_eval(struct org_cherry_symbollist* env, struct org_cherry_value* value)
{
if(IS_SELF_EVALUATING(value))
return value;
else if(IS_VARIABLE(value))
return org_cherry_env_lookup(env, value);
fprintf(stderr, "can not eval unknown expression\n");
exit(1);
return 0;
}
......@@ -18,7 +18,9 @@
#include "cherry/runtime.h"
#include <stdlib.h>
#include <string.h>
#include <gc.h>
#include <assert.h>
// ----------------------------------------------------------------------------
// globals
......@@ -36,6 +38,132 @@ struct org_cherry_value* org_cherry_symbol_if;
struct org_cherry_value* org_cherry_symbol_else;
struct org_cherry_value* org_cherry_symbol_quote;
// ----------------------------------------------------------------------------
// helper methods
// ----------------------------------------------------------------------------
const cy_byte_t*
org_cherry_string_dup(const cy_byte_t* str)
{
assert(str != 0);
size_t length = org_cherry_string_size(str);
cy_byte_t* dest = GC_MALLOC(length);
memcpy(dest, str, length);
return dest;
}
// ----------------------------------------------------------------------------
// string converter
// ----------------------------------------------------------------------------
struct org_cherry_value*
org_cherry_fixnum_from_string(const cy_byte_t* str, int base)
{
cy_fixnum_t value;
switch(base) {
case 2:
value = strtol(str + 2, 0, 2);
break;
case 8:
value = strtol(str + 2, 0, 8);
break;
case 16:
value = strtol(str + 2, 0, 16);
break;
default:
value = strtol(str, 0, 10);
}
return org_cherry_fixnum(value);
}
struct org_cherry_value*
org_cherry_float_from_string(const cy_byte_t* str)
{
return org_cherry_float(strtod(str, 0));
}
struct org_cherry_value*
org_cherry_char_from_string(const cy_byte_t* str)
{
return 0;
}
struct org_cherry_value*
org_cherry_symbol_from_string(const cy_byte_t* str)
{
return org_cherry_symbol(org_cherry_string_dup(str));
}
struct org_cherry_value*
org_cherry_string_from_string(const cy_byte_t* str)
{
cy_byte_t* p = GC_MALLOC(org_cherry_string_size(str));
cy_byte_t* s = p;
cy_byte_t buffer[7];
cy_unicode_t c;
while(*str != '\0') {
if(*str == '\\') {
switch(*(str + 1)) {
case 'a':
*s = '\a';
break;
case 'b':
*s = '\b';
break;
case 'f':
*s = '\f';
break;
case 'n':
*s = '\n';
break;
case 'r':
*s = '\r';
break;
case 't':
*s = '\t';
break;
case 'v':
*s = '\v';
break;
case '0':
*s = '\0';
break;
case '"':
*s = '"';
break;
case 'u':
memcpy(buffer, str + 2, 4);
buffer[4] = '\0';
c = strtol(buffer, 0, 16);
str += 4;
break;
case 'U':
memcpy(buffer, str + 2, 6);
buffer[6] = '\0';
c = strtol(buffer, 0, 16);
str += 6;
break;
}
str++;
} else {
*s = *str;
}
s++;
str++;
}
*s = '\0';
return org_cherry_string(p);
}
// ----------------------------------------------------------------------------
// cherry object constructors
......@@ -76,7 +204,7 @@ org_cherry_float(cy_float_t value)
struct org_cherry_value*
org_cherry_string(cy_byte_t* value)
org_cherry_string(const cy_byte_t* value)
{
struct org_cherry_value* cy_value = org_cherry_value_alloc();
cy_value->meta.type = CY_STRING;
......@@ -95,7 +223,7 @@ org_cherry_char(cy_unicode_t value)
}
struct org_cherry_value*
org_cherry_symbol(cy_byte_t* value)
org_cherry_symbol(const cy_byte_t* value)
{
return org_cherry_symbollist_get(org_cherry_global_symbollist, value);
}
......@@ -204,7 +332,7 @@ print_pair(FILE* out, struct org_cherry_pair* value)
void
org_cherry_print(FILE* out, struct org_cherry_value* value)
{
cy_byte_t* p;
const cy_byte_t* p;
switch(value->meta.type) {
case CY_EMPTYLIST:
......@@ -225,12 +353,33 @@ org_cherry_print(FILE* out, struct org_cherry_value* value)
case CY_CHAR:
fprintf(out, "\\");
switch(value->char_value) {
case '\0':
fprintf(out, "null");
break;
case '\a':
fprintf(out, "bell");
break;
case '\b':
fprintf(out, "backspace");
break;
case '\f':
fprintf(out, "formfeed");
break;
case '\n':
fprintf(out, "newline");
break;
case ' ':
fprintf(out, "space");
break;
case '\r':
fprintf(out, "return");
break;
case '\t':
fprintf(out, "tab");
break;
case '\v':
fprintf(out, "vtab");
break;
default:
fprintf(out, "%c", value->char_value);
}
......@@ -241,15 +390,32 @@ org_cherry_print(FILE* out, struct org_cherry_value* value)
fprintf(out, "\"");
while(*p != '\0') {
switch(*p) {
case '\a':
fprintf(out, "\\a");
break;
case '\b':
fprintf(out, "\\b");
break;
case '\f':
fprintf(out, "\\f");
break;
case '\n':
fprintf(out, "\\n");
break;
case '\\':
fprintf(out, "\\");
case '\r':
fprintf(out, "\\r");
break;
case '\t':
fprintf(out, "\\t");
break;
case '\"':
case '\v':
fprintf(out, "\v");
case '"':
fprintf(out, "\\\"");
break;
case '\\':
fprintf(out, "\\");
break;
default:
fprintf(out, "%c", *p);
}
......
......@@ -17,147 +17,150 @@
*/
#include <crystal/unittest.h>
#include <cherry/lexer.h>
#include <cherry.h>
#include <stdio.h>
#include <string.h>
static void test_lex_fixnum(const_pointer data)
{
byte_t* fixnum = "0 0xFF 0xFFFF 1000 0777 0b0001 0b00011111";
struct CyContext* c = cy_context_repl_new(fixnum);
byte_t* fixnum = "0 5 0xFF 0xFFFF 1000 0777 0b0001 0b00011111";
struct org_cherry_context* c = org_cherry_context_repl(fixnum);
assert(cy_lex(c) == TOK_DEC);
assert(strcmp(cy_token_string(c), "0") == 0);
assert(org_cherry_lex(c) == TOK_DEC);
assert(strcmp(org_cherry_token_string(c), "0") == 0);
assert(cy_lex(c) == TOK_HEX);
assert(strcmp(cy_token_string(c), "0xFF") == 0);
assert(org_cherry_lex(c) == TOK_DEC);
assert(strcmp(org_cherry_token_string(c), "5") == 0);
assert(cy_lex(c) == TOK_HEX);
assert(strcmp(cy_token_string(c), "0xFFFF") == 0);
assert(org_cherry_lex(c) == TOK_HEX);
assert(strcmp(org_cherry_token_string(c), "0xFF") == 0);
assert(cy_lex(c) == TOK_DEC);
assert(strcmp(cy_token_string(c), "1000") == 0);
assert(org_cherry_lex(c) == TOK_HEX);
assert(strcmp(org_cherry_token_string(c), "0xFFFF") == 0);
assert(cy_lex(c) == TOK_OCT);
assert(strcmp(cy_token_string(c), "0777") == 0);
assert(org_cherry_lex(c) == TOK_DEC);
assert(strcmp(org_cherry_token_string(c), "1000") == 0);
assert(cy_lex(c) == TOK_BIN);
assert(strcmp(cy_token_string(c), "0b0001") == 0);
assert(org_cherry_lex(c) == TOK_OCT);
assert(strcmp(org_cherry_token_string(c), "0777") == 0);
assert(cy_lex(c) == TOK_BIN);
assert(strcmp(cy_token_string(c), "0b00011111") == 0);
assert(org_cherry_lex(c) == TOK_BIN);
assert(strcmp(org_cherry_token_string(c), "0b0001") == 0);
cy_context_free(c);
assert(org_cherry_lex(c) == TOK_BIN);
assert(strcmp(org_cherry_token_string(c), "0b00011111") == 0);
org_cherry_context_free(c);
}
static void test_lex_float(const_pointer data)
{
byte_t* fixnum = "1.0 4e+1 5e-10 1.0e20";
struct CyContext* c = cy_context_repl_new(fixnum);
struct org_cherry_context* c = org_cherry_context_repl(fixnum);
assert(cy_lex(c) == TOK_FLOAT);
assert(strcmp(cy_token_string(c), "1.0") == 0);
assert(org_cherry_lex(c) == TOK_FLOAT);
assert(strcmp(org_cherry_token_string(c), "1.0") == 0);
assert(cy_lex(c) == TOK_FLOAT);
assert(strcmp(cy_token_string(c), "4e+1") == 0);
assert(org_cherry_lex(c) == TOK_FLOAT);
assert(strcmp(org_cherry_token_string(c), "4e+1") == 0);
assert(cy_lex(c) == TOK_FLOAT);
assert(strcmp(cy_token_string(c), "5e-10") == 0);
assert(org_cherry_lex(c) == TOK_FLOAT);
assert(strcmp(org_cherry_token_string(c), "5e-10") == 0);
assert(cy_lex(c) == TOK_FLOAT);
assert(strcmp(cy_token_string(c), "1.0e20") == 0);
assert(org_cherry_lex(c) == TOK_FLOAT);
assert(strcmp(org_cherry_token_string(c), "1.0e20") == 0);
cy_context_free(c);
org_cherry_context_free(c);
}
static void test_lex_string(const_pointer data)
{
byte_t* str = " \"asdf\" \"test\\uFFFF\\UFFFFFFFF\\n\" ";
struct CyContext* c = cy_context_repl_new(str);
struct org_cherry_context* c = org_cherry_context_repl(str);
assert(cy_lex(c) == TOK_STRING);
assert(strcmp(cy_token_string(c), "asdf") == 0);
assert(org_cherry_lex(c) == TOK_STRING);
assert(strcmp(org_cherry_token_string(c), "asdf") == 0);
assert(cy_lex(c) == TOK_STRING);
assert(strcmp(cy_token_string(c), "test\\uFFFF\\UFFFFFFFF\\n") == 0);
assert(org_cherry_lex(c) == TOK_STRING);
assert(strcmp(org_cherry_token_string(c), "test\\uFFFF\\UFFFFFFFF\\n") == 0);
cy_context_free(c);
org_cherry_context_free(c);
}
static void test_lex_comment(const_pointer data)
{
byte_t* comment = "; comment\n";
struct CyContext* c = cy_context_repl_new(comment);
struct org_cherry_context* c = org_cherry_context_repl(comment);
assert(cy_lex(c) == TOK_COMMENT);
assert(strcmp(cy_token_string(c), "; comment") == 0);
assert(org_cherry_lex(c) == TOK_COMMENT);
assert(strcmp(org_cherry_token_string(c), "; comment") == 0);
cy_context_free(c);
org_cherry_context_free(c);
}
static void test_lex_symbols(const_pointer data)
{
byte_t* str = " true false null? + - ";
struct CyContext* c = cy_context_repl_new(str);
struct org_cherry_context* c = org_cherry_context_repl(str);
assert(cy_lex(c) == TOK_TRUE);
assert(cy_lex(c) == TOK_FALSE);
assert(org_cherry_lex(c) == TOK_TRUE);
assert(org_cherry_lex(c) == TOK_FALSE);
assert(cy_lex(c) == TOK_SYMBOL);
assert(strcmp(cy_token_string(c), "null?") == 0);
assert(org_cherry_lex(c) == TOK_SYMBOL);
assert(strcmp(org_cherry_token_string(c), "null?") == 0);
assert(cy_lex(c) == TOK_SYMBOL);
assert(strcmp(cy_token_string(c), "+") == 0);
assert(org_cherry_lex(c) == TOK_SYMBOL);
assert(strcmp(org_cherry_token_string(c), "+") == 0);
assert(cy_lex(c) == TOK_SYMBOL);
assert(strcmp(cy_token_string(c), "-") == 0);
assert(org_cherry_lex(c) == TOK_SYMBOL);
assert(strcmp(org_cherry_token_string(c), "-") == 0);
cy_context_free(c);
org_cherry_context_free(c);
}
static void test_lex_characters(const_pointer data)
{
byte_t* str = " \\a \\A \\uFFFF \\newline \\space ";
struct CyContext* c = cy_context_repl_new(str);
struct org_cherry_context* c = org_cherry_context_repl(str);
assert(cy_lex(c) == TOK_CHAR);
assert(strcmp(cy_token_string(c), "\\a") == 0);
assert(org_cherry_lex(c) == TOK_CHAR);
assert(strcmp(org_cherry_token_string(c), "\\a") == 0);
assert(cy_lex(c) == TOK_CHAR);
assert(strcmp(cy_token_string(c), "\\A") == 0);
assert(org_cherry_lex(c) == TOK_CHAR);
assert(strcmp(org_cherry_token_string(c), "\\A") == 0);
assert(cy_lex(c) == TOK_CHAR);
assert(strcmp(cy_token_string(c), "\\uFFFF") == 0);
assert(org_cherry_lex(c) == TOK_CHAR);
assert(strcmp(org_cherry_token_string(c), "\\uFFFF") == 0);
assert(cy_lex(c) == TOK_CHAR);
assert(strcmp(cy_token_string(c), "\\newline") == 0);
assert(org_cherry_lex(c) == TOK_CHAR);
assert(strcmp(org_cherry_token_string(c), "\\newline") == 0);
assert(cy_lex(c) == TOK_CHAR);
assert(strcmp(cy_token_string(c), "\\space") == 0);
assert(org_cherry_lex(c) == TOK_CHAR);
assert(strcmp(org_cherry_token_string(c), "\\space") == 0);
cy_context_free(c);
org_cherry_context_free(c);
}
static void test_lex_core(const_pointer data)
{
byte_t* str = " [ ] ( ) . ' ";
struct CyContext* c = cy_context_repl_new(str);
struct org_cherry_context* c = org_cherry_context_repl(str);
assert(cy_lex(c) == TOK_SQUARELEFTBRACE);
assert(cy_lex(c) == TOK_SQUARERIGHTBRACE);
assert(cy_lex(c) == TOK_ROUNDLEFTBRACE);
assert(cy_lex(c) == TOK_ROUNDRIGHTBRACE);
assert(cy_lex(c) == TOK_DOT);
assert(cy_lex(c) == TOK_QUOTE);
assert(cy_lex(c) == TOK_EOF);
assert(org_cherry_lex(c) == TOK_SQUARELEFTBRACE);
assert(org_cherry_lex(c) == TOK_SQUARERIGHTBRACE);
assert(org_cherry_lex(c) == TOK_ROUNDLEFTBRACE);
assert(org_cherry_lex(c) == TOK_ROUNDRIGHTBRACE);
assert(org_cherry_lex(c) == TOK_DOT);
assert(org_cherry_lex(c) == TOK_QUOTE);
assert(org_cherry_lex(c) == TOK_EOF);
cy_context_free(c);
org_cherry_context_free(c);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment