From 5629c0c995b595a7da535c9b64fad369d652af3b Mon Sep 17 00:00:00 2001 From: ryanfleury Date: Fri, 23 Apr 2021 14:30:21 -0600 Subject: [PATCH 1/5] command line helper pass --- build.bat | 2 +- source/md.h | 29 +++--- source/md_impl.c | 249 +++++++++++++++++++++++++++-------------------- 3 files changed, 161 insertions(+), 119 deletions(-) diff --git a/build.bat b/build.bat index 03d76e0..812d4a1 100644 --- a/build.bat +++ b/build.bat @@ -34,7 +34,7 @@ pushd static_site_generator pushd example_site if not exist generated mkdir generated pushd generated -..\..\..\..\build\static_site_generator.exe --siteinfo ..\site_info.md --pagedir ..\ +..\..\..\..\build\static_site_generator.exe --siteinfo:..\site_info.md --pagedir:..\ popd popd popd diff --git a/source/md.h b/source/md.h index 7e7f6e6..bd1c2d6 100644 --- a/source/md.h +++ b/source/md.h @@ -525,12 +525,22 @@ struct MD_ParseResult }; //~ Command line parsing helper types. + +typedef struct MD_CommandLineOption MD_CommandLineOption; +struct MD_CommandLineOption +{ + MD_CommandLineOption *next; + MD_String8 name; + MD_String8List values; +}; + typedef struct MD_CommandLine MD_CommandLine; struct MD_CommandLine { - // TODO(rjf): Linked-list vs. array? - MD_String8 *arguments; - int argument_count; + MD_String8List arguments; + MD_String8List inputs; + MD_CommandLineOption *first_option; + MD_CommandLineOption *last_option; }; //~ File system access types. @@ -712,15 +722,12 @@ MD_FUNCTION MD_b32 MD_NodeDeepMatch(MD_Node *a, MD_Node *b, MD_MatchFlags node_f //~ Generation MD_FUNCTION void MD_OutputTree(FILE *file, MD_Node *node); -// TODO(allen): needs another pass //~ Command Line Argument Helper -MD_FUNCTION MD_CommandLine MD_CommandLine_Start(int argument_count, char **arguments); -MD_FUNCTION MD_b32 MD_CommandLine_Flag(MD_CommandLine *cmdln, MD_String8 string); -MD_FUNCTION MD_b32 MD_CommandLine_FlagStrings(MD_CommandLine *cmdln, MD_String8 string, int out_count, MD_String8 *out); -MD_FUNCTION MD_b32 MD_CommandLine_FlagIntegers(MD_CommandLine *cmdln, MD_String8 string, int out_count, MD_i64 *out); -MD_FUNCTION MD_b32 MD_CommandLine_FlagString(MD_CommandLine *cmdln, MD_String8 string, MD_String8 *out); -MD_FUNCTION MD_b32 MD_CommandLine_FlagInteger(MD_CommandLine *cmdln, MD_String8 string, MD_i64 *out); -MD_FUNCTION MD_b32 MD_CommandLine_Increment(MD_CommandLine *cmdln, MD_String8 **string_ptr); +MD_FUNCTION MD_String8List MD_StringListFromArgCV(int argument_count, char **arguments); +MD_FUNCTION MD_CommandLine MD_CommandLineFromOptions(MD_String8List options); +MD_FUNCTION MD_String8List MD_CommandLineOptionValues(MD_CommandLine cmdln, MD_String8 name); +MD_FUNCTION MD_b32 MD_CommandLineOptionPassed(MD_CommandLine cmdln, MD_String8 name); +MD_FUNCTION MD_i64 MD_CommandLineOptionI64(MD_CommandLine cmdln, MD_String8 name); //~ File System MD_FUNCTION MD_String8 MD_LoadEntireFile(MD_String8 filename); diff --git a/source/md_impl.c b/source/md_impl.c index 5fbf137..547d0cb 100644 --- a/source/md_impl.c +++ b/source/md_impl.c @@ -2482,132 +2482,167 @@ MD_OutputTree(FILE *file, MD_Node *node) } } -MD_FUNCTION_IMPL MD_CommandLine -MD_CommandLine_Start(int argument_count, char **arguments) +MD_FUNCTION MD_String8List +MD_StringListFromArgCV(int argument_count, char **arguments) +{ + MD_String8List options = MD_ZERO_STRUCT; + for(int i = 0; i < argument_count; i += 1) + { + MD_PushStringToList(&options, MD_S8CString(arguments[i])); + } + return options; +} + +MD_FUNCTION MD_CommandLine +MD_CommandLineFromOptions(MD_String8List options) { MD_CommandLine cmdln = MD_ZERO_STRUCT; - cmdln.arguments = _MD_PushArray(MD_String8, argument_count-1); - for(int i = 1; i < argument_count; i += 1) + cmdln.arguments = options; + + for(MD_String8Node *n = options.first, *next = 0; + n; n = next) { - cmdln.arguments[i-1] = MD_PushStringF("%s", arguments[i]); + next = n->next; + + //- rjf: figure out whether or not this is an option by checking for `-` or `--` + // from the beginning of the string + MD_String8 option_name = MD_ZERO_STRUCT; + if(MD_StringMatch(MD_StringPrefix(n->string, 2), MD_S8Lit("--"), 0)) + { + option_name = MD_StringSkip(n->string, 2); + } + else if(MD_StringMatch(MD_StringPrefix(n->string, 1), MD_S8Lit("-"), 0)) + { + option_name = MD_StringSkip(n->string, 1); + } + //- rjf: trim off anything after a `:` or `=`, use that as the first value string + MD_String8 first_value = MD_ZERO_STRUCT; + MD_b32 has_many_values = 0; + if(option_name.size != 0) + { + MD_u64 colon_signifier_pos = MD_FindSubstring(option_name, MD_S8Lit(":"), 0, 0); + MD_u64 equal_signifier_pos = MD_FindSubstring(option_name, MD_S8Lit("="), 0, 0); + MD_u64 signifier_pos = colon_signifier_pos > equal_signifier_pos ? equal_signifier_pos : colon_signifier_pos; + if(signifier_pos < option_name.size) + { + first_value = MD_StringSkip(option_name, signifier_pos+1); + option_name = MD_StringPrefix(option_name, signifier_pos); + if(MD_StringMatch(MD_StringSuffix(first_value, 1), MD_S8Lit(","), 0)) + { + has_many_values = 1; + } + } + } + + //- rjf: gather arguments + if(option_name.size != 0) + { + MD_String8List option_values = MD_ZERO_STRUCT; + + //- rjf: push first value + if(first_value.size != 0) + { + MD_PushStringToList(&option_values, first_value); + } + + //- rjf: scan next string values, add them to option values until we hit a lack + // of a ',' between values + if(has_many_values) + { + for(MD_String8Node *v = next; v; v = v->next, next = v) + { + MD_String8 value_str = v->string; + MD_b32 next_has_arguments = MD_StringMatch(MD_StringSuffix(value_str, 1), MD_S8Lit(","), 0); + MD_b32 in_quotes = 0; + MD_u64 start = 0; + for(MD_u64 i = 0; i <= value_str.size; i += 1) + { + if(i == value_str.size || (value_str.str[i] == ',' && in_quotes == 0)) + { + if(start != i) + { + MD_PushStringToList(&option_values, MD_StringSubstring(value_str, start, i)); + } + start = i+1; + } + else if(value_str.str[i] == '"') + { + in_quotes = !in_quotes; + } + } + if(next_has_arguments == 0) + { + break; + } + } + } + + //- rjf: insert the fully parsed option + { + MD_CommandLineOption *opt = _MD_PushArray(MD_CommandLineOption, 1); + _MD_MemoryZero(opt, sizeof(*opt)); + opt->name = option_name; + opt->values = option_values; + if(cmdln.last_option == 0) + { + cmdln.first_option = cmdln.last_option = opt; + } + else + { + cmdln.last_option->next = opt; + cmdln.last_option = cmdln.last_option->next; + } + } + } + + //- rjf: this argument is not an option, push it to regular inputs list. + else + { + MD_PushStringToList(&cmdln.inputs, n->string); + } } - cmdln.argument_count = argument_count-1; + return cmdln; } -MD_FUNCTION_IMPL MD_b32 -MD_CommandLine_Flag(MD_CommandLine *cmdln, MD_String8 string) +MD_FUNCTION MD_String8List +MD_CommandLineOptionValues(MD_CommandLine cmdln, MD_String8 name) +{ + MD_String8List values = MD_ZERO_STRUCT; + for(MD_CommandLineOption *opt = cmdln.first_option; opt; opt = opt->next) + { + if(MD_StringMatch(opt->name, name, 0)) + { + values = opt->values; + break; + } + } + return values; +} + +MD_FUNCTION MD_b32 +MD_CommandLineOptionPassed(MD_CommandLine cmdln, MD_String8 name) { MD_b32 result = 0; - for(int i = 0; i < cmdln->argument_count; i += 1) + for(MD_CommandLineOption *opt = cmdln.first_option; opt; opt = opt->next) { - if(MD_StringMatch(string, cmdln->arguments[i], 0)) + if(MD_StringMatch(opt->name, name, 0)) { result = 1; - cmdln->arguments[i].str = 0; - cmdln->arguments[i].size = 0; break; } } return result; } -MD_FUNCTION_IMPL MD_b32 -MD_CommandLine_FlagStrings(MD_CommandLine *cmdln, MD_String8 string, int out_count, MD_String8 *out) +MD_FUNCTION MD_i64 +MD_CommandLineOptionI64(MD_CommandLine cmdln, MD_String8 name) { - MD_b32 result = 0; - for(int i = 0; i < cmdln->argument_count; i += 1) - { - if(MD_StringMatch(string, cmdln->arguments[i], 0)) - { - cmdln->arguments[i].str = 0; - cmdln->arguments[i].size = 0; - if(cmdln->argument_count > i + out_count) - { - for(int out_idx = 0; out_idx < out_count; out_idx += 1) - { - out[out_idx] = cmdln->arguments[i+out_idx+1]; - cmdln->arguments[i+out_idx+1].str = 0; - cmdln->arguments[i+out_idx+1].size = 0; - } - result = 1; - break; - } - } - } - return result; -} - -MD_FUNCTION_IMPL MD_b32 -MD_CommandLine_FlagIntegers(MD_CommandLine *cmdln, MD_String8 string, int out_count, MD_i64 *out) -{ - MD_b32 result = 0; - for(int i = 0; i < cmdln->argument_count; i += 1) - { - if(MD_StringMatch(string, cmdln->arguments[i], 0)) - { - cmdln->arguments[i].str = 0; - cmdln->arguments[i].size = 0; - if(cmdln->argument_count > i + out_count) - { - for(int out_idx = 0; out_idx < out_count; out_idx += 1) - { - out[out_idx] = MD_I64FromString(cmdln->arguments[i+out_idx+1], 10); - cmdln->arguments[i+out_idx+1].str = 0; - cmdln->arguments[i+out_idx+1].size = 0; - } - result = 1; - break; - } - } - } - return result; -} - -MD_FUNCTION_IMPL MD_b32 -MD_CommandLine_FlagString(MD_CommandLine *cmdln, MD_String8 string, MD_String8 *out) -{ - return MD_CommandLine_FlagStrings(cmdln, string, 1, out); -} - -MD_FUNCTION_IMPL MD_b32 -MD_CommandLine_FlagInteger(MD_CommandLine *cmdln, MD_String8 string, MD_i64 *out) -{ - return MD_CommandLine_FlagIntegers(cmdln, string, 1, out); -} - -MD_FUNCTION_IMPL MD_b32 -MD_CommandLine_Increment(MD_CommandLine *cmdln, MD_String8 **string_ptr) -{ - MD_b32 result = 0; - MD_String8 *string = *string_ptr; - if(string == 0) - { - for(int i = 0; i < cmdln->argument_count; i += 1) - { - if(cmdln->arguments[i].str) - { - string = &cmdln->arguments[i]; - break; - } - } - } - else - { - int idx = (int)(string - cmdln->arguments); - string = 0; - for(int i = idx+1; i < cmdln->argument_count; i += 1) - { - if(cmdln->arguments[i].str) - { - string = &cmdln->arguments[i]; - break; - } - } - } - *string_ptr = string; - result = !!string; - return result; + MD_i64 v = 0; + MD_String8List values = MD_CommandLineOptionValues(cmdln, name); + MD_String8 value_str = MD_JoinStringList(values, MD_S8Lit("")); + v = MD_I64FromString(value_str, 10); + return v; } MD_FUNCTION_IMPL MD_String8 From 9c0babe0a6ba643e06a60bfaa5168ffdcfe35406 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 24 Apr 2021 12:56:02 -0600 Subject: [PATCH 2/5] node flags seeking helper --- source/md.h | 17 ++++------------ source/md_impl.c | 26 +++++++++++++++++++++++- tests/sanity_tests.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/source/md.h b/source/md.h index bd1c2d6..869607e 100644 --- a/source/md.h +++ b/source/md.h @@ -18,8 +18,7 @@ // [x] MD_StringMap_Next, for iterating matching slots in an MD_Map, that all // share the same key (important in the case of hash collisions) // [x] Helper for making a reference for a node, e.g. MD_ReferenceFromNode -// [ ] Organization decision for C generator helpers: splitting from md.h? file name? folder? - +// [x] Organization decision for C generator helpers: splitting from md.h? file name? folder? // NOTE(allen): "Plugin" functionality // @@ -132,9 +131,6 @@ # define MD_ARCH_32BIT 1 #endif -// NOTE(allen): Review @rjf; Building in C++ -// Added language cracking. Handy for a few pesky problems that can't be solved -// strictly within the intersection of C & C++ #if defined(__cplusplus) # define MD_LANG_CPP 1 #else @@ -195,12 +191,6 @@ # define MD_ZERO_STRUCT {0} #endif -// NOTE(allen): Review @rjf; Building in C++ -// In order to link to C functions from C++ code, we need to mark them as using -// C linkage. In particular I mean FindFirstFileA, FindNextFileA right now. -// We don't necessarily need to apply this to the DD functions if the user is -// building from source, so I haven't done that. - #if MD_LANG_C # define MD_C_LINKAGE_BEGIN # define MD_C_LINKAGE_END @@ -213,8 +203,6 @@ #include #include #include -// NOTE(allen): Review @rjf; Building in C++ -// In C++ compiler I have to include this to get memset and memcpy to compile #include typedef int8_t MD_i8; @@ -701,10 +689,13 @@ MD_FUNCTION MD_Node * MD_TagFromString(MD_Node *node, MD_String8 tag_string); MD_FUNCTION MD_Node * MD_ChildFromIndex(MD_Node *node, int n); MD_FUNCTION MD_Node * MD_TagFromIndex(MD_Node *node, int n); MD_FUNCTION MD_Node * MD_TagArgFromIndex(MD_Node *node, MD_String8 tag_string, int n); +MD_FUNCTION MD_Node * MD_TagArgFromString(MD_Node *node, MD_String8 tag_string, MD_String8 arg_string); MD_FUNCTION MD_b32 MD_NodeHasTag(MD_Node *node, MD_String8 tag_string); MD_FUNCTION MD_i64 MD_ChildCountFromNode(MD_Node *node); MD_FUNCTION MD_i64 MD_TagCountFromNode(MD_Node *node); MD_FUNCTION MD_Node * MD_Deref(MD_Node *node); +MD_FUNCTION MD_Node * MD_SeekNodeWithFlags(MD_Node *start, MD_NodeFlags one_past_last_flags); + // NOTE(rjf): For-Loop Helpers #define MD_EachNode(it, first) MD_Node *it = (first); !MD_NodeIsNil(it); it = it->next #define MD_EachNodeRef(it, first) MD_Node *it##_r = (first), *it = MD_Deref(it##_r); \ diff --git a/source/md_impl.c b/source/md_impl.c index 547d0cb..65cc923 100644 --- a/source/md_impl.c +++ b/source/md_impl.c @@ -2356,6 +2356,14 @@ MD_TagArgFromIndex(MD_Node *node, MD_String8 tag_string, int n) return MD_ChildFromIndex(tag, n); } +MD_FUNCTION_IMPL MD_Node * +MD_TagArgFromString(MD_Node *node, MD_String8 tag_string, MD_String8 arg_string) +{ + MD_Node *tag = MD_TagFromString(node, tag_string); + MD_Node *arg = MD_ChildFromString(tag, arg_string); + return arg; +} + MD_FUNCTION_IMPL MD_b32 MD_NodeHasTag(MD_Node *node, MD_String8 tag_string) { @@ -2412,7 +2420,8 @@ MD_TagCountFromNodeAndString(MD_Node *node, MD_String8 string, MD_MatchFlags fla return result; } -MD_FUNCTION_IMPL MD_Node * MD_Deref(MD_Node *node) +MD_FUNCTION_IMPL MD_Node * +MD_Deref(MD_Node *node) { MD_Node *result = node; while(result->kind == MD_NodeKind_Reference) @@ -2422,6 +2431,21 @@ MD_FUNCTION_IMPL MD_Node * MD_Deref(MD_Node *node) return result; } +MD_FUNCTION MD_Node * +MD_SeekNodeWithFlags(MD_Node *start, MD_NodeFlags one_past_last_flags) +{ + MD_Node *result = start; + for(MD_EachNode(it, start->next)) + { + if(it->flags & one_past_last_flags) + { + break; + } + result = it; + } + return result; +} + MD_FUNCTION_IMPL void MD_NodeMessage(MD_Node *node, MD_MessageKind kind, MD_String8 str) { diff --git a/tests/sanity_tests.c b/tests/sanity_tests.c index fe4c648..271e6ae 100644 --- a/tests/sanity_tests.c +++ b/tests/sanity_tests.c @@ -593,5 +593,53 @@ int main(void) } } + Test("Node-With-Flags Seeking") + { + + { + MD_ParseResult parse = MD_ParseOneNode(MD_S8Lit(""), MD_S8Lit("foo:{x y z; a b c}")); + MD_Node *node = parse.node; + MD_Node *group_first = node->first_child; + MD_Node *group_last = MD_SeekNodeWithFlags(group_first, MD_NodeFlag_AfterSemicolon); + + TestResult(MD_StringMatch(group_first->string, MD_S8Lit("x"), 0)); + TestResult(MD_StringMatch(group_first->next->string, MD_S8Lit("y"), 0)); + TestResult(MD_StringMatch(group_last->string, MD_S8Lit("z"), 0)); + + group_first = group_last->next; + group_last = MD_SeekNodeWithFlags(group_first, MD_NodeFlag_AfterSemicolon); + + TestResult(MD_StringMatch(group_first->string, MD_S8Lit("a"), 0)); + TestResult(MD_StringMatch(group_first->next->string, MD_S8Lit("b"), 0)); + TestResult(MD_StringMatch(group_last->string, MD_S8Lit("c"), 0)); + } + + { + MD_ParseResult parse = MD_ParseOneNode(MD_S8Lit(""), MD_S8Lit("foo:{a b c , d e f , g h i}")); + MD_Node *node = parse.node; + MD_Node *group_first = 0; + MD_Node *group_last = 0; + + group_first = node->first_child; + group_last = MD_SeekNodeWithFlags(group_first, MD_NodeFlag_AfterComma); + TestResult(MD_StringMatch(group_first->string, MD_S8Lit("a"), 0)); + TestResult(MD_StringMatch(group_first->next->string, MD_S8Lit("b"), 0)); + TestResult(MD_StringMatch(group_last->string, MD_S8Lit("c"), 0)); + + group_first = group_last->next; + group_last = MD_SeekNodeWithFlags(group_first, MD_NodeFlag_AfterComma); + TestResult(MD_StringMatch(group_first->string, MD_S8Lit("d"), 0)); + TestResult(MD_StringMatch(group_first->next->string, MD_S8Lit("e"), 0)); + TestResult(MD_StringMatch(group_last->string, MD_S8Lit("f"), 0)); + + group_first = group_last->next; + group_last = MD_SeekNodeWithFlags(group_first, MD_NodeFlag_AfterComma); + TestResult(MD_StringMatch(group_first->string, MD_S8Lit("g"), 0)); + TestResult(MD_StringMatch(group_first->next->string, MD_S8Lit("h"), 0)); + TestResult(MD_StringMatch(group_last->string, MD_S8Lit("i"), 0)); + } + + } + return 0; } \ No newline at end of file From 30187151ecfa4e9c9b65bd070800c3e1bb373ff1 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 24 Apr 2021 16:07:34 -0600 Subject: [PATCH 3/5] toy language sample; fix a couple of bugs --- build.bat | 1 + samples/toy_language/test.mdesk | 8 ++ samples/toy_language/toy_language.c | 199 ++++++++++++++++++++++++++++ source/md_c_helpers.c | 23 +++- source/md_impl.c | 2 +- 5 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 samples/toy_language/test.mdesk create mode 100644 samples/toy_language/toy_language.c diff --git a/build.bat b/build.bat index 812d4a1..55d6159 100644 --- a/build.bat +++ b/build.bat @@ -8,6 +8,7 @@ pushd build echo. echo ~~~ Build All Samples ~~~ cl %compile_flags% ..\samples\old_style_custom_layer.c +cl %compile_flags% ..\samples\toy_language\toy_language.c cl %compile_flags% ..\samples\static_site_generator\static_site_generator.c cl %compile_flags% ..\samples\output_parse\output_parse.c cl %compile_flags% ..\samples\c_code_generation.c diff --git a/samples/toy_language/test.mdesk b/samples/toy_language/test.mdesk new file mode 100644 index 0000000..bc207c3 --- /dev/null +++ b/samples/toy_language/test.mdesk @@ -0,0 +1,8 @@ +add: (x, y) { x + y } + +main:() +{ + a: 1; + b: 2; + add(a, b); +} diff --git a/samples/toy_language/toy_language.c b/samples/toy_language/toy_language.c new file mode 100644 index 0000000..30f2055 --- /dev/null +++ b/samples/toy_language/toy_language.c @@ -0,0 +1,199 @@ +#include "md.h" +#include "md_c_helpers.h" +#include "md.c" +#include "md_c_helpers.c" + +typedef struct NodeSubList NodeSubList; +struct NodeSubList +{ + MD_Node *first; + MD_Node *last; +}; + +typedef struct NamespaceNode NamespaceNode; +struct NamespaceNode +{ + NamespaceNode *parent; + MD_Map symbol_map; +}; + +static NodeSubList +MakeNodeSubList(MD_Node *first, MD_Node *last) +{ + NodeSubList sublist = { first, last }; + return sublist; +} + +static void +InsertNodeSubListToNamespace(NamespaceNode *ns, MD_String8 string, NodeSubList sublist) +{ + NodeSubList *sublist_store = malloc(sizeof(*sublist_store)); + *sublist_store = sublist; + MD_StringMap_Insert(&ns->symbol_map, MD_MapCollisionRule_Chain, string, sublist_store); +} + +static NodeSubList +NodeSubListFromNamespaceAndString(NamespaceNode *ns, MD_String8 string) +{ + NodeSubList sublist = {MD_NilNode(), MD_NilNode()}; + for(NamespaceNode *n = ns; n; n = n->parent) + { + MD_MapSlot *slot = MD_StringMap_Lookup(&n->symbol_map, string); + if(slot && slot->value) + { + sublist = *(NodeSubList *)slot->value; + break; + } + } + return sublist; +} + +static MD_f64 EvaluateScope(NamespaceNode *ns, MD_Node *code); +static MD_f64 EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr); + +static MD_f64 +EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr) +{ + MD_f64 result = 0; + switch(expr->kind) + { +#define BinaryOp(name, op) case MD_C_ExprKind_##name: { result = EvaluateExpr(ns, expr->sub[0]) op EvaluateExpr(ns, expr->sub[1]); }break + BinaryOp(Add, +); + BinaryOp(Subtract, -); + BinaryOp(Multiply, *); + BinaryOp(Divide, /); +#undef BinaryOp + + case MD_C_ExprKind_Call: + { + MD_Node *call = expr->node; + NodeSubList callee = NodeSubListFromNamespaceAndString(ns, expr->sub[0]->node->string); + if(!MD_NodeIsNil(callee.first) && !MD_NodeIsNil(callee.last)) + { + //- rjf: find top-level namespace + NamespaceNode *top_level_ns = ns; + for(NamespaceNode *n = ns; n; n = n->parent) + { + top_level_ns = n; + } + + //- rjf: build namespace for function + NamespaceNode args_ns = {0}; + MD_Node *param = callee.first->first_child; + for(MD_Node *arg_first = call->first_child; !MD_NodeIsNil(arg_first); param = param->next) + { + MD_Node *arg_last = MD_SeekNodeWithFlags(arg_first, MD_NodeFlag_AfterComma|MD_NodeFlag_AfterSemicolon); + InsertNodeSubListToNamespace(&args_ns, param->string, MakeNodeSubList(arg_first, arg_last)); + arg_first = arg_last->next; + } + + args_ns.parent = ns; + result = EvaluateScope(&args_ns, callee.first->next); + } + }break; + + case MD_C_ExprKind_Atom: + { + if(expr->node->flags & MD_NodeFlag_Identifier) + { + NodeSubList decl_value = NodeSubListFromNamespaceAndString(ns, expr->node->string); + MD_C_Expr *decl_expr = MD_C_ParseAsExpr(decl_value.first, decl_value.last); + result = EvaluateExpr(ns, decl_expr); + } + else if(expr->node->flags & MD_NodeFlag_Numeric) + { + result = MD_F64FromString(expr->node->string); + } + }break; + + default: break; + } + return result; +} + +static MD_f64 +EvaluateScope(NamespaceNode *ns, MD_Node *code) +{ + MD_f64 result = 0; + + NamespaceNode local_namespace = {0}; + local_namespace.parent = ns; + + for(MD_Node *first = code->first_child; !MD_NodeIsNil(first);) + { + MD_Node *last = MD_SeekNodeWithFlags(first, MD_NodeFlag_AfterSemicolon|MD_NodeFlag_AfterComma); + + //- rjf: declaration + if(first == last && first->string.size != 0 && !MD_NodeIsNil(first->first_child)) + { + InsertNodeSubListToNamespace(&local_namespace, first->string, + MakeNodeSubList(first->first_child, first->last_child)); + } + //- rjf: expr + else + { + MD_C_Expr *expr = MD_C_ParseAsExpr(first, last); + if(!MD_C_ExprIsNil(expr)) + { + result = EvaluateExpr(&local_namespace, expr); + } + } + + //- rjf: bump + first = last->next; + } + + return result; +} + +int main(int argument_count, char **arguments) +{ + //- rjf: parse command line + MD_CommandLine cmdln = MD_CommandLineFromOptions(MD_StringListFromArgCV(argument_count, arguments)); + + //- rjf: parse all input files + MD_Node *first_file = MD_NilNode(); + MD_Node *last_file = MD_NilNode(); + for(MD_String8Node *n = cmdln.inputs.first; n; n = n->next) + { + MD_ParseResult parse = MD_ParseWholeFile(n->string); + MD_PushSibling(&first_file, &last_file, parse.node); + } + + //- rjf: gather top-level symbol map + NamespaceNode global_ns_node = {0}; + for(MD_EachNode(file, first_file)) + { + for(MD_EachNode(top_level, file->first_child)) + { + if(top_level->string.size > 0) + { + InsertNodeSubListToNamespace(&global_ns_node, top_level->string, + MakeNodeSubList(top_level, top_level)); + } + } + } + + //- rjf: find `main` procedure + NodeSubList main_proc = NodeSubListFromNamespaceAndString(&global_ns_node, MD_S8Lit("main")); + MD_Node *main_code = main_proc.first->next; + if(MD_NodeIsNil(main_proc.first)) + { + fprintf(stderr, "no `main` procedure found"); + goto end; + } + + //- rjf: validate that we got `main` code + if(MD_NodeIsNil(main_code)) + { + fprintf(stderr, "`main` requires an implementation"); + goto end; + } + + //- rjf: start interpreting at `main` + MD_f64 result = EvaluateScope(&global_ns_node, main_code); + printf("result: %f\n", result); + + end:; + return 0; +} diff --git a/source/md_c_helpers.c b/source/md_c_helpers.c index 4adbe3b..7c31e27 100644 --- a/source/md_c_helpers.c +++ b/source/md_c_helpers.c @@ -212,7 +212,13 @@ MD_PRIVATE_FUNCTION_IMPL MD_b32 _MD_NodeParse_ConsumeSet(_MD_NodeParseCtx *ctx, MD_Node **out) { MD_b32 result = 0; - if(!MD_NodeIsNil(ctx->at->first_child)) + if(!MD_NodeIsNil(ctx->at->first_child) || + ctx->at->flags & MD_NodeFlag_ParenLeft || + ctx->at->flags & MD_NodeFlag_ParenRight || + ctx->at->flags & MD_NodeFlag_BracketLeft || + ctx->at->flags & MD_NodeFlag_BracketRight || + ctx->at->flags & MD_NodeFlag_BraceLeft || + ctx->at->flags & MD_NodeFlag_BraceRight) { if(out) { @@ -313,6 +319,19 @@ _MD_ParseUnaryExpr(_MD_NodeParseCtx *ctx) result = MD_C_MakeExpr(node, MD_C_ExprKind_BoolNot, 0, _MD_ParseExpr(ctx)); } + // NOTE(rjf): Post-Unary Sets (calls and subscripts) + if(_MD_NodeParse_ConsumeSet(ctx, &set)) + { + if(set->flags & MD_NodeFlag_ParenLeft && set->flags & MD_NodeFlag_ParenRight) + { + result = MD_C_MakeExpr(set, MD_C_ExprKind_Call, result, 0); + } + else if(set->flags & MD_NodeFlag_BracketLeft && set->flags & MD_NodeFlag_BracketRight) + { + result = MD_C_MakeExpr(set, MD_C_ExprKind_Subscript, result, MD_C_ParseAsExpr(set->first_child, set->last_child)); + } + } + return result; } @@ -456,7 +475,7 @@ MD_C_EvaluateExpr_F64(MD_C_Expr *expr) MD_f64 result = 0; switch(expr->kind) { -#define _MD_BinaryOp(name, op) case MD_C_ExprKind_##name: { result = MD_C_EvaluateExpr_I64(expr->sub[0]) op MD_C_EvaluateExpr_F64(expr->sub[1]); }break +#define _MD_BinaryOp(name, op) case MD_C_ExprKind_##name: { result = MD_C_EvaluateExpr_F64(expr->sub[0]) op MD_C_EvaluateExpr_F64(expr->sub[1]); }break _MD_BinaryOp(Add, +); _MD_BinaryOp(Subtract, -); _MD_BinaryOp(Multiply, *); diff --git a/source/md_impl.c b/source/md_impl.c index 65cc923..96f0a70 100644 --- a/source/md_impl.c +++ b/source/md_impl.c @@ -2510,7 +2510,7 @@ MD_FUNCTION MD_String8List MD_StringListFromArgCV(int argument_count, char **arguments) { MD_String8List options = MD_ZERO_STRUCT; - for(int i = 0; i < argument_count; i += 1) + for(int i = 1; i < argument_count; i += 1) { MD_PushStringToList(&options, MD_S8CString(arguments[i])); } From 5f3528bea55a4b2e39a51af1bd8a68fc98b871e3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 24 Apr 2021 16:20:31 -0600 Subject: [PATCH 4/5] re-order md_impl; keep everything in same order as header file --- source/md.h | 11 +- source/md_impl.c | 822 +++++++++++++++++++++++------------------------ 2 files changed, 414 insertions(+), 419 deletions(-) diff --git a/source/md.h b/source/md.h index 869607e..ae1d6b4 100644 --- a/source/md.h +++ b/source/md.h @@ -629,21 +629,26 @@ MD_FUNCTION MD_String16 MD_S16FromS8(MD_String8 str); MD_FUNCTION MD_String8 MD_S8FromS32(MD_String32 str); MD_FUNCTION MD_String32 MD_S32FromS8(MD_String8 str); -//~ String-To-Pointer Table +//~ Map Table Data Structure + +MD_FUNCTION MD_u64 MD_HashPointer(void *p); + +//- String-To-Pointer Table MD_FUNCTION MD_MapSlot * MD_StringMap_Lookup(MD_Map *table, MD_String8 string); MD_FUNCTION MD_b32 MD_StringMap_Insert(MD_Map *table, MD_MapCollisionRule collision_rule, MD_String8 string, void *value); MD_FUNCTION MD_MapSlot * MD_StringMap_Next(MD_MapSlot *slot, MD_String8 key); -//~ Pointer-To-Pointer Table +//- Pointer-To-Pointer Table MD_FUNCTION MD_MapSlot *MD_PtrMap_Lookup(MD_Map *map, void *key); MD_FUNCTION MD_b32 MD_PtrMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, void *key, void *value); //~ Parsing + MD_FUNCTION MD_b32 MD_TokenKindIsWhitespace(MD_TokenKind kind); MD_FUNCTION MD_b32 MD_TokenKindIsComment(MD_TokenKind kind); MD_FUNCTION MD_b32 MD_TokenKindIsRegular(MD_TokenKind kind); -MD_FUNCTION MD_ParseCtx MD_Parse_InitializeCtx(MD_String8 filename, MD_String8 contents); +MD_FUNCTION MD_ParseCtx MD_Parse_InitializeCtx(MD_String8 filename, MD_String8 contents); MD_FUNCTION void MD_Parse_Bump(MD_ParseCtx *ctx, MD_Token token); MD_FUNCTION void MD_Parse_BumpNext(MD_ParseCtx *ctx); MD_FUNCTION MD_Token MD_Parse_LexNext(MD_ParseCtx *ctx); diff --git a/source/md_impl.c b/source/md_impl.c index 96f0a70..cc00a94 100644 --- a/source/md_impl.c +++ b/source/md_impl.c @@ -68,6 +68,8 @@ _MD_AllocZero(MD_u64 size) #define _MD_PushArray(type, count) (type *)_MD_AllocZero(sizeof(type)*(count)) +//~ Basic Utilities + MD_FUNCTION_IMPL MD_b32 MD_CharIsAlpha(MD_u8 c) { @@ -135,6 +137,8 @@ MD_CorrectSlash(MD_u8 c) return (c == '\\' ? '/' : c); } +//~ Strings + MD_FUNCTION_IMPL MD_String8 MD_S8(MD_u8 *str, MD_u64 size) { @@ -635,6 +639,8 @@ MD_StyledStringFromString(MD_String8 string, MD_WordStyle word_style, MD_String8 return result; } +//~ Enum/Flag Strings + MD_FUNCTION_IMPL MD_String8 MD_StringFromNodeKind(MD_NodeKind kind) { @@ -689,10 +695,9 @@ MD_StringListFromNodeFlags(MD_NodeFlags flags) return list; } -//////////////////////////////// -// NOTE(allen): Unicode +//~ Unicode Conversions -MD_GLOBAL MD_u8 dd_utf8_class[32] = { +MD_GLOBAL MD_u8 md_utf8_class[32] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, }; @@ -712,7 +717,7 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) MD_UnicodeConsume result = {~((MD_u32)0), 1}; MD_u8 byte = str[0]; - MD_u8 byte_class = dd_utf8_class[byte >> 3]; + MD_u8 byte_class = md_utf8_class[byte >> 3]; switch (byte_class) { case 1: @@ -725,7 +730,7 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) if (2 <= max) { MD_u8 cont_byte = str[1]; - if (dd_utf8_class[cont_byte >> 3] == 0) + if (md_utf8_class[cont_byte >> 3] == 0) { result.codepoint = (byte & MD_bitmask5) << 6; result.codepoint |= (cont_byte & MD_bitmask6); @@ -739,8 +744,8 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) if (3 <= max) { MD_u8 cont_byte[2] = {str[1], str[2]}; - if (dd_utf8_class[cont_byte[0] >> 3] == 0 && - dd_utf8_class[cont_byte[1] >> 3] == 0) + if (md_utf8_class[cont_byte[0] >> 3] == 0 && + md_utf8_class[cont_byte[1] >> 3] == 0) { result.codepoint = (byte & MD_bitmask4) << 12; result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 6); @@ -755,9 +760,9 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) if (4 <= max) { MD_u8 cont_byte[3] = {str[1], str[2], str[3]}; - if (dd_utf8_class[cont_byte[0] >> 3] == 0 && - dd_utf8_class[cont_byte[1] >> 3] == 0 && - dd_utf8_class[cont_byte[2] >> 3] == 0) + if (md_utf8_class[cont_byte[0] >> 3] == 0 && + md_utf8_class[cont_byte[1] >> 3] == 0 && + md_utf8_class[cont_byte[2] >> 3] == 0) { result.codepoint = (byte & MD_bitmask3) << 18; result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 12); @@ -924,8 +929,8 @@ MD_S32FromS8(MD_String8 in) return(result); } -///////////////////////////////////////////// -//~ String-To-Ptr and Ptr-To-Ptr tables +//~ Map Table Data Structure + MD_PRIVATE_FUNCTION_IMPL void _MD_Map_Initialize(MD_Map *map) { @@ -936,13 +941,24 @@ _MD_Map_Initialize(MD_Map *map) } } -///////////////////////////////////////////// -//~ NOTE(mal): MD_StringMap +// NOTE(mal): Generic 64-bit hash function (https://nullprogram.com/blog/2018/07/31/) +// Reversible, so no collisions. Assumes all bits of the pointer matter. +MD_FUNCTION_IMPL MD_u64 +MD_HashPointer(void *p) +{ + MD_u64 h = (MD_u64)p; + h = (h ^ (h >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); + h = (h ^ (h >> 27)) * UINT64_C(0x94d049bb133111eb); + h = h ^ (h >> 31); + return h; +} + +//- String-To-Pointer Table + MD_FUNCTION_IMPL MD_MapSlot * -MD_StringMap_Lookup(MD_Map *map, MD_String8 string) // NOTE(mal): Or MD_PtrFromString +MD_StringMap_Lookup(MD_Map *map, MD_String8 string) { _MD_Map_Initialize(map); - MD_MapSlot *slot = 0; MD_u64 hash = MD_HashString(string); MD_u64 index = hash % map->table_size; @@ -954,7 +970,6 @@ MD_StringMap_Lookup(MD_Map *map, MD_String8 string) // NOTE(mal): Or MD_Pt break; } } - return slot; } @@ -1030,20 +1045,7 @@ MD_StringMap_Next(MD_MapSlot *slot, MD_String8 key) return next; } -///////////////////////////////////////////// -//~ NOTE(mal): MD_PtrMap - -// NOTE(mal): Generic 64-bit hash function (https://nullprogram.com/blog/2018/07/31/) -// Reversible, so no collisions. Assumes all bits of the pointer matter. -MD_FUNCTION_IMPL MD_u64 -MD_HashPointer(void *p) -{ - MD_u64 h = (MD_u64)p; - h = (h ^ (h >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); - h = (h ^ (h >> 27)) * UINT64_C(0x94d049bb133111eb); - h = h ^ (h >> 31); - return h; -} +//- Pointer-To-Pointer Table MD_FUNCTION_IMPL MD_MapSlot * MD_PtrMap_Lookup(MD_Map *map, void *key) @@ -1117,6 +1119,154 @@ MD_PtrMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, void *key, voi return !!slot; } +//~ Parsing + +MD_PRIVATE_FUNCTION_IMPL void +_MD_Error(MD_ParseCtx *ctx, MD_Node *node, MD_MessageKind kind, char *fmt, ...) +{ + // NOTE(mal): Sort errors. Traverse the whole list assuming it will be short. + // The alternative is to drop a prev pointer into MD_Error and search backwards + MD_Error *prev_error = 0; + for(MD_Error *e = ctx->first_error; e; e = e->next) + { + if(e->node->at < node->at) + { + prev_error = e; + } + else + { + break; + } + } + + // NOTE(mal): Ignore errors after first catastrophic error + if(ctx->error_level < MD_MessageKind_CatastrophicError || !prev_error || prev_error->next) + { + MD_Error *error = _MD_PushArray(MD_Error, 1); + error->node = node; + error->kind = kind; + va_list args; + va_start(args, fmt); + error->string = MD_PushStringFV(fmt, args); + va_end(args); + + if(prev_error) + { + error->next = prev_error->next; + prev_error->next = error; + } + else + { + error->next = ctx->first_error; + ctx->first_error = error; + } + + if(!ctx->last_error || ctx->last_error == prev_error) + { + ctx->last_error = error; + } + + if(kind > ctx->error_level) + { + ctx->error_level = kind; + } + } +} +#define _MD_TokenError(ctx, token, kind, fmt, ...) \ +_MD_Error(ctx, _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_ErrorMarker, token), kind, fmt, __VA_ARGS__) + +MD_PRIVATE_FUNCTION_IMPL MD_Node * +_MD_MakeNodeFromToken_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_Token token) +{ + return MD_MakeNode(kind, token.string, token.outer_string, ctx->filename, + ctx->file_contents.str, + token.outer_string.str); +} + +MD_PRIVATE_FUNCTION_IMPL MD_Node * +_MD_MakeNodeFromString_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_String8 string, MD_u8 *at) +{ + return MD_MakeNode(kind, string, string, ctx->filename, ctx->file_contents.str, at); +} + +MD_PRIVATE_FUNCTION_IMPL void _MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out); + +MD_PRIVATE_FUNCTION_IMPL MD_NodeFlags +_MD_NodeFlagsFromTokenKind(MD_TokenKind kind) +{ + MD_NodeFlags result = 0; + switch (kind){ + case MD_TokenKind_Identifier: result = MD_NodeFlag_Identifier; break; + case MD_TokenKind_NumericLiteral: result = MD_NodeFlag_Numeric; break; + case MD_TokenKind_StringLiteral: result = MD_NodeFlag_StringLiteral; break; + case MD_TokenKind_CharLiteral: result = MD_NodeFlag_CharLiteral; break; + } + return(result); +} + +MD_PRIVATE_FUNCTION_IMPL MD_b32 +_MD_StringLiteralIsBalanced(MD_Token token) +{ + MD_u64 front_len = token.string.str - token.outer_string.str; + MD_u64 back_len = (token.outer_string.str + token.outer_string.size) - (token.string.str + token.string.size); + MD_b32 result = (front_len == back_len); + return result; +} + +MD_PRIVATE_FUNCTION_IMPL MD_b32 +_MD_CommentIsSyntacticallyCorrect(MD_Token comment_token) +{ + MD_String8 inner = comment_token.string; + MD_String8 outer = comment_token.outer_string; + MD_b32 incorrect = (MD_StringMatch(MD_StringPrefix(outer, 2), MD_S8Lit("/*"), 0) && // C-style comment + (inner.str != outer.str + 2 || inner.str + inner.size != outer.str + outer.size - 2)); // Internally unbalanced + MD_b32 result = !incorrect; + return result; +} +MD_PRIVATE_FUNCTION_IMPL void +_MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out) +{ + MD_Node *first = MD_NilNode(); + MD_Node *last = MD_NilNode(); + + for(;;) + { + MD_Token next_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment | MD_TokenGroup_Whitespace); + if(MD_StringMatch(next_token.string, MD_S8Lit("@"), 0) && + next_token.kind == MD_TokenKind_Symbol) + { + MD_Parse_Bump(ctx, next_token); + + MD_Token name = MD_ZERO_STRUCT; + if(MD_Parse_RequireKind(ctx, MD_TokenKind_Identifier, &name)) + { + MD_Node *tag = _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_Tag, name); + MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); + if(MD_StringMatch(token.string, MD_S8Lit("("), 0)) + { + MD_Parse_Set(ctx, tag, MD_ParseSetFlag_Paren); + } + MD_PushSibling(&first, &last, tag); + } + else + { + MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); + _MD_TokenError(ctx, token, MD_MessageKind_Error, "\"%.*s\" is not a proper tag identifier", + MD_StringExpand(token.outer_string)); + // NOTE(mal): There are reasons to consume the non-tag token, but also to leave it. + break; + } + } + else + { + break; + } + } + + *first_out = first; + *last_out = last; +} + MD_FUNCTION_IMPL MD_b32 MD_TokenKindIsWhitespace(MD_TokenKind kind) { @@ -1488,125 +1638,136 @@ MD_Parse_RequireKind(MD_ParseCtx *ctx, MD_TokenKind kind, MD_Token *out_token) return result; } -MD_PRIVATE_FUNCTION_IMPL void -_MD_Error(MD_ParseCtx *ctx, MD_Node *node, MD_MessageKind kind, char *fmt, ...) +MD_FUNCTION_IMPL void +MD_Parse_Set(MD_ParseCtx *ctx, MD_Node *parent, MD_ParseSetFlags flags) { - // NOTE(mal): Sort errors. Traverse the whole list assuming it will be short. - // The alternative is to drop a prev pointer into MD_Error and search backwards - MD_Error *prev_error = 0; - for(MD_Error *e = ctx->first_error; e; e = e->next) + MD_b32 brace = 0; + MD_b32 paren = 0; + MD_b32 bracket = 0; + MD_b32 terminate_with_separator = (!!(flags & MD_ParseSetFlag_Implicit)); + + MD_Token initial_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment|MD_TokenGroup_Whitespace); + + if((flags & MD_ParseSetFlag_Brace) && + MD_Parse_Require(ctx, MD_S8Lit("{"), MD_TokenKind_Symbol)) { - if(e->node->at < node->at) + parent->flags |= MD_NodeFlag_BraceLeft; + brace = 1; + terminate_with_separator = 0; + } + else if((flags & MD_ParseSetFlag_Paren) && + MD_Parse_Require(ctx, MD_S8Lit("("), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_ParenLeft; + paren = 1; + terminate_with_separator = 0; + } + else if((flags & MD_ParseSetFlag_Bracket) && + MD_Parse_Require(ctx, MD_S8Lit("["), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_BracketLeft; + bracket = 1; + terminate_with_separator = 0; + } + + // NOTE(rjf): Parse children. + if(brace || paren || bracket || terminate_with_separator) + { + MD_u8 *at_before_children = ctx->at; + MD_NodeFlags next_child_flags = 0; + for(MD_u64 child_idx = 0;; child_idx += 1) { - prev_error = e; - } - else - { - break; + if(brace) + { + if(MD_Parse_Require(ctx, MD_S8Lit("}"), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_BraceRight; + goto end_parse; + } + } + else if(paren || bracket) + { + if((flags & MD_ParseSetFlag_Paren) && + MD_Parse_Require(ctx, MD_S8Lit(")"), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_ParenRight; + goto end_parse; + } + else if((flags & MD_ParseSetFlag_Bracket) && + MD_Parse_Require(ctx, MD_S8Lit("]"), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_BracketRight; + goto end_parse; + } + } + else + { + MD_Token peek = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Whitespace | MD_TokenGroup_Comment); + if(peek.kind == MD_TokenKind_Symbol && + (MD_Parse_TokenMatch(peek, MD_S8Lit("}"), 0) || + MD_Parse_TokenMatch(peek, MD_S8Lit(")"), 0) || + MD_Parse_TokenMatch(peek, MD_S8Lit("]"), 0))) + { + goto end_parse; + } + } + + MD_ParseResult parse = MD_ParseOneNodeFromCtx(ctx); + MD_Node *child = parse.node; + child->flags |= next_child_flags; + next_child_flags = 0; + if(MD_NodeIsNil(child)) + { + if(brace || paren || bracket) + { + char delimiter_char = 0; + if(brace) delimiter_char = '{'; + else if(paren) delimiter_char = '('; + else if(bracket) delimiter_char = '['; + _MD_TokenError(ctx, initial_token, MD_MessageKind_CatastrophicError, "Unbalanced \"%c\"", delimiter_char); + } + goto end_parse; + } + else + { + MD_PushSibling(&parent->first_child, &parent->last_child, child); + child->parent = parent; + } + + // NOTE(rjf): Separators. + { + MD_b32 result = 0; + if(terminate_with_separator) + { + MD_Token next_token = MD_Parse_PeekSkipSome(ctx, 0); + if(next_token.kind == MD_TokenKind_Newline || + (next_token.kind == MD_TokenKind_Symbol && + (MD_StringMatch(next_token.string, MD_S8Lit(","), 0) || + MD_StringMatch(next_token.string, MD_S8Lit(";"), 0)))) + { + result = 1; + } + } + else if(MD_Parse_Require(ctx, MD_S8Lit(","), MD_TokenKind_Symbol)) + { + child->flags |= MD_NodeFlag_BeforeComma; + next_child_flags |= MD_NodeFlag_AfterComma; + } + else if(MD_Parse_Require(ctx, MD_S8Lit(";"), MD_TokenKind_Symbol)) + { + child->flags |= MD_NodeFlag_BeforeSemicolon; + next_child_flags |= MD_NodeFlag_AfterSemicolon; + } + + if(result) + { + goto end_parse; + } + } } } - // NOTE(mal): Ignore errors after first catastrophic error - if(ctx->error_level < MD_MessageKind_CatastrophicError || !prev_error || prev_error->next) - { - MD_Error *error = _MD_PushArray(MD_Error, 1); - error->node = node; - error->kind = kind; - va_list args; - va_start(args, fmt); - error->string = MD_PushStringFV(fmt, args); - va_end(args); - - if(prev_error) - { - error->next = prev_error->next; - prev_error->next = error; - } - else - { - error->next = ctx->first_error; - ctx->first_error = error; - } - - if(!ctx->last_error || ctx->last_error == prev_error) - { - ctx->last_error = error; - } - - if(kind > ctx->error_level) - { - ctx->error_level = kind; - } - } -} -#define _MD_TokenError(ctx, token, kind, fmt, ...) \ -_MD_Error(ctx, _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_ErrorMarker, token), kind, fmt, __VA_ARGS__) - -MD_FUNCTION_IMPL MD_Node * -MD_MakeNode(MD_NodeKind kind, MD_String8 string, - MD_String8 whole_string, MD_String8 filename, - MD_u8 *file_contents, MD_u8 *at) -{ - MD_Node *node = _MD_PushArray(MD_Node, 1); - node->kind = kind; - node->string = string; - node->whole_string = whole_string; - node->next = node->prev = node->parent = - node->first_child = node->last_child = - node->first_tag = node->last_tag = node->ref_target = MD_NilNode(); - node->filename = filename; - node->file_contents = file_contents; - node->at = at; - return node; -} - -MD_PRIVATE_FUNCTION_IMPL MD_Node * -_MD_MakeNodeFromToken_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_Token token) -{ - return MD_MakeNode(kind, token.string, token.outer_string, ctx->filename, - ctx->file_contents.str, - token.outer_string.str); -} - -MD_PRIVATE_FUNCTION_IMPL MD_Node * -_MD_MakeNodeFromString_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_String8 string, MD_u8 *at) -{ - return MD_MakeNode(kind, string, string, ctx->filename, ctx->file_contents.str, at); -} - -MD_PRIVATE_FUNCTION_IMPL void _MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out); - -MD_PRIVATE_FUNCTION_IMPL MD_NodeFlags -_MD_NodeFlagsFromTokenKind(MD_TokenKind kind) -{ - MD_NodeFlags result = 0; - switch (kind){ - case MD_TokenKind_Identifier: result = MD_NodeFlag_Identifier; break; - case MD_TokenKind_NumericLiteral: result = MD_NodeFlag_Numeric; break; - case MD_TokenKind_StringLiteral: result = MD_NodeFlag_StringLiteral; break; - case MD_TokenKind_CharLiteral: result = MD_NodeFlag_CharLiteral; break; - } - return(result); -} - -MD_PRIVATE_FUNCTION_IMPL MD_b32 -_MD_StringLiteralIsBalanced(MD_Token token) -{ - MD_u64 front_len = token.string.str - token.outer_string.str; - MD_u64 back_len = (token.outer_string.str + token.outer_string.size) - (token.string.str + token.string.size); - MD_b32 result = (front_len == back_len); - return result; -} - -MD_PRIVATE_FUNCTION_IMPL MD_b32 -_MD_CommentIsSyntacticallyCorrect(MD_Token comment_token) -{ - MD_String8 inner = comment_token.string; - MD_String8 outer = comment_token.outer_string; - MD_b32 incorrect = (MD_StringMatch(MD_StringPrefix(outer, 2), MD_S8Lit("/*"), 0) && // C-style comment - (inner.str != outer.str + 2 || inner.str + inner.size != outer.str + outer.size - 2)); // Internally unbalanced - MD_b32 result = !incorrect; - return result; + end_parse:; } MD_FUNCTION_IMPL MD_ParseResult @@ -1806,182 +1967,6 @@ MD_ParseOneNodeFromCtx(MD_ParseCtx *ctx) return result; } -MD_FUNCTION_IMPL void -MD_Parse_Set(MD_ParseCtx *ctx, MD_Node *parent, MD_ParseSetFlags flags) -{ - MD_b32 brace = 0; - MD_b32 paren = 0; - MD_b32 bracket = 0; - MD_b32 terminate_with_separator = (!!(flags & MD_ParseSetFlag_Implicit)); - - MD_Token initial_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment|MD_TokenGroup_Whitespace); - - if((flags & MD_ParseSetFlag_Brace) && - MD_Parse_Require(ctx, MD_S8Lit("{"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BraceLeft; - brace = 1; - terminate_with_separator = 0; - } - else if((flags & MD_ParseSetFlag_Paren) && - MD_Parse_Require(ctx, MD_S8Lit("("), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_ParenLeft; - paren = 1; - terminate_with_separator = 0; - } - else if((flags & MD_ParseSetFlag_Bracket) && - MD_Parse_Require(ctx, MD_S8Lit("["), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BracketLeft; - bracket = 1; - terminate_with_separator = 0; - } - - // NOTE(rjf): Parse children. - if(brace || paren || bracket || terminate_with_separator) - { - MD_u8 *at_before_children = ctx->at; - MD_NodeFlags next_child_flags = 0; - for(MD_u64 child_idx = 0;; child_idx += 1) - { - if(brace) - { - if(MD_Parse_Require(ctx, MD_S8Lit("}"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BraceRight; - goto end_parse; - } - } - else if(paren || bracket) - { - if((flags & MD_ParseSetFlag_Paren) && - MD_Parse_Require(ctx, MD_S8Lit(")"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_ParenRight; - goto end_parse; - } - else if((flags & MD_ParseSetFlag_Bracket) && - MD_Parse_Require(ctx, MD_S8Lit("]"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BracketRight; - goto end_parse; - } - } - else - { - MD_Token peek = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Whitespace | MD_TokenGroup_Comment); - if(peek.kind == MD_TokenKind_Symbol && - (MD_Parse_TokenMatch(peek, MD_S8Lit("}"), 0) || - MD_Parse_TokenMatch(peek, MD_S8Lit(")"), 0) || - MD_Parse_TokenMatch(peek, MD_S8Lit("]"), 0))) - { - goto end_parse; - } - } - - MD_ParseResult parse = MD_ParseOneNodeFromCtx(ctx); - MD_Node *child = parse.node; - child->flags |= next_child_flags; - next_child_flags = 0; - if(MD_NodeIsNil(child)) - { - if(brace || paren || bracket) - { - char delimiter_char = 0; - if(brace) delimiter_char = '{'; - else if(paren) delimiter_char = '('; - else if(bracket) delimiter_char = '['; - _MD_TokenError(ctx, initial_token, MD_MessageKind_CatastrophicError, "Unbalanced \"%c\"", delimiter_char); - } - goto end_parse; - } - else - { - MD_PushSibling(&parent->first_child, &parent->last_child, child); - child->parent = parent; - } - - // NOTE(rjf): Separators. - { - MD_b32 result = 0; - if(terminate_with_separator) - { - MD_Token next_token = MD_Parse_PeekSkipSome(ctx, 0); - if(next_token.kind == MD_TokenKind_Newline || - (next_token.kind == MD_TokenKind_Symbol && - (MD_StringMatch(next_token.string, MD_S8Lit(","), 0) || - MD_StringMatch(next_token.string, MD_S8Lit(";"), 0)))) - { - result = 1; - } - } - else if(MD_Parse_Require(ctx, MD_S8Lit(","), MD_TokenKind_Symbol)) - { - child->flags |= MD_NodeFlag_BeforeComma; - next_child_flags |= MD_NodeFlag_AfterComma; - } - else if(MD_Parse_Require(ctx, MD_S8Lit(";"), MD_TokenKind_Symbol)) - { - child->flags |= MD_NodeFlag_BeforeSemicolon; - next_child_flags |= MD_NodeFlag_AfterSemicolon; - } - - if(result) - { - goto end_parse; - } - } - } - } - - end_parse:; -} - -MD_PRIVATE_FUNCTION_IMPL void -_MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out) -{ - MD_Node *first = MD_NilNode(); - MD_Node *last = MD_NilNode(); - - for(;;) - { - MD_Token next_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment | MD_TokenGroup_Whitespace); - if(MD_StringMatch(next_token.string, MD_S8Lit("@"), 0) && - next_token.kind == MD_TokenKind_Symbol) - { - MD_Parse_Bump(ctx, next_token); - - MD_Token name = MD_ZERO_STRUCT; - if(MD_Parse_RequireKind(ctx, MD_TokenKind_Identifier, &name)) - { - MD_Node *tag = _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_Tag, name); - MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); - if(MD_StringMatch(token.string, MD_S8Lit("("), 0)) - { - MD_Parse_Set(ctx, tag, MD_ParseSetFlag_Paren); - } - MD_PushSibling(&first, &last, tag); - } - else - { - MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); - _MD_TokenError(ctx, token, MD_MessageKind_Error, "\"%.*s\" is not a proper tag identifier", - MD_StringExpand(token.outer_string)); - // NOTE(mal): There are reasons to consume the non-tag token, but also to leave it. - break; - } - } - else - { - break; - } - } - - *first_out = first; - *last_out = last; -} - MD_FUNCTION_IMPL MD_ParseResult MD_ParseOneNode(MD_String8 filename, MD_String8 contents) { @@ -1989,16 +1974,6 @@ MD_ParseOneNode(MD_String8 filename, MD_String8 contents) return MD_ParseOneNodeFromCtx(&ctx); } -MD_FUNCTION_IMPL void -MD_InsertToNamespace(MD_Node *ns, MD_Node *node) -{ - MD_Node *ref = MD_MakeNode(MD_NodeKind_Reference, node->string, - node->whole_string, node->filename, - node->file_contents, node->at); - ref->ref_target = node; - MD_PushChild(ns, ref); -} - MD_FUNCTION_IMPL MD_ParseResult MD_ParseWholeString(MD_String8 filename, MD_String8 contents) { @@ -2103,6 +2078,8 @@ MD_ParseWholeFile(MD_String8 filename) return parse; } +//~ Location Conversions + MD_PRIVATE_FUNCTION_IMPL MD_CodeLoc MD_CodeLocFromFileOffset(MD_String8 filename, MD_u8 *base, MD_u8 *at) { @@ -2132,6 +2109,7 @@ MD_CodeLocFromNode(MD_Node *node) return loc; } +//~ Tree/List Building MD_FUNCTION_IMPL MD_b32 MD_NodeIsNil(MD_Node *node) @@ -2142,6 +2120,24 @@ MD_NodeIsNil(MD_Node *node) MD_FUNCTION_IMPL MD_Node * MD_NilNode(void) { return &_md_nil_node; } +MD_FUNCTION_IMPL MD_Node * +MD_MakeNode(MD_NodeKind kind, MD_String8 string, + MD_String8 whole_string, MD_String8 filename, + MD_u8 *file_contents, MD_u8 *at) +{ + MD_Node *node = _MD_PushArray(MD_Node, 1); + node->kind = kind; + node->string = string; + node->whole_string = whole_string; + node->next = node->prev = node->parent = + node->first_child = node->last_child = + node->first_tag = node->last_tag = node->ref_target = MD_NilNode(); + node->filename = filename; + node->file_contents = file_contents; + node->at = at; + return node; +} + MD_FUNCTION_IMPL MD_Node * MD_MakeNodeFromToken(MD_NodeKind kind, MD_String8 filename, MD_u8 *file, MD_u8 *at, MD_Token token) { @@ -2200,67 +2196,17 @@ MD_PushTag(MD_Node *node, MD_Node *tag) tag->parent = node; } -MD_FUNCTION_IMPL MD_b32 -MD_NodeMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) +MD_FUNCTION_IMPL void +MD_InsertToNamespace(MD_Node *ns, MD_Node *node) { - MD_b32 result = 0; - if(a->kind == b->kind && MD_StringMatch(a->string, b->string, flags)) - { - result = 1; - if(a->kind != MD_NodeKind_Tag && (flags & MD_MatchFlag_Tags)) - { - for(MD_Node *a_tag = a->first_tag, *b_tag = b->first_tag; - !MD_NodeIsNil(a_tag) || !MD_NodeIsNil(b_tag); - a_tag = a_tag->next, b_tag = b_tag->next) - { - if(MD_NodeMatch(a_tag, b_tag, flags)) - { - if(flags & MD_MatchFlag_TagArguments) - { - for(MD_Node *a_tag_arg = a_tag->first_child, *b_tag_arg = b_tag->first_child; - !MD_NodeIsNil(a_tag_arg) || !MD_NodeIsNil(b_tag_arg); - a_tag_arg = a_tag_arg->next, b_tag_arg = b_tag_arg->next) - { - if(!MD_NodeDeepMatch(a_tag_arg, b_tag_arg, flags)) - { - result = 0; - goto end; - } - } - } - } - else - { - result = 0; - goto end; - } - } - } - } - end:; - return result; + MD_Node *ref = MD_MakeNode(MD_NodeKind_Reference, node->string, + node->whole_string, node->filename, + node->file_contents, node->at); + ref->ref_target = node; + MD_PushChild(ns, ref); } -MD_FUNCTION_IMPL MD_b32 -MD_NodeDeepMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) -{ - MD_b32 result = MD_NodeMatch(a, b, flags); - if(result) - { - for(MD_Node *a_child = a->first_child, *b_child = b->first_child; - !MD_NodeIsNil(a_child) || !MD_NodeIsNil(b_child); - a_child = a_child->next, b_child = b_child->next) - { - if(!MD_NodeDeepMatch(a_child, b_child, flags)) - { - result = 0; - goto end; - } - } - } - end:; - return result; -} +//~ Introspection Helpers MD_FUNCTION_IMPL MD_Node * MD_NodeFromString(MD_Node *first, MD_Node *last, MD_String8 string) @@ -2392,34 +2338,6 @@ MD_TagCountFromNode(MD_Node *node) return result; } -MD_FUNCTION_IMPL MD_i64 -MD_ChildCountFromNodeAndString(MD_Node *node, MD_String8 string, MD_MatchFlags flags) -{ - MD_i64 result = 0; - for(MD_EachNode(child, node->first_child)) - { - if(MD_StringMatch(child->string, string, flags)) - { - result += 1; - } - } - return result; -} - -MD_FUNCTION_IMPL MD_i64 -MD_TagCountFromNodeAndString(MD_Node *node, MD_String8 string, MD_MatchFlags flags) -{ - MD_i64 result = 0; - for(MD_EachNode(tag, node->first_tag)) - { - if(MD_StringMatch(tag->string, string, flags)) - { - result += 1; - } - } - return result; -} - MD_FUNCTION_IMPL MD_Node * MD_Deref(MD_Node *node) { @@ -2446,6 +2364,8 @@ MD_SeekNodeWithFlags(MD_Node *start, MD_NodeFlags one_past_last_flags) return result; } +//~ Error/Warning Helpers + MD_FUNCTION_IMPL void MD_NodeMessage(MD_Node *node, MD_MessageKind kind, MD_String8 str) { @@ -2467,6 +2387,72 @@ MD_NodeMessageF(MD_Node *node, MD_MessageKind kind, char *fmt, ...) va_end(args); } +//~ Tree Comparison/Verification + +MD_FUNCTION_IMPL MD_b32 +MD_NodeMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) +{ + MD_b32 result = 0; + if(a->kind == b->kind && MD_StringMatch(a->string, b->string, flags)) + { + result = 1; + if(a->kind != MD_NodeKind_Tag && (flags & MD_MatchFlag_Tags)) + { + for(MD_Node *a_tag = a->first_tag, *b_tag = b->first_tag; + !MD_NodeIsNil(a_tag) || !MD_NodeIsNil(b_tag); + a_tag = a_tag->next, b_tag = b_tag->next) + { + if(MD_NodeMatch(a_tag, b_tag, flags)) + { + if(flags & MD_MatchFlag_TagArguments) + { + for(MD_Node *a_tag_arg = a_tag->first_child, *b_tag_arg = b_tag->first_child; + !MD_NodeIsNil(a_tag_arg) || !MD_NodeIsNil(b_tag_arg); + a_tag_arg = a_tag_arg->next, b_tag_arg = b_tag_arg->next) + { + if(!MD_NodeDeepMatch(a_tag_arg, b_tag_arg, flags)) + { + result = 0; + goto end; + } + } + } + } + else + { + result = 0; + goto end; + } + } + } + } + end:; + return result; +} + +MD_FUNCTION_IMPL MD_b32 +MD_NodeDeepMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) +{ + MD_b32 result = MD_NodeMatch(a, b, flags); + if(result) + { + for(MD_Node *a_child = a->first_child, *b_child = b->first_child; + !MD_NodeIsNil(a_child) || !MD_NodeIsNil(b_child); + a_child = a_child->next, b_child = b_child->next) + { + if(!MD_NodeDeepMatch(a_child, b_child, flags)) + { + result = 0; + goto end; + } + } + } + end:; + return result; +} + +//~ Generation + MD_FUNCTION_IMPL void MD_OutputTree(FILE *file, MD_Node *node) { @@ -2506,6 +2492,8 @@ MD_OutputTree(FILE *file, MD_Node *node) } } +//~ Command Line Argument Helper + MD_FUNCTION MD_String8List MD_StringListFromArgCV(int argument_count, char **arguments) { @@ -2669,6 +2657,8 @@ MD_CommandLineOptionI64(MD_CommandLine cmdln, MD_String8 name) return v; } +//~ File System + MD_FUNCTION_IMPL MD_String8 MD_LoadEntireFile(MD_String8 filename) { From 25a80c1def53e88e06b7738998a58871ec2b8521 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 24 Apr 2021 19:48:25 -0600 Subject: [PATCH 5/5] flesh out values in the toy language --- samples/toy_language/test.mdesk | 12 ++- samples/toy_language/toy_language.c | 138 ++++++++++++++++++---------- 2 files changed, 98 insertions(+), 52 deletions(-) diff --git a/samples/toy_language/test.mdesk b/samples/toy_language/test.mdesk index bc207c3..a0c4ecc 100644 --- a/samples/toy_language/test.mdesk +++ b/samples/toy_language/test.mdesk @@ -1,8 +1,10 @@ -add: (x, y) { x + y } -main:() +@proc foo:(x, y, z) { - a: 1; - b: 2; - add(a, b); + (x + y) * z +} + +@proc main:() +{ + foo(10, 20, 30); } diff --git a/samples/toy_language/toy_language.c b/samples/toy_language/toy_language.c index 30f2055..38ae3fb 100644 --- a/samples/toy_language/toy_language.c +++ b/samples/toy_language/toy_language.c @@ -3,13 +3,6 @@ #include "md.c" #include "md_c_helpers.c" -typedef struct NodeSubList NodeSubList; -struct NodeSubList -{ - MD_Node *first; - MD_Node *last; -}; - typedef struct NamespaceNode NamespaceNode; struct NamespaceNode { @@ -17,58 +10,94 @@ struct NamespaceNode MD_Map symbol_map; }; -static NodeSubList -MakeNodeSubList(MD_Node *first, MD_Node *last) +typedef enum ValueKind { - NodeSubList sublist = { first, last }; - return sublist; + ValueKind_Null, + ValueKind_Number, + ValueKind_Procedure, +} +ValueKind; + +typedef struct Value Value; +struct Value +{ + ValueKind kind; + MD_f64 number; + MD_Node *node; +}; + +static Value +MakeValue_Number(MD_f64 v) +{ + Value value = {0}; + value.kind = ValueKind_Number; + value.number = v; + return value; +} + +static Value +MakeValue_Procedure(MD_Node *node) +{ + Value value = {0}; + value.kind = ValueKind_Procedure; + value.node = node; + return value; } static void -InsertNodeSubListToNamespace(NamespaceNode *ns, MD_String8 string, NodeSubList sublist) +InsertValueToNamespace(NamespaceNode *ns, MD_String8 string, Value v) { - NodeSubList *sublist_store = malloc(sizeof(*sublist_store)); - *sublist_store = sublist; - MD_StringMap_Insert(&ns->symbol_map, MD_MapCollisionRule_Chain, string, sublist_store); + Value *v_store = malloc(sizeof(*v_store)); + *v_store = v; + MD_StringMap_Insert(&ns->symbol_map, MD_MapCollisionRule_Overwrite, string, v_store); } -static NodeSubList -NodeSubListFromNamespaceAndString(NamespaceNode *ns, MD_String8 string) +static Value +ValueFromString(NamespaceNode *ns, MD_String8 string) { - NodeSubList sublist = {MD_NilNode(), MD_NilNode()}; + Value v = {0}; for(NamespaceNode *n = ns; n; n = n->parent) { MD_MapSlot *slot = MD_StringMap_Lookup(&n->symbol_map, string); if(slot && slot->value) { - sublist = *(NodeSubList *)slot->value; + v = *(Value *)slot->value; break; } } - return sublist; + return v; } -static MD_f64 EvaluateScope(NamespaceNode *ns, MD_Node *code); -static MD_f64 EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr); +static Value EvaluateScope(NamespaceNode *ns, MD_Node *code); +static Value EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr); -static MD_f64 +static Value EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr) { - MD_f64 result = 0; + Value result = {0}; switch(expr->kind) { -#define BinaryOp(name, op) case MD_C_ExprKind_##name: { result = EvaluateExpr(ns, expr->sub[0]) op EvaluateExpr(ns, expr->sub[1]); }break + +#define BinaryOp(name, op) \ +case MD_C_ExprKind_##name:\ +{\ +Value left = EvaluateExpr(ns, expr->sub[0]);\ +Value right = EvaluateExpr(ns, expr->sub[1]);\ +result = MakeValue_Number(left.number op right.number);\ +}break + BinaryOp(Add, +); BinaryOp(Subtract, -); BinaryOp(Multiply, *); BinaryOp(Divide, /); + #undef BinaryOp case MD_C_ExprKind_Call: { MD_Node *call = expr->node; - NodeSubList callee = NodeSubListFromNamespaceAndString(ns, expr->sub[0]->node->string); - if(!MD_NodeIsNil(callee.first) && !MD_NodeIsNil(callee.last)) + Value callee = ValueFromString(ns, expr->sub[0]->node->string); + if(!MD_NodeIsNil(callee.node)) { //- rjf: find top-level namespace NamespaceNode *top_level_ns = ns; @@ -79,16 +108,17 @@ EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr) //- rjf: build namespace for function NamespaceNode args_ns = {0}; - MD_Node *param = callee.first->first_child; + MD_Node *param = callee.node->first_child; for(MD_Node *arg_first = call->first_child; !MD_NodeIsNil(arg_first); param = param->next) { MD_Node *arg_last = MD_SeekNodeWithFlags(arg_first, MD_NodeFlag_AfterComma|MD_NodeFlag_AfterSemicolon); - InsertNodeSubListToNamespace(&args_ns, param->string, MakeNodeSubList(arg_first, arg_last)); + MD_C_Expr *expr = MD_C_ParseAsExpr(arg_first, arg_last); + InsertValueToNamespace(&args_ns, param->string, EvaluateExpr(ns, expr)); arg_first = arg_last->next; } - args_ns.parent = ns; - result = EvaluateScope(&args_ns, callee.first->next); + args_ns.parent = top_level_ns; + result = EvaluateScope(&args_ns, callee.node->next); } }break; @@ -96,13 +126,11 @@ EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr) { if(expr->node->flags & MD_NodeFlag_Identifier) { - NodeSubList decl_value = NodeSubListFromNamespaceAndString(ns, expr->node->string); - MD_C_Expr *decl_expr = MD_C_ParseAsExpr(decl_value.first, decl_value.last); - result = EvaluateExpr(ns, decl_expr); + result = ValueFromString(ns, expr->node->string); } else if(expr->node->flags & MD_NodeFlag_Numeric) { - result = MD_F64FromString(expr->node->string); + result = MakeValue_Number(MD_F64FromString(expr->node->string)); } }break; @@ -111,10 +139,10 @@ EvaluateExpr(NamespaceNode *ns, MD_C_Expr *expr) return result; } -static MD_f64 +static Value EvaluateScope(NamespaceNode *ns, MD_Node *code) { - MD_f64 result = 0; + Value result = {0}; NamespaceNode local_namespace = {0}; local_namespace.parent = ns; @@ -126,8 +154,8 @@ EvaluateScope(NamespaceNode *ns, MD_Node *code) //- rjf: declaration if(first == last && first->string.size != 0 && !MD_NodeIsNil(first->first_child)) { - InsertNodeSubListToNamespace(&local_namespace, first->string, - MakeNodeSubList(first->first_child, first->last_child)); + MD_C_Expr *expr = MD_C_ParseAsExpr(first->first_child, first->last_child); + InsertValueToNamespace(&local_namespace, first->string, EvaluateExpr(&local_namespace, expr)); } //- rjf: expr else @@ -166,18 +194,17 @@ int main(int argument_count, char **arguments) { for(MD_EachNode(top_level, file->first_child)) { - if(top_level->string.size > 0) + if(MD_NodeHasTag(top_level, MD_S8Lit("proc"))) { - InsertNodeSubListToNamespace(&global_ns_node, top_level->string, - MakeNodeSubList(top_level, top_level)); + InsertValueToNamespace(&global_ns_node, top_level->string, MakeValue_Procedure(top_level)); } } } //- rjf: find `main` procedure - NodeSubList main_proc = NodeSubListFromNamespaceAndString(&global_ns_node, MD_S8Lit("main")); - MD_Node *main_code = main_proc.first->next; - if(MD_NodeIsNil(main_proc.first)) + Value main_proc = ValueFromString(&global_ns_node, MD_S8Lit("main")); + MD_Node *main_code = main_proc.node->next; + if(MD_NodeIsNil(main_proc.node)) { fprintf(stderr, "no `main` procedure found"); goto end; @@ -191,8 +218,25 @@ int main(int argument_count, char **arguments) } //- rjf: start interpreting at `main` - MD_f64 result = EvaluateScope(&global_ns_node, main_code); - printf("result: %f\n", result); + Value result = EvaluateScope(&global_ns_node, main_code); + switch(result.kind) + { + default: + case ValueKind_Null: + { + printf("[null]\n"); + }break; + + case ValueKind_Number: + { + printf("[number] %f\n", result.number); + }break; + + case ValueKind_Procedure: + { + printf("[proc] %.*s\n", MD_StringExpand(result.node->string)); + }break; + } end:; return 0;