diff --git a/README.md b/README.md index 934d7b4..da99e18 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # Chloride + An Argon interpreter written in C diff --git a/src/lexer/lexer.c b/src/lexer/lexer.c index bd8b8a1..525388c 100644 --- a/src/lexer/lexer.c +++ b/src/lexer/lexer.c @@ -1,17 +1,9 @@ #include "lex.yy.h" #include "lexer.h" -#include "../string/string.h" -#include void lexer(LexerState state) { yyscan_t scanner; - char *unquoted = unquote(state.content); - if (unquoted) { - printf("%s\n", unquoted); - free(unquoted); - } - yylex_init(&scanner); yyset_extra(&state, scanner); diff --git a/src/lexer/token.c b/src/lexer/token.c index 41b3d5b..546975c 100644 --- a/src/lexer/token.c +++ b/src/lexer/token.c @@ -6,7 +6,7 @@ TokenStruct* init_token() { - TokenStruct *tokenStruct = malloc(sizeof(TokenStruct));\ + TokenStruct *tokenStruct = malloc(sizeof(TokenStruct)); if (tokenStruct == NULL) { // handle malloc failure return NULL; diff --git a/src/lexer/token.h b/src/lexer/token.h index cb0edb2..242dd44 100644 --- a/src/lexer/token.h +++ b/src/lexer/token.h @@ -2,85 +2,86 @@ #define TOKEN_H typedef enum { - TOKEN_STRING, - TOKEN_NUMBER, - TOKEN_FRACTION, - TOKEN_IDENTIFIER, - TOKEN_KEYWORD, - TOKEN_NEW_LINE, - TOKEN_INDENT, + TOKEN_STRING, + TOKEN_NUMBER, + TOKEN_FRACTION, + TOKEN_IDENTIFIER, + TOKEN_KEYWORD, + TOKEN_NEW_LINE, + TOKEN_INDENT, - // Operators - TOKEN_AND, // && - TOKEN_OR, // || - TOKEN_NOT_IN, // not in - TOKEN_LE, // <= - TOKEN_GE, // >= - TOKEN_LT, // < - TOKEN_GT, // > - TOKEN_NE, // != - TOKEN_EQ, // == - TOKEN_ASSIGN, - TOKEN_PLUS, // + - TOKEN_MINUS, // - - TOKEN_MODULO, // % - TOKEN_STAR, // * - TOKEN_FLOORDIV, // // - TOKEN_SLASH, // / - TOKEN_CARET, // ^ + // Operators + TOKEN_AND, // && + TOKEN_OR, // || + TOKEN_NOT_IN, // not in + TOKEN_LE, // <= + TOKEN_GE, // >= + TOKEN_LT, // < + TOKEN_GT, // > + TOKEN_NE, // != + TOKEN_EQ, // == + TOKEN_ASSIGN, + TOKEN_PLUS, // + + TOKEN_MINUS, // - + TOKEN_MODULO, // % + TOKEN_STAR, // * + TOKEN_FLOORDIV, // // + TOKEN_SLASH, // / + TOKEN_CARET, // ^ - // Keywords - TOKEN_IF, - TOKEN_ELSE, - TOKEN_WHILE, - TOKEN_FOREVER, - TOKEN_FOR, - TOKEN_BREAK, - TOKEN_CONTINUE, - TOKEN_RETURN, - TOKEN_LET, - TOKEN_IMPORT, - TOKEN_FROM, - TOKEN_DO, - TOKEN_TRUE, - TOKEN_FALSE, - TOKEN_NULL, - TOKEN_DELETE, - TOKEN_NOT, - TOKEN_IN, - TOKEN_TRY, - TOKEN_CATCH, + // Keywords + TOKEN_IF, + TOKEN_ELSE, + TOKEN_WHILE, + TOKEN_FOREVER, + TOKEN_FOR, + TOKEN_BREAK, + TOKEN_CONTINUE, + TOKEN_RETURN, + TOKEN_LET, + TOKEN_IMPORT, + TOKEN_FROM, + TOKEN_DO, + TOKEN_TRUE, + TOKEN_FALSE, + TOKEN_NULL, + TOKEN_DELETE, + TOKEN_NOT, + TOKEN_IN, + TOKEN_TRY, + TOKEN_CATCH, - // parentheses, brackets, and braces - TOKEN_LPAREN, // ( - TOKEN_RPAREN, // ) - TOKEN_LBRACKET, // [ - TOKEN_RBRACKET, // ] - TOKEN_LBRACE, // { - TOKEN_RBRACE, // } + // parentheses, brackets, and braces + TOKEN_LPAREN, // ( + TOKEN_RPAREN, // ) + TOKEN_LBRACKET, // [ + TOKEN_RBRACKET, // ] + TOKEN_LBRACE, // { + TOKEN_RBRACE, // } - TOKEN_DOT, - TOKEN_COMMA, - TOKEN_COLON, + TOKEN_DOT, + TOKEN_COMMA, + TOKEN_COLON, } TokenType; typedef struct { - TokenType type; - int line; - int column; - char* value; + TokenType type; + int line; + int column; + char *value; } Token; typedef struct { - int count; - int capacity; - Token* tokens; + int count; + int capacity; + Token *tokens; } TokenStruct; -TokenStruct* init_token(); +TokenStruct *init_token(); -void add_token(TokenStruct* token,TokenType type, const char* value, int line, int column); +void add_token(TokenStruct *token, TokenType type, const char *value, int line, + int column); -void free_tokens(TokenStruct* token); +void free_tokens(TokenStruct *token); #endif \ No newline at end of file diff --git a/src/main.c b/src/main.c index 41973c9..c15764d 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,7 @@ #include "lexer/lexer.h" +#include "parser/parser.h" +#include #include #include @@ -46,9 +48,11 @@ int main() { }; lexer(state); free(content); - for (int i = 0; icount; i++) { - printf("%d\n", tokenStruct->tokens[i].type); - } + + TaggedValueStruct taggedValueStruct = init_TaggedValueStruct(); + + parser(&taggedValueStruct, tokenStruct, false); + free_tokens(tokenStruct); return 0; } diff --git a/src/parser/parser.c b/src/parser/parser.c new file mode 100644 index 0000000..50162a1 --- /dev/null +++ b/src/parser/parser.c @@ -0,0 +1,20 @@ +#include "parser.h" + +TaggedValue parse_token(TokenStruct * tokenStruct, int *index) { + Token token = tokenStruct->tokens[*index]; + switch (token.type) { + case TOKEN_STRING: + index++; + return parse_string(token); + default: + perror("unreachable"); + exit(0); + } +} + +void parser(TaggedValueStruct * taggedValueStruct, TokenStruct * tokenStruct, bool inline_flag) { + int index = 0; + while (index < tokenStruct->count) { + TaggedValueStruct_append(taggedValueStruct, parse_token(tokenStruct, &index)); + } +} \ No newline at end of file diff --git a/src/parser/parser.h b/src/parser/parser.h new file mode 100644 index 0000000..e82622d --- /dev/null +++ b/src/parser/parser.h @@ -0,0 +1,9 @@ +#include "../lexer/token.h" +#include "string/string.h" +#include +#include +#include + +void parser(TaggedValueStruct * TaggedValueStruct, TokenStruct * tokenStruct, bool inline_flag); + +TaggedValue parse_token(TokenStruct * tokenStruct, int *index); \ No newline at end of file diff --git a/src/parser/string/string.c b/src/parser/string/string.c new file mode 100644 index 0000000..7e06f48 --- /dev/null +++ b/src/parser/string/string.c @@ -0,0 +1,78 @@ +#include "string.h" +#include "../../lexer/token.h" + +#include +#include +#include +#include + +char *swap_quotes(const char *input) { + size_t len = strlen(input); + char *result = malloc(len + 1); + if (!result) + return NULL; + + for (size_t i = 0; i < len; ++i) { + if (input[i] == '"') + result[i] = '\''; + else if (input[i] == '\'') + result[i] = '"'; + else + result[i] = input[i]; + } + result[len] = '\0'; + return result; +} + +char *unquote(const char *str) { + if (*str == '\0') + return NULL; + + char quote = str[0]; + char *swapped = NULL; + char *unescaped = NULL; + + if (quote == '\'') { + swapped = swap_quotes(str); + if (!swapped) + return NULL; + str = swapped; + } + + cJSON *json = cJSON_Parse(str); + if (!json || !cJSON_IsString(json)) { + if (swapped) + free(swapped); + return NULL; + } + + // Copy unescaped string before freeing JSON object + const char *decoded = cJSON_GetStringValue(json); + if (!decoded) { + cJSON_Delete(json); + if (swapped) + free(swapped); + return NULL; + } + + unescaped = strdup(decoded); + cJSON_Delete(json); + if (swapped) + free(swapped); + + // If input was single-quoted, swap quotes back in the output + if (quote == '\'') { + char *final = swap_quotes(unescaped); + free(unescaped); + return final; + } + + return unescaped; +} + +TaggedValue parse_string(Token token) { + return (TaggedValue){ + TYPE_STRING, + unquote(token.value) + }; +} \ No newline at end of file diff --git a/src/parser/string/string.h b/src/parser/string/string.h new file mode 100644 index 0000000..0536c91 --- /dev/null +++ b/src/parser/string/string.h @@ -0,0 +1,8 @@ +#include "../../lexer/token.h" +#include "../taggedValue.h" + +char *swap_quotes(const char *input); + +char *unquote(const char *str); + +TaggedValue parse_string(Token token); \ No newline at end of file diff --git a/src/parser/taggedValue.c b/src/parser/taggedValue.c new file mode 100644 index 0000000..17bfc8f --- /dev/null +++ b/src/parser/taggedValue.c @@ -0,0 +1,26 @@ +#include "taggedValue.h" +#include + +TaggedValueStruct init_TaggedValueStruct() { + TaggedValueStruct taggedValueStruct = { + 0, + INITIAL_CAPACITY, + malloc(sizeof(TaggedValue)*INITIAL_CAPACITY) + }; + return taggedValueStruct; +} + +void TaggedValueStruct_append(TaggedValueStruct *TaggedValueStruct, + TaggedValue TaggedValue) { + if (TaggedValueStruct->count >= TaggedValueStruct->capacity) { + TaggedValueStruct->capacity *= 2; + TaggedValueStruct->TaggedValue = + realloc(TaggedValueStruct->TaggedValue, + sizeof(TaggedValue) * TaggedValueStruct->capacity); + } + TaggedValueStruct[TaggedValueStruct->count].TaggedValue->data = + TaggedValue.data; + TaggedValueStruct[TaggedValueStruct->count].TaggedValue->type = + TaggedValue.type; + TaggedValueStruct->count++; +} \ No newline at end of file diff --git a/src/parser/taggedValue.h b/src/parser/taggedValue.h new file mode 100644 index 0000000..ca2c1fd --- /dev/null +++ b/src/parser/taggedValue.h @@ -0,0 +1,23 @@ +typedef enum { + TYPE_STRING, +} ValueType; + +typedef struct { + ValueType type; + void *data; + +} TaggedValue; + + +#define INITIAL_CAPACITY 64 + + +typedef struct { + int count; + int capacity; + TaggedValue * TaggedValue; +} TaggedValueStruct; + +TaggedValueStruct init_TaggedValueStruct(); +void TaggedValueStruct_append(TaggedValueStruct *TaggedValueStruct, + TaggedValue TaggedValue); \ No newline at end of file diff --git a/src/string/string.c b/src/string/string.c index 1a969d7..c0c8f0b 100644 --- a/src/string/string.c +++ b/src/string/string.c @@ -3,65 +3,6 @@ #include #include #include -#include -#include -#include -#include - -char *swap_quotes(const char *input) { - size_t len = strlen(input); - char *result = malloc(len + 1); - if (!result) return NULL; - - for (size_t i = 0; i < len; ++i) { - if (input[i] == '"') result[i] = '\''; - else if (input[i] == '\'') result[i] = '"'; - else result[i] = input[i]; - } - result[len] = '\0'; - return result; -} - -char *unquote(const char *str) { - if (*str == '\0') return NULL; - - char quote = str[0]; - char *swapped = NULL; - char *unescaped = NULL; - - if (quote == '\'') { - swapped = swap_quotes(str); - if (!swapped) return NULL; - str = swapped; - } - - cJSON *json = cJSON_Parse(str); - if (!json || !cJSON_IsString(json)) { - if (swapped) free(swapped); - return NULL; - } - - // Copy unescaped string before freeing JSON object - const char *decoded = cJSON_GetStringValue(json); - if (!decoded) { - cJSON_Delete(json); - if (swapped) free(swapped); - return NULL; - } - - unescaped = strdup(decoded); - cJSON_Delete(json); - if (swapped) free(swapped); - - // If input was single-quoted, swap quotes back in the output - if (quote == '\'') { - char *final = swap_quotes(unescaped); - free(unescaped); - return final; - } - - return unescaped; -} const char *WHITE_SPACE = " \t\n\r\f\v"; diff --git a/src/string/string.h b/src/string/string.h index bd89403..90039d0 100644 --- a/src/string/string.h +++ b/src/string/string.h @@ -7,9 +7,5 @@ char* cloneString(char* str); void stripString(char* str, const char* chars); -char *swap_quotes(const char *input); - -char *unquote(const char *str); - #endif // CLONESTRING_H diff --git a/test.ar b/test.ar index d6dac33..cfcb15c 100644 --- a/test.ar +++ b/test.ar @@ -1,54 +1 @@ -import "url.ar" as url - -let __makeFile(name, type, data) = do - let File = {name: name, type: type, data: data} - let save(path) = do - let file = file.write(path) - file.buffer(data) - file.close() - File.save = save - return File - -let __multipart(req, res) = do - let boundary = buffer().from(req.headers["content-type"].splitN("boundary=", 2)[1]) - let newLineSplit = buffer().from("\r\n\r\n") - let parts = req.buffer.body.split(boundary) - for (i from 0 to parts.length) do - let str = parts[i].to("string") - if (str == "" || str=="--" || str=="--\r\n") continue - str = null - let headers = {} - let lines = parts[i].splitN(newLineSplit, 2) - let headerLines = lines[0].to("string").split("\r\n") - for (j from 0 to headerLines.length) do - let header = headerLines[j].splitN(": ", 2) - if (header.length != 2) continue - headers[header[0].lower()] = header[1] - if (lines.length != 2) continue - let body = lines[1] - if (i != parts.length-1) do - body = body.slice(0, body.length-4) - if ("content-disposition" in headers) do - let disposition = headers["content-disposition"].split("; ") - if (disposition[0] == "form-data") do - let name = json.parse(disposition[1].splitN("=", 2)[1]) - if (disposition.length >= 3) do - let filename = json.parse(disposition[2].splitN("=", 2)[1]) - req.files[name] = __makeFile(filename, headers["content-type"], body) - else do - req.formdata[name] = body.to("string") - res.next() - - -let formdata(req, res) = do - req.formdata = {} - req.files = {} - - if (req.method != "POST") return res.next() - if ("content-type" not in req.headers) return res.next() - let loweredContentType = req.headers["content-type"].lower() - if (loweredContentType.startswith("multipart/form-data")) return __multipart(req, res) - else if (loweredContentType.startswith("application/x-www-form-urlencoded")) req.formdata = url.decodeURLQuery(req.buffer.body.to("string")) - else if (loweredContentType.startswith("application/json")) req.formdata = json.parse(req.buffer.body.to("string")) - else req.files.file = __makeFile("file", req.headers["content-type"], req.buffer.body) - res.next() \ No newline at end of file +"hello world" \ No newline at end of file