Function call, declaration

This commit is contained in:
Night Kaly 2025-01-21 01:29:31 +00:00
parent 56d5d9d84b
commit 6d9d68d693
Signed by: night0721
SSH key fingerprint: SHA256:B/hgVwUoBpx5vdNsXl9w8XwZljA9766uk6T4ubZp5HM
11 changed files with 622 additions and 310 deletions

View file

@ -3,13 +3,20 @@
#include "lexer.h" #include "lexer.h"
#define DEFAULT_STMTS_SIZE 512
#define DEFAULT_ARGS_SIZE 255
/* /*
expression literal | unary | binary | grouping ; expression equality ;
literal NUMBER | STRING | "true" | "false" | "nil" ; equality comparison ( ( "!=" | "==" ) comparison )* ;
grouping "(" expression ")" ; comparison term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
unary ( "-" | "!" ) expression ; term factor ( ( "-" | "+" ) factor )* ;
binary expression operator expression ; factor unary ( ( "/" | "*" ) unary )* ;
operator "==" | "!=" | "<" | "<=" | ">" | ">=" | "+" | "-" | "*" | "/" ; unary ( "!" | "-" ) unary | primary ;
primary NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" ;
statement exprStmt | ifStmt | printStmt | block ;
ifStmt "if" "(" expression ")" statement ( "else" statement )? ;
block "{" declaration* "}" ;
*/ */
typedef enum { typedef enum {
@ -32,18 +39,68 @@ typedef enum {
VAL_NIL, VAL_NIL,
VAL_NUMBER, VAL_NUMBER,
VAL_STRING, VAL_STRING,
VAL_FN,
} value_type_t; } value_type_t;
typedef enum {
STMT_BLOCK,
STMT_CLASS,
STMT_EXPR,
STMT_FUN,
STMT_IF,
STMT_PRINT,
STMT_VAR,
STMT_WHILE,
} stmt_type_t;
typedef enum {
FN_NATIVE,
FN_CUSTOM,
} fn_type_t;
typedef struct expr_t expr_t;
typedef struct value_t value_t;
typedef struct stmt_t stmt_t;
typedef struct fn_t fn_t;
typedef struct { typedef struct {
expr_t **arguments;
int length;
int capacity;
} arg_array_t;
typedef struct {
value_t **arguments;
int length;
int capacity;
} val_array_t;
typedef struct {
stmt_t **statements;
int length;
int capacity;
} stmt_array_t;
struct value_t {
value_type_t type; value_type_t type;
union { union {
int boolean; int boolean;
double number; double number;
char *string; char *string;
fn_t *function;
} as; } as;
} value_t; };
typedef struct expr_t { typedef struct ht_t ht_t;
struct fn_t {
fn_type_t type;
int arity;
stmt_t *stmt;
value_t *(*call)(stmt_t *stmt, val_array_t *arguments, ht_t *env);
};
struct expr_t {
expr_type_t type; expr_type_t type;
int line; int line;
union { union {
@ -59,7 +116,7 @@ typedef struct expr_t {
struct { struct {
struct expr_t *callee; struct expr_t *callee;
token_t paren; token_t paren;
struct expr_t **arguments; arg_array_t *args;
} call; } call;
struct { struct {
struct expr_t *object; struct expr_t *object;
@ -69,7 +126,7 @@ typedef struct expr_t {
struct expr_t *expression; struct expr_t *expression;
} grouping; } grouping;
struct { struct {
value_t value; value_t *value;
} literal; } literal;
struct { struct {
token_t operator; token_t operator;
@ -96,7 +153,49 @@ typedef struct expr_t {
token_t name; token_t name;
} variable; } variable;
} as; } as;
} expr_t; };
struct stmt_t {
stmt_type_t type;
union {
struct {
stmt_array_t *statements;
} block;
struct {
token_t name;
token_t superclass;
struct stmt_t **methods;
} class;
struct {
expr_t *expression;
} expr;
struct {
token_t name;
array_t *params;
struct stmt_t *body;
} function;
struct {
expr_t *condition;
struct stmt_t *then_branch;
struct stmt_t *else_branch;
} _if;
struct {
expr_t *expression;
} print;
struct {
token_t keyword;
expr_t *value;
} _return;
struct {
token_t name;
expr_t *initializer;
} variable;
struct {
expr_t *condition;
struct stmt_t *body;
} _while;
} as;
};
expr_t *create_binary_expr(token_t *operator, expr_t *left, expr_t *right); expr_t *create_binary_expr(token_t *operator, expr_t *left, expr_t *right);
expr_t *create_unary_expr(token_t *operator, expr_t *right); expr_t *create_unary_expr(token_t *operator, expr_t *right);
@ -105,6 +204,7 @@ expr_t *create_grouping_expr(expr_t *expression);
expr_t *create_variable_expr(token_t *name); expr_t *create_variable_expr(token_t *name);
expr_t *create_assign_expr(expr_t *name, expr_t *value); expr_t *create_assign_expr(expr_t *name, expr_t *value);
expr_t *create_logical_expr(token_t *operator, expr_t *left, expr_t *right); expr_t *create_logical_expr(token_t *operator, expr_t *left, expr_t *right);
expr_t *create_call_expr(expr_t *callee, token_t *paren, arg_array_t *args);
void print_ast(expr_t *expr); void print_ast(expr_t *expr);
#endif #endif

View file

@ -13,10 +13,10 @@ typedef struct ht_t {
#define DEFAULT_HT_SIZE 50 #define DEFAULT_HT_SIZE 50
ht_t *ht_init(ht_t *env); ht_t *ht_init(ht_t *env);
void ht_add(ht_t *ht, char *name, value_t value); void ht_add(ht_t *ht, char *name, value_t *value);
value_t *ht_get(ht_t *ht, token_t *name, int check_enclosing); value_t *ht_get(ht_t *ht, token_t *name, int check_enclosing);
void ht_replace(ht_t *ht, char *name, value_t value); void ht_replace(ht_t *ht, char *name, value_t *value);
void ht_assign(ht_t *ht, token_t *name, value_t value); void ht_assign(ht_t *ht, token_t *name, value_t *value);
void ht_free(ht_t *ht); void ht_free(ht_t *ht);
#endif #endif

View file

@ -3,11 +3,11 @@
#include "ast.h" #include "ast.h"
#include "env.h" #include "env.h"
#include "stmt.h"
void free_val(value_t *value);
void runtime_error(const char *message, int line); void runtime_error(const char *message, int line);
value_t evaluate(expr_t *expr, ht_t *env); value_t *evaluate(expr_t *expr, ht_t *env);
void print_value(value_t value); void print_value(value_t *value);
void evaluate_statements(stmt_array_t *array, ht_t *env); void interpret(stmt_array_t *array);
#endif #endif

View file

@ -41,6 +41,7 @@ typedef struct {
int capacity; int capacity;
} array_t; } array_t;
void token_add(array_t *array, token_t token);
array_t *tokenize(char *filename); array_t *tokenize(char *filename);
void print_tokens(token_t *tokens); void print_tokens(token_t *tokens);
void free_array(array_t *array); void free_array(array_t *array);

View file

@ -1,19 +1,8 @@
#ifndef PARSER_H #ifndef PARSER_H
#define PARSER_H #define PARSER_H
/*
expression equality ;
equality comparison ( ( "!=" | "==" ) comparison )* ;
comparison term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
term factor ( ( "-" | "+" ) factor )* ;
factor unary ( ( "/" | "*" ) unary )* ;
unary ( "!" | "-" ) unary | primary ;
primary NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" ;
*/
#include "ast.h" #include "ast.h"
#include "lexer.h" #include "lexer.h"
#include "stmt.h"
stmt_array_t *parse(token_t *tks); stmt_array_t *parse(token_t *tks);
expr_t *parse_expr(token_t *tks); expr_t *parse_expr(token_t *tks);

View file

@ -1,77 +0,0 @@
#ifndef STMT_H
#define STMT_H
#include "ast.h"
#include "lexer.h"
#define DEFAULT_STMTS_SIZE 512
/*
statement exprStmt | ifStmt | printStmt | block ;
ifStmt "if" "(" expression ")" statement
( "else" statement )? ;
block "{" declaration* "}" ;
*/
typedef enum {
STMT_BLOCK,
STMT_CLASS,
STMT_EXPR,
STMT_FUN,
STMT_IF,
STMT_PRINT,
STMT_VAR,
STMT_WHILE,
} stmt_type_t;
typedef struct stmt_t stmt_t;
typedef struct {
stmt_t **statements;
int length;
int capacity;
} stmt_array_t;
struct stmt_t {
stmt_type_t type;
union {
struct {
stmt_array_t *statements;
} block;
struct {
token_t name;
token_t superclass;
struct stmt_t **methods;
} class;
struct {
expr_t *expression;
} expr;
struct {
token_t name;
array_t *params;
struct stmt_t **body;
} function;
struct {
expr_t *condition;
struct stmt_t *then_branch;
struct stmt_t *else_branch;
} _if;
struct {
expr_t *expression;
} print;
struct {
token_t keyword;
expr_t *value;
} _return;
struct {
token_t name;
expr_t *initializer;
} variable;
struct {
expr_t *condition;
struct stmt_t *body;
} _while;
} as;
};
#endif

View file

@ -35,28 +35,29 @@ expr_t *create_literal_expr(token_t *token)
expr_t *expr = malloc(sizeof(expr_t)); expr_t *expr = malloc(sizeof(expr_t));
expr->type = EXPR_LITERAL; expr->type = EXPR_LITERAL;
expr->line = token->line; expr->line = token->line;
expr->as.literal.value = malloc(sizeof(value_t));
switch (token->type) { switch (token->type) {
case TOKEN_NUMBER: case TOKEN_NUMBER:
expr->as.literal.value.type = VAL_NUMBER; expr->as.literal.value->type = VAL_NUMBER;
double num; double num;
sscanf(token->value, "%lf", &num); sscanf(token->value, "%lf", &num);
expr->as.literal.value.as.number = num; expr->as.literal.value->as.number = num;
break; break;
case TOKEN_NIL: case TOKEN_NIL:
expr->as.literal.value.type = VAL_NIL; expr->as.literal.value->type = VAL_NIL;
expr->as.literal.value.as.number = 0; expr->as.literal.value->as.number = 0;
break; break;
case TOKEN_TRUE: case TOKEN_TRUE:
case TOKEN_FALSE: case TOKEN_FALSE:
expr->as.literal.value.type = VAL_BOOL; expr->as.literal.value->type = VAL_BOOL;
expr->as.literal.value.as.boolean = token->type == TOKEN_TRUE; expr->as.literal.value->as.boolean = token->type == TOKEN_TRUE;
break; break;
case TOKEN_STRING: case TOKEN_STRING:
expr->as.literal.value.type = VAL_STRING; expr->as.literal.value->type = VAL_STRING;
expr->as.literal.value.as.string = strdup(token->value); expr->as.literal.value->as.string = strdup(token->value);
break; break;
default: default:
@ -113,14 +114,27 @@ expr_t *create_logical_expr(token_t *operator, expr_t *left, expr_t *right)
return expr; return expr;
} }
expr_t *create_call_expr(expr_t *callee, token_t *paren, arg_array_t *args)
{
expr_t *expr = malloc(sizeof(expr_t));
expr->type = EXPR_CALL;
expr->line = paren->line;
expr->as.call.callee = callee;
expr->as.call.paren.type = paren->type;
expr->as.call.paren.value = strdup(paren->value);
expr->as.call.paren.line = paren->line;
expr->as.call.args = args;
return expr;
}
void print_ast(expr_t *expr) void print_ast(expr_t *expr)
{ {
if (!expr) if (!expr)
return; return;
if (expr->type == EXPR_LITERAL) { if (expr->type == EXPR_LITERAL) {
switch (expr->as.literal.value.type) { switch (expr->as.literal.value->type) {
case VAL_BOOL: case VAL_BOOL:
printf("%s", expr->as.literal.value.as.boolean ? "true" : "false"); printf("%s", expr->as.literal.value->as.boolean ? "true" : "false");
break; break;
case VAL_NIL: case VAL_NIL:
@ -128,7 +142,7 @@ void print_ast(expr_t *expr)
break; break;
case VAL_NUMBER:; case VAL_NUMBER:;
double value = expr->as.literal.value.as.number; double value = expr->as.literal.value->as.number;
if (value == (int) value) { if (value == (int) value) {
printf("%.1f", value); printf("%.1f", value);
} else { } else {
@ -137,7 +151,11 @@ void print_ast(expr_t *expr)
break; break;
case VAL_STRING: case VAL_STRING:
printf("%s", expr->as.literal.value.as.string); printf("%s", expr->as.literal.value->as.string);
break;
case VAL_FN:
printf("<native fn>");
break; break;
} }
} else if (expr->type == EXPR_BINARY) { } else if (expr->type == EXPR_BINARY) {

View file

@ -5,6 +5,8 @@
#include "env.h" #include "env.h"
#include "interpreter.h" #include "interpreter.h"
void free_statement(stmt_t *stmt);
ht_t *ht_init(ht_t *env) ht_t *ht_init(ht_t *env)
{ {
ht_t *ht = malloc(sizeof(ht_t) * DEFAULT_HT_SIZE); ht_t *ht = malloc(sizeof(ht_t) * DEFAULT_HT_SIZE);
@ -28,7 +30,7 @@ unsigned int hash(char *key)
return h; return h;
} }
void ht_add(ht_t *ht, char *name, value_t value) void ht_add(ht_t *ht, char *name, value_t *value)
{ {
unsigned int idx = hash(name) % DEFAULT_HT_SIZE; unsigned int idx = hash(name) % DEFAULT_HT_SIZE;
/* Linear probing for collision resolution */ /* Linear probing for collision resolution */
@ -36,11 +38,14 @@ void ht_add(ht_t *ht, char *name, value_t value)
int probe_idx = (idx + i) % DEFAULT_HT_SIZE; int probe_idx = (idx + i) % DEFAULT_HT_SIZE;
if (!ht[probe_idx].name) { if (!ht[probe_idx].name) {
ht[probe_idx].name = strdup(name); ht[probe_idx].name = strdup(name);
ht[probe_idx].value.type = value.type; ht[probe_idx].value.type = value->type;
if (value.type == VAL_STRING) { if (value->type == VAL_STRING) {
ht[probe_idx].value.as.string = strdup(value.as.string); ht[probe_idx].value.as.string = strdup(value->as.string);
} else if (value->type == VAL_FN) {
ht[probe_idx].value.as.function = malloc(sizeof(fn_t));
memcpy(ht[probe_idx].value.as.function, value->as.function, sizeof(fn_t));
} else { } else {
ht[probe_idx].value.as = value.as; ht[probe_idx].value.as = value->as;
} }
return; return;
} else { } else {
@ -56,8 +61,15 @@ value_t *ht_get(ht_t *ht, token_t *name, int check_enclosing)
/* Linear probing to search for the key */ /* Linear probing to search for the key */
for (int i = 0; i < DEFAULT_HT_SIZE; i++) { for (int i = 0; i < DEFAULT_HT_SIZE; i++) {
int probe_idx = (idx + i) % DEFAULT_HT_SIZE; int probe_idx = (idx + i) % DEFAULT_HT_SIZE;
if (ht[probe_idx].name && !strcmp(ht[probe_idx].name, name->value)) if (ht[probe_idx].name && !strcmp(ht[probe_idx].name, name->value)) {
return &ht[probe_idx].value; value_t *val = malloc(sizeof(value_t));
memcpy(val, &ht[probe_idx].value, sizeof(value_t));
if (val->type == VAL_STRING) {
val->as.string = strdup(ht[probe_idx].value.as.string);
}
return val;
}
} }
if (check_enclosing) { if (check_enclosing) {
if (ht->enclosing) { if (ht->enclosing) {
@ -73,7 +85,7 @@ value_t *ht_get(ht_t *ht, token_t *name, int check_enclosing)
return NULL; return NULL;
} }
void ht_replace(ht_t *ht, char *name, value_t value) void ht_replace(ht_t *ht, char *name, value_t *value)
{ {
unsigned int idx = hash(name) % DEFAULT_HT_SIZE; unsigned int idx = hash(name) % DEFAULT_HT_SIZE;
@ -87,20 +99,22 @@ void ht_replace(ht_t *ht, char *name, value_t value)
if (ht[probe_idx].value.type == VAL_STRING) { if (ht[probe_idx].value.type == VAL_STRING) {
free(ht[probe_idx].value.as.string); free(ht[probe_idx].value.as.string);
} }
ht[probe_idx].value.type = value.type; ht[probe_idx].value.type = value->type;
ht[probe_idx].value.as = value.as; ht[probe_idx].value.as = value->as;
if (value.type == VAL_STRING) { if (value->type == VAL_STRING) {
ht[probe_idx].value.as.string = strdup(value.as.string); ht[probe_idx].value.as.string = strdup(value->as.string);
} }
return; return;
} }
} }
} }
void ht_assign(ht_t *ht, token_t *name, value_t value) void ht_assign(ht_t *ht, token_t *name, value_t *value)
{ {
if (ht_get(ht, name, 0)) { value_t *val = ht_get(ht, name, 0);
if (val) {
ht_replace(ht, name->value, value); ht_replace(ht, name->value, value);
free_val(val);
return; return;
} }
if (ht->enclosing) { if (ht->enclosing) {
@ -119,6 +133,8 @@ void ht_free(ht_t *ht)
free(ht[i].name); free(ht[i].name);
if (ht[i].value.type == VAL_STRING) { if (ht[i].value.type == VAL_STRING) {
free(ht[i].value.as.string); free(ht[i].value.as.string);
} else if (ht[i].value.type == VAL_FN) {
free(ht[i].value.as.function);
} }
} }
} }

View file

@ -1,7 +1,8 @@
#include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <time.h>
#include "ast.h" #include "ast.h"
#include "env.h" #include "env.h"
@ -9,12 +10,30 @@
#include "lexer.h" #include "lexer.h"
#include "parser.h" #include "parser.h"
value_t visit_literal(expr_t *expr) void evaluate_statement(stmt_t *stmt, ht_t *env);
void free_val(value_t *value)
{ {
return expr->as.literal.value; if (!value)
return;
if (value->type == VAL_STRING) {
if (value->as.string) {
free(value->as.string);
}
} else if (value->type == VAL_FN) {
}
free(value);
} }
value_t visit_grouping(expr_t *expr, ht_t *env) value_t *visit_literal(expr_t *expr)
{
value_t *val = malloc(sizeof(value_t));
memcpy(val, expr->as.literal.value, sizeof(value_t));
return val;
}
value_t *visit_grouping(expr_t *expr, ht_t *env)
{ {
return evaluate(expr->as.grouping.expression, env); return evaluate(expr->as.grouping.expression, env);
} }
@ -26,56 +45,66 @@ void runtime_error(const char *message, int line)
exit(70); exit(70);
} }
value_t visit_binary(expr_t *expr, ht_t *env) value_t *visit_binary(expr_t *expr, ht_t *env)
{ {
token_type_t op_type = expr->as.binary.operator.type; token_type_t op_type = expr->as.binary.operator.type;
value_t right = evaluate(expr->as.binary.right, env); value_t *right = evaluate(expr->as.binary.right, env);
value_t left = evaluate(expr->as.binary.left, env); value_t *left = evaluate(expr->as.binary.left, env);
// Arithmetic // Arithmetic
if (left.type == VAL_NUMBER && right.type == VAL_NUMBER) { if (left->type == VAL_NUMBER && right->type == VAL_NUMBER) {
value_t result = {.type = VAL_NUMBER}; value_t *result = malloc(sizeof(value_t));
result->type = VAL_NUMBER;
switch (op_type) { switch (op_type) {
case TOKEN_PLUS: case TOKEN_PLUS:
result.as.number = left.as.number + right.as.number; result->as.number = left->as.number + right->as.number;
free_val(left);
free_val(right);
return result; return result;
case TOKEN_MINUS: case TOKEN_MINUS:
result.as.number = left.as.number - right.as.number; result->as.number = left->as.number - right->as.number;
free_val(left);
free_val(right);
return result; return result;
case TOKEN_STAR: case TOKEN_STAR:
result.as.number = left.as.number * right.as.number; result->as.number = left->as.number * right->as.number;
free_val(left);
free_val(right);
return result; return result;
case TOKEN_SLASH: case TOKEN_SLASH:
if (right.as.number == 0) { if (right->as.number == 0) {
runtime_error("Division by zero.", expr->line); runtime_error("Division by zero.", expr->line);
} }
result.as.number = left.as.number / right.as.number; result->as.number = left->as.number / right->as.number;
free_val(left);
free_val(right);
return result; return result;
default: default:
break; break;
} }
free_val(result);
} }
// Comparison // Comparison
if (op_type == TOKEN_EQUAL_EQUAL || op_type == TOKEN_BANG_EQUAL) { if (op_type == TOKEN_EQUAL_EQUAL || op_type == TOKEN_BANG_EQUAL) {
int is_equal; int is_equal;
if (left.type != right.type) { if (left->type != right->type) {
is_equal = 0; is_equal = 0;
} else { } else {
switch (left.type) { switch (left->type) {
case VAL_NUMBER: case VAL_NUMBER:
is_equal = left.as.number == right.as.number; is_equal = left->as.number == right->as.number;
break; break;
case VAL_BOOL: case VAL_BOOL:
is_equal = left.as.boolean == right.as.boolean; is_equal = left->as.boolean == right->as.boolean;
break; break;
case VAL_STRING: case VAL_STRING:
is_equal = strcmp(left.as.string, right.as.string) == 0; is_equal = strcmp(left->as.string, right->as.string) == 0;
break; break;
case VAL_NIL: case VAL_NIL:
@ -87,29 +116,41 @@ value_t visit_binary(expr_t *expr, ht_t *env)
break; break;
} }
} }
value_t result = {.type = VAL_BOOL}; value_t *result = malloc(sizeof(value_t));
result.as.boolean = op_type == TOKEN_EQUAL_EQUAL ? is_equal : !is_equal; result->type = VAL_BOOL;
result->as.boolean = op_type == TOKEN_EQUAL_EQUAL ? is_equal : !is_equal;
free_val(left);
free_val(right);
return result; return result;
} }
// Number Comparison // Number Comparison
if (left.type == VAL_NUMBER && right.type == VAL_NUMBER) { if (left->type == VAL_NUMBER && right->type == VAL_NUMBER) {
value_t result = {.type = VAL_BOOL }; value_t *result = malloc(sizeof(value_t));
result->type = VAL_BOOL;
switch (op_type) { switch (op_type) {
case TOKEN_GREATER: case TOKEN_GREATER:
result.as.boolean= left.as.number > right.as.number; result->as.boolean = left->as.number > right->as.number;
free_val(left);
free_val(right);
return result; return result;
case TOKEN_GREATER_EQUAL: case TOKEN_GREATER_EQUAL:
result.as.boolean = left.as.number >= right.as.number; result->as.boolean = left->as.number >= right->as.number;
free_val(left);
free_val(right);
return result; return result;
case TOKEN_LESS: case TOKEN_LESS:
result.as.boolean = left.as.number < right.as.number; result->as.boolean = left->as.number < right->as.number;
free_val(left);
free_val(right);
return result; return result;
case TOKEN_LESS_EQUAL: case TOKEN_LESS_EQUAL:
result.as.boolean = left.as.number <= right.as.number; result->as.boolean = left->as.number <= right->as.number;
free_val(left);
free_val(right);
return result; return result;
default: break; default: break;
@ -117,40 +158,46 @@ value_t visit_binary(expr_t *expr, ht_t *env)
} }
// String concatenation // String concatenation
if (left.type == VAL_STRING && right.type == VAL_STRING) { if (left->type == VAL_STRING && right->type == VAL_STRING) {
if (op_type == TOKEN_PLUS) { if (op_type == TOKEN_PLUS) {
value_t result = {.type = VAL_STRING}; value_t *result = malloc(sizeof(value_t));
size_t left_len = strlen(left.as.string); result->type = VAL_STRING;
size_t right_len = strlen(right.as.string); size_t left_len = strlen(left->as.string);
result.as.string = malloc(left_len + right_len + 1); size_t right_len = strlen(right->as.string);
strcpy(result.as.string, left.as.string); result->as.string = malloc(left_len + right_len + 1);
strcat(result.as.string, right.as.string); strcpy(result->as.string, left->as.string);
strcat(result->as.string, right->as.string);
free_val(left);
free_val(right);
return result; return result;
} }
} }
// String/number comparisons // String/number comparisons
if ((left.type == VAL_STRING && right.type == VAL_NUMBER) || if ((left->type == VAL_STRING && right->type == VAL_NUMBER) ||
(left.type == VAL_NUMBER && right.type == VAL_STRING)) { (left->type == VAL_NUMBER && right->type == VAL_STRING)) {
runtime_error("Operands must be numbers.", expr->line); runtime_error("Operands must be numbers.", expr->line);
} }
runtime_error("Operands must be two numbers or two strings.", expr->line); runtime_error("Operands must be two numbers or two strings.", expr->line);
return (value_t){.type = VAL_NIL}; value_t *val = malloc(sizeof(value_t));
val->type = VAL_NIL;
free_val(left);
free_val(right);
return val;
} }
int is_truthy(value_t value) int is_truthy(value_t *value)
{ {
switch (value.type) { switch (value->type) {
case VAL_NIL: case VAL_NIL:
return 0; return 0;
case VAL_BOOL: case VAL_BOOL:
return value.as.boolean; return value->as.boolean;
case VAL_NUMBER: case VAL_NUMBER:
if (value.as.number == 0) if (value->as.number == 0)
return 0; return 0;
return 1; return 1;
@ -162,45 +209,57 @@ int is_truthy(value_t value)
} }
} }
value_t visit_unary(expr_t *expr, ht_t *env) value_t *visit_unary(expr_t *expr, ht_t *env)
{ {
value_t operand = evaluate(expr->as.unary.right, env); value_t *operand = evaluate(expr->as.unary.right, env);
if (expr->as.unary.operator.type == TOKEN_MINUS) { if (expr->as.unary.operator.type == TOKEN_MINUS) {
if (operand.type == VAL_NUMBER) { if (operand->type == VAL_NUMBER) {
value_t result = {.type = VAL_NUMBER, .as.number = -operand.as.number}; value_t *result = malloc(sizeof(value_t));
result->type = VAL_NUMBER;
result->as.number = -operand->as.number;
free_val(operand);
return result; return result;
} else { } else {
runtime_error("Operand must be a number.", expr->line); runtime_error("Operand must be a number.", expr->line);
} }
} else if (expr->as.unary.operator.type == TOKEN_BANG) { } else if (expr->as.unary.operator.type == TOKEN_BANG) {
value_t result = {.type = VAL_BOOL, .as.boolean = !is_truthy(operand)}; value_t *result = malloc(sizeof(value_t));
result->type = VAL_BOOL;
result->as.boolean = !is_truthy(operand);
free_val(operand);
return result; return result;
} }
return (value_t){.type = VAL_NIL}; value_t *val = malloc(sizeof(value_t));
val->type = VAL_NIL;
free_val(operand);
return val;
} }
value_t visit_variable(expr_t *expr, ht_t *env) value_t *visit_variable(expr_t *expr, ht_t *env)
{ {
value_t *val = ht_get(env, &expr->as.variable.name, 1); value_t *val = ht_get(env, &expr->as.variable.name, 1);
if (val) { if (val) {
return *val; return val;
} else { } else {
return (value_t) {.type = VAL_NIL}; val = malloc(sizeof(value_t));
val->type = VAL_NIL;
return val;
} }
} }
value_t visit_assign(expr_t *expr, ht_t *env) value_t *visit_assign(expr_t *expr, ht_t *env)
{ {
value_t value = evaluate(expr->as.assign.value, env); value_t *value = evaluate(expr->as.assign.value, env);
ht_assign(env, &expr->as.assign.name->as.variable.name, value); ht_assign(env, &expr->as.assign.name->as.variable.name, value);
return value; return value;
} }
value_t visit_logical(expr_t *expr, ht_t *env) value_t *visit_logical(expr_t *expr, ht_t *env)
{ {
value_t left = evaluate(expr->as.logical.left, env); value_t *left = evaluate(expr->as.logical.left, env);
if (expr->as.logical.operator.type == TOKEN_OR) { if (expr->as.logical.operator.type == TOKEN_OR) {
if (is_truthy(left)) if (is_truthy(left))
@ -213,11 +272,58 @@ value_t visit_logical(expr_t *expr, ht_t *env)
return evaluate(expr->as.logical.right, env); return evaluate(expr->as.logical.right, env);
} }
value_t evaluate(expr_t *expr, ht_t *env) void val_add(val_array_t *array, value_t *expr)
{
if (array->length == array->capacity) {
array->capacity *= 2;
array->arguments = realloc(array->arguments, array->capacity * sizeof(expr_t *));
}
array->arguments[array->length++] = expr;
}
void free_vals(val_array_t *array)
{
for (int i = 0; i < array->length; i++) {
free_val(array->arguments[i]);
}
free(array->arguments);
free(array);
}
value_t *visit_call(expr_t *expr, ht_t *env)
{
value_t *callee = evaluate(expr->as.call.callee, env);
if (callee->type != VAL_FN) {
runtime_error("Can only call functions and classes.", expr->line);
}
val_array_t *arguments = malloc(sizeof(val_array_t));
arguments->arguments = malloc(DEFAULT_ARGS_SIZE * sizeof(value_t *));
arguments->length = 0;
arguments->capacity = DEFAULT_ARGS_SIZE;
for (int i = 0; i < expr->as.call.args->length; i++) {
value_t *val = evaluate(expr->as.call.args->arguments[i], env);
val_add(arguments, val);
}
if (arguments->length != callee->as.function->arity) {
char err[512];
snprintf(err, 512, "Expected %d arguments but got %d.", callee->as.function->arity, arguments->length);
runtime_error(err, expr->line);
}
value_t *res = callee->as.function->call(callee->as.function->stmt, arguments, env);
free_vals(arguments);
free_val(callee);
return res;
}
value_t *evaluate(expr_t *expr, ht_t *env)
{ {
if (!expr) { if (!expr) {
value_t nil_value = {.type = VAL_NIL }; value_t *nil = malloc(sizeof(value_t));
return nil_value; nil->type = VAL_NIL;
return nil;
} }
switch (expr->type) { switch (expr->type) {
case EXPR_LITERAL: case EXPR_LITERAL:
@ -234,17 +340,19 @@ value_t evaluate(expr_t *expr, ht_t *env)
return visit_assign(expr, env); return visit_assign(expr, env);
case EXPR_LOGICAL: case EXPR_LOGICAL:
return visit_logical(expr, env); return visit_logical(expr, env);
case EXPR_CALL:
return visit_call(expr, env);
default: default:
exit(65); exit(65);
break; break;
} }
} }
void print_value(value_t value) void print_value(value_t *value)
{ {
switch (value.type) { switch (value->type) {
case VAL_BOOL: case VAL_BOOL:
printf("%s\n", value.as.boolean == 1 ? "true" : "false"); printf("%s\n", value->as.boolean == 1 ? "true" : "false");
break; break;
case VAL_NIL: case VAL_NIL:
@ -252,66 +360,22 @@ void print_value(value_t value)
break; break;
case VAL_STRING: case VAL_STRING:
printf("%s\n", value.as.string); printf("%s\n", value->as.string);
break; break;
case VAL_NUMBER: case VAL_NUMBER:
if (value.as.number == (int) value.as.number) { if (value->as.number == (int) value->as.number) {
printf("%d\n", (int) value.as.number); printf("%d\n", (int) value->as.number);
} else { } else {
printf("%g\n", value.as.number); printf("%g\n", value->as.number);
} }
break; break;
default: case VAL_FN:
break; if (value->as.function->type == FN_NATIVE) {
} printf("<native fn>\n");
} } else {
printf("<fn %s>\n", value->as.function->stmt->as.function.name.value);
void evaluate_block(stmt_array_t *array, ht_t *cur_env, ht_t *scope_env)
{
ht_t *previous = cur_env;
cur_env = scope_env;
evaluate_statements(array, cur_env);
ht_free(scope_env);
cur_env = previous;
}
void evaluate_statement(stmt_t *stmt, ht_t *env)
{
switch (stmt->type) {
case STMT_IF:
if (is_truthy(evaluate(stmt->as._if.condition, env))) {
evaluate_statement(stmt->as._if.then_branch, env);
} else if (stmt->as._if.else_branch) {
evaluate_statement(stmt->as._if.else_branch, env);
}
break;
case STMT_PRINT:
print_value(evaluate(stmt->as.print.expression, env));
break;
case STMT_EXPR:
evaluate(stmt->as.expr.expression, env);
break;
case STMT_VAR: {
value_t value = {.type = VAL_NIL};
if (stmt->as.variable.initializer) {
value = evaluate(stmt->as.variable.initializer, env);
}
ht_add(env, stmt->as.variable.name.value, value);
break;
}
case STMT_BLOCK:
evaluate_block(stmt->as.block.statements, env, ht_init(env));
break;
case STMT_WHILE:
while (is_truthy(evaluate(stmt->as._while.condition, env))) {
evaluate_statement(stmt->as._while.body, env);
} }
break; break;
@ -326,3 +390,121 @@ void evaluate_statements(stmt_array_t *array, ht_t *env)
evaluate_statement(array->statements[i], env); evaluate_statement(array->statements[i], env);
} }
} }
void evaluate_block(stmt_array_t *array, ht_t *cur_env, ht_t *scope_env)
{
ht_t *previous = cur_env;
cur_env = scope_env;
evaluate_statements(array, cur_env);
ht_free(scope_env);
cur_env = previous;
}
value_t *_clock(stmt_t *stmt, val_array_t *arguments, ht_t *env)
{
value_t *val = malloc(sizeof(value_t));
val->type = VAL_NUMBER;
val->as.number = time(NULL);
return val;
}
value_t *_call(stmt_t *stmt, val_array_t *arguments, ht_t *env)
{
ht_t *fn_env = ht_init(env);
for (int i = 0; i < stmt->as.function.params->length; i++) {
ht_add(fn_env, stmt->as.function.params->tokens[i].value, arguments->arguments[i]);
}
evaluate_block(stmt->as.function.body->as.block.statements, env, fn_env);
return NULL;
}
void evaluate_statement(stmt_t *stmt, ht_t *env)
{
switch (stmt->type) {
case STMT_IF:
if (is_truthy(evaluate(stmt->as._if.condition, env))) {
evaluate_statement(stmt->as._if.then_branch, env);
} else if (stmt->as._if.else_branch) {
evaluate_statement(stmt->as._if.else_branch, env);
}
break;
case STMT_PRINT:;
value_t *val = evaluate(stmt->as.print.expression, env);
print_value(val);
free_val(val);
break;
case STMT_EXPR:;
value_t *res = evaluate(stmt->as.expr.expression, env);
free_val(res);
break;
case STMT_VAR: {
value_t *value = malloc(sizeof(value_t));
value->type = VAL_NIL;
if (stmt->as.variable.initializer) {
free(value);
value = evaluate(stmt->as.variable.initializer, env);
}
ht_add(env, stmt->as.variable.name.value, value);
free_val(value);
break;
}
case STMT_BLOCK:
evaluate_block(stmt->as.block.statements, env, ht_init(env));
break;
case STMT_WHILE:;
value_t *cond = evaluate(stmt->as._while.condition, env);
while (is_truthy(cond)) {
evaluate_statement(stmt->as._while.body, env);
free_val(cond);
cond = evaluate(stmt->as._while.condition, env);
}
free_val(cond);
break;
case STMT_FUN:;
fn_t *fn = malloc(sizeof(fn_t));
fn->type = FN_CUSTOM;
fn->arity = stmt->as.function.params->length;
fn->stmt = stmt;
fn->call = _call;
value_t *fn_val = malloc(sizeof(value_t));
fn_val->type = VAL_FN;
fn_val->as.function = fn;
ht_add(env, stmt->as.function.name.value, fn_val);
free_val(fn_val);
free(fn);
break;
default:
break;
}
}
void interpret(stmt_array_t *array)
{
ht_t *env = ht_init(NULL);
value_t *clock_fn = malloc(sizeof(value_t));
clock_fn->type = VAL_FN;
fn_t *fn = malloc(sizeof(fn_t));
fn->type = FN_NATIVE;
fn->arity = 0;
/* Native function don't have body */
fn->stmt = NULL;
fn->call = _clock;
clock_fn->as.function = fn;
ht_add(env, "clock", clock_fn);
evaluate_statements(array, env);
ht_free(env);
free(clock_fn);
free(fn);
free_statements(array);
}

View file

@ -4,11 +4,13 @@
#include <errno.h> #include <errno.h>
#include "ast.h" #include "ast.h"
#include "interpreter.h"
#include "lexer.h" #include "lexer.h"
#include "parser.h" #include "parser.h"
int current = 0; int current = 0;
token_t *tokens; token_t *tokens;
void free_args(arg_array_t *array);
expr_t *expression(void); expr_t *expression(void);
stmt_t *expression_stmt(void); stmt_t *expression_stmt(void);
stmt_t *statement(void); stmt_t *statement(void);
@ -54,9 +56,7 @@ void free_expr(expr_t *expr)
break; break;
case EXPR_LITERAL: case EXPR_LITERAL:
if (expr->as.literal.value.type == VAL_STRING) { free(expr->as.literal.value);
free(expr->as.literal.value.as.string);
}
free(expr); free(expr);
break; break;
@ -78,6 +78,13 @@ void free_expr(expr_t *expr)
free(expr); free(expr);
break; break;
case EXPR_CALL:
free_args(expr->as.call.args);
free_expr(expr->as.call.callee);
free(expr->as.call.paren.value);
free(expr);
break;
default: default:
break; break;
} }
@ -109,6 +116,16 @@ int check(token_type_t type)
return tokens[current].type == type; return tokens[current].type == type;
} }
int match(token_type_t type)
{
if (check(type)) {
advance();
return 1;
} else {
return 0;
}
}
token_t *consume(token_type_t type, char *message) token_t *consume(token_type_t type, char *message)
{ {
if (!check(type)) { if (!check(type)) {
@ -123,21 +140,18 @@ token_t *consume(token_type_t type, char *message)
expr_t *primary(void) expr_t *primary(void)
{ {
if (check(TOKEN_FALSE) || check(TOKEN_TRUE) || check(TOKEN_NIL) || if (match(TOKEN_FALSE) || match(TOKEN_TRUE) || match(TOKEN_NIL) ||
check(TOKEN_NUMBER) || check(TOKEN_STRING)) { match(TOKEN_NUMBER) || match(TOKEN_STRING)) {
token_t *tok = peek(); token_t *tok = previous();
advance();
return create_literal_expr(tok); return create_literal_expr(tok);
} }
if (check(TOKEN_IDENTIFIER)) { if (match(TOKEN_IDENTIFIER)) {
token_t *tok = peek(); token_t *tok = previous();
advance();
return create_variable_expr(tok); return create_variable_expr(tok);
} }
if (check(TOKEN_LEFT_PAREN)) { if (match(TOKEN_LEFT_PAREN)) {
advance();
expr_t *expr = expression(); expr_t *expr = expression();
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression."); consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
return create_grouping_expr(expr); return create_grouping_expr(expr);
@ -146,25 +160,67 @@ expr_t *primary(void)
return NULL; return NULL;
} }
void arg_add(arg_array_t *array, expr_t *expr)
{
if (array->length == array->capacity) {
array->capacity *= 2;
array->arguments = realloc(array->arguments, array->capacity * sizeof(expr_t *));
}
array->arguments[array->length++] = expr;
}
void free_args(arg_array_t *array)
{
for (int i = 0; i < array->length; i++) {
free_expr(array->arguments[i]);
}
free(array->arguments);
free(array);
}
expr_t *call(void)
{
expr_t *expr = primary();
while (1) {
if (match(TOKEN_LEFT_PAREN)) {
arg_array_t *args = malloc(sizeof(arg_array_t));
args->arguments = malloc(DEFAULT_ARGS_SIZE * sizeof(expr_t *));
args->length = 0;
args->capacity = DEFAULT_ARGS_SIZE;
if (!check(TOKEN_RIGHT_PAREN)) {
do {
if (args->length >= 255) {
error(peek(), "Can't have more than 255 arguments.");
}
arg_add(args, expression());
} while (match(TOKEN_COMMA));
}
token_t *paren = consume(TOKEN_RIGHT_PAREN, "Expect ')' after arguments.");
expr = create_call_expr(expr, paren, args);
} else {
break;
}
}
return expr;
}
expr_t *unary(void) expr_t *unary(void)
{ {
if (check(TOKEN_BANG) || check(TOKEN_MINUS)) { if (match(TOKEN_BANG) || match(TOKEN_MINUS)) {
token_t *operator = peek(); token_t *operator = previous();
advance();
expr_t *right = unary(); expr_t *right = unary();
return create_unary_expr(operator, right); return create_unary_expr(operator, right);
} }
return primary(); return call();
} }
expr_t *factor(void) expr_t *factor(void)
{ {
expr_t *expr = unary(); expr_t *expr = unary();
while (check(TOKEN_SLASH) || check(TOKEN_STAR)) { while (match(TOKEN_SLASH) || match(TOKEN_STAR)) {
token_t *operator = peek(); token_t *operator = previous();
advance();
expr_t *right = unary(); expr_t *right = unary();
expr = create_binary_expr(operator, expr, right); expr = create_binary_expr(operator, expr, right);
} }
@ -176,9 +232,8 @@ expr_t *term(void)
{ {
expr_t *expr = factor(); expr_t *expr = factor();
while (check(TOKEN_MINUS) || check(TOKEN_PLUS)) { while (match(TOKEN_MINUS) || match(TOKEN_PLUS)) {
token_t *operator = peek(); token_t *operator = previous();
advance();
expr_t *right = factor(); expr_t *right = factor();
expr = create_binary_expr(operator, expr, right); expr = create_binary_expr(operator, expr, right);
} }
@ -190,10 +245,9 @@ expr_t *comparison(void)
{ {
expr_t *expr = term(); expr_t *expr = term();
while (check(TOKEN_GREATER) || check(TOKEN_GREATER_EQUAL) || check(TOKEN_LESS) while (match(TOKEN_GREATER) || match(TOKEN_GREATER_EQUAL) || match(TOKEN_LESS)
|| check(TOKEN_LESS_EQUAL)) { || match(TOKEN_LESS_EQUAL)) {
token_t *operator = peek(); token_t *operator = previous();
advance();
expr_t *right = term(); expr_t *right = term();
expr = create_binary_expr(operator, expr, right); expr = create_binary_expr(operator, expr, right);
} }
@ -205,9 +259,8 @@ expr_t *equality(void)
{ {
expr_t *expr = comparison(); expr_t *expr = comparison();
while (check(TOKEN_BANG_EQUAL) || check(TOKEN_EQUAL_EQUAL)) { while (match(TOKEN_BANG_EQUAL) || match(TOKEN_EQUAL_EQUAL)) {
token_t *operator = peek(); token_t *operator = previous();
advance();
expr_t *right = comparison(); expr_t *right = comparison();
expr = create_binary_expr(operator, expr, right); expr = create_binary_expr(operator, expr, right);
} }
@ -219,9 +272,8 @@ expr_t *and(void)
{ {
expr_t *expr = equality(); expr_t *expr = equality();
while (check(TOKEN_AND)) { while (match(TOKEN_AND)) {
token_t *operator = peek(); token_t *operator = previous();
advance();
expr_t *right = equality(); expr_t *right = equality();
expr = create_logical_expr(operator, expr, right); expr = create_logical_expr(operator, expr, right);
} }
@ -233,9 +285,8 @@ expr_t *or(void)
{ {
expr_t *expr = and(); expr_t *expr = and();
while (check(TOKEN_OR)) { while (match(TOKEN_OR)) {
token_t *operator = peek(); token_t *operator = previous();
advance();
expr_t *right = and(); expr_t *right = and();
expr = create_logical_expr(operator, expr, right); expr = create_logical_expr(operator, expr, right);
} }
@ -247,9 +298,8 @@ expr_t *assignment(void)
{ {
expr_t *expr = or(); expr_t *expr = or();
if (check(TOKEN_EQUAL)) { if (match(TOKEN_EQUAL)) {
token_t *equals = peek(); token_t *equals = previous();
advance();
expr_t *value = assignment(); expr_t *value = assignment();
if (expr->type == EXPR_VARIABLE) { if (expr->type == EXPR_VARIABLE) {
@ -302,6 +352,11 @@ void free_statement(stmt_t *stmt)
free_expr(stmt->as._while.condition); free_expr(stmt->as._while.condition);
free_statement(stmt->as._while.body); free_statement(stmt->as._while.body);
free(stmt); free(stmt);
} else if (stmt->type == STMT_FUN) {
free(stmt->as.function.name.value);
free_array(stmt->as.function.params);
free_statement(stmt->as.function.body);
free(stmt);
} }
} }
@ -318,10 +373,8 @@ stmt_t *for_stmt(void)
{ {
consume(TOKEN_LEFT_PAREN, "Expect '(' after 'for'."); consume(TOKEN_LEFT_PAREN, "Expect '(' after 'for'.");
stmt_t *initializer = NULL; stmt_t *initializer = NULL;
if (check(TOKEN_SEMICOLON)) { if (match(TOKEN_SEMICOLON)) {
advance(); } else if (match(TOKEN_VAR)) {
} else if (check(TOKEN_VAR)) {
advance();
initializer = var_declaration(); initializer = var_declaration();
} else { } else {
initializer = expression_stmt(); initializer = expression_stmt();
@ -393,8 +446,7 @@ stmt_t *if_stmt(void)
consume(TOKEN_RIGHT_PAREN, "Expect ')' after if condition."); consume(TOKEN_RIGHT_PAREN, "Expect ')' after if condition.");
stmt_t *then_branch = statement(); stmt_t *then_branch = statement();
stmt_t *else_branch = NULL; stmt_t *else_branch = NULL;
if (check(TOKEN_ELSE)) { if (match(TOKEN_ELSE)) {
advance();
else_branch = statement(); else_branch = statement();
} }
stmt_t *stmt = malloc(sizeof(stmt_t)); stmt_t *stmt = malloc(sizeof(stmt_t));
@ -461,36 +513,68 @@ stmt_t *expression_stmt(void)
stmt_t *statement(void) stmt_t *statement(void)
{ {
if (check(TOKEN_FOR)) { if (match(TOKEN_FOR)) {
advance();
return for_stmt(); return for_stmt();
} }
if (check(TOKEN_IF)) { if (match(TOKEN_IF)) {
advance();
return if_stmt(); return if_stmt();
} }
if (check(TOKEN_PRINT)) { if (match(TOKEN_PRINT)) {
advance();
return print_stmt(); return print_stmt();
} }
if (check(TOKEN_WHILE)) { if (match(TOKEN_WHILE)) {
advance();
return while_stmt(); return while_stmt();
} }
if (check(TOKEN_LEFT_BRACE)) { if (match(TOKEN_LEFT_BRACE)) {
advance();
return block_stmt(); return block_stmt();
} }
return expression_stmt(); return expression_stmt();
} }
stmt_t *function(char *kind)
{
char err[512];
snprintf(err, 512, "Expect %s name.", kind);
token_t *name = consume(TOKEN_IDENTIFIER, err);
snprintf(err, 512, "Expect '(' after %s name.", kind);
consume(TOKEN_LEFT_PAREN, err);
array_t *parameters = malloc(sizeof(array_t));
parameters->tokens = malloc(DEFAULT_ARGS_SIZE * sizeof(token_t));
parameters->length = 0;
parameters->capacity = DEFAULT_ARGS_SIZE;
if (!check(TOKEN_RIGHT_PAREN)) {
do {
if (parameters->length >= 255) {
error(peek(), "Can't have more than 255 parameters.");
}
token_t *param = consume(TOKEN_IDENTIFIER, "Expect parameter name.");
token_t param_cpy;
memcpy(&param_cpy, param, sizeof(token_t));
param_cpy.value = strdup(param->value);
token_add(parameters, param_cpy);
} while (match(TOKEN_COMMA));
}
consume(TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
snprintf(err, 512, "Expect '{' before %s body.", kind);
consume(TOKEN_LEFT_BRACE, err);
stmt_t *stmt = malloc(sizeof(stmt_t));
stmt->type = STMT_FUN;
stmt->as.function.name.type = name->type;
stmt->as.function.name.value = strdup(name->value);
stmt->as.function.name.line = name->line;
stmt->as.function.params = parameters;
stmt->as.function.body = block_stmt();
return stmt;
}
stmt_t *var_declaration(void) stmt_t *var_declaration(void)
{ {
token_t *name = consume(TOKEN_IDENTIFIER, "Expect variable name."); token_t *name = consume(TOKEN_IDENTIFIER, "Expect variable name.");
expr_t *initializer = NULL; expr_t *initializer = NULL;
if (check(TOKEN_EQUAL)) { if (match(TOKEN_EQUAL)) {
advance();
initializer = expression(); initializer = expression();
} }
@ -507,8 +591,10 @@ stmt_t *var_declaration(void)
stmt_t *declaration(void) stmt_t *declaration(void)
{ {
if (check(TOKEN_VAR)) { if (match(TOKEN_FUN)) {
advance(); return function("function");
}
if (match(TOKEN_VAR)) {
return var_declaration(); return var_declaration();
} }
@ -522,7 +608,7 @@ stmt_array_t *parse(token_t *tks)
return NULL; return NULL;
} else { } else {
stmt_array_t *statements = malloc(sizeof(stmt_array_t)); stmt_array_t *statements = malloc(sizeof(stmt_array_t));
statements->statements = malloc(DEFAULT_STMTS_SIZE * sizeof(stmt_t)); statements->statements = malloc(DEFAULT_STMTS_SIZE * sizeof(stmt_t *));
statements->length = 0; statements->length = 0;
statements->capacity = DEFAULT_STMTS_SIZE; statements->capacity = DEFAULT_STMTS_SIZE;
while (!end()) { while (!end()) {

View file

@ -34,18 +34,15 @@ int main(int argc, char **argv)
free_expr(expr); free_expr(expr);
} else if (!strcmp(command, "evaluate")) { } else if (!strcmp(command, "evaluate")) {
expr_t *expr = parse_expr(array->tokens); expr_t *expr = parse_expr(array->tokens);
value_t val = evaluate(expr, NULL); value_t *val = evaluate(expr, NULL);
print_value(val); print_value(val);
free_array(array); free_array(array);
free_expr(expr); free_expr(expr);
} else if (!strcmp(command, "run")) { } else if (!strcmp(command, "run")) {
ht_t *env = ht_init(NULL);
stmt_array_t *stmts = parse(array->tokens); stmt_array_t *stmts = parse(array->tokens);
if (errno != 65) { if (errno != 65) {
evaluate_statements(stmts, env); interpret(stmts);
ht_free(env);
free_array(array); free_array(array);
free_statements(stmts);
} }
} else { } else {
fprintf(stderr, "Unknown command: %s\n", command); fprintf(stderr, "Unknown command: %s\n", command);