Compare commits

..

15 Commits

Author SHA1 Message Date
1544332b90 build a release build for linux as well 2023-09-04 20:15:15 -05:00
b73d865447 even more error handling refactoring
removing all of these useless checks has actually made cosmoV_execute just a
lil bit faster :)
2023-09-04 20:14:53 -05:00
5a00d61646 lol oops 2023-09-01 17:16:10 -05:00
83dfd36c5c switched to a better linenoise fork
https://github.com/msteveb/linenoise

this version has several benefits, namely win32 support :D
2023-09-01 17:12:39 -05:00
2d889a37d1 fix artifacts path 2023-09-01 14:43:20 -05:00
0f0a8fb085 better repl input, using linenoise 2023-08-31 23:17:13 -05:00
c03df8f506 include util path 2023-08-31 23:16:28 -05:00
38d9c499ea whoops, wrong path to the workflow file 2023-08-30 21:30:20 -05:00
79d40d4bb0 ig that runner doesn't work lol 2023-08-30 21:28:50 -05:00
dc44adba6e removed CERROR 2023-08-30 20:14:03 -05:00
7c0bec5e6c allow manual runs 2023-08-30 20:12:06 -05:00
a44450ff22 wrong output path for windows build 2023-08-30 20:09:06 -05:00
58c857d2ea oops 2023-08-30 20:03:30 -05:00
38136d028f switched from appveyor to github workflow 2023-08-30 20:02:04 -05:00
420cd3e856 Merge pull request #7 from CPunch/error-handling
Error handling
2023-08-30 12:05:57 -05:00
16 changed files with 3422 additions and 164 deletions

45
.github/workflows/check_build.yaml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Check Builds
on:
push:
paths:
- src/**
- util/**
- main.c
- Makefile
- CMakeLists.txt
- .github/workflows/check_build.yaml
workflow_dispatch:
jobs:
ubuntu-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: CMake
run: cmake -B build -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build build --config Release
- name: Upload build artifact
uses: actions/upload-artifact@v2
with:
name: Cosmo-Ubuntu
path: build/bin
windows-build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Create CMake build files
run: cmake -B build -DCMAKE_BUILD_TYPE=MinSizeRel
- name: Check compilation
run: cmake --build build --config MinSizeRel
- name: Upload build artifact
uses: actions/upload-artifact@v2
with:
name: Cosmo-Windows
path: build/bin

View File

@@ -16,7 +16,7 @@ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT c
include(FetchContent)
file(GLOB sources CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/src/*.c)
add_executable(${PROJECT_NAME} main.c)
add_executable(${PROJECT_NAME} main.c ${PROJECT_SOURCE_DIR}/util/linenoise.c)
target_sources(${PROJECT_NAME} PRIVATE ${sources})
IF (NOT WIN32)

View File

@@ -21,6 +21,7 @@ CHDR=\
src/cbaselib.h\
src/cdump.h\
src/cundump.h\
util/linenoise.h\
CSRC=\
src/cchunk.c\
@@ -37,6 +38,7 @@ CSRC=\
src/cbaselib.c\
src/cdump.c\
src/cundump.c\
util/linenoise.c\
main.c\
COBJ=$(CSRC:.c=.o)

View File

@@ -1,5 +1,5 @@
# Cosmo
[![AppVeyor](https://ci.appveyor.com/api/projects/status/github/CPunch/Cosmo?svg=true)](https://ci.appveyor.com/project/CPunch/Cosmo)
[![Check Build](https://github.com/CPunch/Cosmo/actions/workflows/check_build.yaml/badge.svg?branch=main)](https://github.com/CPunch/Cosmo/actions/workflows/check_build.yaml)
## Usage

View File

@@ -1,33 +0,0 @@
version: 'cosmo-0.1.{build}'
# we compile every commit under all branches
#branch:
# only:
# - main
# only run CI if we changed actual code
only_commits:
files:
- src/
- main.c
- Makefile
- CMakeLists.txt
- appveyor.yml
# images we're using
image:
- Ubuntu2004
platform:
- x64
install:
- sudo apt install clang cmake -y
build_script:
- make && ./bin/cosmo examples/testsuite.cosmo -s examples/getters_setters.cosmo
artifacts:
- path: bin
name: ubuntu20_04-bin-x64
type: zip

11
main.c
View File

@@ -8,6 +8,8 @@
#include "cundump.h"
#include "cvm.h"
#include "util/linenoise.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
@@ -63,7 +65,7 @@ static bool interpret(CState *state, const char *script, const char *mod)
static void repl(CState *state)
{
char line[1024];
char *line;
_ACTIVE = true;
// add our custom REPL functions
@@ -76,14 +78,13 @@ static void repl(CState *state)
cosmoV_register(state, 2);
while (_ACTIVE) {
printf("> ");
if (!fgets(line, sizeof(line), stdin)) { // better than gets()
printf("\n> ");
if (!(line = linenoise("> "))) { // better than gets()
break;
}
linenoiseHistoryAdd(line);
interpret(state, line, "REPL");
free(line);
}
}

View File

@@ -56,7 +56,7 @@ void *cosmoM_reallocate(CState *state, void *buf, size_t oldSize, size_t newSize
#endif
if (newBuf == NULL) {
CERROR("failed to allocate memory!");
printf("[ERROR] failed to allocate memory!");
exit(1);
}

View File

@@ -397,7 +397,7 @@ bool cosmoO_isDescendant(CObj *obj, CObjObject *proto)
}
// returns false if error thrown
bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj)
void cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj)
{
if (!cosmoT_get(state, &proto->tbl, key,
val)) { // if the field doesn't exist in the object, check the proto
@@ -407,18 +407,17 @@ bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *v
cosmoV_pushRef(state, (CObj *)obj); // push object
cosmoV_call(state, 1, 1); // call the function with the 1 argument
*val = *cosmoV_pop(state); // set value to the return value of __index
return true;
return;
}
if (proto->_obj.proto != NULL &&
cosmoO_getRawObject(state, proto->_obj.proto, key, val, obj))
return true;
// maybe the field is defined in the proto?
if (proto->_obj.proto != NULL) {
cosmoO_getRawObject(state, proto->_obj.proto, key, val, obj);
return;
}
*val = cosmoV_newNil();
return true; // no protoobject to check against / key not found
}
return true;
}
void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue val, CObj *obj)
@@ -519,7 +518,7 @@ bool cosmoO_getIString(CState *state, CObjObject *object, int flag, CValue *val)
return false; // obj->proto was false, the istring doesn't exist in this object chain
}
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val)
void cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val)
{
if (cosmoO_getIString(state, object, ISTRING_INDEX, val)) {
cosmoV_pushValue(state, *val); // push function
@@ -527,15 +526,12 @@ bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *v
cosmoV_pushValue(state, key); // push key
cosmoV_call(state, 2, 1); // call the function with the 2 arguments
*val = *cosmoV_pop(state); // set value to the return value of __index
return true;
} else { // there's no __index function defined!
} else { // there's no __index function defined!
cosmoV_error(state, "Couldn't index object without __index function!");
}
return false;
}
bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val)
void cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val)
{
CValue ret; // return value for cosmoO_getIString
@@ -545,12 +541,9 @@ bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue
cosmoV_pushValue(state, key); // push key & value pair
cosmoV_pushValue(state, val);
cosmoV_call(state, 3, 0);
return true;
} else { // there's no __newindex function defined
cosmoV_error(state, "Couldn't set index on object without __newindex function!");
}
return false;
}
CObjString *cosmoO_toString(CState *state, CObj *obj)

View File

@@ -3,6 +3,8 @@
#include "cosmo.h"
#include <stdarg.h>
typedef enum CObjType
{
COBJ_STRING,
@@ -172,10 +174,10 @@ static inline CObjObject *cosmoO_grabProto(CObj *obj)
return obj->type == COBJ_OBJECT ? (CObjObject *)obj : obj->proto;
}
bool cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj);
void cosmoO_getRawObject(CState *state, CObjObject *proto, CValue key, CValue *val, CObj *obj);
void cosmoO_setRawObject(CState *state, CObjObject *proto, CValue key, CValue val, CObj *obj);
bool cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val);
bool cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val);
void cosmoO_indexObject(CState *state, CObjObject *object, CValue key, CValue *val);
void cosmoO_newIndexObject(CState *state, CObjObject *object, CValue key, CValue val);
// sets the user-defined pointer, if a user-define integer is already defined it will be over
// written

View File

@@ -64,6 +64,4 @@ typedef int (*cosmo_Writer)(CState *state, const void *data, size_t size, const
#define UNNAMEDCHUNK "_main"
#define COSMOASSERT(x) assert(x)
#define CERROR(err) printf("%s : %s\n", "[ERROR]", err)
#endif

View File

@@ -32,7 +32,7 @@ CState *cosmoV_newState()
CState *state = malloc(sizeof(CState));
if (state == NULL) {
CERROR("failed to allocate memory!");
printf("[ERROR] failed to allocate memory!");
exit(1);
}

113
src/cvm.c
View File

@@ -497,7 +497,7 @@ COSMO_API void cosmoV_makeTable(CState *state, int pairs)
cosmoV_pushRef(state, (CObj *)newObj);
}
bool cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
void cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
{
CObjObject *object = cosmoO_grabProto(_obj);
@@ -506,23 +506,16 @@ bool cosmoV_rawget(CState *state, CObj *_obj, CValue key, CValue *val)
CObjString *field = cosmoV_toString(state, key);
cosmoV_error(state, "No proto defined! Couldn't get field '%s' from type %s", field->str,
cosmoO_typeStr(_obj));
*val = cosmoV_newNil();
return false;
}
// push the object onto the stack so the GC can find it
cosmoV_pushRef(state, (CObj *)object);
if (cosmoO_getRawObject(state, object, key, val, _obj)) {
// *val now equals the response, pop the object
cosmoV_pop(state);
return true;
}
cosmoO_getRawObject(state, object, key, val, _obj);
cosmoV_pop(state);
return false;
}
bool cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
void cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
{
CObjObject *object = cosmoO_grabProto(_obj);
@@ -531,14 +524,12 @@ bool cosmoV_rawset(CState *state, CObj *_obj, CValue key, CValue val)
CObjString *field = cosmoV_toString(state, key);
cosmoV_error(state, "No proto defined! Couldn't set field '%s' to type %s", field->str,
cosmoO_typeStr(_obj));
return false;
}
cosmoO_setRawObject(state, object, key, val, _obj);
return true;
}
COSMO_API bool cosmoV_get(CState *state)
COSMO_API void cosmoV_get(CState *state)
{
CValue val;
StkPtr obj = cosmoV_getTop(state, 1); // object was pushed first
@@ -546,20 +537,17 @@ COSMO_API bool cosmoV_get(CState *state)
if (!IS_REF(*obj)) {
cosmoV_error(state, "Couldn't get field from type %s!", cosmoV_typeStr(*obj));
return false;
}
if (!cosmoV_rawget(state, cosmoV_readRef(*obj), *key, &val))
return false;
cosmoV_rawget(state, cosmoV_readRef(*obj), *key, &val);
// pop the obj & key, push the value
cosmoV_setTop(state, 2);
cosmoV_pushValue(state, val);
return true;
}
// yes, this would technically make it possible to set fields of types other than <string>. go crazy
COSMO_API bool cosmoV_set(CState *state)
COSMO_API void cosmoV_set(CState *state)
{
StkPtr obj = cosmoV_getTop(state, 2); // object was pushed first
StkPtr key = cosmoV_getTop(state, 1); // then the key
@@ -567,21 +555,17 @@ COSMO_API bool cosmoV_set(CState *state)
if (!IS_REF(*obj)) {
cosmoV_error(state, "Couldn't set field on type %s!", cosmoV_typeStr(*obj));
return false;
}
if (!cosmoV_rawset(state, cosmoV_readRef(*obj), *key, *val))
return false;
cosmoV_rawset(state, cosmoV_readRef(*obj), *key, *val);
// pop the obj, key & value
cosmoV_setTop(state, 3);
return true;
}
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val)
COSMO_API void cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val)
{
if (!cosmoV_rawget(state, obj, key, val))
return false;
cosmoV_rawget(state, obj, key, val);
// if the result is callable, wrap it in an method
if (IS_CALLABLE(*val)) {
@@ -591,8 +575,6 @@ COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *va
cosmoV_pop(state); // pop the object
*val = cosmoV_newRef(method);
}
return true;
}
int _tbl__next(CState *state, int nargs, CValue *args)
@@ -696,7 +678,7 @@ static inline uint16_t READUINT(CCallFrame *frame)
# define SWITCH switch (READBYTE(frame))
# define DEFAULT \
default: \
CERROR("unknown opcode!"); \
printf("[ERROR] unknown opcode!"); \
exit(0)
#endif
@@ -849,7 +831,6 @@ int cosmoV_execute(CState *state)
// sanity check
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't index type %s!", cosmoV_typeStr(*temp));
return -1;
}
CObj *obj = cosmoV_readRef(*temp);
@@ -858,9 +839,7 @@ int cosmoV_execute(CState *state)
if (proto != NULL) {
// check for __index metamethod
if (!cosmoO_indexObject(state, proto, *key,
&val)) // if returns false, cosmoV_error was called
return -1;
cosmoO_indexObject(state, proto, *key, &val);
} else if (obj->type == COBJ_TABLE) {
CObjTable *tbl = (CObjTable *)obj;
@@ -868,7 +847,6 @@ int cosmoV_execute(CState *state)
} else {
cosmoV_error(state, "No proto defined! Couldn't __index from type %s",
cosmoV_typeStr(*temp));
return -1;
}
cosmoV_setTop(state, 2); // pops the table & the key
@@ -883,17 +861,13 @@ int cosmoV_execute(CState *state)
// sanity check
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't set index with type %s!", cosmoV_typeStr(*temp));
return -1;
}
CObj *obj = cosmoV_readRef(*temp);
CObjObject *proto = cosmoO_grabProto(obj);
if (proto != NULL) {
if (!cosmoO_newIndexObject(
state, proto, *key,
*value)) // if it returns false, cosmoV_error was called
return -1;
cosmoO_newIndexObject(state, proto, *key, *value);
} else if (obj->type == COBJ_TABLE) {
CObjTable *tbl = (CObjTable *)obj;
CValue *newVal = cosmoT_insert(state, &tbl->tbl, *key);
@@ -902,7 +876,6 @@ int cosmoV_execute(CState *state)
} else {
cosmoV_error(state, "No proto defined! Couldn't __newindex from type %s",
cosmoV_typeStr(*temp));
return -1;
}
// pop everything off the stack
@@ -921,13 +894,11 @@ int cosmoV_execute(CState *state)
// sanity check
if (IS_REF(*temp)) {
if (!cosmoV_rawset(state, cosmoV_readRef(*temp), constants[ident], *value))
return -1;
cosmoV_rawset(state, cosmoV_readRef(*temp), constants[ident], *value);
} else {
CObjString *field = cosmoV_toString(state, constants[ident]);
cosmoV_error(state, "Couldn't set field '%s' on type %s!", field->str,
cosmoV_typeStr(*temp));
return -1;
}
// pop everything off the stack
@@ -941,13 +912,11 @@ int cosmoV_execute(CState *state)
// sanity check
if (IS_REF(*temp)) {
if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val))
return -1;
cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val);
} else {
CObjString *field = cosmoV_toString(state, constants[ident]);
cosmoV_error(state, "Couldn't get field '%s' from type %s!", field->str,
cosmoV_typeStr(*temp));
return -1;
}
cosmoV_setTop(state, 1); // pops the object
@@ -962,13 +931,11 @@ int cosmoV_execute(CState *state)
// this is almost identical to GETOBJECT, however cosmoV_getMethod is used instead
// of just cosmoV_get
if (IS_REF(*temp)) {
if (!cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val))
return -1;
cosmoV_getMethod(state, cosmoV_readRef(*temp), constants[ident], &val);
} else {
CObjString *field = cosmoV_toString(state, constants[ident]);
cosmoV_error(state, "Couldn't get field '%s' from type %s!", field->str,
cosmoV_typeStr(*temp));
return -1;
}
cosmoV_setTop(state, 1); // pops the object
@@ -985,14 +952,12 @@ int cosmoV_execute(CState *state)
// sanity check
if (IS_REF(*temp)) {
// get the field from the object
if (!cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val))
return -1;
cosmoV_rawget(state, cosmoV_readRef(*temp), constants[ident], &val);
// now invoke the method!
invokeMethod(state, cosmoV_readRef(*temp), val, args, nres, 1);
} else {
cosmoV_error(state, "Couldn't get from type %s!", cosmoV_typeStr(*temp));
return -1;
}
}
CASE(OP_ITER) :
@@ -1002,7 +967,6 @@ int cosmoV_execute(CState *state)
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't iterate over non-iterator type %s!",
cosmoV_typeStr(*temp));
return -1;
}
CObj *obj = cosmoV_readRef(*temp);
@@ -1026,7 +990,6 @@ int cosmoV_execute(CState *state)
"Expected iterable object! '__iter' returned %s, expected "
"<object>!",
cosmoV_typeStr(*iObj));
return -1;
}
// get __next method and place it at the top of the stack
@@ -1034,7 +997,6 @@ int cosmoV_execute(CState *state)
cosmoV_newRef(state->iStrings[ISTRING_NEXT]), iObj);
} else {
cosmoV_error(state, "Expected iterable object! '__iter' not defined!");
return -1;
}
} else if (obj->type == COBJ_TABLE) {
CObjTable *tbl = (CObjTable *)obj;
@@ -1059,7 +1021,6 @@ int cosmoV_execute(CState *state)
} else {
cosmoV_error(state, "No proto defined! Couldn't get from type %s",
cosmoO_typeStr(obj));
return -1;
}
}
CASE(OP_NEXT) :
@@ -1071,7 +1032,6 @@ int cosmoV_execute(CState *state)
if (!IS_METHOD(*temp)) {
cosmoV_error(state, "Expected '__next' to be a method, got type %s!",
cosmoV_typeStr(*temp));
return -1;
}
cosmoV_pushValue(state, *temp);
@@ -1114,7 +1074,6 @@ int cosmoV_execute(CState *state)
} else {
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA),
cosmoV_typeStr(*valB));
return -1;
}
}
CASE(OP_POW) :
@@ -1128,7 +1087,6 @@ int cosmoV_execute(CState *state)
} else {
cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA),
cosmoV_typeStr(*valB));
return -1;
}
}
CASE(OP_NOT) :
@@ -1144,7 +1102,6 @@ int cosmoV_execute(CState *state)
cosmoV_pushNumber(state, -(cosmoV_readNumber(*val)));
} else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
return -1;
}
}
CASE(OP_COUNT) :
@@ -1153,7 +1110,6 @@ int cosmoV_execute(CState *state)
if (!IS_REF(*temp)) {
cosmoV_error(state, "Expected non-primitive, got %s!", cosmoV_typeStr(*temp));
return -1;
}
int count = cosmoO_count(state, cosmoV_readRef(*temp));
@@ -1178,7 +1134,6 @@ int cosmoV_execute(CState *state)
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
} else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
return -1;
}
}
CASE(OP_INCGLOBAL) :
@@ -1194,7 +1149,6 @@ int cosmoV_execute(CState *state)
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
} else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
return -1;
}
}
CASE(OP_INCUPVAL) :
@@ -1209,7 +1163,6 @@ int cosmoV_execute(CState *state)
*val = cosmoV_newNumber(cosmoV_readNumber(*val) + inc);
} else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
return -1;
}
}
CASE(OP_INCINDEX) :
@@ -1221,7 +1174,6 @@ int cosmoV_execute(CState *state)
if (!IS_REF(*temp)) {
cosmoV_error(state, "Couldn't index non-indexable type %s!",
cosmoV_typeStr(*temp));
return -1;
}
CObj *obj = cosmoV_readRef(*temp);
@@ -1230,27 +1182,23 @@ int cosmoV_execute(CState *state)
// call __index if the proto was found
if (proto != NULL) {
if (cosmoO_indexObject(state, proto, *key, &val)) {
if (!IS_NUMBER(val)) {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
return -1;
}
cosmoO_indexObject(state, proto, *key, &val);
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
if (!IS_NUMBER(val)) {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
}
// call __newindex
if (!cosmoO_newIndexObject(state, proto, *key,
cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
return -1;
} else
return -1; // cosmoO_indexObject failed and threw an error
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
// call __newindex
cosmoO_newIndexObject(state, proto, *key,
cosmoV_newNumber(cosmoV_readNumber(val) + inc));
} else if (obj->type == COBJ_TABLE) {
CObjTable *tbl = (CObjTable *)obj;
CValue *val = cosmoT_insert(state, &tbl->tbl, *key);
if (!IS_NUMBER(*val)) {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(*val));
return -1;
}
// pops tbl & key from stack
@@ -1260,7 +1208,6 @@ int cosmoV_execute(CState *state)
} else {
cosmoV_error(state, "No proto defined! Couldn't __index from type %s",
cosmoV_typeStr(*temp));
return -1;
}
}
CASE(OP_INCOBJECT) :
@@ -1275,8 +1222,7 @@ int cosmoV_execute(CState *state)
CObj *obj = cosmoV_readRef(*temp);
CValue val;
if (!cosmoV_rawget(state, obj, ident, &val))
return -1;
cosmoV_rawget(state, obj, ident, &val);
// pop the object off the stack
cosmoV_pop(state);
@@ -1284,16 +1230,13 @@ int cosmoV_execute(CState *state)
// check that it's a number value
if (IS_NUMBER(val)) {
cosmoV_pushValue(state, val); // pushes old value onto the stack :)
if (!cosmoV_rawset(state, obj, ident,
cosmoV_newNumber(cosmoV_readNumber(val) + inc)))
return -1;
cosmoV_rawset(state, obj, ident,
cosmoV_newNumber(cosmoV_readNumber(val) + inc));
} else {
cosmoV_error(state, "Expected number, got %s!", cosmoV_typeStr(val));
return -1;
}
} else {
cosmoV_error(state, "Couldn't set a field on type %s!", cosmoV_typeStr(*temp));
return -1;
}
}
CASE(OP_EQUAL) :

View File

@@ -67,27 +67,17 @@ COSMO_API bool cosmoV_compileString(CState *state, const char *src, const char *
COSMO_API bool cosmoV_undump(CState *state, cosmo_Reader reader, const void *ud);
/*
expects object to be pushed, then the key.
returns false if an error was thrown, returns true if the value was pushed onto the stack and
the object and key were popped
expects object to be pushed, then the key. pops the key & object and pushes the value
*/
COSMO_API bool cosmoV_get(CState *state);
COSMO_API void cosmoV_get(CState *state);
/*
expects object to be pushed, then the key, and finally the new value.
returns false if an error was thrown, returns true if the value was set and the object key, and
value were popped
expects object to be pushed, then the key, and finally the new value. pops the key & object
*/
COSMO_API bool cosmoV_set(CState *state);
COSMO_API void cosmoV_set(CState *state);
// wraps the closure into a CObjMethod, so the function is called as an invoked method
COSMO_API bool cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);
// clears the stack, callstack and restores the state into a usable state after a calloverflow or
// another hard to recover error (keeps the global table intact)
COSMO_API bool cosmoV_restore(CState *state);
COSMO_API void cosmoV_getMethod(CState *state, CObj *obj, CValue key, CValue *val);
// nice to have wrappers

379
util/linenoise-win32.c Normal file
View File

@@ -0,0 +1,379 @@
/* this code is not standalone
* it is included into linenoise.c
* for windows.
* It is deliberately kept separate so that
* applications that have no need for windows
* support can omit this
*/
static DWORD orig_consolemode = 0;
static int flushOutput(struct current *current);
static void outputNewline(struct current *current);
static void refreshStart(struct current *current)
{
(void)current;
}
static void refreshEnd(struct current *current)
{
(void)current;
}
static void refreshStartChars(struct current *current)
{
assert(current->output == NULL);
/* We accumulate all output here */
current->output = sb_alloc();
#ifdef USE_UTF8
current->ubuflen = 0;
#endif
}
static void refreshNewline(struct current *current)
{
DRL("<nl>");
outputNewline(current);
}
static void refreshEndChars(struct current *current)
{
assert(current->output);
flushOutput(current);
sb_free(current->output);
current->output = NULL;
}
static int enableRawMode(struct current *current) {
DWORD n;
INPUT_RECORD irec;
current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
current->inh = GetStdHandle(STD_INPUT_HANDLE);
if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
return -1;
}
if (getWindowSize(current) != 0) {
return -1;
}
if (GetConsoleMode(current->inh, &orig_consolemode)) {
SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
}
#ifdef USE_UTF8
/* XXX is this the right thing to do? */
SetConsoleCP(65001);
#endif
return 0;
}
static void disableRawMode(struct current *current)
{
SetConsoleMode(current->inh, orig_consolemode);
}
void linenoiseClearScreen(void)
{
/* XXX: This is ugly. Should just have the caller pass a handle */
struct current current;
current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
if (getWindowSize(&current) == 0) {
COORD topleft = { 0, 0 };
DWORD n;
FillConsoleOutputCharacter(current.outh, ' ',
current.cols * current.rows, topleft, &n);
FillConsoleOutputAttribute(current.outh,
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
current.cols * current.rows, topleft, &n);
SetConsoleCursorPosition(current.outh, topleft);
}
}
static void cursorToLeft(struct current *current)
{
COORD pos;
DWORD n;
pos.X = 0;
pos.Y = (SHORT)current->y;
FillConsoleOutputAttribute(current->outh,
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
current->x = 0;
}
#ifdef USE_UTF8
static void flush_ubuf(struct current *current)
{
COORD pos;
DWORD nwritten;
pos.Y = (SHORT)current->y;
pos.X = (SHORT)current->x;
SetConsoleCursorPosition(current->outh, pos);
WriteConsoleW(current->outh, current->ubuf, current->ubuflen, &nwritten, 0);
current->x += current->ubufcols;
current->ubuflen = 0;
current->ubufcols = 0;
}
static void add_ubuf(struct current *current, int ch)
{
/* This code originally by: Author: Mark E. Davis, 1994. */
static const int halfShift = 10; /* used for shifting by 10 bits */
static const DWORD halfBase = 0x0010000UL;
static const DWORD halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START 0xD800
#define UNI_SUR_HIGH_END 0xDBFF
#define UNI_SUR_LOW_START 0xDC00
#define UNI_SUR_LOW_END 0xDFFF
#define UNI_MAX_BMP 0x0000FFFF
if (ch > UNI_MAX_BMP) {
/* convert from unicode to utf16 surrogate pairs
* There is always space for one extra word in ubuf
*/
ch -= halfBase;
current->ubuf[current->ubuflen++] = (WORD)((ch >> halfShift) + UNI_SUR_HIGH_START);
current->ubuf[current->ubuflen++] = (WORD)((ch & halfMask) + UNI_SUR_LOW_START);
}
else {
current->ubuf[current->ubuflen++] = ch;
}
current->ubufcols += utf8_width(ch);
if (current->ubuflen >= UBUF_MAX_CHARS) {
flush_ubuf(current);
}
}
#endif
static int flushOutput(struct current *current)
{
const char *pt = sb_str(current->output);
int len = sb_len(current->output);
#ifdef USE_UTF8
/* convert utf8 in current->output into utf16 in current->ubuf
*/
while (len) {
int ch;
int n = utf8_tounicode(pt, &ch);
pt += n;
len -= n;
add_ubuf(current, ch);
}
flush_ubuf(current);
#else
DWORD nwritten;
COORD pos;
pos.Y = (SHORT)current->y;
pos.X = (SHORT)current->x;
SetConsoleCursorPosition(current->outh, pos);
WriteConsoleA(current->outh, pt, len, &nwritten, 0);
current->x += len;
#endif
sb_clear(current->output);
return 0;
}
static int outputChars(struct current *current, const char *buf, int len)
{
if (len < 0) {
len = strlen(buf);
}
assert(current->output);
sb_append_len(current->output, buf, len);
return 0;
}
static void outputNewline(struct current *current)
{
/* On the last row output a newline to force a scroll */
if (current->y + 1 == current->rows) {
outputChars(current, "\n", 1);
}
flushOutput(current);
current->x = 0;
current->y++;
}
static void setOutputHighlight(struct current *current, const int *props, int nprops)
{
int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
int bold = 0;
int reverse = 0;
int i;
for (i = 0; i < nprops; i++) {
switch (props[i]) {
case 0:
colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
bold = 0;
reverse = 0;
break;
case 1:
bold = FOREGROUND_INTENSITY;
break;
case 7:
reverse = 1;
break;
case 30:
colour = 0;
break;
case 31:
colour = FOREGROUND_RED;
break;
case 32:
colour = FOREGROUND_GREEN;
break;
case 33:
colour = FOREGROUND_RED | FOREGROUND_GREEN;
break;
case 34:
colour = FOREGROUND_BLUE;
break;
case 35:
colour = FOREGROUND_RED | FOREGROUND_BLUE;
break;
case 36:
colour = FOREGROUND_BLUE | FOREGROUND_GREEN;
break;
case 37:
colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
break;
}
}
flushOutput(current);
if (reverse) {
SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
}
else {
SetConsoleTextAttribute(current->outh, colour | bold);
}
}
static void eraseEol(struct current *current)
{
COORD pos;
DWORD n;
pos.X = (SHORT) current->x;
pos.Y = (SHORT) current->y;
FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
}
static void setCursorXY(struct current *current)
{
COORD pos;
pos.X = (SHORT) current->x;
pos.Y = (SHORT) current->y;
SetConsoleCursorPosition(current->outh, pos);
}
static void setCursorPos(struct current *current, int x)
{
current->x = x;
setCursorXY(current);
}
static void cursorUp(struct current *current, int n)
{
current->y -= n;
setCursorXY(current);
}
static void cursorDown(struct current *current, int n)
{
current->y += n;
setCursorXY(current);
}
static int fd_read(struct current *current)
{
while (1) {
INPUT_RECORD irec;
DWORD n;
if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
break;
}
if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
break;
}
if (irec.EventType == KEY_EVENT) {
KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
if (k->bKeyDown || k->wVirtualKeyCode == VK_MENU) {
if (k->dwControlKeyState & ENHANCED_KEY) {
switch (k->wVirtualKeyCode) {
case VK_LEFT:
return SPECIAL_LEFT;
case VK_RIGHT:
return SPECIAL_RIGHT;
case VK_UP:
return SPECIAL_UP;
case VK_DOWN:
return SPECIAL_DOWN;
case VK_INSERT:
return SPECIAL_INSERT;
case VK_DELETE:
return SPECIAL_DELETE;
case VK_HOME:
return SPECIAL_HOME;
case VK_END:
return SPECIAL_END;
case VK_PRIOR:
return SPECIAL_PAGE_UP;
case VK_NEXT:
return SPECIAL_PAGE_DOWN;
case VK_RETURN:
return k->uChar.UnicodeChar;
}
}
/* Note that control characters are already translated in AsciiChar */
else if (k->wVirtualKeyCode == VK_CONTROL)
continue;
else {
return k->uChar.UnicodeChar;
}
}
}
}
return -1;
}
static int getWindowSize(struct current *current)
{
CONSOLE_SCREEN_BUFFER_INFO info;
if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
return -1;
}
current->cols = info.dwSize.X;
current->rows = info.dwSize.Y;
if (current->cols <= 0 || current->rows <= 0) {
current->cols = 80;
return -1;
}
current->y = info.dwCursorPosition.Y;
current->x = info.dwCursorPosition.X;
return 0;
}

2786
util/linenoise.c Normal file

File diff suppressed because it is too large Load Diff

152
util/linenoise.h Normal file
View File

@@ -0,0 +1,152 @@
/* linenoise.h -- guerrilla line editing library against the idea that a
* line editing lib needs to be 20,000 lines of C code.
*
* See linenoise.c for more information.
*
* ------------------------------------------------------------------------
*
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LINENOISE_H
#define __LINENOISE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include <string.h>
#ifndef NO_COMPLETION
typedef struct linenoiseCompletions {
size_t len;
char **cvec;
} linenoiseCompletions;
/*
* The callback type for tab completion handlers.
*/
typedef void(linenoiseCompletionCallback)(const char *prefix, linenoiseCompletions *comp, void *userdata);
/*
* Sets the current tab completion handler and returns the previous one, or NULL
* if no prior one has been set.
*/
linenoiseCompletionCallback * linenoiseSetCompletionCallback(linenoiseCompletionCallback *comp, void *userdata);
/*
* Adds a copy of the given string to the given completion list. The copy is owned
* by the linenoiseCompletions object.
*/
void linenoiseAddCompletion(linenoiseCompletions *comp, const char *str);
typedef char*(linenoiseHintsCallback)(const char *, int *color, int *bold, void *userdata);
typedef void(linenoiseFreeHintsCallback)(void *hint, void *userdata);
void linenoiseSetHintsCallback(linenoiseHintsCallback *callback, void *userdata);
void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *callback);
#endif
/*
* Prompts for input using the given string as the input
* prompt. Returns when the user has tapped ENTER or (on an empty
* line) EOF (Ctrl-D on Unix, Ctrl-Z on Windows). Returns either
* a copy of the entered string (for ENTER) or NULL (on EOF). The
* caller owns the returned string and must eventually free() it.
*/
char *linenoise(const char *prompt);
/**
* Like linenoise() but starts with an initial buffer.
*/
char *linenoiseWithInitial(const char *prompt, const char *initial);
/**
* Clear the screen.
*/
void linenoiseClearScreen(void);
/*
* Adds a copy of the given line of the command history.
*/
int linenoiseHistoryAdd(const char *line);
/*
* Sets the maximum length of the command history, in lines.
* If the history is currently longer, it will be trimmed,
* retaining only the most recent entries. If len is 0 or less
* then this function does nothing.
*/
int linenoiseHistorySetMaxLen(int len);
/*
* Returns the current maximum length of the history, in lines.
*/
int linenoiseHistoryGetMaxLen(void);
/*
* Saves the current contents of the history to the given file.
* Returns 0 on success.
*/
int linenoiseHistorySave(const char *filename);
/*
* Replaces the current history with the contents
* of the given file. Returns 0 on success.
*/
int linenoiseHistoryLoad(const char *filename);
/*
* Frees all history entries, clearing the history.
*/
void linenoiseHistoryFree(void);
/*
* Returns a pointer to the list of history entries, writing its
* length to *len if len is not NULL. The memory is owned by linenoise
* and must not be freed.
*/
char **linenoiseHistory(int *len);
/*
* Returns the number of display columns in the current terminal.
*/
int linenoiseColumns(void);
/**
* Enable or disable multiline mode (disabled by default)
*/
void linenoiseSetMultiLine(int enableml);
#ifdef __cplusplus
}
#endif
#endif /* __LINENOISE_H */