feat: add NULL type and literal union type
This commit is contained in:
parent
0ced372a77
commit
06260d0a8f
12 changed files with 125 additions and 68 deletions
|
@ -31,8 +31,8 @@ ToDo List:
|
|||
- [ ] add inclusive operators like '!=', '>=', '<='
|
||||
- [ ] add support for priority operators
|
||||
- [X] add input_number() std function
|
||||
- [ ] add null type (dirty way to handle no returns and some errors)
|
||||
- [ ] add type() std function and others type checking functions
|
||||
- [X] add NULL type (dirty way to handle no returns and some errors)
|
||||
- [X] add type() std function and others type checking functions
|
||||
- [X] add ceil() and floor() std functions
|
||||
- [X] base of the CLI
|
||||
- [ ] evaluate expression from stdin
|
||||
|
@ -49,6 +49,7 @@ ToDo List:
|
|||
- [ ] add fully features strings support
|
||||
- [ ] add [classic problem solving](https://rosettacode.org) with code examples
|
||||
- [ ] add Web Assembly support and publish a demo website
|
||||
- [ ] refactor: use malloc for list
|
||||
- [ ] refactor: remove inconsistency on how functions returns error codes
|
||||
|
||||
## Installation
|
||||
|
@ -151,8 +152,7 @@ random_int(min, max)
|
|||
random_float(min, max)
|
||||
type(var) -> return the type of a var as int
|
||||
is_null(var)
|
||||
is_int(var)
|
||||
is_float(var)
|
||||
is_number(var)
|
||||
print_string(str)
|
||||
print_newline()
|
||||
print_ascii(nb)
|
||||
|
|
|
@ -170,7 +170,7 @@ int evaluator_reduce_parenthesis_pattern(struct List* evalList) {
|
|||
if (
|
||||
((i >= 1 && list_get_type(evalList, i-1) != TYPE_FUNC_NAME) || (i == 0)) &&
|
||||
list_get_type(evalList, i) == TYPE_OPEN_PARENTHESIS &&
|
||||
is_type_number(list_get_type(evalList, i+1)) &&
|
||||
is_type_literal(list_get_type(evalList, i+1)) &&
|
||||
list_get_type(evalList, i+2) == TYPE_CLOSE_PARENTHESIS
|
||||
) {
|
||||
patternPos = i;
|
||||
|
@ -208,7 +208,7 @@ int evaluator_reduce_var(struct StateContainer* state, struct List* evalList) {
|
|||
|
||||
byte type = var_store_get_type_from_key(state->varStore, varKey);
|
||||
|
||||
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("Going to reduce var key %d at pos %d\n", patternPos);
|
||||
if (EVALUATOR_DEBUG_LEVEL >= 2) printf("Going to reduce var key %d at pos %d\n", varKey, patternPos);
|
||||
|
||||
byte varVal[get_size_of_type(type)];
|
||||
var_store_copy_from_key(state->varStore, varKey, &varVal);
|
||||
|
@ -288,7 +288,7 @@ int evaluator_reduce_function_call(struct List* evalList, int initialPosition) {
|
|||
}
|
||||
|
||||
if (
|
||||
is_type_number(list_get_type(evalList, pos)) &&
|
||||
is_type_literal(list_get_type(evalList, pos)) &&
|
||||
list_get_type(evalList, pos+1) == TYPE_COMMA
|
||||
) {
|
||||
// this is a new argument
|
||||
|
@ -297,7 +297,7 @@ int evaluator_reduce_function_call(struct List* evalList, int initialPosition) {
|
|||
continue;
|
||||
}
|
||||
if (
|
||||
is_type_number(list_get_type(evalList, pos)) &&
|
||||
is_type_literal(list_get_type(evalList, pos)) &&
|
||||
list_get_type(evalList, pos+1) == TYPE_CLOSE_PARENTHESIS
|
||||
) {
|
||||
// we didn't match the last pattern so it's the last argument
|
||||
|
@ -572,7 +572,7 @@ int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsig
|
|||
printf("Now going to actually evaluate...\n");
|
||||
}
|
||||
|
||||
while (evalList.num_elements > 1 || !is_type_number(list_get_type(&evalList, 0))) {
|
||||
while (evalList.num_elements > 1 || !is_type_literal(list_get_type(&evalList, 0))) {
|
||||
if (EVALUATOR_DEBUG_LEVEL >= 2) list_print(&evalList);
|
||||
|
||||
// int reduceVarOpStat = evaluator_reduce_var(state, &evalList);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#ifndef EVALUATOR_H_
|
||||
#define EVALUATOR_H_
|
||||
|
||||
#define EVALUATOR_DEBUG_LEVEL 0
|
||||
#define EVALUATOR_DEBUG_LEVEL (G_DEBUG_LEVEL)
|
||||
|
||||
int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr);
|
||||
|
||||
|
|
48
src/funcs.c
48
src/funcs.c
|
@ -5,6 +5,35 @@
|
|||
#include "./config.h"
|
||||
#include "./types.h"
|
||||
#include "./utils.h"
|
||||
#include "./number_parsing.h"
|
||||
|
||||
// just return the type id of a variable
|
||||
int type_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
||||
{
|
||||
UNUSED(args);
|
||||
*resType = TYPE_INT;
|
||||
*res = types[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_null_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
||||
{
|
||||
UNUSED(args);
|
||||
*resType = TYPE_INT;
|
||||
*res = types[0] == TYPE_NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_number_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
||||
{
|
||||
UNUSED(args);
|
||||
*resType = TYPE_INT;
|
||||
*res = is_type_number(types[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int abs_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
||||
{
|
||||
|
@ -100,6 +129,9 @@ int print_ascii_impl(int* res, unsigned char* resType, unsigned char* types, int
|
|||
|
||||
int print_newline_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
||||
{
|
||||
UNUSED(types);
|
||||
UNUSED(args);
|
||||
|
||||
*resType = TYPE_INT;
|
||||
*res = 1;
|
||||
printf("\n");
|
||||
|
@ -109,6 +141,8 @@ int print_newline_impl(int* res, unsigned char* resType, unsigned char* types, i
|
|||
|
||||
int input_number_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
||||
{
|
||||
UNUSED(types);
|
||||
UNUSED(args);
|
||||
printf("? ");
|
||||
|
||||
char* line;
|
||||
|
@ -119,16 +153,16 @@ int input_number_impl(int* res, unsigned char* resType, unsigned char* types, in
|
|||
|
||||
// printf("len=%d, lineSize=%d '%s' \n", len, lineSize, line);
|
||||
|
||||
char* toParse[lineSize+1];
|
||||
str_extract(toParse, line, 0, lineSize-1);
|
||||
char toParse[lineSize+1];
|
||||
str_extract((char*) toParse, line, 0, lineSize-1);
|
||||
|
||||
int st = parse_int(toParse, res);
|
||||
int st = parse_int((char*) &toParse, res);
|
||||
if (st == 0) {
|
||||
*resType = TYPE_INT;
|
||||
return 0;
|
||||
}
|
||||
if (st != 0) {
|
||||
st = parse_float(toParse, (float*) res);
|
||||
st = parse_float((char*) &toParse, (float*) res);
|
||||
if (st == 0) {
|
||||
*resType = TYPE_FLOAT;
|
||||
return 0;
|
||||
|
@ -248,6 +282,8 @@ int max_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
|||
|
||||
int get_pi_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
|
||||
{
|
||||
UNUSED(args);
|
||||
UNUSED(types);
|
||||
float val = CST_PI;
|
||||
*res = *(int *)(&val);
|
||||
*resType = TYPE_FLOAT;
|
||||
|
@ -294,6 +330,10 @@ struct FuncIntro {
|
|||
// void* are actually long!
|
||||
|
||||
struct FuncIntro intros[] = {
|
||||
{"type", &type_impl, 1},
|
||||
{"is_null", &is_null_impl, 1},
|
||||
{"is_number", &is_number_impl, 1},
|
||||
|
||||
{"abs", &abs_impl, 1},
|
||||
|
||||
{"sqrt", &sqrt_impl, 1},
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#ifndef LINE_PROCESSING_H_
|
||||
#define LINE_PROCESSING_H_
|
||||
|
||||
#define LINE_PROCESSING_DEBUG_LEVEL 0
|
||||
#define LINE_PROCESSING_DEBUG_LEVEL (G_DEBUG_LEVEL)
|
||||
|
||||
#define BLOCK_IF 2
|
||||
#define BLOCK_WHILE 3
|
||||
|
|
46
src/list.c
46
src/list.c
|
@ -188,48 +188,12 @@ void list_print(struct List* list)
|
|||
printf("=== LIST REPORT === \n");
|
||||
printf("num of elements: %d \n", list->num_elements);
|
||||
for (int i = 0; i < list->num_elements; i++) {
|
||||
printf("- i: %d, ", i);
|
||||
|
||||
int type = list_get_type(list, i);
|
||||
if (type == TYPE_INT) {
|
||||
int d = 0;
|
||||
list_get(list, i, &d);
|
||||
|
||||
printf("type: INT, val: %d", d);
|
||||
}
|
||||
if (type == TYPE_FLOAT) {
|
||||
float d = 0;
|
||||
list_get(list, i, &d);
|
||||
|
||||
printf("type: FLOAT, val: %f", d);
|
||||
}
|
||||
if (type == TYPE_OPERATOR) {
|
||||
char d = 0;
|
||||
list_get(list, i, &d);
|
||||
|
||||
printf("type: OPERATOR, val: %d '%c'", d, d);
|
||||
}
|
||||
if (type == TYPE_FUNC_NAME) {
|
||||
short d = 0;
|
||||
list_get(list, i, &d);
|
||||
|
||||
printf("type: FUNC_NAME, val: %d", d);
|
||||
}
|
||||
if (type == TYPE_VAR_NAME) {
|
||||
short d = 0;
|
||||
list_get(list, i, &d);
|
||||
|
||||
printf("type: VAR_NAME, val: %d", d);
|
||||
}
|
||||
if (type == TYPE_OPEN_PARENTHESIS) {
|
||||
printf("type: OPEN_PARENTHESIS");
|
||||
}
|
||||
if (type == TYPE_COMMA) {
|
||||
printf("type: COMMA");
|
||||
}
|
||||
if (type == TYPE_CLOSE_PARENTHESIS) {
|
||||
printf("type: CLOSE_PARENTHESIS");
|
||||
}
|
||||
printf("\n");
|
||||
int data = 0;
|
||||
list_get(list, i, &data);
|
||||
|
||||
printf("- i: %d, %s \n", i, get_repr(type, (void*) &data));
|
||||
}
|
||||
printf("=== END === \n");
|
||||
}
|
||||
|
|
37
src/types.c
37
src/types.c
|
@ -3,6 +3,11 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int is_type_literal(byte type)
|
||||
{
|
||||
return is_type_number(type) || type == TYPE_NULL;
|
||||
}
|
||||
|
||||
int is_type_number(byte type)
|
||||
{
|
||||
return type == TYPE_INT || type == TYPE_FLOAT;
|
||||
|
@ -25,6 +30,7 @@ int get_size_of_type(byte type)
|
|||
return 1;
|
||||
}
|
||||
if (
|
||||
t == TYPE_NULL ||
|
||||
t == TYPE_OPEN_PARENTHESIS ||
|
||||
t == TYPE_CLOSE_PARENTHESIS ||
|
||||
t == TYPE_COMMA
|
||||
|
@ -36,25 +42,36 @@ int get_size_of_type(byte type)
|
|||
|
||||
char* get_repr(byte type, void* valPtr)
|
||||
{
|
||||
char* res= (char*) malloc(sizeof(char)*32);
|
||||
char* res = (char*) malloc(sizeof(char)*32);
|
||||
if (res == 0) return 0;
|
||||
if (type == 0) {
|
||||
sprintf(res, "NO_TYPE");
|
||||
} else if (type == TYPE_NULL) {
|
||||
sprintf(res, "NULL");
|
||||
return res;
|
||||
}
|
||||
if (type == TYPE_INT) {
|
||||
} else if (type == TYPE_INT) {
|
||||
sprintf(res, "INT(%d)", *((int*) valPtr));
|
||||
return res;
|
||||
}
|
||||
if (type == TYPE_FLOAT) {
|
||||
} else if (type == TYPE_FLOAT) {
|
||||
sprintf(res, "FLOAT(%f)", *((float*) valPtr));
|
||||
return res;
|
||||
} else if (type == TYPE_OPEN_PARENTHESIS) {
|
||||
sprintf(res, "OPEN_PARENTHESIS");
|
||||
} else if (type == TYPE_CLOSE_PARENTHESIS) {
|
||||
sprintf(res, "CLOSE_PARENTHESIS");
|
||||
} else if (type == TYPE_COMMA) {
|
||||
sprintf(res, "COMMA");
|
||||
} else if (type == TYPE_OPERATOR) {
|
||||
sprintf(res, "OPERATOR(%c)", *((char*) valPtr));
|
||||
} else if (type == TYPE_VAR_NAME) {
|
||||
sprintf(res, "VAR_NAME(ref: %d)", *((int*) valPtr));
|
||||
} else if (type == TYPE_FUNC_NAME) {
|
||||
sprintf(res, "FUNC_NAME(ref: %d)", *((int*) valPtr));
|
||||
} else {
|
||||
sprintf(res, "UNKNOWN type=%d", type);
|
||||
}
|
||||
|
||||
sprintf(res, "UNKNOWN type=%d", type);
|
||||
return res;
|
||||
}
|
||||
|
||||
int convert_to_int(byte type, int repr) {
|
||||
if (type == TYPE_NULL) return 0;
|
||||
if (type == TYPE_FLOAT) return (int) *((int*) &repr);
|
||||
return repr;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#ifndef TYPES_H_
|
||||
#define TYPES_H_
|
||||
|
||||
#define TYPE_NULL 1
|
||||
#define TYPE_INT 2
|
||||
#define TYPE_FLOAT 3
|
||||
#define TYPE_OPERATOR 32
|
||||
|
@ -11,10 +12,15 @@
|
|||
#define TYPE_OPEN_PARENTHESIS 64
|
||||
#define TYPE_CLOSE_PARENTHESIS 65
|
||||
|
||||
|
||||
int is_type_literal(byte type);
|
||||
|
||||
int is_type_number(byte type);
|
||||
|
||||
int get_size_of_type(byte type);
|
||||
|
||||
// get short string representation of a type
|
||||
// usefull when printing a report
|
||||
char* get_repr(byte type, void* data);
|
||||
|
||||
byte convert_to_bool(byte type, int repr);
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#ifndef UTILS_H_
|
||||
#define UTILS_H_
|
||||
|
||||
// useful to silent warning of gcc of uunused parameters in functions
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
#define CST_PI 3.1415926535
|
||||
|
||||
// define custom type (unsigned char)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_INTEGER 47797852
|
||||
|
||||
struct VariableStore* var_store_init()
|
||||
{
|
||||
struct VariableStore* store = (struct VariableStore*) malloc(sizeof(struct VariableStore));
|
||||
|
@ -21,10 +23,16 @@ struct VariableStore* var_store_init()
|
|||
for (int i = 0; i < store->allocatedLength; i++) {
|
||||
store->container[i].type = 0;
|
||||
}
|
||||
var_store_add_constants(store);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
#define MAX_INTEGER 47797852
|
||||
void var_store_add_constants(struct VariableStore* store)
|
||||
{
|
||||
// NULL constant
|
||||
var_store_set(store, "NULL", TYPE_NULL, 0);
|
||||
}
|
||||
|
||||
int var_store_hash_name(struct VariableStore* store, char* varName)
|
||||
{
|
||||
|
@ -42,7 +50,7 @@ int var_store_hash_name(struct VariableStore* store, char* varName)
|
|||
byte var_store_set(struct VariableStore* store, char* varName, byte type, void* valuePtr)
|
||||
{
|
||||
//printf("set variable at var name: '%s' \n", varName);
|
||||
if (!(type == TYPE_FLOAT || type == TYPE_INT)) {
|
||||
if (!(type == TYPE_FLOAT || type == TYPE_INT || type == TYPE_NULL)) {
|
||||
printf("[ERR] VARSTORE: unsupported type, cannot store type %d\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ struct VariableStore {
|
|||
|
||||
struct VariableStore* var_store_init();
|
||||
|
||||
// add to the store some useful constants (like NULL constructor)
|
||||
void var_store_add_constants(struct VariableStore* store);
|
||||
|
||||
int var_store_hash_name(struct VariableStore* store, char* varName);
|
||||
|
||||
// get a pointer to the area of memory where is store the variable
|
||||
|
|
|
@ -175,4 +175,20 @@ void test_evaluation()
|
|||
assert(resType == TYPE_INT);
|
||||
printf("actually got: %d \n", resVal);
|
||||
assert(7 == resVal);
|
||||
|
||||
evaluate(state, "is_number(123)", &resVal, &resType);
|
||||
assert(resType == TYPE_INT);
|
||||
assert(resVal);
|
||||
|
||||
evaluate(state, "is_number(-25.5)", &resVal, &resType);
|
||||
assert(resType == TYPE_INT);
|
||||
assert(resVal);
|
||||
|
||||
evaluate(state, "is_number(NULL)", &resVal, &resType);
|
||||
assert(resType == TYPE_INT);
|
||||
assert(!resVal);
|
||||
|
||||
evaluate(state, "is_null(NULL)", &resVal, &resType);
|
||||
assert(resType == TYPE_INT);
|
||||
assert(resVal);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue