Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • vlasami6/ni-run-template
  • chybijan/ni-run
  • ruzict16/FML
  • rozhovoj/ni-run-template
  • skrabmir/cfml
  • plodeada/ni-run-plodeada
  • stepam38/ni-run
  • hrncikar/ni-run
  • balikvo1/ni-run
9 results
Show changes
Commits on Source (19)
......@@ -2,8 +2,25 @@ image: $CI_REGISTRY/vlasami6/fmltest:master
 
test:
script:
- meson setup build
- meson compile -C build
- cppcheck --error-exitcode=1 *.c
- env FML="$(readlink -f ./build/fml)" FML_REF_BC_INT=/cfml/fml /FMLtest/suite ast_interpret
hello_world.fml
- make
#- cppcheck --error-exitcode=1 *.c
- env FML="$(readlink -f ./fml)" FML_REF_BC_INT=/cfml/fml /FMLtest/suite ast_interpret
$(/FMLtest/suite show fml)
#hello_world
#literals
#variables
#conditionals
#loops
#functions
#function_value
#builtins
#arrays
#iterator
#fibonacci
#fizzbuzz_fun
#fizzbuzz_loop
#roman
#stack
#brainfuck
#langtons_ant
#sudoku
CC=gcc
CFLAGS=-Wall -pedantic -Wextra -g #-fsanitize=address,undefined
LFLAGS=
OUTPUT=fml
SRC_DIR=./src
BUILD_DIR=./build
.PHONY: init fml
all: init fml
fml: $(BUILD_DIR)/arena.o $(BUILD_DIR)/parser.o $(BUILD_DIR)/ast_interpreter.o $(SRC_DIR)/fml.c #$(BUILD_DIR)/%.o
$(CC) $(CFLAGS) $(LFLAGS) $? -o $(OUTPUT)
%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/ast_interpreter.o: $(SRC_DIR)/parser.o $(SRC_DIR)/ast_interpreter.c
$(CC) $(CFLAGS) -c $? -o $@
$(BUILD_DIR)/parser.o: $(SRC_DIR)/parser.c
$(CC) $(CFLAGS) -c $< -o $@
$(BUILD_DIR)/arena.o: $(SRC_DIR)/arena.c
$(CC) $(CFLAGS) -c $< -o $@
init:
mkdir -p build
File moved
File moved
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include "parser.h"
#include "ast_interpreter.h"
bool value_to_bool ( Value * value ) {
if ( value -> kind == VALUE_NULL )
return false;
if ( value -> kind == VALUE_BOOLEAN )
return ((BoolValue*) value ) -> boolean;
return true;
}
void env_push ( ASTInterpreterState * state ) {
Environment * env = (Environment*) malloc ( sizeof (Environment) );
(*env) = (Environment) { .prev = state -> current_env, .start = NULL };
state -> current_env = env;
}
void env_pop ( ASTInterpreterState * state ) {
Environment * tmp = state -> current_env;
EnvironmentEntry * entry;
EnvironmentEntry * next = tmp -> start;
while ( (entry = next) ) {
next = entry -> next;
free ( entry );
}
state -> current_env = tmp -> prev;
free (tmp);
}
void env_put ( ASTInterpreterState * state, Str name, Value * value ) {
Environment * env = state -> current_env;
EnvironmentEntry * entry;
while ( env ) {
entry = env -> start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) ) {
entry -> value = value;
return;
}
entry = entry -> next;
}
env = env -> prev;
}
entry = state -> global_env . start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) ) {
entry -> value = value;
return;
}
entry = entry -> next;
}
env = state -> current_env;
env = env ? env : & state -> global_env;
entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
(*entry) = (EnvironmentEntry) {.name = name, .value = value, .next = env -> start };
env -> start = entry;
}
void env_def ( ASTInterpreterState * state, Str name, Value * value ) {
Environment * env = state -> current_env ? state -> current_env : & state -> global_env;
EnvironmentEntry * parent = NULL;
EnvironmentEntry * entry = env -> start;
while ( entry ) {
if ( str_eq ( name, entry -> name ) ) {
entry -> value = value;
return;
}
parent = entry;
entry = entry -> next;
}
entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
entry -> name = name;
entry -> value = value;
entry -> next = NULL;
if ( parent )
parent -> next = entry;
else
env -> start = entry;
}
Value * env_get ( ASTInterpreterState * state, Str name ) {
Environment * env = state -> current_env;
EnvironmentEntry * entry;
while ( env ) {
entry = env -> start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) )
return entry -> value;
entry = entry -> next;
}
env = env -> prev;
}
entry = state -> global_env . start;
while ( entry ) {
if ( str_eq ( entry -> name, name ) )
return entry -> value;
entry = entry -> next;
}
env = state -> current_env;
env = env ? env : & state -> global_env;
entry = (EnvironmentEntry*) malloc ( sizeof (EnvironmentEntry) );
(*entry) = (EnvironmentEntry) {.name = name, .value = make_null ( state ), .next = env -> start };
env -> start = entry;
return entry -> value;
}
void * heap_alloc_alligned ( Heap * heap, size_t len, size_t align ) {
size_t pos = (size_t) heap -> next;
size_t rem = pos % align;
if ( rem )
heap -> next = heap -> next + align - rem;
if ( heap -> next + len >= heap -> end )
return NULL;
void * ret = heap -> next;
heap -> next += len;
return ret;
}
void * heap_alloc ( Heap * heap, size_t len ) {
size_t pos = (size_t) heap -> next;
size_t rem = pos % 8;
if ( rem )
heap -> next = heap -> next + 8 - rem;
if ( heap -> next + len >= heap -> end )
return NULL;
void * ret = heap -> next;
heap -> next += len;
return ret;
}
void heap_init ( Heap * heap, size_t heap_size ) {
heap -> begin = (u8*) malloc ( heap_size );
heap -> next = heap -> begin;
heap -> end = heap -> begin + heap_size;
}
void heap_destroy ( Heap * heap ) {
free ( heap -> begin );
}
void state_init ( ASTInterpreterState * state, Heap * heap ) {
state -> heap = heap;
state -> global_env . prev = NULL;
state -> global_env . start = NULL;
state -> current_env = NULL;
}
void state_destroy ( ASTInterpreterState * state ) {
heap_destroy ( state -> heap );
Environment * env = & state -> global_env;
EnvironmentEntry * entry;
EnvironmentEntry * next = env -> start;
while ( (entry = next) ) {
next = entry -> next;
free ( entry );
}
Environment * next_env = state -> current_env;
while ( (env = next_env) ) {
next = env -> start;
while ( (entry = next) ) {
next = entry -> next;
free ( entry );
}
next_env = env -> prev;
}
}
Value * make_null ( ASTInterpreterState * state ) {
NullValue * value = heap_alloc ( state -> heap, sizeof (NullValue) );
*value = (NullValue) { .kind = (Value) { .kind = VALUE_NULL } };
return (Value*) value;
}
Value * make_int ( ASTInterpreterState * state, i32 val ) {
IntValue * value = heap_alloc ( state -> heap, sizeof (IntValue) );
*value = (IntValue) { .kind = (Value) { .kind = VALUE_INTEGER }, .integer = val };
return (Value*) value;
}
Value * make_bool ( ASTInterpreterState * state, bool val ) {
BoolValue * value = heap_alloc ( state -> heap, sizeof (BoolValue) );
*value = (BoolValue) { .kind = (Value) { .kind = VALUE_BOOLEAN }, .boolean = val };
return (Value*) value;
}
Value * make_function ( ASTInterpreterState * state, AstFunction * function ) {
FunctionValue * value = heap_alloc ( state -> heap, sizeof (FunctionValue) );
*value = (FunctionValue) { .kind = (Value) { .kind = VALUE_FUNCTION }, .function = function };
return (Value*) value;
}
Value * make_array ( ASTInterpreterState * state, size_t len ) {
ArrayValue * value = heap_alloc ( state -> heap, sizeof (ArrayValue) + len * sizeof (Value*) );
*value = (ArrayValue) { .kind = (Value) { .kind = VALUE_ARRAY }, .length = len };
return (Value*) value;
}
Value * make_object ( ASTInterpreterState * state, size_t member_cnt ) {
ObjectValue * value = heap_alloc ( state -> heap, sizeof (ObjectValue) + member_cnt * sizeof (SimpleEntry) );
*value = (ObjectValue) { .kind = (Value) { .kind = VALUE_OBJECT }, .member_cnt = member_cnt };
return (Value*) value;
}
Value * get_base ( Value * object ) {
Value * curr = object;
while ( curr -> kind == VALUE_OBJECT )
curr = ((ObjectValue *) curr) -> extends;
return curr;
}
Value * try_operator ( ASTInterpreterState * state, Value * object, Value ** arguments, size_t argc, Str * name ) {
switch ( object -> kind ) {
case VALUE_INTEGER: {
if ( argc != 1 ) {
fprintf ( stderr, "Invalid argument count for integer operation %.*s.\n", (int) name -> len, name -> str );
exit ( 10 );
}
IntValue * this = (IntValue*) object;
bool is_int = arguments [ 0 ] -> kind == VALUE_INTEGER;
if ( is_int ) {
IntValue * other = (IntValue*) arguments [ 0 ];
if ( str_eq ( *name, STR ("+") ) )
return make_int ( state, this -> integer + other -> integer );
if ( str_eq ( *name, STR ("-") ) )
return make_int ( state, this -> integer - other -> integer );
if ( str_eq ( *name, STR ("*") ) )
return make_int ( state, this -> integer * other -> integer );
if ( str_eq ( *name, STR ("/") ) )
return make_int ( state, this -> integer / other -> integer );
if ( str_eq ( *name, STR ("%") ) )
return make_int ( state, this -> integer % other -> integer );
if ( str_eq ( *name, STR ("<=") ) )
return make_bool ( state, this -> integer <= other -> integer );
if ( str_eq ( *name, STR (">=") ) )
return make_bool ( state, this -> integer >= other -> integer );
if ( str_eq ( *name, STR ("<") ) )
return make_bool ( state, this -> integer < other -> integer );
if ( str_eq ( *name, STR (">") ) )
return make_bool ( state, this -> integer > other -> integer );
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( state, this -> integer == other -> integer );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( state, this -> integer != other -> integer );
break;
}
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( state, false );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( state, true );
break;
}
case VALUE_BOOLEAN: {
if ( argc != 1 ) {
fprintf ( stderr, "Invalid argument count for bool operation %.*s.\n", (int) name -> len, name -> str );
exit ( 10 );
}
BoolValue * this = (BoolValue*) object;
bool is_bool = arguments [ 0 ] -> kind == VALUE_BOOLEAN;
if ( is_bool ) {
BoolValue * other = (BoolValue*) arguments [ 0 ];
if ( str_eq ( *name, STR ("&") ) )
return make_bool ( state, this -> boolean & other -> boolean );
if ( str_eq ( *name, STR ("|") ) )
return make_bool ( state, this -> boolean | other -> boolean );
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( state, this -> boolean == other -> boolean );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( state, this -> boolean != other -> boolean );
break;
}
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( state, false );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( state, true );
break;
}
case VALUE_NULL: {
if ( argc != 1 ) {
fprintf ( stderr, "Invalid amount of arguments for null operation %.*s.\n", (int) name -> len, name -> str );
exit ( 10 );
}
if ( str_eq ( *name, STR ("==") ) )
return make_bool ( state, arguments [ 0 ] -> kind == VALUE_NULL ? true : false );
if ( str_eq ( *name, STR ("!=") ) )
return make_bool ( state, arguments [ 0 ] -> kind != VALUE_NULL ? true : false );
break;
}
case VALUE_ARRAY:
if ( str_eq ( *name, STR ("get") ) ) {
if ( argc != 1 || arguments [ 0 ] -> kind != VALUE_INTEGER ) {
fprintf ( stderr, "Invalid argument for array get.\n" );
exit ( 11 );
}
ArrayValue * array = (ArrayValue*) object;
i32 index = ((IntValue*) arguments [ 0 ]) -> integer;
if ( index < 0 || index >= array -> length ) {
fprintf ( stderr, "Index is out of bounds.\n" );
exit ( 11 );
}
return array -> elements [ index ];
}
if ( str_eq ( *name, STR ("set") ) ) {
if ( argc != 2 || arguments [ 0 ] -> kind != VALUE_INTEGER ) {
fprintf ( stderr, "Invalid arguments for array set.\n" );
exit ( 12 );
}
ArrayValue * array = (ArrayValue*) object;
i32 index = ((IntValue*) arguments [ 0 ]) -> integer;
if ( index < 0 || index >= array -> length ) {
fprintf ( stderr, "Index is out of bounds.\n" );
exit ( 12 );
}
array -> elements [ index ] = arguments [ 1 ];
return arguments [ 1 ];
}
break;
default:
break;
}
return NULL;
}
Value * function_call ( ASTInterpreterState * state, Value * callee, bool is_function, Ast ** arguments, size_t argc, Str * name ) {
Value ** values = (Value **) malloc ( argc * sizeof (Value*) );
for ( size_t i = 0; i < argc; ++i )
values [ i ] = evaluate ( state, arguments [ i ] );
Value * ret = NULL;
Value * function = callee;
if ( ! is_function ) {
function = NULL;
Value * next = callee;
Value * curr;
ObjectValue * tmp;
while ( next -> kind == VALUE_OBJECT ) {
curr = next;
tmp = (ObjectValue *) curr;
for ( size_t i = 0; i < tmp -> member_cnt; ++i )
if ( str_eq ( tmp -> members [ i ] . name, *name ) ) {
function = tmp -> members [ i ] . value;
callee = curr;
break;
}
next = tmp -> extends;
}
if ( ! function ) {
Value * base = get_base ( callee );
ret = try_operator ( state, base, values, argc, name );
free ( values );
if ( ret )
return ret;
fprintf ( stderr, "Method %.*s does not exist for this object and/or arguments.\n", (int) name -> len, name -> str );
exit ( 13 );
}
}
if ( function -> kind != VALUE_FUNCTION ) {
fprintf ( stderr, "Invalid callee.\n" );
exit ( 4 );
}
FunctionValue * f = (FunctionValue*) function;
Environment * tmp;
tmp = state -> current_env;
state -> current_env = NULL;
env_push ( state );
env_def ( state, STR ("this"), is_function ? make_null ( state ) : callee );
for ( size_t i = 0; i < argc; ++i )
env_def ( state, f -> function -> parameters [ i ], values [ i ] );
ret = evaluate ( state, f -> function -> body );
env_pop ( state );
state -> current_env = tmp;
free ( values );
return ret;
}
Value ** get_object_field ( Value * object, Str name ) {
Value * next = object;
ObjectValue * curr;
do {
curr = (ObjectValue*) next;
for ( size_t i = 0; i < curr -> member_cnt; ++i )
if ( str_eq ( curr -> members [ i ] . name, name ) )
return & curr -> members [ i ] . value;
next = curr -> extends;
} while ( next -> kind == VALUE_OBJECT );
return NULL;
}
int compare_entry ( const void * a, const void * b ) {
return str_cmp ( ((SimpleEntry*) a) -> name, ((SimpleEntry*) b) -> name );
}
void print_value ( Value * value ) {
switch ( value -> kind ) {
case VALUE_INTEGER:
printf ( "%" PRIi32, ((IntValue*) value ) -> integer );
break;
case VALUE_BOOLEAN:
if ( ((BoolValue*) value ) -> boolean )
printf ( "true" );
else
printf ( "false" );
break;
case VALUE_NULL:
printf ( "null" );
break;
case VALUE_FUNCTION:
printf ( "function" );
break;
case VALUE_ARRAY:
putchar ( '[' );
ArrayValue * arr = (ArrayValue*) value;
for ( i32 i = 0; i < arr -> length; ++i ) {
if ( i != 0 )
printf ( ", " );
print_value ( arr -> elements [ i ] );
}
putchar ( ']' );
break;
case VALUE_OBJECT:
printf ( "object(");
ObjectValue * obj = (ObjectValue*) value;
bool parent = false;
if ( obj -> extends -> kind != VALUE_NULL ) {
parent = true;
printf ( "..=" );
print_value ( obj -> extends );
}
if ( obj -> member_cnt )
qsort ( obj -> members, obj -> member_cnt, sizeof (SimpleEntry), compare_entry );
for ( size_t i = 0; i < obj -> member_cnt; ++i ) {
if ( i != 0 || parent )
printf ( ", " );
printf ( "%.*s=", (int) obj -> members [ i ] . name . len, obj -> members [ i ] . name . str );
print_value ( obj -> members [ i ] . value );
}
putchar ( ')' );
break;
case VALUE_INVALID:
fprintf ( stderr, "Invalid value.\n" );
}
}
void fml_print ( Str format, Value ** args, size_t argc ) {
u8 c;
size_t arg = 0;
for ( size_t i = 0; i < format . len; ++i ) {
c = format . str [ i ];
if ( c == '\\' ) {
++i;
c = format . str [ i ];
switch ( c ) {
case '~':
putchar ( '~' );
break;
case 'n':
putchar ( '\n' );
break;
case '"':
putchar ( '"' );
break;
case 'r':
putchar ( '\r' );
break;
case 't':
putchar ( '\t' );
break;
case '\\':
putchar ( '\\' );
break;
default:
fprintf ( stderr, "Invalid escaped character %c.\n", c );
exit ( 1 );
}
} else if ( c == '~' ) {
if ( arg == argc ) {
fprintf ( stderr, "Too many placeholders, not enough arguments.\n" );
exit ( 1 );
}
print_value ( args [ arg++ ] );
} else
putchar ( c );
}
}
Value * evaluate ( ASTInterpreterState * state, Ast * ast ) {
switch ( ast -> kind ) {
case AST_INTEGER:
return make_int ( state, ((AstInteger*) ast ) -> value );
case AST_BOOLEAN:
return make_bool ( state, ((AstBoolean*) ast ) -> value );
case AST_NULL:
return make_null ( state );
case AST_PRINT: {
AstPrint * printAst = (AstPrint*) ast;
Value ** args = (Value **) malloc ( sizeof (Value*) * printAst -> argument_cnt );
for ( size_t i = 0; i < printAst -> argument_cnt; ++i )
args [ i ] = evaluate ( state, printAst -> arguments [ i ] );
fml_print ( printAst -> format, args, printAst -> argument_cnt );
free ( args );
return make_null ( state );
}
case AST_TOP: {
AstTop * topAst = (AstTop*) ast;
Value * val = evaluate ( state, topAst -> expressions [ 0 ] );
for ( size_t i = 1; i < topAst -> expression_cnt; ++i )
val = evaluate ( state, topAst -> expressions [ i ] );
return val;
}
case AST_DEFINITION: {
AstDefinition * defAst = (AstDefinition*) ast;
Value * value = evaluate ( state, defAst -> value );
env_def ( state, defAst -> name, value );
return value;
}
case AST_VARIABLE_ACCESS:
return env_get ( state, ((AstVariableAccess*) ast ) -> name );
case AST_VARIABLE_ASSIGNMENT: {
AstVariableAssignment * assignAst = (AstVariableAssignment*) ast;
Value * value = evaluate ( state, assignAst -> value );
env_put ( state, assignAst -> name, value );
return value;
}
case AST_BLOCK: {
AstBlock * blockAst = (AstBlock*) ast;
env_push ( state );
Value * value = evaluate ( state, blockAst -> expressions [ 0 ] );
for ( size_t i = 1; i < blockAst -> expression_cnt; ++i )
value = evaluate ( state, blockAst -> expressions [ i ] );
env_pop ( state );
return value;
}
case AST_CONDITIONAL: {
AstConditional * condAst = (AstConditional*) ast;
Value * cond = evaluate ( state, condAst -> condition );
env_push ( state );
Ast * cont = value_to_bool ( cond ) ? condAst -> consequent : condAst -> alternative;
Value * value = evaluate ( state, cont );
env_pop ( state );
return value;
}
case AST_LOOP: {
AstLoop * loopAst = (AstLoop*) ast;
while ( value_to_bool ( evaluate ( state, loopAst -> condition ) ) ) {
env_push ( state );
evaluate ( state, loopAst -> body );
env_pop ( state );
}
return make_null ( state );
}
case AST_FUNCTION:
return make_function ( state, (AstFunction*) ast );
case AST_FUNCTION_CALL: {
AstFunctionCall * callAst = (AstFunctionCall*) ast;
Value * function = evaluate ( state, callAst -> function );
return function_call ( state, function, true, callAst -> arguments, callAst -> argument_cnt, NULL );
}
case AST_METHOD_CALL: {
AstMethodCall * methodAst = (AstMethodCall*) ast;
Value * object = evaluate ( state, methodAst -> object );
if ( object -> kind == VALUE_FUNCTION ) {
fprintf ( stderr, "Calling method on function.\n" );
exit ( 4 );
}
return function_call ( state, object, false, methodAst -> arguments, methodAst -> argument_cnt, &methodAst -> name );
}
case AST_ARRAY: {
AstArray * arrAst = (AstArray*) ast;
Value * size = evaluate ( state, arrAst -> size );
IntValue * int_size = (IntValue*) size;
if ( size -> kind != VALUE_INTEGER || int_size -> integer < 0 ) {
fprintf ( stderr, "Invalid array size.\n" );
exit ( 5 );
}
ArrayValue * array = (ArrayValue*) make_array ( state, int_size -> integer );
for ( i32 i = 0; i < array -> length; ++i ) {
env_push ( state );
array -> elements [ i ] = evaluate ( state, arrAst -> initializer );
env_pop ( state );
}
return (Value*) array;
}
case AST_INDEX_ACCESS: {
AstIndexAccess * iaccess = (AstIndexAccess*) ast;
Value * object = evaluate ( state, iaccess -> object );
Str tmp = STR ("get");
return function_call ( state, object, false, &iaccess -> index, 1, &tmp );
}
case AST_INDEX_ASSIGNMENT: {
AstIndexAssignment * iassign = (AstIndexAssignment*) ast;
Value * object = evaluate ( state, iassign -> object );
Ast * arguments [2];
arguments [ 0 ] = iassign -> index;
arguments [ 1 ] = iassign -> value;
Str tmp = STR ("set");
return function_call ( state, object, false, arguments, 2, &tmp );
}
case AST_OBJECT: {
AstObject * objAst = (AstObject*) ast;
ObjectValue * object = (ObjectValue*) make_object ( state, objAst -> member_cnt );
object -> extends = evaluate ( state, objAst -> extends );
Value * value;
AstDefinition * defAst;
for ( size_t i = 0; i < object -> member_cnt; ++i ) {
if ( objAst -> members [ i ] -> kind != AST_DEFINITION ) {
fprintf ( stderr, "Invalid object member.\n" );
exit ( 7 );
}
defAst = (AstDefinition*) objAst -> members [ i ];
env_push ( state );
value = evaluate ( state, defAst -> value );
env_pop ( state );
object -> members [ i ] . name = defAst -> name;
object -> members [ i ] . value = value;
}
return (Value*) object;
}
case AST_FIELD_ACCESS: {
AstFieldAccess * accessAst = (AstFieldAccess *) ast;
Value * object_value = evaluate ( state, accessAst -> object );
if ( object_value -> kind != VALUE_OBJECT ) {
fprintf ( stderr, "Trying to access field of non object.\n" );
exit ( 8 );
}
Value ** result = get_object_field ( object_value, accessAst -> field );
if ( ! result ) {
fprintf ( stderr, "Field %.*s was not found in specified object.\n", (int) accessAst -> field . len, accessAst -> field . str );
exit ( 8 );
}
return *result;
}
case AST_FIELD_ASSIGNMENT: {
AstFieldAssignment * assignAst = (AstFieldAssignment*) ast;
Value * object_value = evaluate ( state, assignAst -> object );
if ( object_value -> kind != VALUE_OBJECT ) {
fprintf ( stderr, "Trying to assign to a field of non object.\n" );
exit ( 8 );
}
Value * value = evaluate ( state, assignAst -> value );
Value ** result = get_object_field ( object_value, assignAst -> field );
if ( ! result ) {
fprintf ( stderr, "Field %.*s was not found in specified object.\n", (int) assignAst -> field . len, assignAst -> field . str );
exit ( 8 );
}
*result = value;
return value;
}
}
return NULL;
}
#include "parser.h"
typedef enum {
VALUE_INTEGER,
VALUE_BOOLEAN,
VALUE_NULL,
VALUE_FUNCTION,
VALUE_ARRAY,
VALUE_OBJECT,
VALUE_INVALID
} ValueType;
typedef struct Heap {
u8 * begin;
u8 * next;
u8 * end;
} Heap;
typedef struct Value {
ValueType kind;
} Value;
typedef struct SimpleEntry {
Str name;
Value * value;
} SimpleEntry;
typedef struct Object {
struct Value * extends;
size_t member_cnt;
SimpleEntry members [];
} Object;
typedef struct Array {
i32 length;
Value * members [];
} Array;
typedef struct NullValue {
Value kind;
} NullValue;
typedef struct IntValue {
Value kind;
i32 integer;
} IntValue;
typedef struct BoolValue {
Value kind;
bool boolean;
} BoolValue;
typedef struct FunctionValue {
Value kind;
AstFunction * function;
} FunctionValue;
typedef struct ObjectValue {
Value kind;
Value * extends;
size_t member_cnt;
SimpleEntry members [];
} ObjectValue;
typedef struct ArrayValue {
Value kind;
i32 length;
Value * elements [];
} ArrayValue;
typedef struct EnvironmentEntry {
struct EnvironmentEntry * next;
Str name;
Value * value;
} EnvironmentEntry;
typedef struct Environment {
struct Environment * prev;
EnvironmentEntry * start;
} Environment;
typedef struct ASTInterpreterState {
Heap * heap;
Environment global_env;
Environment * current_env;
} ASTInterpreterState;
bool value_to_bool ( Value * value );
void env_push ( ASTInterpreterState * state );
void env_pop ( ASTInterpreterState * state );
Value * env_get ( ASTInterpreterState * state, Str name );
void env_put ( ASTInterpreterState * state, Str name, Value * value );
void env_def ( ASTInterpreterState * state, Str name, Value * value );
void * heap_alloc_alligned ( Heap * heap, size_t len, size_t align );
void * heap_alloc ( Heap * heap, size_t len );
void heap_init ( Heap * heap, size_t heap_size );
void heap_destroy ( Heap * heap );
void state_init ( ASTInterpreterState * state, Heap * heap );
void state_destroy ( ASTInterpreterState * state );
Value * make_null ( ASTInterpreterState * state );
Value * make_int ( ASTInterpreterState * state, i32 val );
Value * make_bool ( ASTInterpreterState * state, bool val );
Value * make_function ( ASTInterpreterState * state, AstFunction * function );
Value * make_array ( ASTInterpreterState * state, size_t len );
Value * make_object ( ASTInterpreterState * state, size_t member_cnt );
Value * get_base ( Value * object );
Value ** get_object_field (Value * object, Str name );
Value * try_operator ( ASTInterpreterState * state, Value * object, Value ** arguments, size_t argc, Str * name );
Value * function_call ( ASTInterpreterState * state, Value * callee, bool is_function, Ast ** arguments, size_t argc, Str * name );
void print_value ( Value * value );
void fml_print ( Str format, Value ** args, size_t argc );
Value * evaluate ( ASTInterpreterState * state, Ast * ast );
int compare_entry ( const void * a, const void * b );
\ No newline at end of file
File moved
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>
#include "arena.h"
#include "parser.h"
#include "ast_interpreter.h"
#define AST_INTERPRETER_COMMAND "ast_interpret"
#define RUN "run"
#define HEAP_SIZE_COMMAND "--heap-size"
#define HEAP_LOG_COMMAND "--heap-log"
#define DEFAULT_HEAP_SIZE 512
int main ( int argc, char **argv ) {
if ( argc < 2 ) {
fprintf( stderr, "Input error: expected at least one argument\n" );
return 1;
}
size_t heap_size = DEFAULT_HEAP_SIZE;
char * log_file = NULL;
u8 flag = 0;
u8 ast_interpret = 0;
size_t len;
int f = -1;
for ( int arg = 1; arg < argc; ++arg ) {
len = strlen ( argv [ arg ] );
for ( size_t j = 0; j < len; j++ )
argv [ arg ] [ j ] = tolower ( argv [ arg ] [ j ] );
if ( len == strlen ( AST_INTERPRETER_COMMAND ) && strncmp ( argv [ arg ], AST_INTERPRETER_COMMAND, len ) == 0 ) {
ast_interpret = 1;
f = ++arg;
} else if ( len == strlen ( RUN ) && strncmp ( argv [ arg ], RUN, len ) == 0 ) {
ast_interpret = 1;
for ( size_t opt = 0; opt < 2; ++opt ) {
len = strlen ( argv [ ++arg ] );
if ( len == strlen ( HEAP_SIZE_COMMAND ) && strncmp ( argv [ arg ], HEAP_SIZE_COMMAND, len ) == 0 ) {
heap_size = atoi ( argv [ ++arg ] );
if ( heap_size == 0 ) {
fprintf( stderr, "Input error: invalid heap size %s.\n", argv [ arg ] );
flag = 2;
}
} else if ( len == strlen ( HEAP_LOG_COMMAND ) && strncmp ( argv [ arg ], HEAP_LOG_COMMAND, len ) == 0 ) {
log_file = argv [ ++arg ];
}
}
f = ++arg;
} else {
fprintf( stderr, "Input error: unknown argument %s.\n", argv [ arg ] );
flag = 1;
}
}
if ( flag || f <= 0 )
return 1;
FILE * fp = fopen ( argv [ f ], "r" );
(void) log_file;
if ( ! fp ) {
fprintf ( stderr, "Input error: file does not exists.\n" );
return 1;
}
if ( fseek ( fp, 0, SEEK_END ) ) {
fprintf ( stderr, "Input error: could not advance to the end of the file.\n" );
return 1;
}
int file_len = ftell ( fp );
if ( file_len < 0 ) {
fprintf ( stderr, "Input error: could not count the size of the file.\n" );
return 1;
}
size_t flen = file_len;
rewind ( fp );
u8 * buffer = malloc ( flen );
if ( fread ( buffer, 1, flen, fp ) != flen ) {
fprintf ( stderr, "Input error: could not read to the file.\n" );
return 1;
}
fclose ( fp );
Arena arena;
arena_init( &arena );
Ast *ast = parse_src ( &arena, (Str) { .str = buffer, .len = flen } );
if ( ast == NULL ) {
fprintf ( stderr, "Failed to parse source\n" );
arena_destroy ( &arena );
return 1;
}
if ( ast_interpret ) {
ASTInterpreterState state;
Heap heap;
heap_init ( &heap, heap_size * 1024 * 1024 );
state_init ( &state, &heap );
evaluate ( &state, ast );
state_destroy ( &state );
}
free ( buffer );
arena_destroy( &arena );
return 0;
}
File moved
File moved