some parsing
This commit is contained in:
		
							parent
							
								
									dd73b32372
								
							
						
					
					
						commit
						b478e45198
					
				
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @ -11,13 +11,13 @@ CFLAGS = \ | ||||
| 
 | ||||
| all: compile_flags.txt dirs scirpt | ||||
| 
 | ||||
| UTILS_SRC = stringmap.c | ||||
| UTILS_OBJ = $(patsubst %.c, build/utils/%.o, $(UTILS_SRC)) | ||||
| COMMON_SRC = string.c stringmap.c | ||||
| COMMON_OBJ = $(patsubst %.c, build/common/%.o, $(COMMON_SRC)) | ||||
| 
 | ||||
| SCIRPT_SRC = main.c lexer.c ast.c parser.c | ||||
| SCIRPT_OBJ = $(patsubst %.c, build/scirpt/%.o, $(SCIRPT_SRC)) | ||||
| 
 | ||||
| scirpt: $(SCIRPT_OBJ) $(UTILS_OBJ) | ||||
| scirpt: $(SCIRPT_OBJ) $(COMMON_OBJ) | ||||
| 	$(CC) -o bin/$@ $(CFLAGS) $^ -lm | ||||
| 
 | ||||
| build/%.o: %.c $(shell find -name *.h) | ||||
|  | ||||
							
								
								
									
										102
									
								
								common/string.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								common/string.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| #include "common/string.h" | ||||
| #include "common/panic.h" | ||||
| #include "common/result.h" | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| HeapString stringbuilder_build(StringBuilder* builder) | ||||
| { | ||||
| 	ASSERT(builder->length != 0, "builder cannot be empty"); | ||||
| 	if (*stringbuilder_get(builder, builder->length - 1) != '\0') | ||||
| 		stringbuilder_append(builder, '\0'); | ||||
| 	return heapstring_from(builder->data, builder->length); | ||||
| } | ||||
| 
 | ||||
| RESULT_CTORS( | ||||
| 	HeapString, HeapString, UnescapeStringResult, unescaped_string_result | ||||
| ) | ||||
| 
 | ||||
| UnescapeStringResult common_unescape_string(StringView source) | ||||
| { | ||||
| 	StringBuilder builder; | ||||
| 	stringbuilder_construct(&builder); | ||||
| 	size_t i = 0; | ||||
| 	while (i < source.length) { | ||||
| 		if (source.data[i] == '\\') { | ||||
| 			i++; | ||||
| 			if (i >= source.length) { | ||||
| 				stringbuilder_destroy(&builder); | ||||
| 				return unescaped_string_result_ok( | ||||
| 					heapstring_from_cstring("malformed escape sequence") | ||||
| 				); | ||||
| 			} | ||||
| 			switch (source.data[i]) { | ||||
| 				case '0': | ||||
| 					stringbuilder_append(&builder, '\0'); | ||||
| 					break; | ||||
| 				case 't': | ||||
| 					stringbuilder_append(&builder, '\t'); | ||||
| 					break; | ||||
| 				case 'r': | ||||
| 					stringbuilder_append(&builder, '\r'); | ||||
| 					break; | ||||
| 				case 'n': | ||||
| 					stringbuilder_append(&builder, '\n'); | ||||
| 					break; | ||||
| 				default: | ||||
| 					stringbuilder_append(&builder, source.data[i]); | ||||
| 					break; | ||||
| 			} | ||||
| 		} else { | ||||
| 			stringbuilder_append(&builder, source.data[i]); | ||||
| 		} | ||||
| 		i++; | ||||
| 	} | ||||
| 	HeapString string = stringbuilder_build(&builder); | ||||
| 	stringbuilder_destroy(&builder); | ||||
| 	return unescaped_string_result_ok(string); | ||||
| } | ||||
| 
 | ||||
| HeapString common_escape_string(StringView source) | ||||
| { | ||||
| 	StringBuilder builder; | ||||
| 	stringbuilder_construct(&builder); | ||||
| 	for (size_t i = 0; i < source.length; ++i) { | ||||
| 		switch (source.data[i]) { | ||||
| 			case '\0': | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				stringbuilder_append(&builder, '0'); | ||||
| 				break; | ||||
| 			case '\t': | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				stringbuilder_append(&builder, 't'); | ||||
| 				break; | ||||
| 			case '\r': | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				stringbuilder_append(&builder, 'r'); | ||||
| 				break; | ||||
| 			case '\n': | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				stringbuilder_append(&builder, 'n'); | ||||
| 				break; | ||||
| 			case '\\': | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				break; | ||||
| 			case '\"': | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				stringbuilder_append(&builder, '\"'); | ||||
| 				break; | ||||
| 			case '\'': | ||||
| 				stringbuilder_append(&builder, '\\'); | ||||
| 				stringbuilder_append(&builder, '\''); | ||||
| 				break; | ||||
| 			default: | ||||
| 				stringbuilder_append(&builder, source.data[i]); | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 	HeapString string = stringbuilder_build(&builder); | ||||
| 	stringbuilder_destroy(&builder); | ||||
| 	return string; | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| #include "stringmap.h" | ||||
| #include "utils/math.h" | ||||
| #include "utils/stringmap.h" | ||||
| #include "common/math.h" | ||||
| #include "common/stringmap.h" | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| @ -16,7 +16,7 @@ void stringmap_delete(StringMap* map) { free(map); } | ||||
| size_t* stringmap_get(const StringMap* map, const char* key, size_t key_length) | ||||
| { | ||||
| 	size_t key_hash | ||||
| 		= utils_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 		= common_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 	for (size_t i = 0; i < map->length; ++i) | ||||
| 		if (map->data[i].key_hash == key_hash && !map->data[i].deleted) | ||||
| 			return &map->data[i].value; | ||||
| @ -26,7 +26,7 @@ size_t* stringmap_get(const StringMap* map, const char* key, size_t key_length) | ||||
| bool stringmap_has(const StringMap* map, const char* key, size_t key_length) | ||||
| { | ||||
| 	size_t key_hash | ||||
| 		= utils_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 		= common_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 	for (size_t i = 0; i < map->length; ++i) | ||||
| 		if (map->data[i].key_hash == key_hash && !map->data[i].deleted) | ||||
| 			return true; | ||||
| @ -38,7 +38,7 @@ void stringmap_set( | ||||
| ) | ||||
| { | ||||
| 	size_t key_hash | ||||
| 		= utils_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 		= common_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 	for (size_t i = 0; i < map->length; ++i) { | ||||
| 		if (map->data[i].key_hash == key_hash && !map->data[i].deleted) { | ||||
| 			map->data[i].value = value; | ||||
| @ -64,14 +64,14 @@ void stringmap_reserve(StringMap* map, size_t minimum_size) | ||||
| { | ||||
| 	if (map->capacity >= minimum_size) | ||||
| 		return; | ||||
| 	map->capacity = utils_nearest_bigger_power_of_2_u64(minimum_size); | ||||
| 	map->capacity = common_nearest_bigger_power_of_2_u64(minimum_size); | ||||
| 	map->data = realloc(map->data, sizeof(StringMapEntry) * map->capacity); | ||||
| } | ||||
| 
 | ||||
| void stringmap_remove(StringMap* map, const char* key, size_t key_length) | ||||
| { | ||||
| 	size_t key_hash | ||||
| 		= utils_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 		= common_string_hash_djb2((const unsigned char*)key, key_length); | ||||
| 	for (size_t i = 0; i < map->length; ++i) { | ||||
| 		if (map->data[i].key_hash == key_hash && !map->data[i].deleted) { | ||||
| 			map->data[i].deleted = true; | ||||
| @ -91,7 +91,7 @@ void stringmap_clean(StringMap* map) | ||||
| 
 | ||||
| void stringmap_shrink(StringMap* map) | ||||
| { | ||||
| 	size_t new_size = utils_nearest_bigger_power_of_2_u64(map->length); | ||||
| 	size_t new_size = common_nearest_bigger_power_of_2_u64(map->length); | ||||
| 	if (new_size >= map->capacity) | ||||
| 		return; | ||||
| 	map->capacity = new_size; | ||||
| @ -1,7 +1,7 @@ | ||||
| #ifndef UTILS_H | ||||
| #define UTILS_H | ||||
| #ifndef STRINGMAP_H | ||||
| #define STRINGMAP_H | ||||
| 
 | ||||
| #include "utils/stringmap.h" | ||||
| #include "common/stringmap.h" | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| @ -1,39 +1,37 @@ | ||||
| #ifndef UTILS_GENERIC_ARRAY_H | ||||
| #define UTILS_GENERIC_ARRAY_H | ||||
| #ifndef COMMON_GENERIC_ARRAY_H | ||||
| #define COMMON_GENERIC_ARRAY_H | ||||
| 
 | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #define GENERIC_ARRAY(Type, struct_name, function_prefix)                      \ | ||||
| 	struct struct_name {                                                       \ | ||||
| 	typedef struct {                                                           \ | ||||
| 		Type* data;                                                            \ | ||||
| 		size_t length, capacity;                                               \ | ||||
| 	};                                                                         \ | ||||
| 	} struct_name;                                                             \ | ||||
|                                                                                \ | ||||
| 	static inline void function_prefix##_construct(struct struct_name* array)  \ | ||||
| 	static inline void function_prefix##_construct(struct_name* array)         \ | ||||
| 	{                                                                          \ | ||||
| 		*array = (struct struct_name) {                                        \ | ||||
| 		*array = (struct_name) {                                               \ | ||||
| 			.data = NULL,                                                      \ | ||||
| 			.length = 0,                                                       \ | ||||
| 			.capacity = 0,                                                     \ | ||||
| 		};                                                                     \ | ||||
| 	}                                                                          \ | ||||
|                                                                                \ | ||||
| 	static inline void function_prefix##_destroy(struct struct_name* array)    \ | ||||
| 	static inline void function_prefix##_destroy(struct_name* array)           \ | ||||
| 	{                                                                          \ | ||||
| 		if (array->data)                                                       \ | ||||
| 			free(array->data);                                                 \ | ||||
| 	}                                                                          \ | ||||
|                                                                                \ | ||||
| 	static inline size_t function_prefix##_length(                             \ | ||||
| 		const struct struct_name* array                                        \ | ||||
| 	)                                                                          \ | ||||
| 	static inline size_t function_prefix##_length(const struct_name* array)    \ | ||||
| 	{                                                                          \ | ||||
| 		return array->length;                                                  \ | ||||
| 	}                                                                          \ | ||||
|                                                                                \ | ||||
| 	static inline Type* function_prefix##_get(                                 \ | ||||
| 		const struct struct_name* array, size_t index                          \ | ||||
| 		const struct_name* array, size_t index                                 \ | ||||
| 	)                                                                          \ | ||||
| 	{                                                                          \ | ||||
| 		if (index >= array->length)                                            \ | ||||
| @ -43,7 +41,7 @@ | ||||
| 	}                                                                          \ | ||||
|                                                                                \ | ||||
| 	static inline void function_prefix##_append(                               \ | ||||
| 		struct struct_name* array, Type value                                  \ | ||||
| 		struct_name* array, Type value                                         \ | ||||
| 	)                                                                          \ | ||||
| 	{                                                                          \ | ||||
| 		if (array->data == NULL) {                                             \ | ||||
| @ -1,11 +1,11 @@ | ||||
| #ifndef UTILS_MATH_H | ||||
| #define UTILS_MATH_H | ||||
| #ifndef COMMON_MATH_H | ||||
| #define COMMON_MATH_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| // https://stackoverflow.com/questions/466204/rounding-up-to-next-power-of-2
 | ||||
| // https://stackoverflow.com/questions/1322510/given-an-integer-how-do-i-find-the-next-largest-power-of-two-using-bit-twiddlin/1322548#1322548
 | ||||
| static inline uint64_t utils_nearest_bigger_power_of_2_u64(uint64_t value) | ||||
| static inline uint64_t common_nearest_bigger_power_of_2_u64(uint64_t value) | ||||
| { | ||||
| 	value--; | ||||
| 	value |= value >> 1; | ||||
							
								
								
									
										24
									
								
								include/common/panic.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								include/common/panic.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| #ifndef COMMON_PANIC_H | ||||
| #define COMMON_PANIC_H | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #define PANIC(...)                                                             \ | ||||
| 	(fputs("panic: ", stderr),                                                 \ | ||||
| 	 fprintf(stderr, __VA_ARGS__),                                             \ | ||||
| 	 fprintf(                                                                  \ | ||||
| 		 stderr, "\n\tat ./%s:%d in %s()\n", __FILE__, __LINE__, __func__      \ | ||||
| 	 ),                                                                        \ | ||||
| 	 exit(1)) | ||||
| 
 | ||||
| #define ASSERT(condition, ...)                                                 \ | ||||
| 	if (!(condition))                                                          \ | ||||
| 	(fputs("assertion failed: ", stderr),                                      \ | ||||
| 	 fprintf(stderr, __VA_ARGS__),                                             \ | ||||
| 	 fprintf(                                                                  \ | ||||
| 		 stderr, "\n\tat ./%s:%d in %s()\n", __FILE__, __LINE__, __func__      \ | ||||
| 	 ),                                                                        \ | ||||
| 	 exit(1)) | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										36
									
								
								include/common/result.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								include/common/result.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| #ifndef COMMON_RESULT_H | ||||
| #define COMMON_RESULT_H | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| #define RESULT(Value, Error, struct_name)                                      \ | ||||
| 	typedef struct {                                                           \ | ||||
| 		bool ok;                                                               \ | ||||
| 		union {                                                                \ | ||||
| 			Value value;                                                       \ | ||||
| 			Error error;                                                       \ | ||||
| 		};                                                                     \ | ||||
| 	} struct_name; | ||||
| 
 | ||||
| #define RESULT_CTORS(Value, Error, struct_name, function_prefix)               \ | ||||
| 	static inline struct_name function_prefix##_ok(Value value)                \ | ||||
| 	{                                                                          \ | ||||
| 		return (struct_name) {                                                 \ | ||||
| 			.ok = true,                                                        \ | ||||
| 			.value = value,                                                    \ | ||||
| 		};                                                                     \ | ||||
| 	}                                                                          \ | ||||
|                                                                                \ | ||||
| 	static inline struct_name function_prefix##_error(Error error)             \ | ||||
| 	{                                                                          \ | ||||
| 		return (struct_name) {                                                 \ | ||||
| 			.ok = false,                                                       \ | ||||
| 			.error = error,                                                    \ | ||||
| 		};                                                                     \ | ||||
| 	} | ||||
| 
 | ||||
| #define RESULT_WITH_CTORS(Value, Error, struct_name, function_prefix)          \ | ||||
| 	RESULT(Value, Error, struct_name)                                          \ | ||||
| 	RESULT_CTORS(Value, Error, struct_name, function_prefix) | ||||
| 
 | ||||
| #endif | ||||
| @ -1,6 +1,8 @@ | ||||
| #ifndef UTILS_STRING_H | ||||
| #define UTILS_STRING_H | ||||
| #ifndef COMMON_STRING_H | ||||
| #define COMMON_STRING_H | ||||
| 
 | ||||
| #include "common/generic_array.h" | ||||
| #include "common/result.h" | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| @ -25,13 +27,23 @@ static inline HeapString heapstring_from(const char* text, size_t length) | ||||
| 	}; | ||||
| 	return string; | ||||
| } | ||||
| 
 | ||||
| static inline HeapString heapstring_from_cstring(const char* text) | ||||
| { | ||||
| 	return heapstring_from(text, strlen(text)); | ||||
| } | ||||
| 
 | ||||
| static inline void heapstring_destroy(HeapString* string) | ||||
| { | ||||
| 	free(string->data); | ||||
| 	if (string->data) | ||||
| 		free(string->data); | ||||
| } | ||||
| 
 | ||||
| GENERIC_ARRAY(char, StringBuilder, stringbuilder) | ||||
| HeapString stringbuilder_build(StringBuilder* builder); | ||||
| 
 | ||||
| RESULT(HeapString, HeapString, UnescapeStringResult) | ||||
| UnescapeStringResult common_unescape_string(StringView source); | ||||
| HeapString common_escape_string(StringView source); | ||||
| 
 | ||||
| #endif | ||||
| @ -1,12 +1,11 @@ | ||||
| #ifndef UTILS_STRING_ARRAY_H | ||||
| #define UTILS_STRING_ARRAY_H | ||||
| #ifndef COMMON_STRING_ARRAY_H | ||||
| #define COMMON_STRING_ARRAY_H | ||||
| 
 | ||||
| #include "utils/generic_array.h" | ||||
| #include "utils/string.h" | ||||
| #include "common/generic_array.h" | ||||
| #include "common/string.h" | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| GENERIC_ARRAY(StringView, StringViewArray, stringview_array) | ||||
| typedef struct StringViewArray StringViewArray; | ||||
| 
 | ||||
| static inline StringViewArray* stringview_array_new(void) | ||||
| { | ||||
| @ -21,7 +20,6 @@ static inline void stringview_array_delete(StringViewArray* array) | ||||
| } | ||||
| 
 | ||||
| GENERIC_ARRAY(HeapString, HeapStringArray, heapstring_array) | ||||
| typedef struct HeapStringArray HeapStringArray; | ||||
| 
 | ||||
| static inline HeapStringArray* heapstring_array_new(void) | ||||
| { | ||||
| @ -1,5 +1,5 @@ | ||||
| #ifndef UTILS_STRINGMAP_H | ||||
| #define UTILS_STRINGMAP_H | ||||
| #ifndef COMMON_STRINGMAP_H | ||||
| #define COMMON_STRINGMAP_H | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| @ -7,7 +7,7 @@ | ||||
| // https://stackoverflow.com/questions/7666509/hash-function-for-string
 | ||||
| // http://www.cse.yorku.ca/~oz/hash.html
 | ||||
| static inline size_t | ||||
| utils_string_hash_djb2(const unsigned char* value, size_t length) | ||||
| common_string_hash_djb2(const unsigned char* value, size_t length) | ||||
| { | ||||
| 	size_t hash = 5381; | ||||
| 	for (size_t i = 0; i < length && value[i] != '\0'; ++i) | ||||
| @ -1,6 +1,9 @@ | ||||
| #ifndef SCIRPT_AST_H | ||||
| #define SCIRPT_AST_H | ||||
| 
 | ||||
| #include "common/generic_array.h" | ||||
| #include "common/string.h" | ||||
| #include "scirpt/position.h" | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| @ -10,18 +13,39 @@ typedef enum { | ||||
| 	ScirptAstExprTypeId, | ||||
| 	ScirptAstExprTypeInt, | ||||
| 	ScirptAstExprTypeString, | ||||
| 	ScirptAstExprTypeNull, | ||||
| 	ScirptAstExprTypeBool, | ||||
| 	ScirptAstExprTypeBlock, | ||||
| 	ScirptAstExprTypeIf, | ||||
| } ScirptAstExprType; | ||||
| 
 | ||||
| typedef struct ScirptAstExpr ScirptAstExpr; | ||||
| 
 | ||||
| GENERIC_ARRAY(ScirptAstExpr*, ScirptAstExprArray, scirpt_ast_expr_array) | ||||
| 
 | ||||
| typedef struct { | ||||
| 	ScirptAstExprArray statements; | ||||
| 	ScirptAstExpr* value; | ||||
| } ScirptAstExprBlock; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	ScirptAstExpr* condition; | ||||
| 	ScirptAstExpr* truthy; | ||||
| 	ScirptAstExpr* falsy; | ||||
| } ScirptAstExprIf; | ||||
| 
 | ||||
| struct ScirptAstExpr { | ||||
| 	ScirptAstExprType type; | ||||
| 	ScirptPosition pos; | ||||
| 	union { | ||||
| 		char* id_value; | ||||
| 		HeapString id_value; | ||||
| 		int64_t int_value; | ||||
| 		char* string_value; | ||||
| 		HeapString string_value; | ||||
| 		bool bool_value; | ||||
| 		ScirptAstExprBlock block; | ||||
| 		ScirptAstExprIf if_expr; | ||||
| 	}; | ||||
| } ScirptAstExpr; | ||||
| }; | ||||
| 
 | ||||
| void scirpt_ast_expr_delete(ScirptAstExpr* expr); | ||||
| 
 | ||||
|  | ||||
| @ -1,10 +1,10 @@ | ||||
| #ifndef SCIRPT_PARSER_H | ||||
| #define SCIRPT_PARSER_H | ||||
| 
 | ||||
| #include "common/generic_array.h" | ||||
| #include "common/string.h" | ||||
| #include "scirpt/ast.h" | ||||
| #include "scirpt/lexer.h" | ||||
| #include "utils/generic_array.h" | ||||
| #include "utils/string.h" | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -15,14 +15,13 @@ typedef struct { | ||||
| GENERIC_ARRAY( | ||||
| 	ScirptParserError, ScirptParserErrorArray, scirpt_parser_error_array | ||||
| ) | ||||
| typedef struct ScirptParserErrorArray ScirptParserErrorArray; | ||||
| 
 | ||||
| typedef struct ScirptParser ScirptParser; | ||||
| 
 | ||||
| ScirptParser* | ||||
| scirpt_parser_new(const char* text, size_t text_length, ScirptLexer* lexer); | ||||
| void scirpt_parser_delete(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_next_expr(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_next(ScirptParser* parser); | ||||
| bool scirpt_parser_ok(const ScirptParser* parser); | ||||
| const ScirptParserErrorArray* scirpt_parser_errors(const ScirptParser* parser); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										15
									
								
								scirpt/ast.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								scirpt/ast.c
									
									
									
									
									
								
							| @ -9,14 +9,25 @@ void scirpt_ast_expr_delete(ScirptAstExpr* expr) | ||||
| 		case ScirptAstExprTypeError: | ||||
| 			break; | ||||
| 		case ScirptAstExprTypeId: | ||||
| 			free(expr->id_value); | ||||
| 			heapstring_destroy(&expr->id_value); | ||||
| 			break; | ||||
| 		case ScirptAstExprTypeInt: | ||||
| 			break; | ||||
| 		case ScirptAstExprTypeString: | ||||
| 			free(expr->string_value); | ||||
| 			heapstring_destroy(&expr->string_value); | ||||
| 			break; | ||||
| 		case ScirptAstExprTypeBool: | ||||
| 			break; | ||||
| 		case ScirptAstExprTypeNull: | ||||
| 			break; | ||||
| 		case ScirptAstExprTypeBlock: | ||||
| 			scirpt_ast_expr_array_destroy(&expr->block.statements); | ||||
| 			scirpt_ast_expr_delete(expr->block.value); | ||||
| 			break; | ||||
| 		case ScirptAstExprTypeIf: | ||||
| 			scirpt_ast_expr_delete(expr->if_expr.condition); | ||||
| 			scirpt_ast_expr_delete(expr->if_expr.truthy); | ||||
| 			scirpt_ast_expr_delete(expr->if_expr.falsy); | ||||
| 			break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,8 @@ | ||||
| #include "lexer.h" | ||||
| #include "common/stringmap.h" | ||||
| #include "scirpt/lexer.h" | ||||
| #include "scirpt/position.h" | ||||
| #include "scirpt/token.h" | ||||
| #include "utils/stringmap.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| #ifndef LEXER_H | ||||
| #define LEXER_H | ||||
| 
 | ||||
| #include "common/stringmap.h" | ||||
| #include "scirpt/lexer.h" | ||||
| #include "scirpt/token.h" | ||||
| #include "utils/stringmap.h" | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| 
 | ||||
|  | ||||
| @ -29,7 +29,7 @@ int main(void) | ||||
| 		ScirptLexer* lexer = scirpt_lexer_new(text, strlen(text)); | ||||
| 		ScirptParser* parser = scirpt_parser_new(text, strlen(text), lexer); | ||||
| 		while (true) { | ||||
| 			ScirptAstExpr* expr = scirpt_parser_next_expr(parser); | ||||
| 			ScirptAstExpr* expr = scirpt_parser_next(parser); | ||||
| 			if (expr->type == ScirptAstExprTypeEof) { | ||||
| 				break; | ||||
| 			} else if (!scirpt_parser_ok(parser)) { | ||||
|  | ||||
							
								
								
									
										146
									
								
								scirpt/parser.c
									
									
									
									
									
								
							
							
						
						
									
										146
									
								
								scirpt/parser.c
									
									
									
									
									
								
							| @ -1,10 +1,10 @@ | ||||
| #include "scirpt/parser.h" | ||||
| #include "common/string.h" | ||||
| #include "parser.h" | ||||
| #include "scirpt/ast.h" | ||||
| #include "scirpt/lexer.h" | ||||
| #include "scirpt/position.h" | ||||
| #include "scirpt/token.h" | ||||
| #include "utils/string.h" | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| @ -21,11 +21,17 @@ error(ScirptParser* parser, HeapString message, ScirptPosition pos) | ||||
| { | ||||
| 	scirpt_parser_error(parser, message, pos); | ||||
| } | ||||
| static inline ScirptPosition pos(ScirptParser* parser) | ||||
| static inline ScirptPosition position(ScirptParser* parser) | ||||
| { | ||||
| 	return parser->current.pos; | ||||
| } | ||||
| static inline void step(ScirptParser* parser) { scirpt_parser_step(parser); } | ||||
| static inline ScirptAstExpr* | ||||
| step_alloc_expr(ScirptParser* parser, ScirptAstExpr data) | ||||
| { | ||||
| 	step(parser); | ||||
| 	return alloc_expr(data); | ||||
| } | ||||
| static inline bool current_is(const ScirptParser* parser, ScirptTokenType type) | ||||
| { | ||||
| 	return scirpt_parser_current_is(parser, type); | ||||
| @ -45,14 +51,14 @@ scirpt_parser_new(const char* text, size_t text_length, ScirptLexer* lexer) | ||||
| 
 | ||||
| void scirpt_parser_delete(ScirptParser* parser) { free(parser); } | ||||
| 
 | ||||
| ScirptAstExpr* scirpt_parser_next_expr(ScirptParser* parser) | ||||
| ScirptAstExpr* scirpt_parser_next(ScirptParser* parser) | ||||
| { | ||||
| 	if (done(parser)) { | ||||
| 		return alloc_expr((ScirptAstExpr) { | ||||
| 			.type = ScirptAstExprTypeEof, | ||||
| 		}); | ||||
| 	} else { | ||||
| 		return scirpt_parser_parse_expr(parser); | ||||
| 		return scirpt_parser_parse_statement(parser); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -88,6 +94,11 @@ void scirpt_parser_destroy(ScirptParser* parser) | ||||
| 	scirpt_parser_error_array_construct(&parser->errors); | ||||
| } | ||||
| 
 | ||||
| ScirptAstExpr* scirpt_parser_parse_statement(ScirptParser* parser) | ||||
| { | ||||
| 	return scirpt_parser_parse_expr(parser); | ||||
| } | ||||
| 
 | ||||
| ScirptAstExpr* scirpt_parser_parse_expr(ScirptParser* parser) | ||||
| { | ||||
| 	return scirpt_parser_parse_operand(parser); | ||||
| @ -95,40 +106,143 @@ ScirptAstExpr* scirpt_parser_parse_expr(ScirptParser* parser) | ||||
| 
 | ||||
| ScirptAstExpr* scirpt_parser_parse_operand(ScirptParser* parser) | ||||
| { | ||||
| 	ScirptPosition pos = position(parser); | ||||
| 	switch (parser->current.type) { | ||||
| 		case ScirptTokenTypeInt: { | ||||
| 			HeapString value_string = heapstring_from( | ||||
| 				&parser->text[pos(parser).index], parser->current.length | ||||
| 		case ScirptTokenTypeInt: | ||||
| 			return scirpt_parser_parse_int(parser); | ||||
| 		case ScirptTokenTypeString: | ||||
| 			return scirpt_parser_parse_string(parser); | ||||
| 		case ScirptTokenTypeNull: | ||||
| 			return step_alloc_expr( | ||||
| 				parser, | ||||
| 				(ScirptAstExpr) { | ||||
| 					.type = ScirptAstExprTypeNull, | ||||
| 					.pos = pos, | ||||
| 				} | ||||
| 			); | ||||
| 			int64_t value = atoll(value_string.data); | ||||
| 			step(parser); | ||||
| 			return alloc_expr((ScirptAstExpr) { | ||||
| 				.type = ScirptAstExprTypeInt, | ||||
| 				.int_value = value, | ||||
| 			}); | ||||
| 		} | ||||
| 		case ScirptTokenTypeFalse: | ||||
| 			return step_alloc_expr( | ||||
| 				parser, | ||||
| 				(ScirptAstExpr) { | ||||
| 					.type = ScirptAstExprTypeBool, | ||||
| 					.pos = pos, | ||||
| 					.bool_value = false, | ||||
| 				} | ||||
| 			); | ||||
| 		case ScirptTokenTypeTrue: | ||||
| 			return step_alloc_expr( | ||||
| 				parser, | ||||
| 				(ScirptAstExpr) { | ||||
| 					.type = ScirptAstExprTypeBool, | ||||
| 					.pos = pos, | ||||
| 					.bool_value = true, | ||||
| 				} | ||||
| 			); | ||||
| 		case ScirptTokenTypeIf: | ||||
| 			return scirpt_parser_parse_if(parser); | ||||
| 		case ScirptTokenTypeEof: { | ||||
| 			error( | ||||
| 				parser, | ||||
| 				heapstring_from_cstring("expected value, got Eof"), | ||||
| 				pos(parser) | ||||
| 				position(parser) | ||||
| 			); | ||||
| 			return alloc_expr((ScirptAstExpr) { | ||||
| 				.type = ScirptAstExprTypeError, | ||||
| 				.pos = pos, | ||||
| 			}); | ||||
| 		} | ||||
| 		default: { | ||||
| 			error( | ||||
| 				parser, heapstring_from_cstring("expected value"), pos(parser) | ||||
| 				parser, | ||||
| 				heapstring_from_cstring("expected value"), | ||||
| 				position(parser) | ||||
| 			); | ||||
| 			step(parser); | ||||
| 			return alloc_expr((ScirptAstExpr) { | ||||
| 				.type = ScirptAstExprTypeError, | ||||
| 				.pos = pos, | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ScirptAstExpr* scirpt_parser_parse_int(ScirptParser* parser) | ||||
| { | ||||
| 	ScirptPosition pos = position(parser); | ||||
| 	HeapString value_string = heapstring_from( | ||||
| 		&parser->text[position(parser).index], parser->current.length | ||||
| 	); | ||||
| 	int64_t value = atoll(value_string.data); | ||||
| 	step(parser); | ||||
| 	return alloc_expr((ScirptAstExpr) { | ||||
| 		.type = ScirptAstExprTypeInt, | ||||
| 		.pos = pos, | ||||
| 		.int_value = value, | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| ScirptAstExpr* scirpt_parser_parse_string(ScirptParser* parser) | ||||
| { | ||||
| 	ScirptPosition pos = position(parser); | ||||
| 	UnescapeStringResult result = common_unescape_string((StringView | ||||
| 	) { .data = &parser->text[position(parser).index], | ||||
| 		.length = parser->current.length - 2 }); | ||||
| 	if (!result.ok) { | ||||
| 		error(parser, result.error, position(parser)); | ||||
| 		step(parser); | ||||
| 		return alloc_expr((ScirptAstExpr) { | ||||
| 			.type = ScirptAstExprTypeError, | ||||
| 		}); | ||||
| 	} | ||||
| 	HeapString value = result.value; | ||||
| 	step(parser); | ||||
| 	return alloc_expr((ScirptAstExpr) { | ||||
| 		.type = ScirptAstExprTypeString, | ||||
| 		.pos = pos, | ||||
| 		.string_value = value, | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| ScirptAstExpr* scirpt_parser_parse_if(ScirptParser* parser) | ||||
| { | ||||
| 	ScirptPosition pos = position(parser); | ||||
| 	step(parser); | ||||
| 	ScirptAstExpr* condition = scirpt_parser_parse_expr(parser); | ||||
| 	if (!current_is(parser, ScirptTokenTypeLBrace)) { | ||||
| 		error( | ||||
| 			parser, heapstring_from_cstring("expected '{'"), position(parser) | ||||
| 		); | ||||
| 		scirpt_ast_expr_delete(condition); | ||||
| 		return alloc_expr((ScirptAstExpr) { | ||||
| 			.type = ScirptAstExprTypeError, | ||||
| 		}); | ||||
| 	} | ||||
| 	ScirptAstExpr* truthy = scirpt_parser_parse_expr(parser); | ||||
| 	ScirptAstExpr* falsy = NULL; | ||||
| 	if (current_is(parser, ScirptTokenTypeElse)) { | ||||
| 		step(parser); | ||||
| 		if (!current_is(parser, ScirptTokenTypeLBrace)) { | ||||
| 			error( | ||||
| 				parser, | ||||
| 				heapstring_from_cstring("expected '{'"), | ||||
| 				position(parser) | ||||
| 			); | ||||
| 			scirpt_ast_expr_delete(condition); | ||||
| 			scirpt_ast_expr_delete(truthy); | ||||
| 		} | ||||
| 		falsy = scirpt_parser_parse_expr(parser); | ||||
| 	} | ||||
| 	return alloc_expr((ScirptAstExpr) { | ||||
| 		.type = ScirptAstExprTypeIf, | ||||
| 		.pos = pos, | ||||
| 		.if_expr = (ScirptAstExprIf) { | ||||
| 			.condition = condition, | ||||
| 			.truthy = truthy, | ||||
| 			.falsy = falsy, | ||||
| 		}, | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| void scirpt_parser_error( | ||||
| 	ScirptParser* parser, HeapString message, ScirptPosition pos | ||||
| ) | ||||
|  | ||||
| @ -25,8 +25,12 @@ void scirpt_parser_construct( | ||||
| 	ScirptLexer* lexer | ||||
| ); | ||||
| void scirpt_parser_destroy(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_parse_statement(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_parse_expr(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_parse_operand(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_parse_int(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_parse_string(ScirptParser* parser); | ||||
| ScirptAstExpr* scirpt_parser_parse_if(ScirptParser* parser); | ||||
| void scirpt_parser_error( | ||||
| 	ScirptParser* parser, HeapString message, ScirptPosition pos | ||||
| ); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user