new built-in variables for each type
This commit is contained in:
+4
-16
@@ -9,11 +9,8 @@ fun isDigit(c)
|
||||
and unicode(c) >= unicode('0');
|
||||
|
||||
fun skip(ctx, test)
|
||||
while not ended(ctx): {
|
||||
if not test(current(ctx)):
|
||||
break;
|
||||
while not ended(ctx) and test(current(ctx)):
|
||||
next(ctx);
|
||||
}
|
||||
|
||||
fun ended(ctx)
|
||||
return ctx.i == count(ctx.str);
|
||||
@@ -167,13 +164,8 @@ fun parseString(ctx) {
|
||||
|
||||
buff = '';
|
||||
|
||||
while not ended(ctx): {
|
||||
|
||||
if current(ctx) == '"':
|
||||
break;
|
||||
|
||||
while not ended(ctx) and current(ctx) != '"': {
|
||||
buff = strcat(buff, current(ctx));
|
||||
|
||||
next(ctx);
|
||||
}
|
||||
|
||||
@@ -191,9 +183,7 @@ fun parseNumber(ctx) {
|
||||
# Number (int or float)
|
||||
|
||||
parsed = 0;
|
||||
while not ended(ctx): {
|
||||
if not isDigit(current(ctx)):
|
||||
break;
|
||||
while not ended(ctx) and isDigit(current(ctx)): {
|
||||
parsed = parsed * 10 + unicode(current(ctx)) - unicode('0');
|
||||
next(ctx);
|
||||
}
|
||||
@@ -212,9 +202,7 @@ fun parseNumber(ctx) {
|
||||
return none, "Got something other than a digit after dot";
|
||||
|
||||
fact = 1;
|
||||
while not ended(ctx): {
|
||||
if not isDigit(current(ctx)):
|
||||
break;
|
||||
while not ended(ctx) and isDigit(current(ctx)): {
|
||||
fact = fact / 10.0;
|
||||
parsed = parsed + fact * (unicode(current(ctx)) - unicode('0'));
|
||||
next(ctx);
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
|
||||
fun isSpace(c)
|
||||
return c == " " or c == "\t" or c == "\n";
|
||||
|
||||
fun isDigit(c) {
|
||||
u = unicode(c);
|
||||
d = u - unicode("0");
|
||||
return d >= 0 and d <= 9;
|
||||
}
|
||||
|
||||
fun skipSpaces(context) {
|
||||
# Skip zero or more whitespace characters.
|
||||
while context.cur < count(context.str)
|
||||
and isSpace(context.str[context.cur]):
|
||||
context.cur = context.cur + 1;
|
||||
}
|
||||
|
||||
fun parseNull(context) {
|
||||
|
||||
assert(context.cur < count(context)
|
||||
and context.str[context.cur] == 'n');
|
||||
|
||||
if context.cur+3 > count(context)
|
||||
or context.str[context.cur+1] != 'u'
|
||||
or context.str[context.cur+2] != 'l'
|
||||
or context.str[context.cur+3] != 'l':
|
||||
return none, "Unexpected token starting with \"n\"";
|
||||
|
||||
context.cur = context.cur + count("null");
|
||||
return none;
|
||||
}
|
||||
|
||||
fun parseTrue(context) {
|
||||
|
||||
assert(context.cur < count(context)
|
||||
and context.str[context.cur] == 't');
|
||||
|
||||
if context.cur+3 > count(context)
|
||||
or context.str[context.cur+1] != 'r'
|
||||
or context.str[context.cur+2] != 'u'
|
||||
or context.str[context.cur+3] != 'e':
|
||||
return none, "Unexpected token starting with \"t\"";
|
||||
|
||||
context.cur = context.cur + count("true");
|
||||
return true;
|
||||
}
|
||||
|
||||
fun parseFalse(context) {
|
||||
|
||||
assert(context.cur < count(context)
|
||||
and context.str[context.cur] == 'f');
|
||||
|
||||
if context.cur+3 > count(context)
|
||||
or context.str[context.cur+1] != 'a'
|
||||
or context.str[context.cur+2] != 'l'
|
||||
or context.str[context.cur+3] != 's'
|
||||
or context.str[context.cur+4] != 'e':
|
||||
return none, "Unexpected token starting with \"f\"";
|
||||
|
||||
context.cur = context.cur + count("false");
|
||||
return false;
|
||||
}
|
||||
|
||||
fun skip(context, test_callback) {
|
||||
k = context.cur;
|
||||
while k < count(context) and test_callback(context.str[k]):
|
||||
k = k + 1;
|
||||
return k;
|
||||
}
|
||||
|
||||
fun parseInteger(context) {
|
||||
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
||||
|
||||
buffer = 0;
|
||||
|
||||
do {
|
||||
c = context.str[context.cur];
|
||||
d = unicode(c) - unicode('0');
|
||||
buffer = buffer * 10 + d;
|
||||
context.cur = context.cur + 1;
|
||||
} while context.cur < count(context)
|
||||
and isDigit(context.str[context.cur]);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
fun parseFloating(context) {
|
||||
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
||||
|
||||
# It's ensured by the caller (parseIntegerOrFloating)
|
||||
# that now the strings contains two sequences of
|
||||
# digits with a dot in the middle.
|
||||
|
||||
buffer = 0.0;
|
||||
|
||||
# Scan the integer part.
|
||||
do {
|
||||
c = context.str[context.cur];
|
||||
d = unicode(c) - unicode('0');
|
||||
buffer = buffer * 10 + d;
|
||||
context.cur = context.cur + 1;
|
||||
} while context.str[context.cur] != ".";
|
||||
|
||||
assert(isDigit(context.str[context.cur+1]));
|
||||
|
||||
# Scan the decimal part.
|
||||
q = 1;
|
||||
do {
|
||||
c = context.str[context.cur];
|
||||
d = unicode(c) - unicode('0');
|
||||
q = q / 10;
|
||||
buffer = buffer + q * d;
|
||||
context.cur = context.cur + 1;
|
||||
} while context.cur < count(context)
|
||||
and isDigit(context);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
fun parseIntegerOrFloating(context) {
|
||||
assert(context.cur < count(context) and isDigit(context.str[context.cur]));
|
||||
|
||||
# Is the first digit sequence followed by a dot
|
||||
# and then one or more digits?
|
||||
|
||||
k = skip(context, isDigit);
|
||||
if k+1 < count(context) and context.str[k] == "." and isDigit(context.str[k+1]):
|
||||
# It's a floating point value, then!
|
||||
return parseFloating(context);
|
||||
else
|
||||
# It's good old integer!
|
||||
return parseInteger(context);
|
||||
}
|
||||
|
||||
fun parseValue(context) {
|
||||
|
||||
if context.cur == count(context):
|
||||
return none, "Source ended where a value was expected";
|
||||
|
||||
c = context.str[context.cur];
|
||||
if c == "{":
|
||||
val, err = parseObject(context);
|
||||
else if c == "[":
|
||||
val, err = parseArray(context);
|
||||
else if c == '"':
|
||||
val, err = parseString(context);
|
||||
else if isDigit(c):
|
||||
val, err = parseIntegerOrFloating(context);
|
||||
else if c == 'n':
|
||||
val, err = parseNull(context);
|
||||
else if c == 't':
|
||||
val, err = parseTrue(context);
|
||||
else if c == 'f':
|
||||
val, err = parseFalse(context);
|
||||
else {
|
||||
val = none;
|
||||
err = strcat("Unexepected character \"", c, "\" where a value was expected");
|
||||
}
|
||||
return val, err;
|
||||
}
|
||||
|
||||
fun parse(str) {
|
||||
context = {str: str, cur: 0};
|
||||
skipSpaces(context);
|
||||
val, err = parseValue(context);
|
||||
return val, err;
|
||||
}
|
||||
|
||||
val, err = parse('3.14');
|
||||
print("val=[", val, "]\n");
|
||||
print("err=[", err, "]\n");
|
||||
@@ -32,11 +32,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "math.h"
|
||||
#include "basic.h"
|
||||
#include "files.h"
|
||||
#include "math.h"
|
||||
#include "../utils/utf8.h"
|
||||
|
||||
#include "../objects/objects.h"
|
||||
static int bin_print(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
|
||||
{
|
||||
(void) runtime;
|
||||
@@ -378,7 +378,31 @@ static int bin_bufferToString(Runtime *runtime, Object **argv, unsigned int argc
|
||||
return 1;
|
||||
}
|
||||
|
||||
const StaticMapSlot bins_basic[] = {
|
||||
void bins_basic_init(StaticMapSlot slots[])
|
||||
{
|
||||
slots[0].as_type = Object_GetTypeType();
|
||||
slots[1].as_type = Object_GetNoneType();
|
||||
slots[2].as_type = Object_GetIntType();
|
||||
slots[3].as_type = Object_GetFloatType();
|
||||
slots[4].as_type = Object_GetStringType();
|
||||
slots[5].as_type = Object_GetListType();
|
||||
slots[6].as_type = Object_GetMapType();
|
||||
slots[7].as_type = Object_GetFileType();
|
||||
slots[8].as_type = Object_GetDirType();
|
||||
}
|
||||
|
||||
StaticMapSlot bins_basic[] = {
|
||||
|
||||
{ "Type", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "None", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "int", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "float", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "String", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "List", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "Map", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "File", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ "Dir", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
|
||||
{ "math", SM_SMAP, .as_smap = bins_math, },
|
||||
// { "files", SM_SMAP, .as_smap = bins_files, },
|
||||
// { "net", SM_SMAP, .as_smap = bins_net, },
|
||||
|
||||
@@ -29,4 +29,5 @@
|
||||
*/
|
||||
|
||||
#include "../runtime/runtime.h"
|
||||
extern const StaticMapSlot bins_basic[];
|
||||
void bins_basic_init(StaticMapSlot slots[]);
|
||||
extern StaticMapSlot bins_basic[];
|
||||
@@ -296,7 +296,7 @@ static Object *bin_nextDirItem(Runtime *runtime, Object **argv, unsigned int arg
|
||||
return Object_FromString(ent->d_name, -1, heap, error);
|
||||
}
|
||||
|
||||
const StaticMapSlot bins_files[] = {
|
||||
StaticMapSlot bins_files[] = {
|
||||
{ "READ", SM_INT, .as_int = MD_READ, },
|
||||
{ "WRITE", SM_INT, .as_int = MD_WRITE, },
|
||||
{ "APPEND", SM_INT, .as_int = MD_APPEND, },
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
*/
|
||||
|
||||
#include "../runtime/runtime.h"
|
||||
extern const StaticMapSlot bins_files[];
|
||||
extern StaticMapSlot bins_files[];
|
||||
@@ -109,7 +109,7 @@ WRAP_FUNC(sqrt)
|
||||
WRAP_FUNC_2(atan2)
|
||||
WRAP_FUNC_2(pow)
|
||||
|
||||
const StaticMapSlot bins_math[] = {
|
||||
StaticMapSlot bins_math[] = {
|
||||
{ "PI", SM_FLOAT, .as_float = M_PI },
|
||||
{ "E", SM_FLOAT, .as_float = M_E },
|
||||
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
*/
|
||||
|
||||
#include "../runtime/runtime.h"
|
||||
extern const StaticMapSlot bins_math[];
|
||||
extern StaticMapSlot bins_math[];
|
||||
@@ -504,7 +504,7 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
|
||||
|
||||
static void emitInstrForIfElseNode(CodegenContext *ctx, IfElseNode *ifelse, Label *label_break)
|
||||
{
|
||||
emitInstrForExprNode(ctx, ifelse->condition, label_break);
|
||||
emitInstrForNode(ctx, ifelse->condition, label_break);
|
||||
if(ifelse->false_branch)
|
||||
{
|
||||
Label *label_else = Label_New(ctx);
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ static _Bool interpret(Executable *exe)
|
||||
RuntimeError error;
|
||||
RuntimeError_Init(&error, runt); // Here we specify the runtime to snapshot in case of failure.
|
||||
|
||||
Object *bins = Object_NewStaticMap(bins_basic, runt, (Error*) &error);
|
||||
Object *bins = Object_NewStaticMap(bins_basic, bins_basic_init, runt, (Error*) &error);
|
||||
|
||||
if(bins == NULL)
|
||||
{
|
||||
|
||||
@@ -97,6 +97,11 @@ static _Bool to_bool(Object *obj, Error *err)
|
||||
return obj == &the_true_object;
|
||||
}
|
||||
|
||||
TypeObject *Object_GetBoolType()
|
||||
{
|
||||
return &t_bool;
|
||||
}
|
||||
|
||||
Object *Object_FromBool(_Bool val, Heap *heap, Error *error)
|
||||
{
|
||||
(void) heap;
|
||||
|
||||
@@ -82,6 +82,11 @@ static TypeObject t_buffer_slice = {
|
||||
|
||||
#define THRESHOLD 128
|
||||
|
||||
TypeObject *Object_GetBufferType()
|
||||
{
|
||||
return &t_buffer;
|
||||
}
|
||||
|
||||
_Bool Object_IsBuffer(Object *obj)
|
||||
{
|
||||
return obj->type == &t_buffer_slice || obj->type == &t_buffer;
|
||||
|
||||
@@ -44,6 +44,11 @@ static TypeObject t_dir = {
|
||||
.free = dir_free,
|
||||
};
|
||||
|
||||
TypeObject *Object_GetDirType()
|
||||
{
|
||||
return &t_dir;
|
||||
}
|
||||
|
||||
_Bool Object_IsDir(Object *obj)
|
||||
{
|
||||
return obj->type == &t_dir;
|
||||
|
||||
@@ -44,6 +44,11 @@ static TypeObject t_file = {
|
||||
.free = file_free,
|
||||
};
|
||||
|
||||
TypeObject *Object_GetFileType()
|
||||
{
|
||||
return &t_file;
|
||||
}
|
||||
|
||||
_Bool Object_IsFile(Object *obj)
|
||||
{
|
||||
return obj->type == &t_file;
|
||||
|
||||
@@ -98,6 +98,11 @@ static double to_float(Object *obj, Error *err)
|
||||
return ((FloatObject*) obj)->val;
|
||||
}
|
||||
|
||||
TypeObject *Object_GetFloatType()
|
||||
{
|
||||
return &t_float;
|
||||
}
|
||||
|
||||
Object *Object_FromFloat(double val, Heap *heap, Error *error)
|
||||
{
|
||||
FloatObject *obj = (FloatObject*) Heap_Malloc(heap, &t_float, error);
|
||||
|
||||
@@ -84,6 +84,11 @@ static long long int to_int(Object *obj, Error *err)
|
||||
return ((IntObject*) obj)->val;
|
||||
}
|
||||
|
||||
TypeObject *Object_GetIntType()
|
||||
{
|
||||
return &t_int;
|
||||
}
|
||||
|
||||
Object *Object_FromInt(long long int val, Heap *heap, Error *error)
|
||||
{
|
||||
assert(heap != NULL);
|
||||
|
||||
@@ -99,6 +99,11 @@ static Object *copy(Object *self, Heap *heap, Error *err)
|
||||
return (Object*) ls2;
|
||||
}
|
||||
|
||||
TypeObject *Object_GetListType()
|
||||
{
|
||||
return &t_list;
|
||||
}
|
||||
|
||||
Object *Object_NewList(int capacity, Heap *heap, Error *error)
|
||||
{
|
||||
// Handle default args.
|
||||
|
||||
@@ -108,6 +108,11 @@ static int hash(Object *self)
|
||||
return h;
|
||||
}
|
||||
|
||||
TypeObject *Object_GetMapType()
|
||||
{
|
||||
return &t_map;
|
||||
}
|
||||
|
||||
Object *Object_NewMap(int num, Heap *heap, Error *error)
|
||||
{
|
||||
// Handle default args.
|
||||
|
||||
@@ -52,6 +52,11 @@ static Object the_none_object = {
|
||||
.flags = Object_STATIC,
|
||||
};
|
||||
|
||||
TypeObject *Object_GetNoneType()
|
||||
{
|
||||
return &t_none;
|
||||
}
|
||||
|
||||
_Bool Object_IsNone(Object *obj)
|
||||
{
|
||||
return obj == &the_none_object;
|
||||
|
||||
@@ -134,6 +134,11 @@ static char *to_string(Object *self, int *size, Heap *heap, Error *err)
|
||||
return s->body;
|
||||
}
|
||||
|
||||
TypeObject *Object_GetStringType()
|
||||
{
|
||||
return &t_string;
|
||||
}
|
||||
|
||||
Object *Object_FromString(const char *str, int len, Heap *heap, Error *error)
|
||||
{
|
||||
assert(str != NULL);
|
||||
|
||||
@@ -41,6 +41,11 @@ TypeObject t_type = {
|
||||
.op_eql = op_eql,
|
||||
};
|
||||
|
||||
TypeObject *Object_GetTypeType()
|
||||
{
|
||||
return &t_type;
|
||||
}
|
||||
|
||||
static _Bool op_eql(Object *self, Object *other)
|
||||
{
|
||||
return self == other;
|
||||
|
||||
@@ -149,6 +149,18 @@ Object* Object_FromString(const char *str, int len, Heap *heap, Error *error);
|
||||
Object* Object_FromStream(FILE *fp, Heap *heap, Error *error);
|
||||
Object* Object_FromDIR(DIR *handle, Heap *heap, Error *error);
|
||||
|
||||
TypeObject *Object_GetTypeType();
|
||||
TypeObject *Object_GetNoneType();
|
||||
TypeObject *Object_GetIntType();
|
||||
TypeObject *Object_GetBoolType();
|
||||
TypeObject *Object_GetFloatType();
|
||||
TypeObject *Object_GetStringType();
|
||||
TypeObject *Object_GetListType();
|
||||
TypeObject *Object_GetMapType();
|
||||
TypeObject *Object_GetBufferType();
|
||||
TypeObject *Object_GetFileType();
|
||||
TypeObject *Object_GetDirType();
|
||||
|
||||
_Bool Object_IsNone(Object *obj);
|
||||
_Bool Object_IsInt(Object *obj);
|
||||
_Bool Object_IsBool(Object *obj);
|
||||
|
||||
@@ -83,7 +83,7 @@ static int hash(Object *self)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Object *Object_NewStaticMap(const StaticMapSlot *slots, Runtime *runt, Error *error)
|
||||
Object *Object_NewStaticMap(StaticMapSlot slots[], void (*initfn)(StaticMapSlot[]), Runtime *runt, Error *error)
|
||||
{
|
||||
Heap *heap = Runtime_GetHeap(runt);
|
||||
|
||||
@@ -97,6 +97,9 @@ Object *Object_NewStaticMap(const StaticMapSlot *slots, Runtime *runt, Error *er
|
||||
obj->slots = slots;
|
||||
}
|
||||
|
||||
if(initfn != NULL)
|
||||
initfn(slots);
|
||||
|
||||
return (Object*) obj;
|
||||
}
|
||||
|
||||
@@ -130,7 +133,7 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
||||
case SM_FLOAT: return Object_FromFloat(slot.as_float, heap, error);
|
||||
case SM_FUNCT: return Object_FromNativeFunction(map->runt, slot.as_funct, slot.argc, heap, error);
|
||||
case SM_STRING: return Object_FromString(slot.as_string, slot.length, heap, error);
|
||||
case SM_SMAP: return Object_NewStaticMap(slot.as_smap, map->runt, error);
|
||||
case SM_SMAP: return Object_NewStaticMap(slot.as_smap, NULL, map->runt, error);
|
||||
case SM_NONE: return Object_NewNone(heap, error);
|
||||
case SM_TYPE: return (Object*) slot.as_type;
|
||||
default: assert(0); break;
|
||||
|
||||
@@ -74,18 +74,18 @@ struct StaticMapSlot {
|
||||
const char *name;
|
||||
StaticMapSlotKind kind;
|
||||
union {
|
||||
const StaticMapSlot *as_smap;
|
||||
const char *as_string;
|
||||
_Bool as_bool;
|
||||
long long int as_int;
|
||||
double as_float;
|
||||
int (*as_funct)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*);
|
||||
TypeObject *as_type;
|
||||
StaticMapSlot *as_smap;
|
||||
const char *as_string;
|
||||
_Bool as_bool;
|
||||
long long int as_int;
|
||||
double as_float;
|
||||
int (*as_funct)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*);
|
||||
TypeObject *as_type;
|
||||
};
|
||||
union { int argc; int length; };
|
||||
};
|
||||
|
||||
Object *Object_NewStaticMap(const StaticMapSlot *slots, Runtime *runt, Error *error);
|
||||
Object *Object_NewStaticMap(StaticMapSlot slots[], void (*initfn)(StaticMapSlot[]), 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, int (*callback)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error);
|
||||
typedef struct {
|
||||
|
||||
@@ -116,4 +116,14 @@
|
||||
assert(r);
|
||||
}
|
||||
|
||||
# Test type variables
|
||||
{
|
||||
assert(type(none) == None);
|
||||
assert(type(1) == int);
|
||||
assert(type(10.4) == float);
|
||||
assert(type("Hello, world!") == String);
|
||||
assert(type([]) == List);
|
||||
assert(type({}) == Map);
|
||||
}
|
||||
|
||||
print('No assertion failed.\n');
|
||||
Reference in New Issue
Block a user