add function assignment
This commit is contained in:
@@ -33,7 +33,6 @@ typedef enum {
|
|||||||
field__address,
|
field__address,
|
||||||
__call__,
|
__call__,
|
||||||
__number__,
|
__number__,
|
||||||
field_log,
|
|
||||||
field_length,
|
field_length,
|
||||||
__getattribute__,
|
__getattribute__,
|
||||||
__set_attr__,
|
__set_attr__,
|
||||||
|
|||||||
@@ -32,13 +32,6 @@ int yywrap(void * unused_param) {
|
|||||||
":" { return TOKEN_COLON; }
|
":" { return TOKEN_COLON; }
|
||||||
|
|
||||||
"=" { return TOKEN_ASSIGN; }
|
"=" { return TOKEN_ASSIGN; }
|
||||||
"+=" { return TOKEN_ASSIGN_PLUS; }
|
|
||||||
"-=" { return TOKEN_ASSIGN_MINUS; }
|
|
||||||
"//=" { return TOKEN_ASSIGN_FLOORDIV; }
|
|
||||||
"/=" { return TOKEN_ASSIGN_SLASH; }
|
|
||||||
"%=" { return TOKEN_ASSIGN_MODULO; }
|
|
||||||
"*=" { return TOKEN_ASSIGN_STAR; }
|
|
||||||
"^=" { return TOKEN_ASSIGN_CARET; }
|
|
||||||
|
|
||||||
"not"[ \t]+"in" { return TOKEN_NOT_IN; }
|
"not"[ \t]+"in" { return TOKEN_NOT_IN; }
|
||||||
"in" { return TOKEN_IN; }
|
"in" { return TOKEN_IN; }
|
||||||
|
|||||||
@@ -17,13 +17,6 @@ typedef enum {
|
|||||||
TOKEN_INDENT,
|
TOKEN_INDENT,
|
||||||
|
|
||||||
TOKEN_ASSIGN,
|
TOKEN_ASSIGN,
|
||||||
TOKEN_ASSIGN_PLUS,
|
|
||||||
TOKEN_ASSIGN_MINUS,
|
|
||||||
TOKEN_ASSIGN_FLOORDIV,
|
|
||||||
TOKEN_ASSIGN_SLASH,
|
|
||||||
TOKEN_ASSIGN_MODULO,
|
|
||||||
TOKEN_ASSIGN_STAR,
|
|
||||||
TOKEN_ASSIGN_CARET,
|
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
TOKEN_CARET, // ^ (Exponentiation)
|
TOKEN_CARET, // ^ (Exponentiation)
|
||||||
@@ -31,8 +24,8 @@ typedef enum {
|
|||||||
TOKEN_SLASH, // / (Division)
|
TOKEN_SLASH, // / (Division)
|
||||||
TOKEN_FLOORDIV, // // (Floor Division)
|
TOKEN_FLOORDIV, // // (Floor Division)
|
||||||
TOKEN_MODULO, // % (Modulo)
|
TOKEN_MODULO, // % (Modulo)
|
||||||
TOKEN_PLUS, // + (Addition)
|
|
||||||
TOKEN_MINUS, // - (Subtraction)
|
TOKEN_MINUS, // - (Subtraction)
|
||||||
|
TOKEN_PLUS, // + (Addition)
|
||||||
TOKEN_LT, // <
|
TOKEN_LT, // <
|
||||||
TOKEN_GT, // >
|
TOKEN_GT, // >
|
||||||
TOKEN_LE, // <=
|
TOKEN_LE, // <=
|
||||||
|
|||||||
@@ -7,25 +7,38 @@
|
|||||||
#include "assign.h"
|
#include "assign.h"
|
||||||
#include "../../../lexer/token.h"
|
#include "../../../lexer/token.h"
|
||||||
#include "../../../memory.h"
|
#include "../../../memory.h"
|
||||||
|
#include "../../function/function.h"
|
||||||
#include "../../parser.h"
|
#include "../../parser.h"
|
||||||
|
#include "../../string/string.h"
|
||||||
|
#include "../access/access.h"
|
||||||
#include "../call/call.h"
|
#include "../call/call.h"
|
||||||
|
#include "../identifier/identifier.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
||||||
ParsedValue *assign_to, size_t *index) {
|
ParsedValue *assign_to, size_t *index) {
|
||||||
Token *token = darray_get(tokens, *index);
|
Token *token = darray_get(tokens, *index);
|
||||||
|
bool is_function = false;
|
||||||
|
char *function_name;
|
||||||
|
bool to_free_function_name = false;
|
||||||
|
DArray function_args;
|
||||||
|
ParsedValue *function_assign_to;
|
||||||
switch (assign_to->type) {
|
switch (assign_to->type) {
|
||||||
case AST_IDENTIFIER:
|
case AST_IDENTIFIER:
|
||||||
case AST_ACCESS:
|
case AST_ACCESS:
|
||||||
break;
|
break;
|
||||||
case AST_CALL:;
|
case AST_CALL:;
|
||||||
ParsedCall *call = assign_to->data;
|
ParsedCall *call = assign_to->data;
|
||||||
|
darray_init(&function_args, sizeof(char *));
|
||||||
for (size_t i = 0; i < call->args.size; i++) {
|
for (size_t i = 0; i < call->args.size; i++) {
|
||||||
if (((ParsedValue *)darray_get(&call->args, i))->type != AST_IDENTIFIER) {
|
ParsedValue *arg = darray_get(&call->args, i);
|
||||||
|
if (arg->type != AST_IDENTIFIER) {
|
||||||
free_parsed(assign_to);
|
free_parsed(assign_to);
|
||||||
free(assign_to);
|
free(assign_to);
|
||||||
|
darray_free(&function_args, free_parameter);
|
||||||
return (ParsedValueReturn){
|
return (ParsedValueReturn){
|
||||||
create_err(
|
create_err(
|
||||||
token->line, token->column, token->length, file, "Syntax Error",
|
token->line, token->column, token->length, file, "Syntax Error",
|
||||||
@@ -34,6 +47,32 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
|||||||
"only use letters, digits, or _, and can't be keywords."),
|
"only use letters, digits, or _, and can't be keywords."),
|
||||||
NULL};
|
NULL};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *param = strdup(((ParsedIdentifier *)arg->data)->name);
|
||||||
|
darray_push(&function_args, ¶m);
|
||||||
|
}
|
||||||
|
darray_free(&call->args, free_parsed);
|
||||||
|
is_function = true;
|
||||||
|
function_assign_to = call->to_call;
|
||||||
|
switch (function_assign_to->type) {
|
||||||
|
case AST_IDENTIFIER:
|
||||||
|
function_name = ((ParsedIdentifier *)function_assign_to->data)->name;
|
||||||
|
break;
|
||||||
|
case AST_ACCESS:
|
||||||
|
if (((ParsedAccess *)function_assign_to->data)->access->type ==
|
||||||
|
AST_STRING) {
|
||||||
|
ParsedString *name =
|
||||||
|
((ParsedAccess *)function_assign_to->data)->access->data;
|
||||||
|
function_name = checked_malloc(name->length + 1);
|
||||||
|
function_name[name->length] = 0;
|
||||||
|
memcpy(function_name, name->string, name->length);
|
||||||
|
to_free_function_name = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// FALL THROUGH
|
||||||
|
default:
|
||||||
|
function_name = "anonymous";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
@@ -44,36 +83,40 @@ ParsedValueReturn parse_assign(char *file, DArray *tokens,
|
|||||||
free(assign_to);
|
free(assign_to);
|
||||||
return (ParsedValueReturn){err, NULL};
|
return (ParsedValueReturn){err, NULL};
|
||||||
}
|
}
|
||||||
|
(*index)++;
|
||||||
|
token = darray_get(tokens, *index);
|
||||||
|
ParsedValueReturn from = parse_token(file, tokens, index, true);
|
||||||
|
if (from.err.exists) {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
if (!from.value) {
|
||||||
|
return (ParsedValueReturn){create_err(token->line, token->column,
|
||||||
|
token->length, file, "Syntax Error",
|
||||||
|
"expected body"),
|
||||||
|
NULL};
|
||||||
|
}
|
||||||
|
if (is_function) {
|
||||||
|
from.value =
|
||||||
|
create_parsed_function(function_name, function_args, from.value);
|
||||||
|
if (to_free_function_name) free(function_name);
|
||||||
|
free(assign_to->data);
|
||||||
|
free(assign_to);
|
||||||
|
assign_to = function_assign_to;
|
||||||
|
}
|
||||||
ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
|
ParsedAssign *assign = checked_malloc(sizeof(ParsedAssign));
|
||||||
assign->to = assign_to;
|
assign->to = assign_to;
|
||||||
assign->type = token->type;
|
assign->type = 0;
|
||||||
assign->from = NULL;
|
assign->from = NULL;
|
||||||
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
ParsedValue *parsedValue = checked_malloc(sizeof(ParsedValue));
|
||||||
parsedValue->type = AST_ASSIGN;
|
parsedValue->type = AST_ASSIGN;
|
||||||
parsedValue->data = assign;
|
parsedValue->data = assign;
|
||||||
(*index)++;
|
|
||||||
ArErr err = error_if_finished(file, tokens, index);
|
ArErr err = error_if_finished(file, tokens, index);
|
||||||
if (err.exists) {
|
if (err.exists) {
|
||||||
free_parsed(parsedValue);
|
free_parsed(parsedValue);
|
||||||
free(parsedValue);
|
free(parsedValue);
|
||||||
return (ParsedValueReturn){err, NULL};
|
return (ParsedValueReturn){err, NULL};
|
||||||
}
|
}
|
||||||
token = darray_get(tokens, *index);
|
|
||||||
ParsedValueReturn from = parse_token(file, tokens, index, true);
|
|
||||||
if (from.err.exists) {
|
|
||||||
free_parsed(parsedValue);
|
|
||||||
free(parsedValue);
|
|
||||||
return from;
|
|
||||||
}
|
|
||||||
assign->from = from.value;
|
assign->from = from.value;
|
||||||
if (!assign->from) {
|
|
||||||
free_parsed(parsedValue);
|
|
||||||
free(parsedValue);
|
|
||||||
return (ParsedValueReturn){create_err(token->line, token->column,
|
|
||||||
token->length, file, "Syntax Error",
|
|
||||||
"expected body"),
|
|
||||||
NULL};
|
|
||||||
}
|
|
||||||
return (ParsedValueReturn){no_err, parsedValue};
|
return (ParsedValueReturn){no_err, parsedValue};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,13 +158,6 @@ ParsedValueReturn parse_token_full(char *file, DArray *tokens, size_t *index,
|
|||||||
token = darray_get(tokens, *index);
|
token = darray_get(tokens, *index);
|
||||||
switch (token->type) {
|
switch (token->type) {
|
||||||
case TOKEN_ASSIGN:
|
case TOKEN_ASSIGN:
|
||||||
case TOKEN_ASSIGN_CARET:
|
|
||||||
case TOKEN_ASSIGN_FLOORDIV:
|
|
||||||
case TOKEN_ASSIGN_MINUS:
|
|
||||||
case TOKEN_ASSIGN_MODULO:
|
|
||||||
case TOKEN_ASSIGN_PLUS:
|
|
||||||
case TOKEN_ASSIGN_SLASH:
|
|
||||||
case TOKEN_ASSIGN_STAR:
|
|
||||||
output = parse_assign(file, tokens, output.value, index);
|
output = parse_assign(file, tokens, output.value, index);
|
||||||
break;
|
break;
|
||||||
case TOKEN_LPAREN:
|
case TOKEN_LPAREN:
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ ArgonObject *create_ARGON_DICTIONARY_TYPE___string__(size_t argc,
|
|||||||
string_object->value.as_str->length);
|
string_object->value.as_str->length);
|
||||||
string_length += string_object->value.as_str->length;
|
string_length += string_object->value.as_str->length;
|
||||||
} else {
|
} else {
|
||||||
char *string_obj = "<object>";
|
char *string_obj = "{...}";
|
||||||
size_t length = strlen(string_obj);
|
size_t length = strlen(string_obj);
|
||||||
string = realloc(string, string_length + length);
|
string = realloc(string, string_length + length);
|
||||||
memcpy(string + string_length, string_obj, length);
|
memcpy(string + string_length, string_obj, length);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
|
|||||||
"__string__",
|
"__string__",
|
||||||
"__subtract__",
|
"__subtract__",
|
||||||
"__multiply__",
|
"__multiply__",
|
||||||
"__divide__",
|
"__divide__",
|
||||||
"__new__",
|
"__new__",
|
||||||
"__init__",
|
"__init__",
|
||||||
"__boolean__",
|
"__boolean__",
|
||||||
@@ -49,7 +49,6 @@ const char *built_in_field_names[BUILT_IN_FIELDS_COUNT] = {
|
|||||||
"address",
|
"address",
|
||||||
"__call__",
|
"__call__",
|
||||||
"__number__",
|
"__number__",
|
||||||
"log",
|
|
||||||
"length",
|
"length",
|
||||||
"__getattribute__",
|
"__getattribute__",
|
||||||
"__set_attr__",
|
"__set_attr__",
|
||||||
|
|||||||
@@ -31,6 +31,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
extern char **environ;
|
||||||
|
#endif
|
||||||
|
|
||||||
ArgonObject *ARGON_METHOD_TYPE;
|
ArgonObject *ARGON_METHOD_TYPE;
|
||||||
Stack *Global_Scope = NULL;
|
Stack *Global_Scope = NULL;
|
||||||
@@ -692,11 +697,11 @@ void bootstrap_types() {
|
|||||||
create_ARGON_DICTIONARY_TYPE();
|
create_ARGON_DICTIONARY_TYPE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_to_scope(Stack *stack, char *name, ArgonObject *value) {
|
void add_to_hashmap(struct hashmap_GC *hashmap, char *name, ArgonObject *value) {
|
||||||
size_t length = strlen(name);
|
size_t length = strlen(name);
|
||||||
uint64_t hash = siphash64_bytes(name, length, siphash_key);
|
uint64_t hash = siphash64_bytes(name, length, siphash_key);
|
||||||
ArgonObject *key = new_string_object(name, length, 0, hash);
|
ArgonObject *key = new_string_object(name, length, 0, hash);
|
||||||
hashmap_insert_GC(stack->scope, hash, key, value, 0);
|
hashmap_insert_GC(hashmap, hash, key, value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bootstrap_globals() {
|
void bootstrap_globals() {
|
||||||
@@ -712,11 +717,56 @@ void bootstrap_globals() {
|
|||||||
add_to_scope(Global_Scope, "divide", DIVIDE_FUNCTION);
|
add_to_scope(Global_Scope, "divide", DIVIDE_FUNCTION);
|
||||||
add_to_scope(Global_Scope, "dictionary", ARGON_DICTIONARY_TYPE);
|
add_to_scope(Global_Scope, "dictionary", ARGON_DICTIONARY_TYPE);
|
||||||
|
|
||||||
ArgonObject *argon_term = new_class();
|
struct hashmap_GC *argon_term = createHashmap_GC();
|
||||||
add_builtin_field(argon_term, __init__, ARGON_NULL);
|
add_to_hashmap(argon_term, "log",
|
||||||
add_builtin_field(argon_term, field_log,
|
|
||||||
create_argon_native_function("log", term_log));
|
create_argon_native_function("log", term_log));
|
||||||
add_to_scope(Global_Scope, "term", argon_term);
|
add_to_scope(Global_Scope, "term", create_dictionary(argon_term));
|
||||||
|
|
||||||
|
|
||||||
|
struct hashmap_GC *environment_variables = createHashmap_GC();
|
||||||
|
#if defined(_WIN32)
|
||||||
|
// Windows: use WinAPI
|
||||||
|
LPCH env = GetEnvironmentStringsA();
|
||||||
|
if (!env) return;
|
||||||
|
|
||||||
|
for (LPCH var = env; *var; var += strlen(var) + 1) {
|
||||||
|
// Each string is like "KEY=VALUE"
|
||||||
|
const char *equals = strchr(var, '=');
|
||||||
|
if (equals) {
|
||||||
|
size_t key_len = equals - var;
|
||||||
|
char key[256];
|
||||||
|
if (key_len >= sizeof(key))
|
||||||
|
key_len = sizeof(key) - 1;
|
||||||
|
strncpy(key, var, key_len);
|
||||||
|
key[key_len] = '\0';
|
||||||
|
|
||||||
|
const char *value = getenv(key);
|
||||||
|
add_to_hashmap(environment_variables, key,
|
||||||
|
value?new_string_object_null_terminated((char *)value):ARGON_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeEnvironmentStringsA(env);
|
||||||
|
#else
|
||||||
|
// POSIX systems: use environ
|
||||||
|
for (char **env = environ; *env != NULL; env++) {
|
||||||
|
const char *equals = strchr(*env, '=');
|
||||||
|
if (equals) {
|
||||||
|
size_t key_len = equals - *env;
|
||||||
|
char key[256];
|
||||||
|
if (key_len >= sizeof(key))
|
||||||
|
key_len = sizeof(key) - 1;
|
||||||
|
strncpy(key, *env, key_len);
|
||||||
|
key[key_len] = '\0';
|
||||||
|
|
||||||
|
const char *value = getenv(key);
|
||||||
|
add_to_hashmap(environment_variables, key,
|
||||||
|
value?new_string_object_null_terminated((char *)value):ARGON_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
add_to_scope(Global_Scope, "env", create_dictionary(environment_variables));
|
||||||
}
|
}
|
||||||
|
|
||||||
int compare_by_order(const void *a, const void *b) {
|
int compare_by_order(const void *a, const void *b) {
|
||||||
@@ -800,6 +850,13 @@ Stack *create_scope(Stack *prev, bool force) {
|
|||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_to_scope(Stack *stack, char *name, ArgonObject *value) {
|
||||||
|
size_t length = strlen(name);
|
||||||
|
uint64_t hash = siphash64_bytes(name, length, siphash_key);
|
||||||
|
ArgonObject *key = new_string_object(name, length, 0, hash);
|
||||||
|
hashmap_insert_GC(stack->scope, hash, key, value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void runtime(Translated _translated, RuntimeState _state, Stack *stack,
|
void runtime(Translated _translated, RuntimeState _state, Stack *stack,
|
||||||
ArErr *err) {
|
ArErr *err) {
|
||||||
static void *const dispatch_table[] = {
|
static void *const dispatch_table[] = {
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ Stack *create_scope(Stack *prev, bool force);
|
|||||||
|
|
||||||
void add_to_scope(Stack *stack, char *name, ArgonObject *value);
|
void add_to_scope(Stack *stack, char *name, ArgonObject *value);
|
||||||
|
|
||||||
|
void add_to_hashmap(struct hashmap_GC *hashmap, char *name, ArgonObject *value);
|
||||||
|
|
||||||
void runtime(Translated translated, RuntimeState state, Stack *stack,
|
void runtime(Translated translated, RuntimeState state, Stack *stack,
|
||||||
ArErr *err);
|
ArErr *err);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "../../hash_data/hash_data.h"
|
#include "../../hash_data/hash_data.h"
|
||||||
#include "../../parser/assignable/access/access.h"
|
#include "../../parser/assignable/access/access.h"
|
||||||
#include "../../parser/assignable/identifier/identifier.h"
|
#include "../../parser/assignable/identifier/identifier.h"
|
||||||
#include "../../parser/string/string.h"
|
|
||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -71,6 +70,7 @@ size_t translate_parsed_assignment(Translated *translated,
|
|||||||
push_instruction_byte(translated, OP_CALL);
|
push_instruction_byte(translated, OP_CALL);
|
||||||
translated->registerAssignment--;
|
translated->registerAssignment--;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "panic: unsupported assignment\n");
|
fprintf(stderr, "panic: unsupported assignment\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|||||||
1
tests/anonymous_function.ar
Normal file
1
tests/anonymous_function.ar
Normal file
@@ -0,0 +1 @@
|
|||||||
|
term.log(()=10)
|
||||||
1
tests/env.ar
Normal file
1
tests/env.ar
Normal file
@@ -0,0 +1 @@
|
|||||||
|
term.log("hello,", env.USER+'.', 'how is', env.XDG_SESSION_TYPE+'?')
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
term.log(global."hello world")
|
term.log(global)
|
||||||
let i = 1e8
|
let i = 1e8
|
||||||
while (i) do
|
while (i) do
|
||||||
i=i-1
|
i=i-1
|
||||||
6
tests/number-memory-leak.ar
Normal file
6
tests/number-memory-leak.ar
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
let i = 10
|
||||||
|
let x = 1
|
||||||
|
while (i) do
|
||||||
|
x = x * 1e100000000
|
||||||
|
term.log(i=i-1)
|
||||||
|
term.log(x)
|
||||||
Reference in New Issue
Block a user