added tuples and multiple return values
This commit is contained in:
+28
-58
@@ -37,10 +37,8 @@ fun parse(str) {
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if ended(ctx): {
|
||||
print('Source only contains whitespace');
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, 'Source only contains whitespace';
|
||||
|
||||
return parseAny(ctx);
|
||||
}
|
||||
@@ -53,10 +51,8 @@ fun parseArray(ctx) {
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source ended inside an array");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source ended inside an array";
|
||||
|
||||
arr = [];
|
||||
|
||||
@@ -76,27 +72,21 @@ fun parseArray(ctx) {
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source ended inside an array");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source ended inside an array";
|
||||
|
||||
if current(ctx) == ']':
|
||||
break;
|
||||
|
||||
if current(ctx) != ',': {
|
||||
error("Bad character inside array");
|
||||
return none;
|
||||
}
|
||||
if current(ctx) != ',':
|
||||
return none, "Bad character inside array";
|
||||
|
||||
next(ctx); # Skip ','.
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source ended inside an array");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source ended inside an array";
|
||||
}
|
||||
|
||||
next(ctx);
|
||||
@@ -111,10 +101,8 @@ fun parseObject(ctx) {
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source ended inside an object");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source ended inside an object";
|
||||
|
||||
obj = {};
|
||||
|
||||
@@ -125,10 +113,8 @@ fun parseObject(ctx) {
|
||||
|
||||
while true: {
|
||||
|
||||
if current(ctx) != '"': {
|
||||
error("Bad character where a string was expected");
|
||||
return none;
|
||||
}
|
||||
if current(ctx) != '"':
|
||||
return none, "Bad character where a string was expected";
|
||||
|
||||
key = parseString(ctx);
|
||||
|
||||
@@ -137,10 +123,8 @@ fun parseObject(ctx) {
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if current(ctx) != ':': {
|
||||
error("Bad character where ':' was expected");
|
||||
return none;
|
||||
}
|
||||
if current(ctx) != ':':
|
||||
return none, "Bad character where ':' was expected";
|
||||
|
||||
next(ctx); # Skip ':'.
|
||||
|
||||
@@ -155,27 +139,21 @@ fun parseObject(ctx) {
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source ended inside an arrays");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source ended inside an arrays";
|
||||
|
||||
if current(ctx) == '}':
|
||||
break;
|
||||
|
||||
if current(ctx) != ',': {
|
||||
error("Bad character inside array");
|
||||
return none;
|
||||
}
|
||||
if current(ctx) != ',':
|
||||
return none, "Bad character inside array";
|
||||
|
||||
next(ctx); # Skip ','.
|
||||
|
||||
skip(ctx, isSpace);
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source ended inside an array");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source ended inside an array";
|
||||
}
|
||||
|
||||
next(ctx);
|
||||
@@ -198,10 +176,8 @@ fun parseString(ctx) {
|
||||
next(ctx);
|
||||
}
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source ended inside a string");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source ended inside a string";
|
||||
|
||||
next(ctx); # Skip the '"'.
|
||||
return buff;
|
||||
@@ -228,15 +204,11 @@ fun parseNumber(ctx) {
|
||||
|
||||
next(ctx);
|
||||
|
||||
if ended(ctx): {
|
||||
error("Source string ended unexpectedly after dot");
|
||||
return none;
|
||||
}
|
||||
if ended(ctx):
|
||||
return none, "Source string ended unexpectedly after dot";
|
||||
|
||||
if not isDigit(current(ctx)): {
|
||||
error("Got something other than a digit after dot");
|
||||
return none;
|
||||
}
|
||||
if not isDigit(current(ctx)):
|
||||
return none, "Got something other than a digit after dot";
|
||||
|
||||
fact = 1;
|
||||
while not ended(ctx): {
|
||||
@@ -253,8 +225,6 @@ fun parseNumber(ctx) {
|
||||
|
||||
fun parseAny(ctx) {
|
||||
|
||||
print('Parsing value\n');
|
||||
|
||||
assert(not ended(ctx));
|
||||
|
||||
if current(ctx) == '[':
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
print('Start\n');
|
||||
|
||||
i = 0;
|
||||
n = 1000;
|
||||
n = 10000000;
|
||||
|
||||
while i < n: {
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
fun hello()
|
||||
return 1, "hello";
|
||||
|
||||
a, b = hello();
|
||||
|
||||
print('a = ', a, '\n');
|
||||
print('b = ', b, '\n');
|
||||
+120
-44
@@ -37,24 +37,32 @@
|
||||
#include "math.h"
|
||||
#include "../utils/utf8.h"
|
||||
|
||||
static Object *bin_print(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_print(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
(void) runtime;
|
||||
(void) rets;
|
||||
(void) maxretc;
|
||||
(void) error;
|
||||
|
||||
for(int i = 0; i < (int) argc; i += 1)
|
||||
Object_Print(argv[i], stdout);
|
||||
|
||||
return Object_NewNone(Runtime_GetHeap(runtime), error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Object *bin_type(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_type(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
assert(argc == 1);
|
||||
(void) runtime;
|
||||
(void) error;
|
||||
return (Object*) argv[0]->type;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = (Object*) argv[0]->type;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
(void) runtime;
|
||||
(void) error;
|
||||
@@ -66,29 +74,37 @@ static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, E
|
||||
if(!Object_IsString(argv[0]))
|
||||
{
|
||||
Error_Report(error, 0, "Argument #%d is not a string", 1);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *string;
|
||||
int n;
|
||||
string = Object_ToString(argv[0],&n,Runtime_GetHeap(runtime),error);
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
if(n == 0)
|
||||
{
|
||||
Error_Report(error, 0, "Argument #%d is an empty string", 1);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int k = utf8_sequence_to_utf32_codepoint(string,n,&ret);
|
||||
assert(k >= 0);
|
||||
|
||||
return Object_FromInt(ret,Runtime_GetHeap(runtime),error);
|
||||
|
||||
Object *temp = Object_FromInt(ret,Runtime_GetHeap(runtime),error);
|
||||
|
||||
if(temp == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = temp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
|
||||
assert(argc == 1);
|
||||
@@ -97,7 +113,7 @@ static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error
|
||||
if(!Object_IsInt(argv[0]))
|
||||
{
|
||||
Error_Report(error, 0, "Argument #%d is not an integer", 1);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +122,7 @@ static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error
|
||||
int value = Object_ToInt(argv[0],error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
|
||||
int k = utf8_sequence_from_utf32_codepoint(buff,sizeof(buff),value);
|
||||
@@ -114,25 +130,41 @@ static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error
|
||||
if(k<0)
|
||||
{
|
||||
Error_Report(error, 0, "Argument #%d is not valid utf-32", 1);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Object_FromString(buff,k,Runtime_GetHeap(runtime),error);
|
||||
Object *temp = Object_FromString(buff,k,Runtime_GetHeap(runtime),error);
|
||||
|
||||
if(temp == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = temp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Object *bin_count(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_count(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
assert(argc == 1);
|
||||
|
||||
int n = Object_Count(argv[0], error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
return Object_FromInt(n, Runtime_GetHeap(runtime), error);
|
||||
Object *temp = Object_FromInt(n, Runtime_GetHeap(runtime), error);
|
||||
|
||||
if(temp == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = temp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_input(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
(void) argv;
|
||||
|
||||
@@ -158,7 +190,7 @@ static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Err
|
||||
{
|
||||
if(str != maybe) free(str);
|
||||
Error_Report(error, 1, "No memory");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
str = tmp;
|
||||
@@ -175,23 +207,36 @@ static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Err
|
||||
if(str != maybe)
|
||||
free(str);
|
||||
|
||||
return res;
|
||||
if(res == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = res;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
(void) runtime;
|
||||
(void) rets;
|
||||
(void) maxretc;
|
||||
|
||||
for(unsigned int i = 0; i < argc; i += 1)
|
||||
if(!Object_ToBool(argv[i], error))
|
||||
{
|
||||
if(!error->occurred)
|
||||
Error_Report(error, 0, "Assertion failed");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
return Object_NewNone(Runtime_GetHeap(runtime), error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Object *bin_error(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_error(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
(void) rets;
|
||||
(void) maxretc;
|
||||
|
||||
assert(argc == 1);
|
||||
|
||||
int length;
|
||||
@@ -200,13 +245,13 @@ static Object *bin_error(Runtime *runtime, Object **argv, unsigned int argc, Err
|
||||
string = Object_ToString(argv[0], &length, Runtime_GetHeap(runtime), error);
|
||||
|
||||
if(string == NULL)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
Error_Report(error, 0, "%s", string);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
unsigned int total_count = 0;
|
||||
|
||||
@@ -215,13 +260,13 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
|
||||
if(!Object_IsString(argv[i]))
|
||||
{
|
||||
Error_Report(error, 0, "Argument #%d is not a string", i+1);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
total_count += Object_Count(argv[i], error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char starting[128];
|
||||
@@ -234,7 +279,7 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
|
||||
if(buffer == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "No memory");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,35 +305,58 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
|
||||
done:
|
||||
if(starting != buffer)
|
||||
free(buffer);
|
||||
return result;
|
||||
|
||||
if(result == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Object *bin_newBuffer(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_newBuffer(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
assert(argc == 1);
|
||||
|
||||
long long int size = Object_ToInt(argv[0], error);
|
||||
|
||||
if(error->occurred == 1)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
return Object_NewBuffer(size, Runtime_GetHeap(runtime), error);
|
||||
Object *temp = Object_NewBuffer(size, Runtime_GetHeap(runtime), error);
|
||||
|
||||
if(temp == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = temp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Object *bin_sliceBuffer(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_sliceBuffer(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
assert(argc == 3);
|
||||
|
||||
long long int offset = Object_ToInt(argv[1], error);
|
||||
if(error->occurred == 1) return NULL;
|
||||
if(error->occurred == 1) return -1;
|
||||
|
||||
long long int length = Object_ToInt(argv[2], error);
|
||||
if(error->occurred == 1) return NULL;
|
||||
if(error->occurred == 1) return -1;
|
||||
|
||||
return Object_SliceBuffer(argv[0], offset, length, Runtime_GetHeap(runtime), error);
|
||||
Object *temp = Object_SliceBuffer(argv[0], offset, length, Runtime_GetHeap(runtime), error);
|
||||
|
||||
if(temp == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = temp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static Object *bin_bufferToString(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
static int bin_bufferToString(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
assert(argc == 1);
|
||||
|
||||
@@ -298,14 +366,22 @@ static Object *bin_bufferToString(Runtime *runtime, Object **argv, unsigned int
|
||||
buffaddr = Object_GetBufferAddrAndSize(argv[0], &buffsize, error);
|
||||
|
||||
if(error->occurred)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
return Object_FromString(buffaddr, buffsize, Runtime_GetHeap(runtime), error);
|
||||
Object *temp = Object_FromString(buffaddr, buffsize, Runtime_GetHeap(runtime), error);
|
||||
|
||||
if(temp == NULL)
|
||||
return -1;
|
||||
|
||||
if(maxretc == 0)
|
||||
return 0;
|
||||
rets[0] = temp;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const StaticMapSlot bins_basic[] = {
|
||||
{ "math", SM_SMAP, .as_smap = bins_math, },
|
||||
{ "files", SM_SMAP, .as_smap = bins_files, },
|
||||
// { "files", SM_SMAP, .as_smap = bins_files, },
|
||||
// { "net", SM_SMAP, .as_smap = bins_net, },
|
||||
|
||||
{ "newBuffer", SM_FUNCT, .as_funct = bin_newBuffer, .argc = 1 },
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
|
||||
** +--------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#warning "Commented out whole file"
|
||||
/*
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include "files.h"
|
||||
@@ -305,4 +306,5 @@ const StaticMapSlot bins_files[] = {
|
||||
{ "read", SM_FUNCT, .as_funct = bin_read, .argc = 3, },
|
||||
{ "write", SM_FUNCT, .as_funct = bin_write, .argc = 3, },
|
||||
{ NULL, SM_END, {}, {} },
|
||||
};
|
||||
};
|
||||
*/
|
||||
+21
-10
@@ -33,7 +33,7 @@
|
||||
#include "math.h"
|
||||
|
||||
#define WRAP_FUNC(name) \
|
||||
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
|
||||
static int bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error) \
|
||||
{ \
|
||||
assert(argc == 1); \
|
||||
\
|
||||
@@ -42,45 +42,56 @@
|
||||
double v = Object_ToFloat(argv[0], error); \
|
||||
\
|
||||
if(error->occurred) \
|
||||
return NULL; \
|
||||
return -1; \
|
||||
\
|
||||
return Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \
|
||||
if(maxretc > 0) \
|
||||
{ \
|
||||
rets[0] = Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \
|
||||
if(rets[0] == NULL) \
|
||||
return -1; \
|
||||
return 1; \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
|
||||
return NULL; \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define WRAP_FUNC_2(name) \
|
||||
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
|
||||
static int bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error) \
|
||||
{ \
|
||||
assert(argc == 2); \
|
||||
\
|
||||
if(!Object_IsFloat(argv[0])) \
|
||||
{ \
|
||||
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
|
||||
return NULL; \
|
||||
return -1; \
|
||||
} \
|
||||
\
|
||||
if(!Object_IsFloat(argv[1])) \
|
||||
{ \
|
||||
Error_Report(error, 0, "Expected second argument to be a float, but it's a %s", Object_GetName(argv[1]));\
|
||||
return NULL; \
|
||||
return -1; \
|
||||
} \
|
||||
\
|
||||
double v1 = Object_ToFloat(argv[0], error); \
|
||||
\
|
||||
if(error->occurred) \
|
||||
return NULL; \
|
||||
return -1; \
|
||||
\
|
||||
double v2 = Object_ToFloat(argv[1], error); \
|
||||
\
|
||||
if(error->occurred) \
|
||||
return NULL; \
|
||||
return -1; \
|
||||
\
|
||||
return Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \
|
||||
Object *res = Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \
|
||||
if(res == NULL) return -1; \
|
||||
if(maxretc == 0) return 0; \
|
||||
rets[0] = res; \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
WRAP_FUNC(ceil)
|
||||
|
||||
@@ -90,7 +90,7 @@ static const InstrInfo instr_table[] = {
|
||||
|
||||
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
|
||||
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_CALL] = {"CALL", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_CALL] = {"CALL", 2, (OperandType[]) {OPTP_INT, OPTP_INT}},
|
||||
[OPCODE_SELECT] = {"SELECT", 0, NULL},
|
||||
[OPCODE_INSERT] = {"INSERT", 0, NULL},
|
||||
[OPCODE_INSERT2] = {"INSERT2", 0, NULL},
|
||||
@@ -105,7 +105,7 @@ static const InstrInfo instr_table[] = {
|
||||
[OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_PUSHMAP] = {"PUSHMAP", 1, (OperandType[]) {OPTP_INT}},
|
||||
|
||||
[OPCODE_RETURN] = {"RETURN", 0, NULL},
|
||||
[OPCODE_RETURN] = {"RETURN", 1, (OperandType[]) {OPTP_INT}},
|
||||
|
||||
[OPCODE_JUMPIFNOTANDPOP] = {"JUMPIFNOTANDPOP", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_JUMPIFANDPOP] = {"JUMPIFANDPOP", 1, (OperandType[]) {OPTP_INT}},
|
||||
@@ -299,7 +299,7 @@ Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error)
|
||||
|
||||
if(exeb->promc > 0)
|
||||
{
|
||||
Error_Report(error, 0, "There are still %d unfulfilled promises", exeb->promc);
|
||||
Error_Report(error, 1, "There are still %d unfulfilled promises", exeb->promc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
|
||||
if(opc != info->opcount)
|
||||
{
|
||||
// ERROR: Too many operands were provided.
|
||||
Error_Report(error, 0,
|
||||
Error_Report(error, 1,
|
||||
"Instruction %s expects %d operands, but %d were provided",
|
||||
info->name, info->opcount, opc);
|
||||
return 0;
|
||||
@@ -409,13 +409,13 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
|
||||
|
||||
if(expected_type == OPTP_STRING)
|
||||
{
|
||||
Error_Report(error, 0, "Promise values can't be provided as string operands");
|
||||
Error_Report(error, 1, "Promise values can't be provided as string operands");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(Promise_Size(opv[i].as_promise) != operand_type_sizes[expected_type])
|
||||
{
|
||||
Error_Report(error, 0,
|
||||
Error_Report(error, 1,
|
||||
"Provided promise has a value size of %d, "
|
||||
"but since %s %s was expected, the promise "
|
||||
"size must be %d",
|
||||
@@ -429,7 +429,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
|
||||
else if(expected_type != provided_type)
|
||||
{
|
||||
// ERROR: Wrong operand type provided.
|
||||
Error_Report(error, 0,
|
||||
Error_Report(error, 1,
|
||||
"Instruction %s expects %s %s as operand %d, but %s %s was provided instead",
|
||||
info->name,
|
||||
operand_type_arts[expected_type],
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef enum {
|
||||
EXPR_INT,
|
||||
EXPR_MAP,
|
||||
EXPR_CALL,
|
||||
EXPR_PAIR,
|
||||
EXPR_LIST,
|
||||
EXPR_NONE,
|
||||
EXPR_TRUE,
|
||||
|
||||
+120
-45
@@ -50,6 +50,8 @@
|
||||
#include "compile.h"
|
||||
#include "ASTi.h"
|
||||
|
||||
static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_dest, Error *error);
|
||||
|
||||
static Opcode exprkind_to_opcode(ExprKind kind)
|
||||
{
|
||||
switch(kind)
|
||||
@@ -75,6 +77,43 @@ static Opcode exprkind_to_opcode(ExprKind kind)
|
||||
}
|
||||
}
|
||||
|
||||
static _Bool emit_instr_for_funccall(ExeBuilder *exeb, CallExprNode *expr, Promise *break_dest, int returns, Error *error)
|
||||
{
|
||||
Node *arg = expr->argv;
|
||||
|
||||
while(arg)
|
||||
{
|
||||
if(!emit_instr_for_node(exeb, arg, break_dest, error))
|
||||
return 0;
|
||||
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
if(!emit_instr_for_node(exeb, expr->func, break_dest, error))
|
||||
return 0;
|
||||
|
||||
Operand ops[2];
|
||||
ops[0] = (Operand) { .type = OPTP_INT, .as_int = expr->argc };
|
||||
ops[1] = (Operand) { .type = OPTP_INT, .as_int = returns };
|
||||
return ExeBuilder_Append(exeb, error, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length);
|
||||
}
|
||||
|
||||
static _Bool flatten_tuple_tree(ExprNode *root, ExprNode **tuple, int max, int *count, Error *error)
|
||||
{
|
||||
if(root->kind == EXPR_PAIR)
|
||||
return flatten_tuple_tree((ExprNode*) ((OperExprNode*) root)->head, tuple, max, count, error) &&
|
||||
flatten_tuple_tree((ExprNode*) ((OperExprNode*) root)->head->next, tuple, max, count, error);
|
||||
|
||||
if(max == *count)
|
||||
{
|
||||
Error_Report(error, 0, "Static buffer is too small");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tuple[(*count)++] = root;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_dest, Error *error)
|
||||
{
|
||||
assert(node != NULL);
|
||||
@@ -86,6 +125,10 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
|
||||
ExprNode *expr = (ExprNode*) node;
|
||||
switch(expr->kind)
|
||||
{
|
||||
case EXPR_PAIR:
|
||||
Error_Report(error, 0, "Tuple outside of assignment or return statement");
|
||||
return 0;
|
||||
|
||||
case EXPR_NOT:
|
||||
case EXPR_POS:
|
||||
case EXPR_NEG:
|
||||
@@ -123,35 +166,75 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
|
||||
lop = oper->head;
|
||||
rop = lop->next;
|
||||
|
||||
if(!emit_instr_for_node(exeb, rop, break_dest, error))
|
||||
ExprNode *tuple[32];
|
||||
int count = 0;
|
||||
|
||||
if(!flatten_tuple_tree((ExprNode*) lop, tuple, sizeof(tuple)/sizeof(tuple[0]), &count, error))
|
||||
return 0;
|
||||
|
||||
if(((ExprNode*) lop)->kind == EXPR_IDENT)
|
||||
assert(count > 0);
|
||||
|
||||
if(count == 1) /* No tuple. */
|
||||
{
|
||||
const char *name = ((IdentExprNode*) lop)->val;
|
||||
|
||||
Operand op = { .type = OPTP_STRING, .as_string = name };
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length))
|
||||
return 0;
|
||||
}
|
||||
else if(((ExprNode*) lop)->kind == EXPR_SELECT)
|
||||
{
|
||||
Node *idx = ((IndexSelectionExprNode*) lop)->idx;
|
||||
Node *set = ((IndexSelectionExprNode*) lop)->set;
|
||||
|
||||
if(!emit_instr_for_node(exeb, set, break_dest, error))
|
||||
return 0;
|
||||
|
||||
if(!emit_instr_for_node(exeb, idx, break_dest, error))
|
||||
return 0;
|
||||
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length))
|
||||
if(!emit_instr_for_node(exeb, rop, break_dest, error))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error_Report(error, 0, "Assignment left operand can't be assigned to");
|
||||
return 0;
|
||||
if(((ExprNode*) rop)->kind == EXPR_CALL)
|
||||
{
|
||||
if(!emit_instr_for_funccall(exeb, (CallExprNode*) rop, break_dest, count, error))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error_Report(error, 0, "Assigning to %d variables only 1 value", count);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < count; i += 1)
|
||||
{
|
||||
ExprNode *tuple_item = tuple[count-i-1];
|
||||
switch(tuple_item->kind)
|
||||
{
|
||||
case EXPR_IDENT:
|
||||
{
|
||||
const char *name = ((IdentExprNode*) tuple_item)->val;
|
||||
|
||||
Operand op = { .type = OPTP_STRING, .as_string = name };
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, tuple_item->base.offset, tuple_item->base.length))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case EXPR_SELECT:
|
||||
{
|
||||
Node *idx = ((IndexSelectionExprNode*) tuple_item)->idx;
|
||||
Node *set = ((IndexSelectionExprNode*) tuple_item)->set;
|
||||
|
||||
if(!emit_instr_for_node(exeb, set, break_dest, error))
|
||||
return 0;
|
||||
|
||||
if(!emit_instr_for_node(exeb, idx, break_dest, error))
|
||||
return 0;
|
||||
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, tuple_item->base.offset, tuple_item->base.length))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Error_Report(error, 0, "Assigning to something that it can't be assigned to");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(i+1 < count)
|
||||
{
|
||||
Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 };
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, node->offset, 0))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -253,25 +336,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
|
||||
}
|
||||
|
||||
case EXPR_CALL:
|
||||
{
|
||||
CallExprNode *p = (CallExprNode*) expr;
|
||||
|
||||
Node *arg = p->argv;
|
||||
|
||||
while(arg)
|
||||
{
|
||||
if(!emit_instr_for_node(exeb, arg, break_dest, error))
|
||||
return 0;
|
||||
|
||||
arg = arg->next;
|
||||
}
|
||||
|
||||
if(!emit_instr_for_node(exeb, p->func, break_dest, error))
|
||||
return 0;
|
||||
|
||||
Operand op = { .type = OPTP_INT, .as_int = p->argc };
|
||||
return ExeBuilder_Append(exeb, error, OPCODE_CALL, &op, 1, node->offset, node->length);
|
||||
}
|
||||
return emit_instr_for_funccall(exeb, (CallExprNode*) expr, break_dest, 1, error);
|
||||
|
||||
case EXPR_SELECT:
|
||||
{
|
||||
@@ -526,10 +591,18 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
|
||||
{
|
||||
ReturnNode *ret = (ReturnNode*) node;
|
||||
|
||||
if(!emit_instr_for_node(exeb, ret->val, break_dest, error))
|
||||
ExprNode *tuple[32];
|
||||
int count = 0;
|
||||
|
||||
if(!flatten_tuple_tree((ExprNode*) ret->val, tuple, sizeof(tuple)/sizeof(tuple[0]), &count, error))
|
||||
return 0;
|
||||
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, ret->base.offset, ret->base.length))
|
||||
for(int i = 0; i < count; i += 1)
|
||||
if(!emit_instr_for_node(exeb, (Node*) tuple[i], break_dest, error))
|
||||
return 0;
|
||||
|
||||
Operand op = (Operand) { .type = OPTP_INT, .as_int = count };
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, &op, 1, ret->base.offset, ret->base.length))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -608,7 +681,8 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
|
||||
|
||||
// Write a return instruction, just
|
||||
// in case it didn't already return.
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, func->body->offset, 0))
|
||||
Operand op = (Operand) { .type = OPTP_INT, .as_int = 0 };
|
||||
if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, &op, 1, func->body->offset, 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -672,7 +746,8 @@ Executable *compile(AST *ast, BPAlloc *alloc, Error *error)
|
||||
if(!emit_instr_for_node(exeb, ast->root, NULL, error))
|
||||
return 0;
|
||||
|
||||
if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, Source_GetSize(ast->src), 0))
|
||||
Operand op = (Operand) { .type = OPTP_INT, .as_int = 0 };
|
||||
if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, &op, 1, Source_GetSize(ast->src), 0))
|
||||
{
|
||||
exe = ExeBuilder_Finalize(exeb, error);
|
||||
|
||||
|
||||
+46
-28
@@ -83,6 +83,7 @@ typedef enum {
|
||||
TLCBRK = '{',
|
||||
TRCBRK = '}',
|
||||
TDOT = '.',
|
||||
TCOMMA = ',',
|
||||
|
||||
TDONE = 256,
|
||||
TINT,
|
||||
@@ -126,7 +127,7 @@ typedef struct {
|
||||
} Context;
|
||||
|
||||
static Node *parse_statement(Context *ctx);
|
||||
static Node *parse_expression(Context *ctx);
|
||||
static Node *parse_expression(Context *ctx, _Bool allow_toplev_tuples);
|
||||
static Node *parse_expression_statement(Context *ctx);
|
||||
static Node *parse_ifelse_statement(Context *ctx);
|
||||
static Node *parse_compound_statement(Context *ctx, TokenKind end);
|
||||
@@ -141,7 +142,8 @@ static inline _Bool isoper(char c)
|
||||
return c == '+' || c == '-' ||
|
||||
c == '*' || c == '/' ||
|
||||
c == '<' || c == '>' ||
|
||||
c == '!' || c == '=';
|
||||
c == '!' || c == '=' ||
|
||||
c == ',';
|
||||
}
|
||||
|
||||
/* Symbol: tokenize
|
||||
@@ -311,17 +313,18 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
||||
int size;
|
||||
const char *text;
|
||||
} optable[] = {
|
||||
{ TADD, 1, "+" },
|
||||
{ TSUB, 1, "-" },
|
||||
{ TMUL, 1, "*" },
|
||||
{ TDIV, 1, "/" },
|
||||
{ TEQL, 2, "==" },
|
||||
{ TNQL, 2, "!=" },
|
||||
{ TLSS, 1, "<" },
|
||||
{ TLEQ, 2, "<=" },
|
||||
{ TGRT, 1, ">" },
|
||||
{ TGEQ, 2, ">=" },
|
||||
{ TASS, 1, "=" },
|
||||
{ TADD, 1, "+" },
|
||||
{ TSUB, 1, "-" },
|
||||
{ TMUL, 1, "*" },
|
||||
{ TDIV, 1, "/" },
|
||||
{ TEQL, 2, "==" },
|
||||
{ TNQL, 2, "!=" },
|
||||
{ TLSS, 1, "<" },
|
||||
{ TLEQ, 2, "<=" },
|
||||
{ TGRT, 1, ">" },
|
||||
{ TGEQ, 2, ">=" },
|
||||
{ TASS, 1, "=" },
|
||||
{ TCOMMA, 1, "," },
|
||||
};
|
||||
|
||||
_Bool found = 0;
|
||||
@@ -598,11 +601,19 @@ static Node *parse_statement(Context *ctx)
|
||||
|
||||
next(ctx); // Consume the "return" keyword.
|
||||
|
||||
Node *val = parse_expression_statement(ctx);
|
||||
Node *val = parse_expression(ctx, 1);
|
||||
|
||||
if(val == NULL)
|
||||
return NULL;
|
||||
|
||||
if(current(ctx) != ';')
|
||||
{
|
||||
Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
next(ctx); // Consume the ';'.
|
||||
|
||||
ReturnNode *node = BPAlloc_Malloc(ctx->alloc, sizeof(ReturnNode));
|
||||
|
||||
if(node == NULL)
|
||||
@@ -638,7 +649,7 @@ static Node *parse_expression_statement(Context *ctx)
|
||||
{
|
||||
assert(ctx != NULL);
|
||||
|
||||
Node *expr = parse_expression(ctx);
|
||||
Node *expr = parse_expression(ctx, 1);
|
||||
|
||||
if(expr == NULL)
|
||||
return NULL;
|
||||
@@ -829,7 +840,7 @@ static Node *parse_list_primary_expression(Context *ctx)
|
||||
while(1)
|
||||
{
|
||||
// Parse.
|
||||
Node *item = parse_expression(ctx);
|
||||
Node *item = parse_expression(ctx, 0);
|
||||
|
||||
if(item == NULL)
|
||||
return NULL;
|
||||
@@ -940,7 +951,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
key = parse_expression(ctx);
|
||||
key = parse_expression(ctx, 0);
|
||||
}
|
||||
|
||||
if(key == NULL)
|
||||
@@ -961,7 +972,7 @@ static Node *parse_map_primary_expression(Context *ctx)
|
||||
next(ctx);
|
||||
|
||||
// Parse.
|
||||
Node *item = parse_expression(ctx);
|
||||
Node *item = parse_expression(ctx, 0);
|
||||
|
||||
if(item == NULL)
|
||||
return NULL;
|
||||
@@ -1100,7 +1111,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
||||
{
|
||||
next(ctx); // Consume the '('.
|
||||
|
||||
Node *node = parse_expression(ctx);
|
||||
Node *node = parse_expression(ctx, 1);
|
||||
|
||||
if(node == NULL)
|
||||
return NULL;
|
||||
@@ -1419,7 +1430,7 @@ static Node *parse_postfix_expression(Context *ctx)
|
||||
while(1)
|
||||
{
|
||||
// Parse.
|
||||
Node *arg = parse_expression(ctx);
|
||||
Node *arg = parse_expression(ctx, 0);
|
||||
|
||||
if(arg == NULL)
|
||||
return NULL;
|
||||
@@ -1552,7 +1563,7 @@ static inline _Bool isbinop(Token *tok)
|
||||
tok->kind == TLEQ || tok->kind == TGEQ ||
|
||||
tok->kind == TEQL || tok->kind == TNQL ||
|
||||
tok->kind == TKWAND || tok->kind == TKWOR ||
|
||||
tok->kind == '=';
|
||||
tok->kind == '=' || tok->kind == ',';
|
||||
}
|
||||
|
||||
static inline _Bool isrightassoc(Token *tok)
|
||||
@@ -1592,6 +1603,9 @@ static inline int precedenceof(Token *tok)
|
||||
case '*':
|
||||
case '/':
|
||||
return 5;
|
||||
|
||||
case ',':
|
||||
return 6;
|
||||
|
||||
default:
|
||||
return -100000000;
|
||||
@@ -1601,12 +1615,15 @@ static inline int precedenceof(Token *tok)
|
||||
return -100000000;
|
||||
}
|
||||
|
||||
static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
|
||||
static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec, _Bool allow_toplev_tuples)
|
||||
{
|
||||
while(isbinop(ctx->token) && precedenceof(ctx->token) >= min_prec)
|
||||
{
|
||||
Token *op = ctx->token;
|
||||
|
||||
if(op->kind == ',' && allow_toplev_tuples == 0)
|
||||
break;
|
||||
|
||||
next(ctx);
|
||||
|
||||
Node *right_expr = parse_prefix_expression(ctx);
|
||||
@@ -1616,7 +1633,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
|
||||
|
||||
while(isbinop(ctx->token) && (precedenceof(ctx->token) > precedenceof(op) || (precedenceof(ctx->token) == precedenceof(op) && isrightassoc(ctx->token))))
|
||||
{
|
||||
right_expr = parse_expression_2(ctx, right_expr, precedenceof(op) + 1);
|
||||
right_expr = parse_expression_2(ctx, right_expr, precedenceof(op) + 1, allow_toplev_tuples);
|
||||
|
||||
if(right_expr == NULL)
|
||||
return NULL;
|
||||
@@ -1652,6 +1669,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
|
||||
case TKWAND: temp->base.kind = EXPR_AND; break;
|
||||
case TKWOR: temp->base.kind = EXPR_OR; break;
|
||||
case '=': temp->base.kind = EXPR_ASS; break;
|
||||
case ',': temp->base.kind = EXPR_PAIR; break;
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@@ -1670,7 +1688,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
|
||||
return left_expr;
|
||||
}
|
||||
|
||||
static Node *parse_expression(Context *ctx)
|
||||
static Node *parse_expression(Context *ctx, _Bool allow_toplev_tuples)
|
||||
{
|
||||
Node *left_expr = parse_prefix_expression(ctx);
|
||||
|
||||
@@ -1680,7 +1698,7 @@ static Node *parse_expression(Context *ctx)
|
||||
if(done(ctx))
|
||||
return left_expr;
|
||||
|
||||
return parse_expression_2(ctx, left_expr, -1000000000);
|
||||
return parse_expression_2(ctx, left_expr, -1000000000, allow_toplev_tuples);
|
||||
}
|
||||
|
||||
static Node *parse_ifelse_statement(Context *ctx)
|
||||
@@ -1704,7 +1722,7 @@ static Node *parse_ifelse_statement(Context *ctx)
|
||||
|
||||
next(ctx); // Consume the "if" keyword.
|
||||
|
||||
Node *condition = parse_expression(ctx);
|
||||
Node *condition = parse_expression(ctx, 1);
|
||||
|
||||
if(condition == NULL)
|
||||
return NULL;
|
||||
@@ -1987,7 +2005,7 @@ static Node *parse_while_statement(Context *ctx)
|
||||
|
||||
next(ctx); // Consume the "while" keyword.
|
||||
|
||||
Node *condition = parse_expression(ctx);
|
||||
Node *condition = parse_expression(ctx, 1);
|
||||
|
||||
if(condition == NULL)
|
||||
return NULL;
|
||||
@@ -2073,7 +2091,7 @@ static Node *parse_dowhile_statement(Context *ctx)
|
||||
|
||||
next(ctx); // Consume the "while" keyword.
|
||||
|
||||
Node *condition = parse_expression(ctx);
|
||||
Node *condition = parse_expression(ctx, 1);
|
||||
|
||||
if(condition == NULL)
|
||||
return NULL;
|
||||
|
||||
+6
-3
@@ -159,12 +159,15 @@ static _Bool interpret(Source *src)
|
||||
|
||||
Runtime_SetBuiltins(runt, bins);
|
||||
|
||||
Object *o = run(runt, (Error*) &error, exe, 0, NULL, NULL, 0);
|
||||
Object *rets[8];
|
||||
unsigned int maxretc = sizeof(rets)/sizeof(rets[0]);
|
||||
|
||||
int retc = run(runt, (Error*) &error, exe, 0, NULL, NULL, 0, rets, maxretc);
|
||||
|
||||
// NOTE: The pointer to the builtins object is invalidated
|
||||
// now because it may be moved by the garbage collector.
|
||||
|
||||
if(o == NULL)
|
||||
if(retc < 0)
|
||||
{
|
||||
print_error("Runtime", (Error*) &error);
|
||||
|
||||
@@ -179,7 +182,7 @@ static _Bool interpret(Source *src)
|
||||
Runtime_Free(runt);
|
||||
Executable_Free(exe);
|
||||
|
||||
return o != NULL;
|
||||
return retc > -1;
|
||||
}
|
||||
|
||||
static _Bool disassemble(Source *src)
|
||||
|
||||
@@ -120,10 +120,9 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err)
|
||||
return type->copy(obj, heap, err);
|
||||
}
|
||||
|
||||
Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err)
|
||||
int Object_Call(Object *obj, Object **argv, unsigned int argc, Object **rets, unsigned int maxrets, Heap *heap, Error *err)
|
||||
{
|
||||
assert(err);
|
||||
assert(obj);
|
||||
assert(err != NULL && obj != NULL);
|
||||
|
||||
const TypeObject *type = Object_GetType(obj);
|
||||
assert(type);
|
||||
@@ -131,10 +130,10 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E
|
||||
if(type->call == NULL)
|
||||
{
|
||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return type->call(obj, argv, argc, heap, err);
|
||||
return type->call(obj, argv, argc, rets, maxrets, heap, err);
|
||||
}
|
||||
|
||||
void Object_Print(Object *obj, FILE *fp)
|
||||
|
||||
@@ -66,12 +66,12 @@ struct TypeObject {
|
||||
unsigned int size;
|
||||
AtomicType atomic;
|
||||
|
||||
_Bool (*init)(Object *self, Error *err);
|
||||
_Bool (*free)(Object *self, Error *err);
|
||||
int (*hash)(Object *self);
|
||||
Object* (*copy)(Object *self, Heap *heap, Error *err);
|
||||
Object* (*call)(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *err);
|
||||
void (*print)(Object *self, FILE *fp);
|
||||
_Bool (*init)(Object *self, Error *err);
|
||||
_Bool (*free)(Object *self, Error *err);
|
||||
int (*hash)(Object *self);
|
||||
Object* (*copy)(Object *self, Heap *heap, Error *err);
|
||||
int (*call)(Object *self, Object **argv, unsigned int argc, Object **rets, unsigned int maxrets, Heap *heap, Error *err);
|
||||
void (*print)(Object *self, FILE *fp);
|
||||
unsigned int (*deepsize)(const Object *self);
|
||||
|
||||
// Collections.
|
||||
@@ -123,7 +123,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err);
|
||||
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error);
|
||||
int Object_Hash (Object *obj);
|
||||
Object* Object_Copy (Object *obj, Heap *heap, Error *err);
|
||||
Object* Object_Call (Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err);
|
||||
int Object_Call (Object *obj, Object **argv, unsigned int argc, Object **rets, unsigned int maxrets, Heap *heap, Error *err);
|
||||
void Object_Print (Object *obj, FILE *fp);
|
||||
Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err);
|
||||
Object* Object_Delete(Object *coll, Object *key, Heap *heap, Error *err);
|
||||
|
||||
@@ -57,7 +57,7 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp),
|
||||
callback(&func->closure, userp);
|
||||
}
|
||||
|
||||
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
|
||||
static int call(Object *self, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Heap *heap, Error *error)
|
||||
{
|
||||
assert(self != NULL && heap != NULL && error != NULL);
|
||||
|
||||
@@ -88,7 +88,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
|
||||
if(argv2 == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "No memory");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy the provided arguments.
|
||||
@@ -101,21 +101,21 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
|
||||
argv2[i] = Object_NewNone(heap, error);
|
||||
|
||||
if(argv2[i] == NULL)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
// The right amount of arguments was provided.
|
||||
argv2 = argv;
|
||||
|
||||
Object *result = run(func->runtime, error, func->exe, func->index, func->closure, argv2, expected_argc);
|
||||
int retc = run(func->runtime, error, func->exe, func->index, func->closure, argv2, expected_argc, rets, maxretc);
|
||||
|
||||
// NOTE: Every object reference is invalidated from here.
|
||||
|
||||
if(argv2 != argv)
|
||||
free(argv2);
|
||||
|
||||
return result;
|
||||
return retc;
|
||||
}
|
||||
|
||||
static TypeObject t_func = {
|
||||
|
||||
+7
-10
@@ -43,11 +43,11 @@
|
||||
typedef struct {
|
||||
Object base;
|
||||
Runtime *runtime;
|
||||
Object *(*callback)(Runtime *runtime, Object **argv, unsigned int argc, Error *error);
|
||||
int (*callback)(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error);
|
||||
int argc;
|
||||
} NativeFunctionObject;
|
||||
|
||||
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
|
||||
static int call(Object *self, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Heap *heap, Error *error)
|
||||
{
|
||||
assert(self != NULL);
|
||||
assert(heap != NULL);
|
||||
@@ -87,7 +87,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
|
||||
if(argv2 == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "No memory");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Copy the provided arguments.
|
||||
@@ -102,27 +102,24 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
|
||||
if(argv2[i] == NULL)
|
||||
{
|
||||
free(argv2);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else UNREACHABLE;
|
||||
|
||||
assert(func->callback != NULL);
|
||||
Object *result = func->callback(func->runtime, argv2, argc2, error);
|
||||
int retc = func->callback(func->runtime, argv2, argc2, rets, maxretc, error);
|
||||
|
||||
// NOTE: Since the callback may have executed some bytecode, a GC
|
||||
// cycle may have been triggered, therefore we must assume
|
||||
// every object reference that was locally saved is invalidated
|
||||
// from here (the returned object is good tho).
|
||||
|
||||
if(result == NULL && error->occurred == 0)
|
||||
Error_Report(error, 1, "Native callback returned NULL but didn't report errors");
|
||||
|
||||
if(argv2 != argv)
|
||||
free(argv2);
|
||||
|
||||
return result;
|
||||
return retc;
|
||||
}
|
||||
|
||||
static TypeObject t_nfunc = {
|
||||
@@ -156,7 +153,7 @@ static TypeObject t_nfunc = {
|
||||
* The newly created object. If an error occurred, NULL is returned
|
||||
* and information about the error is stored in the [error] argument.
|
||||
*/
|
||||
Object *Object_FromNativeFunction(Runtime *runtime, Object *(*callback)(Runtime*, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error)
|
||||
Object *Object_FromNativeFunction(Runtime *runtime, int (*callback)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error)
|
||||
{
|
||||
assert(callback != NULL);
|
||||
|
||||
|
||||
+46
-31
@@ -77,7 +77,7 @@ int Runtime_GetCurrentIndex(Runtime *runtime)
|
||||
Executable *Runtime_GetCurrentExecutable(Runtime *runtime)
|
||||
{
|
||||
if(runtime->depth == 0)
|
||||
return NULL;
|
||||
return NULL;
|
||||
else
|
||||
return runtime->frame->exe;
|
||||
}
|
||||
@@ -805,11 +805,13 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
|
||||
case OPCODE_CALL:
|
||||
{
|
||||
assert(opc == 1);
|
||||
assert(opc == 2);
|
||||
assert(ops[0].type == OPTP_INT);
|
||||
assert(ops[1].type == OPTP_INT);
|
||||
|
||||
int argc = ops[0].as_int;
|
||||
assert(argc >= 0);
|
||||
int retc = ops[1].as_int;
|
||||
assert(argc >= 0 && retc > 0);
|
||||
|
||||
if(runtime->frame->used < argc + 1)
|
||||
{
|
||||
@@ -839,19 +841,32 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
(void) Runtime_Pop(runtime, error, argc+1);
|
||||
assert(error->occurred == 0);
|
||||
|
||||
Object *obj = Object_Call(callable, argv, argc, runtime->heap, error);
|
||||
// NOTE: Every local object reference is invalidated from here.
|
||||
|
||||
if(obj == NULL)
|
||||
{
|
||||
assert(error->occurred != 0);
|
||||
Object *rets[8];
|
||||
unsigned int maxrets = sizeof(rets)/sizeof(rets[0]);
|
||||
|
||||
int num_rets = Object_Call(callable, argv, argc, rets, maxrets, runtime->heap, error);
|
||||
|
||||
if(num_rets < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Every local object reference is invalidated from here.
|
||||
|
||||
assert(error->occurred == 0);
|
||||
|
||||
if(!Runtime_Push(runtime, error, obj))
|
||||
return 0;
|
||||
for(int g = 0; g < MIN(num_rets, retc); g += 1)
|
||||
if(!Runtime_Push(runtime, error, rets[g]))
|
||||
return 0;
|
||||
|
||||
for(int g = 0; g < retc - num_rets; g += 1)
|
||||
{
|
||||
Object *temp = Object_NewNone(Runtime_GetHeap(runtime), error);
|
||||
|
||||
if(temp == NULL)
|
||||
return NULL;
|
||||
|
||||
if(!Runtime_Push(runtime, error, temp))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1126,7 +1141,14 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
}
|
||||
|
||||
case OPCODE_RETURN:
|
||||
return 0;
|
||||
{
|
||||
assert(opc == 1);
|
||||
assert(ops[0].type == OPTP_INT);
|
||||
int retc = ops[0].as_int;
|
||||
assert(retc >= 0);
|
||||
assert(retc == runtime->frame->used);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case OPCODE_JUMP:
|
||||
assert(opc == 1);
|
||||
@@ -1233,7 +1255,7 @@ static _Bool collect(Runtime *runtime, Error *error)
|
||||
return Heap_StopCollection(runtime->heap);
|
||||
}
|
||||
|
||||
Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc)
|
||||
int run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc, Object **rets, int maxretc)
|
||||
{
|
||||
assert(runtime != NULL);
|
||||
assert(error != NULL);
|
||||
@@ -1244,7 +1266,7 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
|
||||
if(runtime->depth == MAX_FRAMES)
|
||||
{
|
||||
Error_Report(error, 1, "Maximum nested call limit of %d was reached", MAX_FRAMES);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(runtime->depth < MAX_FRAMES);
|
||||
@@ -1260,12 +1282,12 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
|
||||
frame.used = 0;
|
||||
|
||||
if(frame.locals == NULL)
|
||||
return NULL;
|
||||
return -1;
|
||||
|
||||
if(frame.exe == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "Failed to copy executable");
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add the frame to the runtime.
|
||||
@@ -1275,7 +1297,7 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
|
||||
}
|
||||
|
||||
// This is what the function will return.
|
||||
Object *result = NULL;
|
||||
int retc = -1;
|
||||
|
||||
// Push the initial values of the frame.
|
||||
for(int i = 0; i < argc; i += 1)
|
||||
@@ -1317,19 +1339,12 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
|
||||
// If an error occurred, we want to return NULL.
|
||||
if(error->occurred == 0)
|
||||
{
|
||||
// If the step function left something
|
||||
// on the stack, we return that. If it
|
||||
// didn't, we return some other default
|
||||
// value like "none".
|
||||
if(frame.used == 0)
|
||||
retc = MIN(frame.used, maxretc);
|
||||
|
||||
for(int i = 0; i < retc; i += 1)
|
||||
{
|
||||
// Nothing to return on the stack. Set to none.
|
||||
result = Object_NewNone(runtime->heap, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Stack_Top(runtime->stack, 0);
|
||||
assert(result != NULL);
|
||||
rets[i] = Stack_Top(runtime->stack, i - retc + 1);
|
||||
assert(rets[i] != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,5 +1363,5 @@ cleanup:
|
||||
Executable_Free(frame.exe);
|
||||
}
|
||||
|
||||
return result;
|
||||
return retc;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ Executable *Runtime_GetCurrentExecutable(Runtime *runtime);
|
||||
Snapshot *Snapshot_New(Runtime *runtime);
|
||||
void Snapshot_Free(Snapshot *snapshot);
|
||||
void Snapshot_Print(Snapshot *snapshot, FILE *fp);
|
||||
Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc);
|
||||
int run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc, Object **rets, int maxretc);
|
||||
|
||||
typedef enum {
|
||||
SM_END,
|
||||
@@ -79,7 +79,7 @@ struct StaticMapSlot {
|
||||
_Bool as_bool;
|
||||
long long int as_int;
|
||||
double as_float;
|
||||
Object *(*as_funct)(Runtime*, Object**, unsigned int, Error*);
|
||||
int (*as_funct)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*);
|
||||
TypeObject *as_type;
|
||||
};
|
||||
union { int argc; int length; };
|
||||
@@ -87,8 +87,7 @@ struct StaticMapSlot {
|
||||
|
||||
Object *Object_NewStaticMap(const StaticMapSlot *slots, Runtime *runt, Error *error);
|
||||
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error);
|
||||
Object *Object_FromNativeFunction(Runtime *runtime, Object *(*callback)(Runtime*, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error);
|
||||
|
||||
Object *Object_FromNativeFunction(Runtime *runtime, int (*callback)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error);
|
||||
typedef struct {
|
||||
Error base;
|
||||
Runtime *runtime;
|
||||
|
||||
Reference in New Issue
Block a user