Skip to content

Commit

Permalink
Merge pull request #189 from KennyOliver/issue-188
Browse files Browse the repository at this point in the history
  • Loading branch information
KennyOliver authored Jan 9, 2025
2 parents 8444ab2 + e9c2bae commit ec60be7
Show file tree
Hide file tree
Showing 14 changed files with 326 additions and 158 deletions.
26 changes: 26 additions & 0 deletions docs/syntax_examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ These are examples showcasing the unique (& fun) syntax of FlavorLang. They give
17. [Nested Function Application](#17)
18. [Basic Arrays & Operations](#18)
19. [2D Arrays](#19)
20. [Call Functions by Reference (Even in Arrays)](#20)

---

Expand Down Expand Up @@ -490,6 +491,31 @@ serve("Length of nested array:", length(mixed_array[2]));
serve("All array operation tests complete!");
```

### 20. Call Functions by Reference (Even in Arrays) <a id="20"></a>

```js
serve(length("hello"));

const a = [random(), random(), random()];
const b = [random, random, random];

serve(a);

for i in 0..(length(b)) {
serve(b[i](1, 2));
}

create my_func(x, y, z) {
deliver x * y * z;
}

const c = [my_func, my_func, my_func, my_func];

for i in 0..(length(c)) {
serve(c[i](0.5, 3, i));
}
```

---

## License
Expand Down
52 changes: 42 additions & 10 deletions src/interpreter/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ bool literal_type_matches_arg_type(LiteralType lit_type, ArgType arg_type) {
return lit_type == TYPE_BOOLEAN;
case ARG_TYPE_ARRAY:
return lit_type == TYPE_ARRAY;
case ARG_TYPE_NUMERIC:
return (lit_type == TYPE_INTEGER) || (lit_type == TYPE_FLOAT);
default:
return false; // Unknown ArgType
}
Expand Down Expand Up @@ -55,6 +57,15 @@ InterpretResult interpret_arguments(ASTNode *node, Environment *env,
case ARG_TYPE_FLOAT:
*((FLOAT_SIZE *)current_spec.out_ptr) = lv.data.floating_point;
break;
case ARG_TYPE_NUMERIC:
if (lv.type == TYPE_INTEGER) {
*((FLOAT_SIZE *)current_spec.out_ptr) =
(FLOAT_SIZE)lv.data.integer;
} else { // TYPE_FLOAT
*((FLOAT_SIZE *)current_spec.out_ptr) =
lv.data.floating_point;
}
break;
case ARG_TYPE_STRING:
*((char **)current_spec.out_ptr) = lv.data.string;
break;
Expand All @@ -70,14 +81,17 @@ InterpretResult interpret_arguments(ASTNode *node, Environment *env,
}
} else {
// Construct a string of expected type for the error message
char expected_type[32] = "";
char expected_type[64] = "";
switch (current_spec.type) {
case ARG_TYPE_INTEGER:
strcpy(expected_type, "integer");
break;
case ARG_TYPE_FLOAT:
strcpy(expected_type, "float");
break;
case ARG_TYPE_NUMERIC:
strcpy(expected_type, "numeric (integer or float)");
break;
case ARG_TYPE_STRING:
strcpy(expected_type, "string");
break;
Expand Down Expand Up @@ -185,7 +199,7 @@ InterpretResult builtin_input(ASTNode *node, Environment *env) {
return make_result(result, false, false);
}

// Built-in `random()` function with 0, 1, or 2 arguments
// Built-in `random()` function with 0, 1, or 2 numeric arguments
InterpretResult builtin_random(ASTNode *node, Environment *env) {
FLOAT_SIZE min = 0.0L; // default min
FLOAT_SIZE max = 1.0L; // default max
Expand All @@ -199,15 +213,15 @@ InterpretResult builtin_random(ASTNode *node, Environment *env) {
temp = temp->next;
}
if (num_args > 2) {
return raise_error(
"`random()` takes at most 2 arguments, but %zu provided.\n",
num_args);
return raise_error("`random()` takes at most 2 numeric arguments "
"(integer or float), but %zu provided.\n",
num_args);
}

if (num_args == 1) {
// One argument provided: set max, min remains 0.0
ArgumentSpec specs[1];
specs[0].type = ARG_TYPE_FLOAT;
specs[0].type = ARG_TYPE_NUMERIC;
specs[0].out_ptr = &max;

InterpretResult args_res = interpret_arguments(arg_node, env, 1, specs);
Expand All @@ -217,9 +231,9 @@ InterpretResult builtin_random(ASTNode *node, Environment *env) {
} else if (num_args == 2) {
// Two arguments provided: set min and max
ArgumentSpec specs[2];
specs[0].type = ARG_TYPE_FLOAT;
specs[0].type = ARG_TYPE_NUMERIC;
specs[0].out_ptr = &min;
specs[1].type = ARG_TYPE_FLOAT;
specs[1].type = ARG_TYPE_NUMERIC;
specs[1].out_ptr = &max;

InterpretResult args_res = interpret_arguments(arg_node, env, 2, specs);
Expand Down Expand Up @@ -285,7 +299,7 @@ void print_literal_value(LiteralValue lv) {
printf("]");
break;
case TYPE_FUNCTION:
printf("<Function %s>", lv.data.function_ptr->name);
printf("<Function %s>", lv.data.function_name);
break;
case TYPE_ERROR:
printf("<Error>");
Expand Down Expand Up @@ -416,19 +430,28 @@ InterpretResult builtin_cast(ASTNode *node, Environment *env) {
"`builtin_cast()` expects an `AST_FUNCTION_CALL` node.\n");
}

char *cast_type = strdup(node->function_call.name);
// Extract the cast type from function_ref
ASTNode *func_ref = node->function_call.function_ref;
if (func_ref->type != AST_VARIABLE_REFERENCE) {
return raise_error("`builtin_cast()` expects the function reference to "
"be a variable name.\n");
}

char *cast_type = strdup(func_ref->variable_name);
if (!cast_type) {
return raise_error("No cast type provided to `builtin_cast()`.\n");
}

ASTNode *arg_node = node->function_call.arguments;
if (!arg_node) {
free(cast_type);
return raise_error(
"No expression provided for cast in `builtin_cast()`.\n");
}

// Ensure there's only one argument
if (arg_node->next != NULL) {
free(cast_type);
return raise_error("`%s` cast function takes exactly one argument.\n",
cast_type);
}
Expand All @@ -438,6 +461,7 @@ InterpretResult builtin_cast(ASTNode *node, Environment *env) {
// Interpret the expression to be casted
InterpretResult expr_result = interpret_node(expr, env);
if (expr_result.is_error) {
free(cast_type);
return expr_result; // Propagate the error
}

Expand Down Expand Up @@ -474,10 +498,12 @@ InterpretResult builtin_cast(ASTNode *node, Environment *env) {
cast_val.data.string = strdup(original.data.string);
break;
default:
free(cast_type);
return raise_error("Unsupported type for string cast.\n");
}

if (!cast_val.data.string) {
free(cast_type);
return raise_error(
"Memory allocation failed during string cast.\n");
}
Expand All @@ -491,6 +517,7 @@ InterpretResult builtin_cast(ASTNode *node, Environment *env) {
case TYPE_STRING: {
INT_SIZE temp;
if (!is_valid_int(original.data.string, &temp)) {
free(cast_type);
return raise_error("Cannot cast string \"%s\" to int.\n",
original.data.string);
}
Expand All @@ -507,6 +534,7 @@ InterpretResult builtin_cast(ASTNode *node, Environment *env) {
cast_val.data.integer = original.data.integer;
break;
default:
free(cast_type);
return raise_error("Unsupported type for int cast.\n");
}

Expand All @@ -519,6 +547,7 @@ InterpretResult builtin_cast(ASTNode *node, Environment *env) {
case TYPE_STRING: {
FLOAT_SIZE temp;
if (!is_valid_float(original.data.string, &temp)) {
free(cast_type);
return raise_error("Cannot cast string \"%s\" to float.\n",
original.data.string);
}
Expand All @@ -535,14 +564,17 @@ InterpretResult builtin_cast(ASTNode *node, Environment *env) {
cast_val.data.floating_point = original.data.floating_point;
break;
default:
free(cast_type);
return raise_error("Unsupported type for float cast.\n");
}

result_res.value = cast_val;
} else {
free(cast_type);
return raise_error("Unsupported cast type: `%s`\n", cast_type);
}

free(cast_type);
return result_res;
}

Expand Down
1 change: 1 addition & 0 deletions src/interpreter/builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ typedef enum {
ARG_TYPE_STRING,
ARG_TYPE_BOOLEAN,
ARG_TYPE_ARRAY,
ARG_TYPE_NUMERIC // Either float or int
} ArgType;
typedef struct {
size_t num_types; // number of acceptable types
Expand Down
Loading

0 comments on commit ec60be7

Please sign in to comment.