feat: add NULL type and literal union type

This commit is contained in:
Matthieu Bessat 2022-05-17 09:01:58 +02:00
parent 0ced372a77
commit 06260d0a8f
12 changed files with 125 additions and 68 deletions

View file

@ -31,8 +31,8 @@ ToDo List:
- [ ] add inclusive operators like '!=', '>=', '<=' - [ ] add inclusive operators like '!=', '>=', '<='
- [ ] add support for priority operators - [ ] add support for priority operators
- [X] add input_number() std function - [X] add input_number() std function
- [ ] add null type (dirty way to handle no returns and some errors) - [X] add NULL type (dirty way to handle no returns and some errors)
- [ ] add type() std function and others type checking functions - [X] add type() std function and others type checking functions
- [X] add ceil() and floor() std functions - [X] add ceil() and floor() std functions
- [X] base of the CLI - [X] base of the CLI
- [ ] evaluate expression from stdin - [ ] evaluate expression from stdin
@ -49,6 +49,7 @@ ToDo List:
- [ ] add fully features strings support - [ ] add fully features strings support
- [ ] add [classic problem solving](https://rosettacode.org) with code examples - [ ] add [classic problem solving](https://rosettacode.org) with code examples
- [ ] add Web Assembly support and publish a demo website - [ ] add Web Assembly support and publish a demo website
- [ ] refactor: use malloc for list
- [ ] refactor: remove inconsistency on how functions returns error codes - [ ] refactor: remove inconsistency on how functions returns error codes
## Installation ## Installation
@ -151,8 +152,7 @@ random_int(min, max)
random_float(min, max) random_float(min, max)
type(var) -> return the type of a var as int type(var) -> return the type of a var as int
is_null(var) is_null(var)
is_int(var) is_number(var)
is_float(var)
print_string(str) print_string(str)
print_newline() print_newline()
print_ascii(nb) print_ascii(nb)

View file

@ -170,7 +170,7 @@ int evaluator_reduce_parenthesis_pattern(struct List* evalList) {
if ( if (
((i >= 1 && list_get_type(evalList, i-1) != TYPE_FUNC_NAME) || (i == 0)) && ((i >= 1 && list_get_type(evalList, i-1) != TYPE_FUNC_NAME) || (i == 0)) &&
list_get_type(evalList, i) == TYPE_OPEN_PARENTHESIS && 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 list_get_type(evalList, i+2) == TYPE_CLOSE_PARENTHESIS
) { ) {
patternPos = i; 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); 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)]; byte varVal[get_size_of_type(type)];
var_store_copy_from_key(state->varStore, varKey, &varVal); var_store_copy_from_key(state->varStore, varKey, &varVal);
@ -288,7 +288,7 @@ int evaluator_reduce_function_call(struct List* evalList, int initialPosition) {
} }
if ( 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 list_get_type(evalList, pos+1) == TYPE_COMMA
) { ) {
// this is a new argument // this is a new argument
@ -297,7 +297,7 @@ int evaluator_reduce_function_call(struct List* evalList, int initialPosition) {
continue; continue;
} }
if ( 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 list_get_type(evalList, pos+1) == TYPE_CLOSE_PARENTHESIS
) { ) {
// we didn't match the last pattern so it's the last argument // 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"); 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); if (EVALUATOR_DEBUG_LEVEL >= 2) list_print(&evalList);
// int reduceVarOpStat = evaluator_reduce_var(state, &evalList); // int reduceVarOpStat = evaluator_reduce_var(state, &evalList);

View file

@ -2,7 +2,7 @@
#ifndef EVALUATOR_H_ #ifndef EVALUATOR_H_
#define 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); int evaluate(struct StateContainer* state, char* inputStr, int* resultPtr, unsigned char* typePtr);

View file

@ -5,6 +5,35 @@
#include "./config.h" #include "./config.h"
#include "./types.h" #include "./types.h"
#include "./utils.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) 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) int print_newline_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
{ {
UNUSED(types);
UNUSED(args);
*resType = TYPE_INT; *resType = TYPE_INT;
*res = 1; *res = 1;
printf("\n"); 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) int input_number_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
{ {
UNUSED(types);
UNUSED(args);
printf("? "); printf("? ");
char* line; 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); // printf("len=%d, lineSize=%d '%s' \n", len, lineSize, line);
char* toParse[lineSize+1]; char toParse[lineSize+1];
str_extract(toParse, line, 0, 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) { if (st == 0) {
*resType = TYPE_INT; *resType = TYPE_INT;
return 0; return 0;
} }
if (st != 0) { if (st != 0) {
st = parse_float(toParse, (float*) res); st = parse_float((char*) &toParse, (float*) res);
if (st == 0) { if (st == 0) {
*resType = TYPE_FLOAT; *resType = TYPE_FLOAT;
return 0; 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) int get_pi_impl(int* res, unsigned char* resType, unsigned char* types, int* args)
{ {
UNUSED(args);
UNUSED(types);
float val = CST_PI; float val = CST_PI;
*res = *(int *)(&val); *res = *(int *)(&val);
*resType = TYPE_FLOAT; *resType = TYPE_FLOAT;
@ -294,6 +330,10 @@ struct FuncIntro {
// void* are actually long! // void* are actually long!
struct FuncIntro intros[] = { struct FuncIntro intros[] = {
{"type", &type_impl, 1},
{"is_null", &is_null_impl, 1},
{"is_number", &is_number_impl, 1},
{"abs", &abs_impl, 1}, {"abs", &abs_impl, 1},
{"sqrt", &sqrt_impl, 1}, {"sqrt", &sqrt_impl, 1},

View file

@ -2,7 +2,7 @@
#ifndef LINE_PROCESSING_H_ #ifndef LINE_PROCESSING_H_
#define 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_IF 2
#define BLOCK_WHILE 3 #define BLOCK_WHILE 3

View file

@ -188,48 +188,12 @@ void list_print(struct List* list)
printf("=== LIST REPORT === \n"); printf("=== LIST REPORT === \n");
printf("num of elements: %d \n", list->num_elements); printf("num of elements: %d \n", list->num_elements);
for (int i = 0; i < list->num_elements; i++) { for (int i = 0; i < list->num_elements; i++) {
printf("- i: %d, ", i);
int type = list_get_type(list, i); int type = list_get_type(list, i);
if (type == TYPE_INT) { int data = 0;
int d = 0; list_get(list, i, &data);
list_get(list, i, &d);
printf("type: INT, val: %d", d); printf("- i: %d, %s \n", i, get_repr(type, (void*) &data));
}
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");
} }
printf("=== END === \n"); printf("=== END === \n");
} }

View file

@ -3,6 +3,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
int is_type_literal(byte type)
{
return is_type_number(type) || type == TYPE_NULL;
}
int is_type_number(byte type) int is_type_number(byte type)
{ {
return type == TYPE_INT || type == TYPE_FLOAT; return type == TYPE_INT || type == TYPE_FLOAT;
@ -25,6 +30,7 @@ int get_size_of_type(byte type)
return 1; return 1;
} }
if ( if (
t == TYPE_NULL ||
t == TYPE_OPEN_PARENTHESIS || t == TYPE_OPEN_PARENTHESIS ||
t == TYPE_CLOSE_PARENTHESIS || t == TYPE_CLOSE_PARENTHESIS ||
t == TYPE_COMMA t == TYPE_COMMA
@ -36,25 +42,36 @@ int get_size_of_type(byte type)
char* get_repr(byte type, void* valPtr) 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) { if (type == 0) {
sprintf(res, "NO_TYPE");
} else if (type == TYPE_NULL) {
sprintf(res, "NULL"); sprintf(res, "NULL");
return res; } else if (type == TYPE_INT) {
}
if (type == TYPE_INT) {
sprintf(res, "INT(%d)", *((int*) valPtr)); sprintf(res, "INT(%d)", *((int*) valPtr));
return res; } else if (type == TYPE_FLOAT) {
}
if (type == TYPE_FLOAT) {
sprintf(res, "FLOAT(%f)", *((float*) valPtr)); 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; return res;
} }
int convert_to_int(byte type, int repr) { int convert_to_int(byte type, int repr) {
if (type == TYPE_NULL) return 0;
if (type == TYPE_FLOAT) return (int) *((int*) &repr); if (type == TYPE_FLOAT) return (int) *((int*) &repr);
return repr; return repr;
} }

View file

@ -2,6 +2,7 @@
#ifndef TYPES_H_ #ifndef TYPES_H_
#define TYPES_H_ #define TYPES_H_
#define TYPE_NULL 1
#define TYPE_INT 2 #define TYPE_INT 2
#define TYPE_FLOAT 3 #define TYPE_FLOAT 3
#define TYPE_OPERATOR 32 #define TYPE_OPERATOR 32
@ -11,10 +12,15 @@
#define TYPE_OPEN_PARENTHESIS 64 #define TYPE_OPEN_PARENTHESIS 64
#define TYPE_CLOSE_PARENTHESIS 65 #define TYPE_CLOSE_PARENTHESIS 65
int is_type_literal(byte type);
int is_type_number(byte type); int is_type_number(byte type);
int get_size_of_type(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); char* get_repr(byte type, void* data);
byte convert_to_bool(byte type, int repr); byte convert_to_bool(byte type, int repr);

View file

@ -3,6 +3,9 @@
#ifndef UTILS_H_ #ifndef UTILS_H_
#define 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 CST_PI 3.1415926535
// define custom type (unsigned char) // define custom type (unsigned char)

View file

@ -4,6 +4,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#define MAX_INTEGER 47797852
struct VariableStore* var_store_init() struct VariableStore* var_store_init()
{ {
struct VariableStore* store = (struct VariableStore*) malloc(sizeof(struct VariableStore)); 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++) { for (int i = 0; i < store->allocatedLength; i++) {
store->container[i].type = 0; store->container[i].type = 0;
} }
var_store_add_constants(store);
return 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) 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) byte var_store_set(struct VariableStore* store, char* varName, byte type, void* valuePtr)
{ {
//printf("set variable at var name: '%s' \n", varName); //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); printf("[ERR] VARSTORE: unsupported type, cannot store type %d\n", type);
return 0; return 0;
} }

View file

@ -32,6 +32,9 @@ struct VariableStore {
struct VariableStore* var_store_init(); 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); int var_store_hash_name(struct VariableStore* store, char* varName);
// get a pointer to the area of memory where is store the variable // get a pointer to the area of memory where is store the variable

View file

@ -175,4 +175,20 @@ void test_evaluation()
assert(resType == TYPE_INT); assert(resType == TYPE_INT);
printf("actually got: %d \n", resVal); printf("actually got: %d \n", resVal);
assert(7 == 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);
} }