renamed prog to begin and added basics for the manual
This commit is contained in:
+3
-3
@@ -113,9 +113,9 @@ proc load_built_ins_into_environment(Environment* env) -> void {
|
||||
}
|
||||
|
||||
// we are now in the function body, just wrap it in an
|
||||
// implicit prog
|
||||
// implicit begin
|
||||
try ret->value.function.body = Memory::create_lisp_object_pair(
|
||||
Memory::get_or_create_lisp_object_symbol("prog"),
|
||||
Memory::get_or_create_lisp_object_symbol("begin"),
|
||||
arguments);
|
||||
|
||||
|
||||
@@ -617,7 +617,7 @@ proc load_built_ins_into_environment(Environment* env) -> void {
|
||||
});
|
||||
|
||||
|
||||
defun("prog", cLambda {
|
||||
defun("begin", cLambda {
|
||||
try evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
||||
|
||||
if (evaluated_arguments == Memory::nil)
|
||||
|
||||
+50
-12
@@ -152,7 +152,7 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
}
|
||||
|
||||
/*
|
||||
(prog
|
||||
(begin
|
||||
(define type--before type)
|
||||
(define type
|
||||
(lambda (e)
|
||||
@@ -436,11 +436,23 @@ proc interprete_file (char* file_name) -> Lisp_Object* {
|
||||
try user_env = Memory::create_child_environment(root_env);
|
||||
Parser::environment_for_macros = user_env;
|
||||
|
||||
// char* file_content;
|
||||
// try file_content = read_entire_file(file_name);
|
||||
// save the current working directory
|
||||
char cwd[1024];
|
||||
getcwd(cwd, 1024);
|
||||
|
||||
// get the direction of the exe
|
||||
char* exe_path = exe_dir();
|
||||
|
||||
// switch to the exe directory for loading pre.slime
|
||||
chdir(exe_path);
|
||||
free(exe_path);
|
||||
|
||||
built_in_import(Memory::create_string("pre.slime"), user_env);
|
||||
|
||||
|
||||
// switch back to the users directory
|
||||
chdir(cwd);
|
||||
|
||||
Lisp_Object* result;
|
||||
result = built_in_load(Memory::create_string(file_name), user_env);
|
||||
|
||||
@@ -450,10 +462,11 @@ proc interprete_file (char* file_name) -> Lisp_Object* {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
print(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
proc interprete_stdin() -> void {
|
||||
proc interprete_stdin(bool is_emacs_repl = false) -> void {
|
||||
Memory::init(4096 * 256, 1024, 4096 * 256);
|
||||
Environment* root_env = Globals::root_environment;
|
||||
Environment* user_env = Memory::create_child_environment(root_env);
|
||||
@@ -463,14 +476,29 @@ proc interprete_stdin() -> void {
|
||||
return;
|
||||
}
|
||||
|
||||
// save the current working directory
|
||||
char cwd[1024];
|
||||
getcwd(cwd, 1024);
|
||||
|
||||
// get the direction of the exe
|
||||
char* exe_path = exe_dir();
|
||||
|
||||
// switch to the exe directory for loading pre.slime
|
||||
chdir(exe_path);
|
||||
free(exe_path);
|
||||
|
||||
built_in_import(Memory::create_string("pre.slime"), user_env);
|
||||
|
||||
|
||||
// switch back to the users directory
|
||||
chdir(cwd);
|
||||
|
||||
Parser::environment_for_macros = user_env;
|
||||
|
||||
printf("Welcome to the lispy interpreter.\n");
|
||||
|
||||
char* line;
|
||||
|
||||
built_in_import(Memory::create_string("pre.slime"), user_env);
|
||||
|
||||
if (Globals::error) {
|
||||
log_error();
|
||||
delete_error();
|
||||
@@ -478,7 +506,7 @@ proc interprete_stdin() -> void {
|
||||
|
||||
Lisp_Object* parsed, * evaluated;
|
||||
while (true) {
|
||||
printf(">");
|
||||
printf("> ");
|
||||
line = read_expression();
|
||||
defer {
|
||||
free(line);
|
||||
@@ -490,12 +518,22 @@ proc interprete_stdin() -> void {
|
||||
continue;
|
||||
}
|
||||
evaluated = eval_expr(parsed, user_env);
|
||||
if (Globals::error) {
|
||||
log_error();
|
||||
delete_error();
|
||||
continue;
|
||||
if (is_emacs_repl) {
|
||||
if (Globals::error) {
|
||||
printf("((error \"%s\"))", &Globals::error->message->data);
|
||||
} else {
|
||||
printf("((result \"");
|
||||
print(evaluated);
|
||||
printf("\"))");
|
||||
}
|
||||
} else {
|
||||
if (Globals::error) {
|
||||
log_error();
|
||||
delete_error();
|
||||
continue;
|
||||
}
|
||||
print(evaluated);
|
||||
}
|
||||
print(evaluated);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Memory {
|
||||
|
||||
namespace Parser {
|
||||
extern String* standard_in;
|
||||
extern String* parser_file;
|
||||
extern int parser_line;
|
||||
extern int parser_col;
|
||||
}
|
||||
|
||||
namespace Globals {
|
||||
|
||||
+72
-3
@@ -63,15 +63,22 @@ proc unescape_string(char* in) -> bool {
|
||||
case 'x':
|
||||
case 'X':
|
||||
if (!isxdigit(p[1]) || !isxdigit(p[2])) {
|
||||
int_err = "Invalid character on hexadecimal escape.";
|
||||
create_parsing_error(
|
||||
"The string '%s' at %s:%d:%d could not be unescaped. "
|
||||
"(Invalid character on hexadecimal escape at char %d)",
|
||||
in, Parser::parser_file, Parser::parser_line, Parser::parser_col,
|
||||
(p+1)-in);
|
||||
} else {
|
||||
*out++ = (char)(get_nibble(p[1]) * 0x10 + get_nibble(p[2]));
|
||||
p += 3;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
int_err = "Unexpected '\\' with no escape sequence.";
|
||||
break;
|
||||
create_parsing_error(
|
||||
"The string '%s' at %s:%d:%d could not be unescaped. "
|
||||
"(Unexpected '\\' with no escape sequence at char %d)",
|
||||
in, Parser::parser_file, Parser::parser_line, Parser::parser_col,
|
||||
(p+1)-in);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,3 +316,65 @@ proc log_error() -> void {
|
||||
print_error_location();
|
||||
puts(console_normal);
|
||||
}
|
||||
|
||||
char* exe_dir() {
|
||||
size_t size = 512, i, n;
|
||||
char *path, *temp;
|
||||
|
||||
while (1) {
|
||||
ssize_t used;
|
||||
|
||||
path = (char*)malloc(size);
|
||||
if (!path) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
used = readlink("/proc/self/exe", path, size);
|
||||
|
||||
if (used == -1) {
|
||||
const int saved_errno = errno;
|
||||
free(path);
|
||||
errno = saved_errno;
|
||||
return NULL;
|
||||
} else
|
||||
if (used < 1) {
|
||||
free(path);
|
||||
errno = EIO;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((size_t)used >= size) {
|
||||
free(path);
|
||||
size = (size | 2047) + 2049;
|
||||
continue;
|
||||
}
|
||||
|
||||
size = (size_t)used;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find final slash. */
|
||||
n = 0;
|
||||
for (i = 0; i < size; i++)
|
||||
if (path[i] == '/')
|
||||
n = i;
|
||||
|
||||
/* Optimize allocated size,
|
||||
ensuring there is room for
|
||||
a final slash and a
|
||||
string-terminating '\0', */
|
||||
temp = path;
|
||||
path = (char*)realloc(temp, n + 2);
|
||||
if (!path) {
|
||||
free(temp);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* and properly trim and terminate the path string. */
|
||||
path[n+0] = '/';
|
||||
path[n+1] = '\0';
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "slime.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
if (argc > 1) {
|
||||
if (Slime::string_equal(argv[1], "--run-tests")) {
|
||||
return Slime::run_all_tests() ? 0 : 1;
|
||||
} else if (Slime::string_equal(argv[1], "--run-as-emacs-repl")) {
|
||||
Slime::interprete_stdin(true);
|
||||
}
|
||||
|
||||
Slime::interprete_file(argv[1]);
|
||||
|
||||
+14
-10
@@ -161,21 +161,25 @@ namespace Parser {
|
||||
|
||||
// okay so the first letter was not actually closing the string...
|
||||
int string_length = 0;
|
||||
while (text[*index_in_text+string_length] != '"' ||
|
||||
text[*index_in_text+string_length] == '\\')
|
||||
bool escaping = false;
|
||||
while (!(text[*index_in_text+string_length] == '"' && !escaping))
|
||||
{
|
||||
if (escaping)
|
||||
escaping = false;
|
||||
else
|
||||
if (text[*index_in_text+string_length] == '\\')
|
||||
escaping = true;
|
||||
|
||||
++string_length;
|
||||
}
|
||||
|
||||
// we found the end of the string
|
||||
text[*index_in_text+string_length] = '\0';
|
||||
|
||||
if (!unescape_string(text+(*index_in_text))) {
|
||||
create_parsing_error(
|
||||
"The string '%s' at %s:%d:%d could not be unescaped.",
|
||||
text+(*index_in_text), parser_file, parser_line, parser_col);
|
||||
return nullptr;
|
||||
}
|
||||
// NOTE(Felix): Tactic: Through unescaping the string will
|
||||
// only get shorter, so we replace it inplace and later jump
|
||||
// to the original end of the string.
|
||||
try unescape_string(text+(*index_in_text));
|
||||
|
||||
String* string = Memory::create_string("", string_length);
|
||||
|
||||
@@ -415,9 +419,9 @@ namespace Parser {
|
||||
}
|
||||
|
||||
// we are now in the function body, just wrap it in an
|
||||
// implicit prog
|
||||
// implicit begin
|
||||
try macro->value.function.body = Memory::create_lisp_object_pair(
|
||||
Memory::get_or_create_lisp_object_symbol("prog"),
|
||||
Memory::get_or_create_lisp_object_symbol("begin"),
|
||||
body);
|
||||
|
||||
// macro->value.function = function;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ struct Function {
|
||||
Keyword_Arguments* keyword_arguments;
|
||||
// rest_argument will be nullptr if no rest argument is declared
|
||||
String* rest_argument;
|
||||
Lisp_Object* body; // implicit prog
|
||||
Lisp_Object* body; // implicit begin
|
||||
Environment* parent_environment; // we are doing closures now!!
|
||||
};
|
||||
|
||||
|
||||
+11
-4
@@ -493,7 +493,7 @@ proc test_built_in_type() -> testresult {
|
||||
try env = Memory::create_built_ins_environment();
|
||||
|
||||
// normal type testing
|
||||
char exp_string1[] = "(prog (define a 10)(type a))";
|
||||
char exp_string1[] = "(begin (define a 10)(type a))";
|
||||
Lisp_Object* expression = Parser::parse_single_expression(exp_string1);
|
||||
Lisp_Object* result = eval_expr(expression, env);
|
||||
|
||||
@@ -503,7 +503,7 @@ proc test_built_in_type() -> testresult {
|
||||
assert_equal_string(result->value.symbol.identifier, "number");
|
||||
|
||||
// setting user type
|
||||
char exp_string2[] = "(prog (set-type a :my-type)(type a))";
|
||||
char exp_string2[] = "(begin (set-type a :my-type)(type a))";
|
||||
expression = Parser::parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression, env);
|
||||
|
||||
@@ -513,7 +513,7 @@ proc test_built_in_type() -> testresult {
|
||||
assert_equal_string(result->value.symbol.identifier, "my-type");
|
||||
|
||||
// trying to set invalid user type
|
||||
char exp_string3[] = "(prog (set-type a \"wrong tpye\")(type a))";
|
||||
char exp_string3[] = "(begin (set-type a \"wrong tpye\")(type a))";
|
||||
expression = Parser::parse_single_expression(exp_string3);
|
||||
|
||||
without_logging {
|
||||
@@ -524,7 +524,7 @@ proc test_built_in_type() -> testresult {
|
||||
delete_error();
|
||||
|
||||
// deleting user type
|
||||
char exp_string4[] = "(prog (delete-type a)(type a))";
|
||||
char exp_string4[] = "(begin (delete-type a)(type a))";
|
||||
expression = Parser::parse_single_expression(exp_string4);
|
||||
result = eval_expr(expression, env);
|
||||
|
||||
@@ -598,6 +598,13 @@ proc run_all_tests() -> bool {
|
||||
Memory::init(4096 * 2000, 1024, 4096 * 16);
|
||||
Parser::environment_for_macros = Globals::root_environment;
|
||||
|
||||
// get the direction of the exe
|
||||
char* exe_path = exe_dir();
|
||||
|
||||
// switch to the exe directory for loading pre.slime
|
||||
chdir(exe_path);
|
||||
free(exe_path);
|
||||
|
||||
bool result = true;
|
||||
|
||||
printf("-- Util --\n");
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
proc visualize_lisp_machine() -> void {
|
||||
|
||||
// save the current working directory
|
||||
char cwd[1024];
|
||||
getcwd(cwd, 1024);
|
||||
// get the direction of the exe
|
||||
char* exe_path = exe_dir();
|
||||
// switch to the exe directory for loading pre.slime
|
||||
chdir(exe_path);
|
||||
free(exe_path);
|
||||
|
||||
defer {
|
||||
// switch back to the users directory
|
||||
chdir(cwd);
|
||||
};
|
||||
|
||||
struct Drawn_Area {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
Reference in New Issue
Block a user