]> git.bts.cx Git - sun.git/commitdiff
Initial commit
authorBen Sherratt <redacted>
Sat, 13 Feb 2021 10:41:36 +0000 (10:41 +0000)
committerBen Sherratt <redacted>
Fri, 8 Dec 2023 12:58:49 +0000 (12:58 +0000)
33 files changed:
CMakeLists.txt [new file with mode: 0644]
aot/c_generator.c [new file with mode: 0644]
aot/c_generator.h [new file with mode: 0644]
runtime/CMakeLists.txt [new file with mode: 0644]
runtime/src/sun/compiler/compiler.c [new file with mode: 0644]
runtime/src/sun/compiler/compiler.h [new file with mode: 0644]
runtime/src/sun/compiler/compiler_internal.h [new file with mode: 0644]
runtime/src/sun/compiler/sun.l [new file with mode: 0644]
runtime/src/sun/compiler/sun.y [new file with mode: 0644]
runtime/src/sun/compiler/vm_generator.c [new file with mode: 0644]
runtime/src/sun/compiler/vm_generator.h [new file with mode: 0644]
runtime/src/sun/tree/crc32.h [new file with mode: 0644]
runtime/src/sun/tree/data_type.c [new file with mode: 0644]
runtime/src/sun/tree/data_type.h [new file with mode: 0644]
runtime/src/sun/tree/node.c [new file with mode: 0644]
runtime/src/sun/tree/node.h [new file with mode: 0644]
runtime/src/sun/tree/node_internal.h [new file with mode: 0644]
runtime/src/sun/tree/node_type.c [new file with mode: 0644]
runtime/src/sun/tree/node_type.h [new file with mode: 0644]
runtime/src/sun/tree/operator_type.c [new file with mode: 0644]
runtime/src/sun/tree/operator_type.h [new file with mode: 0644]
runtime/src/sun/tree/tree.c [new file with mode: 0644]
runtime/src/sun/tree/tree.h [new file with mode: 0644]
runtime/src/sun/vm/fixed.c [new file with mode: 0644]
runtime/src/sun/vm/fixed.h [new file with mode: 0644]
runtime/src/sun/vm/instruction.c [new file with mode: 0644]
runtime/src/sun/vm/instruction.h [new file with mode: 0644]
runtime/src/sun/vm/vm.c [new file with mode: 0644]
runtime/src/sun/vm/vm.h [new file with mode: 0644]
runtime/src/sun/vm/vm_internal.h [new file with mode: 0644]
tests/CMakeLists.txt [new file with mode: 0644]
tests/main.c [new file with mode: 0644]
tests/test_1.sun [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6890ab6
--- /dev/null
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(sun C)
+
+add_subdirectory(core)
+add_subdirectory(compiler)
+add_subdirectory(vm)
+
+#add_subdirectory(tests)
diff --git a/aot/c_generator.c b/aot/c_generator.c
new file mode 100644 (file)
index 0000000..4458fbe
--- /dev/null
@@ -0,0 +1,321 @@
+#include "c_generator.h"
+
+#include "node_internal.h"
+#include "node_type.h"
+
+#include <stdbool.h>
+
+static int c_generator_output_node(FILE *output_file, Node *node);
+static int c_generator_output_sequence_node(FILE *output_file, Node *node, const char *separator);
+static bool c_generator_is_prefix_unary_operator(OperatorType operator_type);
+static char *c_generator_operator_string(OperatorType operator_type);
+
+int c_generator_generate_module(FILE *output_file, Node *module) {
+       return c_generator_output_node(output_file, module);
+}
+
+static int c_generator_output_node(FILE *output_file, Node *node) {
+       if (node != NULL) {
+               switch (node->type) {
+                       case NodeTypeUnknown:
+                               return -1;
+
+                       case NodeTypeIdentifier:
+                               fprintf(output_file, "%s", node->string_value);
+                               break;
+
+                       case NodeTypeInteger:
+                               fprintf(output_file, "%d", node->integer_value);
+                               break;
+                               
+                       case NodeTypeFloat:
+                               fprintf(output_file, "%f", node->float_value);
+                               break;
+
+                       case NodeTypeString:
+                               fprintf(output_file, "%s", node->string_value); // NB: Quotes are left in by lexer
+                               break;
+
+                       case NodeTypeCompound:
+                               fprintf(output_file, "(");
+                               c_generator_output_node(output_file, node->compound_subexpression);
+                               fprintf(output_file, ")");
+                               break;
+
+                       case NodeTypeArgument:
+                               c_generator_output_node(output_file, node->argument_expression);
+                               break;
+
+                       case NodeTypeArrayAccess:
+                               c_generator_output_node(output_file, node->array_access_array);
+                               fprintf(output_file, "[");
+                               c_generator_output_node(output_file, node->array_access_access);
+                               fprintf(output_file, "]");
+                               break;
+
+                       case NodeTypeTypeAccess:
+                               c_generator_output_node(output_file, node->type_access_type);
+                               fprintf(output_file, ".");
+                               c_generator_output_node(output_file, node->type_access_access);
+                               break;
+                       
+                       case NodeTypeFunctionCall:
+                               c_generator_output_node(output_file, node->function_call_function);
+                               fprintf(output_file, "(");
+                               c_generator_output_sequence_node(output_file, node->function_call_parameters, ",");
+                               fprintf(output_file, ")");
+                               break;
+
+
+                       case NodeTypeUnaryOperation:
+                               if (c_generator_is_prefix_unary_operator(node->unary_operation_operator->operator_type)) {
+                                       c_generator_output_node(output_file, node->unary_operation_operator);
+                                       c_generator_output_node(output_file, node->unary_operation_operand);
+                               } else {
+                                       c_generator_output_node(output_file, node->unary_operation_operand);
+                                       c_generator_output_node(output_file, node->unary_operation_operator);
+                               }
+                               break;
+
+                       case NodeTypeBinaryOperation:
+                               c_generator_output_node(output_file, node->binary_operation_lhs);
+                               c_generator_output_node(output_file, node->binary_operation_operator);
+                               c_generator_output_node(output_file, node->binary_operation_rhs);
+                               break;
+
+                       case NodeTypeOperator:
+                               fprintf(output_file, "%s", c_generator_operator_string(node->operator_type));
+                               break;
+
+                       case NodeTypeAssignment:
+                               c_generator_output_node(output_file, node->assignment_target);
+                               fprintf(output_file, "=");
+                               c_generator_output_node(output_file, node->assignment_source);
+                               break;
+
+                       case NodeTypeForIteration:
+                               fprintf(output_file, "for (");
+                               c_generator_output_node(output_file, node->iteration_initial_expression);
+                               fprintf(output_file, ";");
+                               c_generator_output_node(output_file, node->iteration_pre_valid_expression);
+                               fprintf(output_file, ";");
+                               c_generator_output_node(output_file, node->iteration_loop_expression);
+                               fprintf(output_file, ") ");
+                               c_generator_output_node(output_file, node->iteration_statement);
+                               break;
+
+                       case NodeTypeDoIteration:
+                               fprintf(output_file, "do ");
+                               c_generator_output_node(output_file, node->iteration_statement);
+                               fprintf(output_file, " while (");
+                               c_generator_output_node(output_file, node->iteration_post_valid_expression);
+                               fprintf(output_file, ")");
+                               break;
+
+                       case NodeTypeWhileIteration:
+                               fprintf(output_file, "while (");
+                               c_generator_output_node(output_file, node->iteration_pre_valid_expression);
+                               fprintf(output_file, ") ");
+                               c_generator_output_node(output_file, node->iteration_statement);
+                               break;
+
+                       case NodeTypeSelection:
+                               fprintf(output_file, "if (");
+                               c_generator_output_node(output_file, node->selection_valid_expression);
+                               fprintf(output_file, ") ");
+                               c_generator_output_node(output_file, node->selection_valid_statement);
+                               if (node->selection_invalid_statement != NULL) {
+                                       fprintf(output_file, " else ");
+                                       c_generator_output_node(output_file, node->selection_invalid_statement);
+                               }
+                               break;
+
+                       case NodeTypeStatement:
+                               c_generator_output_node(output_file, node->statement_contents);
+                               fprintf(output_file, ";\n");
+                               break;
+
+                       case NodeTypeVariableDefinition:
+                               c_generator_output_node(output_file, node->variable_definition_type);
+                               fprintf(output_file, " ");
+                               c_generator_output_node(output_file, node->variable_definition_identifier);
+                               if (node->variable_definition_default_expression) {
+                                       fprintf(output_file, "=");
+                                       c_generator_output_node(output_file, node->variable_definition_default_expression);
+                               }
+                               break;
+
+                       case NodeTypeTypeDefinition:
+                               fprintf(output_file, "typedef struct ");
+                               c_generator_output_node(output_file, node->type_definition_identifier);
+                               fprintf(output_file, " {\n");
+                               c_generator_output_sequence_node(output_file, node->type_definition_members, NULL);
+                               fprintf(output_file, "} ");
+                               c_generator_output_node(output_file, node->type_definition_identifier);
+                               fprintf(output_file, ";\n");
+                               break;
+
+                       case NodeTypeTypeMemberDefinition:
+                               c_generator_output_node(output_file, node->type_member_definition_type);
+                               fprintf(output_file, " ");
+                               c_generator_output_node(output_file, node->type_member_definition_identifier);
+                               fprintf(output_file, ";\n");
+                               break;
+
+                       case NodeTypeFunctionDefinition:
+                               c_generator_output_node(output_file, node->function_definition_type);
+                               fprintf(output_file, " ");
+                               c_generator_output_node(output_file, node->function_definition_identifier);
+                               fprintf(output_file, "(");
+                               c_generator_output_sequence_node(output_file, node->function_definition_parameters, ",");
+                               fprintf(output_file, ")");
+                               c_generator_output_node(output_file, node->function_definition_body);
+                               break;
+
+                       case NodeTypeFunctionParameterDefinition:
+                               c_generator_output_node(output_file, node->function_parameter_definition_type);
+                               fprintf(output_file, " ");
+                               c_generator_output_node(output_file, node->function_parameter_definition_identifier);
+                               break;
+
+                       case NodeTypeModule:
+                               c_generator_output_sequence_node(output_file, node->module_definitions, NULL);
+                               break;
+
+                       case NodeTypeSequence:
+                               fprintf(output_file, "{\n");
+                               c_generator_output_sequence_node(output_file, node, NULL);
+                               fprintf(output_file, "}");
+                               break;
+               }
+       }
+
+       return 0;
+}
+
+static int c_generator_output_sequence_node(FILE *output_file, Node *node, const char *separator) {
+       if (node != NULL) {
+               if (node->type != NodeTypeSequence) {
+                       c_generator_output_node(output_file, node);
+               } else {
+                       while (node != NULL) {
+                               c_generator_output_node(output_file, node->sequence_node);
+                               if (separator != NULL && node->sequence_next != NULL) fprintf(output_file, "%s", separator);
+                               node = node->sequence_next;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static bool c_generator_is_prefix_unary_operator(OperatorType operator_type) {
+       switch (operator_type) {
+               case OperatorTypeUnknown:
+                       // FIXME, should never reach here
+
+               case OperatorTypeAdd:
+               case OperatorTypeSubtract:
+               case OperatorTypeMultiply:
+               case OperatorTypeDivide:
+               case OperatorTypeModulo:
+               case OperatorTypePositive:
+               case OperatorTypeNegative:
+               case OperatorTypeBitwiseAnd:
+               case OperatorTypeBitwiseOr:
+               case OperatorTypeBitwiseXor:
+               case OperatorTypeBitwiseNot:
+               case OperatorTypeLogicalAnd:
+               case OperatorTypeLogicalOr:
+               case OperatorTypeLogicalNot:
+               case OperatorTypeEqual:
+               case OperatorTypeNotEqual:
+               case OperatorTypeLessThan:
+               case OperatorTypeLessThanEqual:
+               case OperatorTypeGreaterThan:
+               case OperatorTypeGreaterThanEqual:
+               case OperatorTypePreIncrement:
+               case OperatorTypePreDecrement:
+                       return true;
+
+               case OperatorTypePostIncrement:
+               case OperatorTypePostDecrement:
+                       return false;
+       }
+}
+
+char *c_generator_operator_string(OperatorType operator_type) {
+       switch (operator_type) {
+               default:
+               case OperatorTypeUnknown:
+                       return "<unknown>"; // FIXME, should never reach here
+
+               case OperatorTypeAdd:
+                       return "+";
+
+               case OperatorTypeSubtract:
+                       return "-";
+
+               case OperatorTypeMultiply:
+                       return "*";
+
+               case OperatorTypeDivide:
+                       return "/";
+
+               case OperatorTypeModulo:
+                       return "%";
+
+               case OperatorTypePositive:
+                       return "+";
+
+               case OperatorTypeNegative:
+                       return "-";
+
+               case OperatorTypeBitwiseAnd:
+                       return "&";
+
+               case OperatorTypeBitwiseOr:
+                       return "|";
+
+               case OperatorTypeBitwiseXor:
+                       return "^";
+
+               case OperatorTypeBitwiseNot:
+                       return "~";
+
+               case OperatorTypeLogicalAnd:
+                       return "&&";
+
+               case OperatorTypeLogicalOr:
+                       return "||";
+
+               case OperatorTypeLogicalNot:
+                       return "!";
+
+               case OperatorTypeEqual:
+                       return "==";
+
+               case OperatorTypeNotEqual:
+                       return "!=";
+
+               case OperatorTypeLessThan:
+                       return "<";
+
+               case OperatorTypeLessThanEqual:
+                       return "<=";
+
+               case OperatorTypeGreaterThan:
+                       return ">";
+
+               case OperatorTypeGreaterThanEqual:
+                       return ">=";
+
+               case OperatorTypePreIncrement:
+               case OperatorTypePostIncrement:
+                       return "++";
+
+               case OperatorTypePreDecrement:
+               case OperatorTypePostDecrement:
+                       return "--";
+       }
+}
diff --git a/aot/c_generator.h b/aot/c_generator.h
new file mode 100644 (file)
index 0000000..c970c1b
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef C_GENERATOR_H
+#define C_GENERATOR_H
+
+#include "node.h"
+#include <stdio.h>
+
+extern int c_generator_generate_module(FILE *output_file, Node *module);
+
+#endif
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt
new file mode 100644 (file)
index 0000000..26c416c
--- /dev/null
@@ -0,0 +1,48 @@
+cmake_minimum_required(VERSION 3.10)
+
+find_package(BISON)
+find_package(FLEX)
+
+project(sun C)
+
+BISON_TARGET(SunParser ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/compiler/sun.y ${CMAKE_CURRENT_BINARY_DIR}/sun_parser.c COMPILE_FLAGS -v)
+FLEX_TARGET(SunScanner ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/compiler/sun.l  ${CMAKE_CURRENT_BINARY_DIR}/sun_lexer.c COMPILE_FLAGS --header-file=${CMAKE_CURRENT_BINARY_DIR}/sun_lexer.h)
+ADD_FLEX_BISON_DEPENDENCY(SunScanner SunParser)
+
+set(SUN_SOURCES
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/compiler/compiler.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/compiler/compiler_internal.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/compiler/compiler.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/compiler/vm_generator.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/compiler/vm_generator.c
+
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/crc32.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/data_type.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/data_type.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/node.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/node.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/node_type.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/node_type.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/operator_type.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/operator_type.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/tree.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/tree/tree.c
+
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/vm/fixed.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/vm/fixed.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/vm/instruction.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/vm/instruction.c
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/vm/vm.h
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/sun/vm/vm.c
+
+       ${BISON_SunParser_OUTPUTS}
+       ${FLEX_SunScanner_OUTPUTS}
+)
+
+add_library(sun ${SUN_SOURCES})
+
+#add_executable(suncc ${SUNCC_SOURCES})
+target_include_directories(sun PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) # So the Flex/Bison code can find header
+target_include_directories(sun PRIVATE ${CMAKE_CURRENT_BINARY_DIR})     # So our code can find Flex/Bison code
+#target_link_libraries(sun suncore)
+#target_link_libraries(suncc ${FLEX_LIBRARIES})
diff --git a/runtime/src/sun/compiler/compiler.c b/runtime/src/sun/compiler/compiler.c
new file mode 100644 (file)
index 0000000..4ce214f
--- /dev/null
@@ -0,0 +1,44 @@
+#include <sun/compiler/compiler_internal.h>
+
+#include <stdio.h>
+
+#include "sun_parser.h" // This needs to be first.
+#include "sun_lexer.h"
+
+#include <sun/compiler/vm_generator.h>
+#include <sun/tree/node.h>
+#include <sun/tree/tree.h>
+#include <sun/vm/vm.h>
+
+extern int yyparse(SLTNode **moduleOut, yyscan_t *scanner);
+
+SVMModule *slcCompileSource(const SLCCompileConfiguration *configuration) {
+       yyscan_t sc;
+       int res;
+       SLCLexerExtra extra;
+
+       extra.readCallback = configuration->sourceReadCallback;
+       extra.readCallbackParameter = configuration->sourceUserParam;
+
+       yylex_init_extra(&extra, &sc);
+       SLTNode *module = NULL;
+       int parse_return = yyparse(&module, sc);
+       yylex_destroy(sc);
+
+       switch (parse_return) {
+               case 0:
+                       return slcGenerateVMInstructions(module);
+
+               case 1:
+                       printf("Error\n");
+                       return NULL;
+
+               case 2:
+                       printf("Out of memory\n");
+                       return NULL;
+
+               default:
+                       printf("Unknown error...\n");
+                       return NULL;
+       }
+}
diff --git a/runtime/src/sun/compiler/compiler.h b/runtime/src/sun/compiler/compiler.h
new file mode 100644 (file)
index 0000000..408e198
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SUN_COMPILER_COMPILER_H
+#define SUN_COMPILER_COMPILER_H
+
+#include <sun/vm/vm.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*SLCMallocCallback)(void *memory, size_t size);
+typedef void (*SLCFreeCallback)(void *memory);
+
+typedef size_t (*SLCSourceReadCallback)(char *out, size_t outSize, void *userParam);
+
+struct SLCCompileConfiguration {
+       SLCMallocCallback realloc;
+       SLCFreeCallback free;
+
+       SLCSourceReadCallback sourceReadCallback;
+       void *sourceUserParam;
+};
+typedef struct SLCCompileConfiguration SLCCompileConfiguration;
+
+extern SVMModule *slcCompileSource(const SLCCompileConfiguration *configuration);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/compiler/compiler_internal.h b/runtime/src/sun/compiler/compiler_internal.h
new file mode 100644 (file)
index 0000000..07036d1
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SUN_COMPILER_COMPILER_INTERNAL_H
+#define SUN_COMPILER_COMPILER_INTERNAL_H
+
+#include <sun/compiler/compiler.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SLCLexerExtra {
+       SLCSourceReadCallback readCallback;
+       void *readCallbackParameter;
+};
+typedef struct SLCLexerExtra SLCLexerExtra;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/compiler/sun.l b/runtime/src/sun/compiler/sun.l
new file mode 100644 (file)
index 0000000..c519809
--- /dev/null
@@ -0,0 +1,100 @@
+%{
+       #define YYSTYPE SLTNode *
+       #define YY_USER_ACTION yyadvancelocation(yylloc, yyleng, yytext);
+
+       #include <sun/compiler/compiler_internal.h>
+       #include <sun/tree/node.h>
+       #include "sun_parser.h"
+
+       #include <stdbool.h>
+       #include <stdio.h>
+
+       static void yyadvancelocation(YYLTYPE *location, long length, const char *text);
+
+       #define YY_INPUT(buf, result, max_size) result = yyextra->readCallback(buf, max_size,  yyextra->readCallbackParameter);
+       
+       //#define YY_DECL int yylex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner, SunSourceReadCallback readCallback)
+%}
+
+%option bison-bridge
+%option bison-locations
+%option never-interactive
+%option noyywrap
+%option nounput
+%option noinput
+%option reentrant
+%option extra-type="SLCLexerExtra *"
+
+%x SL_COMMENT
+%x ML_COMMENT
+
+%%
+
+"//"              { BEGIN(SL_COMMENT); }
+<SL_COMMENT>\n    { BEGIN(INITIAL); }
+<SL_COMMENT>.     ; /* Eat comments */
+
+"/*"              { BEGIN(ML_COMMENT); }
+<ML_COMMENT>"*/"  { BEGIN(INITIAL); }
+<ML_COMMENT>\n    ; /* Eat comments */
+<ML_COMMENT>.     ; /* Eat comments */
+
+[ \t\n]           ; /* Eat whitespace */
+
+"if"              { return IF; }
+"else"            { return ELSE; }
+"for"             { return FOR; }
+"do"              { return DO; }
+"while"           { return WHILE; }
+"break"           { return BREAK; }
+"struct"          { return TYPE; }
+
+"return"          { return RETURN; }
+"sleep"           { return SLEEP; }
+
+"false"           { *yylval = sltNodeMakeBoolean(false); return BOOL_FALSE; }
+"true"            { *yylval = sltNodeMakeBoolean(true); return BOOL_TRUE; }
+
+"+="              { return ADD_ASSIGN; }
+"-="              { return SUBTRACT_ASSIGN; }
+"*="              { return MULTIPLY_ASSIGN; }
+"/="              { return DIVIDE_ASSIGN; }
+"%="              { return MOD_ASSIGN; }
+
+"&&"              { return LOGICAL_AND; }
+"||"              { return LOGICAL_OR; }
+
+"=="              { return EQUAL; }
+"!="              { return NOT_EQUAL; }
+"<="              { return LT_EQUAL; }
+">="              { return GT_EQUAL; }
+
+       /*"++"              { return INCREMENT; }
+       "--"              { return DECREMENT; }*/
+
+[0-9]+\.[0-9]+    { *yylval = sltNodeMakeFloat(atof(yytext)); return FLOAT; }
+[0-9]+            { *yylval = sltNodeMakeInteger(atoi(yytext)); return INT; }
+i[0-9]+           { *yylval = sltNodeMakeRawInteger(atoi(&yytext[1])); return INT; }
+
+@\"[^\"\n]*\"     { *yylval = sltNodeMakeKey(yytext); return STRING; }
+\"[^\"\n]*\"      { *yylval = sltNodeMakeString(yytext); return STRING; }
+
+[a-zA-Z0-9_]+     { *yylval = sltNodeMakeIdentifier(yytext); return IDENTIFIER; }
+
+.                 { return yytext[0]; }
+
+%%
+
+static void yyadvancelocation(YYLTYPE *location, long length, const char *text) {
+       location->first_column = location->last_column;
+       location->first_line = location->last_line;
+
+       for (long i = 0; i < length; ++i) {
+               if (text[i] == '\n') {
+                       ++location->last_line;
+                       location->last_column = 0;
+               } else {
+                       ++location->last_column;
+               }
+       }
+}
diff --git a/runtime/src/sun/compiler/sun.y b/runtime/src/sun/compiler/sun.y
new file mode 100644 (file)
index 0000000..b71f4de
--- /dev/null
@@ -0,0 +1,465 @@
+%{
+       #define YYSTYPE SLTNode *
+
+       #include <sun/compiler/compiler_internal.h>
+       #include <sun/tree/node.h>
+
+       #include "sun_parser.h"
+       #include "sun_lexer.h"
+
+       void yyerror(const YYLTYPE *location, SLTNode **moduleOut, yyscan_t *scanner, const char *error);
+%}
+
+%pure-parser
+
+%parse-param {SLTNode **moduleOut}
+%parse-param {yyscan_t *scanner}
+
+%lex-param {yyscan_t *scanner}
+
+%error-verbose
+%locations
+
+%token IF "if"
+%token ELSE "else"
+%token FOR "for"
+%token DO "do"
+%token WHILE "while"
+%token BREAK "break"
+%token TYPE "struct"
+
+%token RETURN "return"
+%token SLEEP "sleep"
+
+%token BOOL_FALSE "false"
+%token BOOL_TRUE "true"
+
+%token ADD_ASSIGN "+="
+%token SUBTRACT_ASSIGN "-="
+%token MULTIPLY_ASSIGN "*="
+%token DIVIDE_ASSIGN "/="
+%token MOD_ASSIGN "%="
+
+%token LOGICAL_AND "&&"
+%token LOGICAL_OR "||"
+
+%token EQUAL "=="
+%token NOT_EQUAL "!="
+%token LT_EQUAL "<="
+%token GT_EQUAL ">="
+
+       /*%token INCREMENT "++"
+       %token DECREMENT "--"*/
+
+%token IDENTIFIER
+
+%token INT
+%token FLOAT
+%token STRING
+
+       /* https://en.cppreference.com/w/c/language/operator_precedence */
+%left ','
+%right '=' "+=" "-=" "*=" "/=" "%=" /* etc... */
+%left "||"
+%left "&&"
+%left '|'
+%left '^'
+%left '&'
+%left "==" "!="
+%left '<' "<=" '>' ">="
+       /* %left "<<" ">>" */
+%left '+' '-'
+%left '*' '/' '%'
+%right U_PLUS U_MINUS '!' '~'
+       /* %right "++" "--" "" */
+       /* %left "++" "--" "" */
+
+%start module
+
+%%
+
+module
+       : optional_statements_or_definitions {
+               $$ = sltNodeMakeModule($1);
+               *moduleOut = $$;
+       }
+       ;
+
+optional_statements_or_definitions
+       : /* Nothing */ {
+               $$ = NULL;
+       }
+       | statements_or_definitions
+       ;
+
+statements_or_definitions
+       : definition {
+               $$ = sltNodeMakeSequence(NULL, $1);
+       }
+       | statement {
+               $$ = sltNodeMakeSequence(NULL, $1);
+       }
+       | statements_or_definitions definition {
+               $$ = sltNodeMakeSequence($1, $2);
+       }
+       | statements_or_definitions statement {
+               $$ = sltNodeMakeSequence($1, $2);
+       }
+       ;
+
+definition
+       : function_definition
+       /*| type_definition*/
+       | variable_definition ';'
+       ;
+
+function_definition
+       : IDENTIFIER IDENTIFIER '(' optional_parameter_definitions ')' '{' optional_statements '}' {
+               $$ = sltNodeMakeFunctionDefinition($1, $2, $4, $7);
+       }
+       ;
+
+optional_parameter_definitions
+       : /* Nothing */ {
+               $$ = NULL;
+       }
+       | parameter_definitions
+       ;
+
+parameter_definitions
+       : parameter_definition {
+               $$ = sltNodeMakeSequence(NULL, $1);
+       }
+       | parameter_definitions ',' parameter_definition {
+               $$ = sltNodeMakeSequence($1, $3);
+       }
+       ;
+
+parameter_definition
+       : IDENTIFIER IDENTIFIER {
+               $$ = sltNodeMakeFunctionParameterDefinition($1, $2);
+       }
+       ;
+
+/*type_definition
+       : "struct" IDENTIFIER '{' type_member_definitions '}' {
+               $$ = sltNodeMakeTypeDefinition($2, $4);
+       }
+       ;
+
+type_member_definitions
+       : type_member_definition ';' {
+               $$ = sltNodeMakeSequence(NULL, $1);
+       }
+       | type_member_definitions type_member_definition ';' {
+               $$ = sltNodeMakeSequence($1, $2);
+       }
+       ;
+
+type_member_definition
+       : IDENTIFIER IDENTIFIER {
+               $$ = sltNodeMakeTypeMemberDefinition($1, $2);
+       }
+       ;*/
+
+variable_definition
+       : IDENTIFIER IDENTIFIER {
+               $$ = sltNodeMakeVariableDefinition($1, $2, NULL);
+       }
+       | IDENTIFIER IDENTIFIER '=' expression {
+               $$ = sltNodeMakeVariableDefinition($1, $2, $4);
+       }
+       ;
+
+optional_statements
+       : /* nothing */ {
+               $$ = NULL;
+       }
+       | statements
+       ;
+
+statements
+       : statement {
+               if ($1 != NULL) {
+                       $$ = sltNodeMakeSequence(NULL, $1);
+               }
+               
+       }
+       | statements statement {
+               if ($2 != NULL) {
+                       $$ = sltNodeMakeSequence($1, $2);
+               } else {
+                       $$ = $1;
+               }
+       }
+       ;
+
+statement
+       : ';' {
+               $$ = NULL; /* Otherwise this will pass up the ';' character */
+       }
+       | variable_definition ';'
+       | "return" optional_expression ';' {
+               $$ = sltNodeMakeReturn($2);
+       }
+       | "sleep" ';' {
+               $$ = sltNodeMakeSleep();
+       }
+       | selection_statement
+       | iteration_statement
+       | "break" ';' {
+               $$ = sltNodeMakeBreak();
+       }
+       | expression ';'
+       | '{' optional_statements '}' {
+               if ($2 != NULL) {
+                       $$ = sltNodeMakeStatementBlock($2);
+               } else {
+                       $$ = NULL;
+               }
+       }
+       ;
+
+selection_statement
+       : "if" '(' expression ')' statement {
+               $$ = sltNodeMakeSelection($3, $5, NULL);
+       }
+       | "if" '(' expression ')' statement "else" statement {
+               $$ = sltNodeMakeSelection($3, $5, $7);
+       }
+       ;
+
+iteration_statement
+       : "for" '(' optional_expression_or_variable_definition ';' optional_expression ';' optional_expression ')' statement {
+               $$ = sltNodeMakeForIteration($3, $5, $7, $9);
+       }
+       | "while" '(' expression ')' statement {
+               $$ = sltNodeMakeWhileIteration($3, $5);
+       }
+       | "do" statement "while" '(' expression ')' ';' {
+               $$ = sltNodeMakeDoIteration($5, $2);
+       }
+       ;
+
+optional_expression_or_variable_definition
+       : /* nothing */ {
+               $$ = NULL;
+       }
+       | expression
+       | variable_definition
+       ;
+
+optional_expression
+       : /* nothing */ {
+               $$ = NULL;
+       }
+       | expression
+       ;
+
+expression
+       : assignment_expression
+       ;
+
+assignment_expression
+       : logic_expression
+       | unary_expression assignment_operator assignment_expression {
+               $$ = sltNodeMakeAssignment($1, ($2 == NULL) ? $3 : sltNodeMakeBinaryOperation($2, $1, $3));
+       }
+       ;
+
+assignment_operator
+       : '=' {
+               $$ = NULL;
+       }
+       | "+=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeAdd);
+       }
+       | "-=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeSubtract);
+       }
+       | "*=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeMultiply);
+       }
+       | "/=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeDivide);
+       }
+       | "%=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeModulo);
+       }
+       ;
+
+logic_expression
+       : bit_logic_expression
+       | logic_expression logic_operator bit_logic_expression {
+               $$ = sltNodeMakeBinaryOperation($2, $1, $3);
+       }
+       ;
+
+logic_operator
+       : "&&" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeLogicalAnd);
+       }
+       | "||" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeLogicalOr);
+       }
+       ;
+
+bit_logic_expression
+       : equality_expression
+       | bit_logic_expression bit_logic_operator equality_expression {
+               $$ = sltNodeMakeBinaryOperation($2, $1, $3);
+       }
+       ;
+
+bit_logic_operator
+       : '&' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeBitwiseAnd);
+       }
+       | '|' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeBitwiseOr);
+       }
+       | '^' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeBitwiseXor);
+       }
+       ;
+
+equality_expression
+       : arithmetic_expression
+       | equality_expression equality_operator arithmetic_expression {
+               $$ = sltNodeMakeBinaryOperation($2, $1, $3);
+       }
+       ;
+
+equality_operator
+       : "==" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeEqual);
+       }
+       | "!=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeNotEqual);
+       }
+       | "<=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeLessThanEqual);
+       }
+       | ">=" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeGreaterThanEqual);
+       }
+       | '<' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeLessThan);
+       }
+       | '>' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeGreaterThan);
+       }
+       ;
+
+arithmetic_expression
+       : unary_expression
+       | arithmetic_expression '+' arithmetic_expression {
+               $$ = sltNodeMakeBinaryOperation(sltNodeMakeOperator(SLTOperatorTypeAdd), $1, $3);
+       }
+       | arithmetic_expression '-' arithmetic_expression {
+               $$ = sltNodeMakeBinaryOperation(sltNodeMakeOperator(SLTOperatorTypeSubtract), $1, $3);
+       }
+       | arithmetic_expression '*' arithmetic_expression {
+               $$ = sltNodeMakeBinaryOperation(sltNodeMakeOperator(SLTOperatorTypeMultiply), $1, $3);
+       }
+       | arithmetic_expression '/' arithmetic_expression {
+               $$ = sltNodeMakeBinaryOperation(sltNodeMakeOperator(SLTOperatorTypeDivide), $1, $3);
+       }
+       | arithmetic_expression '%' arithmetic_expression {
+               $$ = sltNodeMakeBinaryOperation(sltNodeMakeOperator(SLTOperatorTypeModulo), $1, $3);
+       }
+       ;
+
+unary_expression
+       : postfix_expression
+       | '-' %prec U_MINUS unary_expression {
+               $$ = sltNodeMakeUnaryOperation(sltNodeMakeOperator(SLTOperatorTypeNegative), $2);
+       }
+       | '~' unary_expression {
+               $$ = sltNodeMakeUnaryOperation(sltNodeMakeOperator(SLTOperatorTypeBitwiseNot), $2);
+       }
+       | '!' unary_expression {
+               $$ = sltNodeMakeUnaryOperation(sltNodeMakeOperator(SLTOperatorTypeLogicalNot), $2);
+       }
+       ;
+
+/*unary_operator
+       : "++" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypePreIncrement);
+       }
+       | "--" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypePreDecrement);
+       }
+       |'+' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypePositive);
+       } 
+       | '-' %prec U_MINUS {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeNegative);
+       }
+       | '~' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeBitwiseNot);
+       }
+       | '!' {
+               $$ = sltNodeMakeOperator(SLTOperatorTypeLogicalNot);
+       }
+       ;*/
+
+postfix_expression
+       : primary_expression
+       | postfix_expression '[' expression ']' {
+               $$ = sltNodeMakeArrayAccess($1, $3);
+       }
+       | postfix_expression '(' optional_arguments ')' {
+               $$ = sltNodeMakeFunctionCall($1, $3);
+       }
+       | postfix_expression '.' IDENTIFIER {
+               $$ = sltNodeMakeTypeAccess($1, $3);
+       }
+       /*| postfix_expression postfix_unary_operator {
+               $$ = sltNodeMakeUnaryOperation($1, $2);
+       }*/
+       ;
+
+/*postfix_unary_operator
+       : "++" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypePostIncrement);
+       }
+       | "--" {
+               $$ = sltNodeMakeOperator(SLTOperatorTypePostDecrement);
+       }
+       ;*/
+
+optional_arguments
+       : /* nothing */ {
+               $$ = NULL;
+       }
+       | arguments
+       ;
+
+arguments
+       : expression {
+               $$ = sltNodeMakeSequence(NULL, sltNodeMakeArgument($1));
+       }
+       | arguments ',' expression {
+               $$ = sltNodeMakeSequence($1, sltNodeMakeArgument($3));
+       }
+       ;
+
+primary_expression
+       : IDENTIFIER
+       | BOOL_FALSE
+       | BOOL_TRUE
+       | INT
+       | FLOAT
+       | STRING
+       | '(' expression ')' {
+               $$ = sltNodeMakeCompound($2);
+       }
+       ;
+
+%%
+
+void yyerror(const YYLTYPE *location, SLTNode **moduleOut, yyscan_t *scanner, const char *error) {
+//void yyerror(const YYLTYPE *location, yyscan_t scanner, const char *error) {
+       printf("[ERROR] Line #%u, Characters %u: %s\n", /*yyget_lineno(scanner)*/location->first_line, /*yyget_column(scanner)*/location->first_column, error);
+}
diff --git a/runtime/src/sun/compiler/vm_generator.c b/runtime/src/sun/compiler/vm_generator.c
new file mode 100644 (file)
index 0000000..deb10b8
--- /dev/null
@@ -0,0 +1,1117 @@
+#include "vm_generator.h"
+
+#include <sun/tree/node_internal.h>
+#include <sun/tree/node_type.h>
+#include <sun/tree/tree.h>
+#include <sun/vm/instruction.h>
+#include <sun/vm/vm_internal.h>
+
+
+#include <stdarg.h> //fixme
+#include <stdbool.h> //fixme
+#include <stdlib.h> //fixme
+#include <stdio.h> //fixme
+#include <string.h> //fixme
+
+#define generator_assert_msg(t,m,...) if(!(t)) { fprintf(stderr,"%s:%u ERROR:"m"\n",__FILE__,__LINE__, ##__VA_ARGS__); exit(1); }
+#define generator_assert(t) generator_assert_msg(t,"invalid")
+
+struct VMGeneratorInstruction {
+       SVMInstruction instruction;
+};
+
+struct VMGeneratorOutputScope {
+       char *stringClump;
+       size_t stringClumpSize;
+       size_t stringClumpMaxSize;
+
+       struct VMGeneratorInstruction *instructions;
+       size_t instructionCount;
+       SVMPointer nextInstructionIdx;
+
+       struct VMGeneratorInstruction *resolvableDefinition;
+};
+typedef struct VMGeneratorOutputScope VMGeneratorOutputScope;
+
+enum VMNodeMetadataIdentifierType {
+       VMNodeMetadataIdentifierTypeUnknown,
+       VMNodeMetadataIdentifierTypeNullType,
+       VMNodeMetadataIdentifierTypeIntegerType,
+       VMNodeMetadataIdentifierTypeFloatType,
+       VMNodeMetadataIdentifierTypeStringType,
+       //VMNodeMetadataIdentifierTypeUserType,
+       VMNodeMetadataIdentifierTypeVariable,
+       VMNodeMetadataIdentifierTypeFunction,
+       VMNodeMetadataIdentifierTypeParameter,
+};
+typedef enum VMNodeMetadataIdentifierType VMNodeMetadataIdentifierType;
+
+struct VMNodeMetadata {
+       struct {
+               bool definesScope;
+               bool holdsVariableScope;
+               SLTNode *parentScope;
+               SLTNode *scopedFunctionsHead;
+               SLTNode *scopedVariablesHead;
+               SLTNode *scopedParametersHead;
+               SLTNode *scopedBreaksHead;
+       } scope;
+
+       struct {
+               SVMPointer address;
+               SLTNode *scopedFunctionNext;
+       } function;
+
+       struct {
+               SLTNode *scopedVariableNext;
+       } variable;
+
+       struct {
+               SLTNode *scopedParameterNext;
+       } parameter;
+
+       struct {
+               SVMPointer breakInstruction;
+               SLTNode *scopedBreakNext;
+       } breakStatement;
+
+       struct {
+               VMNodeMetadataIdentifierType type;
+               SLTNode *resolvedNode;
+       } identifier;
+
+       struct {
+               SVMStackOffset offset;
+       } stack;
+
+       struct {
+               SVMPointer address;
+       } string;
+
+       struct {
+               bool native;
+               SVMPointer instruction;
+       } functionCall;
+};
+typedef struct VMNodeMetadata VMNodeMetadata;
+
+union VMGeneratorVisitor {
+       VMGeneratorOutputScope *generator;
+       SLTNode *currentScope;
+       struct {
+               bool typeChanged;
+               bool typeUnresolved;
+       };
+};
+typedef union VMGeneratorVisitor VMGeneratorVisitor;
+
+
+#define sltGetNodeMetadata(node) ((VMNodeMetadata *)(node)->metadata)
+
+
+
+static VMGeneratorOutputScope *generatorCreate() {
+       VMGeneratorOutputScope *scope = malloc(sizeof(VMGeneratorOutputScope)); // fixme these mallocs
+       memset(scope, 0, sizeof(VMGeneratorOutputScope));
+
+       scope->instructionCount = 1024;
+       scope->instructions = malloc(scope->instructionCount * sizeof(struct VMGeneratorInstruction));
+       scope->nextInstructionIdx = 0;
+
+       scope->stringClumpMaxSize = 1024;
+       scope->stringClump = malloc(scope->stringClumpMaxSize);
+       scope->stringClumpSize = 0;
+
+       return scope;
+}
+
+
+
+static size_t opcodeOperandCount(SVMOpcode opcode) {
+       switch (opcode) {
+               case SVMOpcodeSLEEP:
+               case SVMOpcodePOPJUMP:
+                       return 0;
+
+               case SVMOpcodeSTK:
+               case SVMOpcodeJUMP:
+               case SVMOpcodePUSHJUMP:
+                       return 1;
+
+               case SVMOpcodeMOV:
+               case SVMOpcodeSET:
+               case SVMOpcodeINV:
+               case SVMOpcodeBNOT:
+               case SVMOpcodeNOT:
+               case SVMOpcodeJT:
+               case SVMOpcodeCALL:
+                       return 2;
+
+               case SVMOpcodeADD:
+               case SVMOpcodeSUB:
+               case SVMOpcodeMUL:
+               case SVMOpcodeDIV:
+               case SVMOpcodeMOD:
+               case SVMOpcodeBAND:
+               case SVMOpcodeBOR:
+               case SVMOpcodeBXOR:
+               case SVMOpcodeAND:
+               case SVMOpcodeOR:
+               case SVMOpcodeEQ:
+               case SVMOpcodeNEQ:
+               case SVMOpcodeLT:
+               case SVMOpcodeLTEQ:
+               case SVMOpcodeGT:
+               case SVMOpcodeGTEQ:
+                       return 3;
+
+               default:
+                       generator_assert_msg(false, "invalid opcode %u", opcode);
+                       return -1;
+       }
+}
+
+
+static SVMPointer generatorNextInstruction(VMGeneratorOutputScope *generator) {
+       generator_assert(generator->nextInstructionIdx < generator->instructionCount);
+       SVMPointer idx = generator->nextInstructionIdx;
+       return idx;
+}
+
+static SVMPointer generatorAddInstruction(VMGeneratorOutputScope *generator, SVMOpcode opcode, ...) {
+       generator_assert(generator->nextInstructionIdx < generator->instructionCount);
+
+       SVMPointer idx = generatorNextInstruction(generator);
+       generator->nextInstructionIdx++;
+       struct VMGeneratorInstruction *instruction = &generator->instructions[idx];
+
+       instruction->instruction.opcode = opcode;
+
+       size_t numOperands = opcodeOperandCount(opcode);        
+
+       va_list args;
+       va_start(args, opcode);
+       for (size_t i = 0; i < numOperands; ++i) {
+               instruction->instruction.operands[i] = va_arg(args, SVMOperand);
+       }
+       va_end(args);
+
+       return idx;
+}
+
+static void generatorPatchOperand(VMGeneratorOutputScope *generator, SVMPointer instruction, size_t idx, SVMOperand value) {
+       generator_assert(instruction < generator->instructionCount);
+       generator_assert_msg(idx < opcodeOperandCount(generator->instructions[instruction].instruction.opcode), "invalid idx");
+       generator->instructions[instruction].instruction.operands[idx] = value;
+}
+
+static SVMPointer generatorAddString(VMGeneratorOutputScope *generator, const char *string) {
+       char *ptr = generator->stringClump;
+
+       while (ptr < generator->stringClump + generator->stringClumpSize) {
+               //printf("testing string: %s == %s\n", ptr, string);
+               if (strcmp(string, ptr) == 0) {
+                       return ptr - generator->stringClump;
+               }
+               ptr+=strlen(ptr) + 1;
+       }
+
+       size_t stringLength = strlen(string) + 1;
+       generator_assert_msg(ptr + stringLength <= generator->stringClump + generator->stringClumpMaxSize, "out of string space!!!");
+
+       strcpy(ptr, string);
+       generator->stringClumpSize += stringLength;
+
+       //printf("added string: %s\n", string);
+
+       return ptr - generator->stringClump;
+}
+
+static SVMStackOffset generatorResolveIdentifier(VMGeneratorOutputScope *generator, SLTNode *node) {
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+       generator_assert_msg(metadata->identifier.type != VMNodeMetadataIdentifierTypeUnknown, "could not resolve %s", node->identifierStringValue);
+       SVMStackOffset offset = sltGetNodeMetadata(metadata->identifier.resolvedNode)->stack.offset;
+       return offset;
+}
+
+
+static SVMModule *generatorFinalize(VMGeneratorOutputScope *generator) {
+       size_t memorySize = sizeof(SVMModule) + generator->stringClumpSize + /*0 * sizeof(SVMModuleFunctionDetails) +*/ generator->nextInstructionIdx * sizeof(SVMInstruction);
+
+       SVMModule *module = (SVMModule *)malloc(memorySize);
+       module->header[0] = 's';
+       module->header[1] = 'u';
+       module->header[2] = 'n';
+       module->header[3] = 'l';
+       module->magic = 1525;
+       module->stringBlobLength = generator->stringClumpSize;
+       module->numFunctions = 0; // FIXME
+       module->numInstructions = generator->nextInstructionIdx;
+
+       memcpy((void *)module + sizeof(SVMModule), generator->stringClump, module->stringBlobLength);
+       // COPY FUNCTIONS HERE...
+       memcpy((void *)module + sizeof(SVMModule) + module->stringBlobLength, generator->instructions, module->numInstructions * sizeof(SVMInstruction));
+
+       return module;
+}
+
+
+
+
+static void addNodeMetadata(SLTNode *node, void *userParameter) {
+       VMNodeMetadata *metadata = (VMNodeMetadata *)malloc(sizeof(VMNodeMetadata));// fixme
+       memset(metadata, 0, sizeof(VMNodeMetadata));
+       node->metadata = metadata;
+}
+
+
+static void findStrings(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       switch (node->type) {
+               case SLTNodeTypeString:
+                       metadata->string.address = generatorAddString(visitor->generator, node->stringValue);
+                       break;
+
+               case SLTNodeTypeFunctionCall:
+                       metadata->string.address = generatorAddString(visitor->generator, node->functionCallFunction->identifierStringValue);
+                       break;
+
+               default:
+                       /* do nothing */
+                       break;
+       }
+}
+
+static bool nodeTypeDefinesScope(SLTNodeType type) {
+       switch (type) {
+               case SLTNodeTypeModule:
+               case SLTNodeTypeFunctionDefinition:
+               case SLTNodeTypeTypeDefinition:
+               case SLTNodeTypeForIteration:
+               case SLTNodeTypeDoIteration:
+               case SLTNodeTypeWhileIteration:
+               case SLTNodeTypeStatementBlock:
+                       return true;
+
+               default:
+                       return false;
+       }
+}
+
+static bool nodeTypeHoldsVariables(SLTNodeType type) {
+       switch (type) {
+               case SLTNodeTypeModule:
+               case SLTNodeTypeFunctionDefinition:
+                       return true;
+
+               default:
+                       return false;
+       }
+}
+
+static void beginScopeNode(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       metadata->scope.parentScope = visitor->currentScope;
+
+       if (nodeTypeDefinesScope(node->type)) {
+               metadata->scope.definesScope = true;
+               metadata->scope.holdsVariableScope = nodeTypeHoldsVariables(node->type);
+               visitor->currentScope = node;
+       }
+}
+
+static void endScopeNode(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       if (nodeTypeDefinesScope(node->type)) {
+               visitor->currentScope = metadata->scope.parentScope;
+       }
+}
+
+static SLTNode *findScope(SLTNode *node) {
+       while (sltGetNodeMetadata(node)->scope.definesScope == false) {
+               VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+               node = metadata->scope.parentScope;
+               generator_assert_msg(node != NULL, "failed to scope"); // FIXME
+       }
+       
+       return node;
+}
+
+static SLTNode *findContainingScope(SLTNode *node) {
+       for (;;) {
+               node = findScope(node);
+               
+               VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+               if (metadata->scope.holdsVariableScope) {
+                       return node;
+               }
+
+               node = metadata->scope.parentScope;
+
+               generator_assert_msg(node != NULL, "failed to scope"); // FIXME
+       }
+}
+
+static void scopeDefinitions(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+       
+       switch (node->type) {
+               case SLTNodeTypeFunctionParameterDefinition: {
+                       //printf("def parameter %s\n", node->functionParameterDefinitionIdentifier->stringValue);
+                       VMNodeMetadata *scopeMetadata = sltGetNodeMetadata(findContainingScope(node));
+                       metadata->parameter.scopedParameterNext = scopeMetadata->scope.scopedParametersHead;
+                       scopeMetadata->scope.scopedParametersHead = node;
+                       break;
+               }
+
+               case SLTNodeTypeVariableDefinition: {
+                       //printf("def var %s\n", node->variableDefinitionIdentifier->stringValue);
+                       VMNodeMetadata *scopeMetadata = sltGetNodeMetadata(findContainingScope(node));
+                       metadata->variable.scopedVariableNext = scopeMetadata->scope.scopedVariablesHead;
+                       scopeMetadata->scope.scopedVariablesHead = node;
+                       break;
+               }
+
+               case SLTNodeTypeFunctionDefinition: {
+                       //printf("def func %s\n", node->functionDefinitionIdentifier->stringValue);
+                       VMNodeMetadata *scopeMetadata = sltGetNodeMetadata(findScope((sltGetNodeMetadata(findScope(node))->scope.parentScope))); // Functions define a scope...
+                       metadata->function.scopedFunctionNext = scopeMetadata->scope.scopedFunctionsHead;
+                       scopeMetadata->scope.scopedFunctionsHead = node;
+                       break;
+               }
+
+               default:
+                       break;
+       }
+}
+
+static SLTNode *resolveDefinition(VMNodeMetadataIdentifierType *typeOut, SLTNode *node, const char *name) {
+       if (strcmp(name, "void") == 0) { // FIXME, can de-duplicate these for speed earlier..
+               *typeOut = VMNodeMetadataIdentifierTypeNullType;
+               return NULL;
+       }
+
+       if (strcmp(name, "int") == 0) {
+               *typeOut = VMNodeMetadataIdentifierTypeIntegerType;
+               return NULL;
+       }
+
+       if (strcmp(name, "float") == 0) {
+               *typeOut = VMNodeMetadataIdentifierTypeFloatType;
+               return NULL;
+       }
+
+       if (strcmp(name, "string") == 0) {
+               *typeOut = VMNodeMetadataIdentifierTypeStringType;
+               return NULL;
+       }
+
+       for (;;) {
+               VMNodeMetadata *scopeMetadata = sltGetNodeMetadata(findScope(node));
+               
+               // Should do types here...
+
+               for (SLTNode *n = scopeMetadata->scope.scopedFunctionsHead; n != NULL; n = sltGetNodeMetadata(n)->function.scopedFunctionNext) {
+                       if (strcmp(n->functionDefinitionIdentifier->identifierStringValue, name) == 0) {
+                               *typeOut = VMNodeMetadataIdentifierTypeFunction;
+                               //printf("GOT F %s\n", name);
+                               return n;
+                       }
+               }
+
+               for (SLTNode *n = scopeMetadata->scope.scopedVariablesHead; n != NULL; n = sltGetNodeMetadata(n)->variable.scopedVariableNext) {
+                       if (strcmp(n->variableDefinitionIdentifier->identifierStringValue, name) == 0) {
+                               *typeOut = VMNodeMetadataIdentifierTypeVariable;
+                               //printf("GOT V %s\n", name);
+                               return n;
+                       }
+               }
+
+               for (SLTNode *n = scopeMetadata->scope.scopedParametersHead; n != NULL; n = sltGetNodeMetadata(n)->parameter.scopedParameterNext) {
+                       if (strcmp(n->functionParameterDefinitionIdentifier->identifierStringValue, name) == 0) {
+                               *typeOut = VMNodeMetadataIdentifierTypeParameter;
+                               //printf("GOT P %s\n", name);
+                               return n;
+                       }
+               }
+
+               if (scopeMetadata->scope.parentScope != NULL) {
+                       node = scopeMetadata->scope.parentScope;
+               } else {
+                       break;                  
+               }
+       }
+
+       return NULL;
+}
+
+static void resolveDefinitions(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       switch (node->type) {
+               case SLTNodeTypeIdentifier:
+                       metadata->identifier.resolvedNode = resolveDefinition(&metadata->identifier.type, node, node->identifierStringValue);
+                       //printf("trying to get %s %x\n",  node->stringValue, metadata->identifier.resolvedNode);
+                        //metadata->variable.scopedVariableNext = metadata->scope.scopedVariablesHead;
+                       //metadata->scope.scopedVariablesHead = node;
+                       break;
+
+               default:
+                       break;
+       }
+}
+
+static void resolveDefinitionsNativeFunctions(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       switch (node->type) {
+               case SLTNodeTypeFunctionCall:
+                       if (sltGetNodeMetadata(node->functionCallFunction)->identifier.resolvedNode == NULL) {
+                               metadata->functionCall.instruction = node->functionCallFunction->identifierStringKeyValue;
+                               metadata->functionCall.native = true;
+                       }
+
+               default:
+                       break;
+       }
+}
+
+
+
+static void indexDefinitions(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       // Functions put their return value at the 0th stack position, modules start at -1
+       size_t idx = 1;
+       
+       size_t parameterCount = 0;
+       for (SLTNode *parameter = metadata->scope.scopedParametersHead; parameter != NULL; ++parameterCount, parameter = sltGetNodeMetadata(parameter)->parameter.scopedParameterNext);
+
+       SLTNode *parameter = metadata->scope.scopedParametersHead;
+       while (parameter != NULL) {
+               sltGetNodeMetadata(parameter)->stack.offset = node->type == SLTNodeTypeModule ? -idx : (parameterCount + 1) - idx; // Parameter positions are inverted...
+               ++idx;
+               parameter = sltGetNodeMetadata(parameter)->parameter.scopedParameterNext;
+       }
+
+       SLTNode *variable = metadata->scope.scopedVariablesHead;
+       while (variable != NULL) {
+               sltGetNodeMetadata(variable)->stack.offset = node->type == SLTNodeTypeModule ? -idx : idx;
+               ++idx;
+               variable = sltGetNodeMetadata(variable)->variable.scopedVariableNext;
+       }
+}
+
+
+
+/*static void resolveTypes(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       switch (node->type) {
+               case SLTNodeTypeUnknown:
+               case SLTNodeTypeSequence:
+                       generator_assert_msg(false, "unexpected: %s", sltNodeToString(node));// fixme
+                       break;
+               
+               case SLTNodeTypeIdentifier:
+                       // ...??
+
+               case SLTNodeTypeBoolean:
+               case SLTNodeTypeInteger:
+               case SLTNodeTypeFloat:
+               case SLTNodeTypeString:
+
+               case SLTNodeTypeCompound:
+
+               case SLTNodeTypeArgument:
+
+               case SLTNodeTypeArrayAccess:
+               case SLTNodeTypeTypeAccess:
+
+               case SLTNodeTypeFunctionCall:
+
+               case SLTNodeTypeUnaryOperation:
+               case SLTNodeTypeBinaryOperation:
+
+               case SLTNodeTypeOperator:
+
+               case SLTNodeTypeAssignment:
+
+               case SLTNodeTypeReturn:
+               case SLTNodeTypeSleep:
+
+               case SLTNodeTypeForIteration:
+               case SLTNodeTypeDoIteration:
+               case SLTNodeTypeWhileIteration:
+
+               case SLTNodeTypeSelection:
+
+               case SLTNodeTypeStatementBlock:
+
+               case SLTNodeTypeVariableDefinition:
+
+               case SLTNodeTypeTypeDefinition:
+               case SLTNodeTypeTypeMemberDefinition:
+
+               case SLTNodeTypeFunctionDefinition:
+               case SLTNodeTypeFunctionParameterDefinition:
+
+               case SLTNodeTypeModule:
+
+
+       }
+
+visitor.typeChanged = false;
+       
+       
+       
+       
+       
+               
+       if (node->dataType == SLTDataTypeUnknown) {
+               visitor->typeUnresolved = true;
+       }
+}*/
+
+static bool nodeTypeIsLoop(SLTNodeType type) {
+       switch (type) {
+               case SLTNodeTypeForIteration:
+               case SLTNodeTypeDoIteration:
+               case SLTNodeTypeWhileIteration:
+                       return true;
+
+               default:
+                       return false;
+       }
+}
+
+static SLTNode *findLoopScope(SLTNode *node) {
+       for (;;) {
+               node = findScope(node);
+               
+               if (nodeTypeIsLoop(node->type)) {
+                       return node;
+               }
+
+               VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+               node = metadata->scope.parentScope;
+
+               generator_assert_msg(node != NULL, "failed to scope loop"); // FIXME
+       }
+}
+
+static void scopeIterationBreaks(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+       
+       switch (node->type) {
+               case SLTNodeTypeBreak: {
+                       VMNodeMetadata *scopeMetadata = sltGetNodeMetadata(findLoopScope(node));
+                       metadata->breakStatement.scopedBreakNext = scopeMetadata->scope.scopedBreaksHead;
+                       scopeMetadata->scope.scopedBreaksHead = node;
+                       break;
+               }
+
+               default:
+                       break;
+       }
+}
+
+
+static SVMPointer generateValueInstructions(VMGeneratorOutputScope *generator, SLTNode *node, SVMOperand target) {
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       switch (node->type) {
+               case SLTNodeTypeIdentifier: {
+                       SVMOperand source = { .stackOffset = generatorResolveIdentifier(generator, node) };
+                       return generatorAddInstruction(generator, SVMOpcodeMOV, target, source);
+               }
+
+               case SLTNodeTypeBoolean: {
+                       SVMOperand source = { .integerLiteral = node->booleanValue ? 1 : 0 };
+                       return generatorAddInstruction(generator, SVMOpcodeSET, target, source);
+               }
+
+               case SLTNodeTypeInteger: {
+                       SVMOperand source = { .integerLiteral = FIXED(node->integerValue) };
+                       return generatorAddInstruction(generator, SVMOpcodeSET, target, source);
+               }
+
+               case SLTNodeTypeRawInteger: {
+                       SVMOperand source = { .__raw = node->integerValue };
+                       return generatorAddInstruction(generator, SVMOpcodeSET, target, source);
+               }
+
+               case SLTNodeTypeFloat: {
+                       SVMOperand source = { .floatLiteral = FIXED_FROM_FLOAT(node->floatValue) };
+                       return generatorAddInstruction(generator, SVMOpcodeSET, target, source);
+               }
+
+               case SLTNodeTypeString: {
+                       SVMOperand source = { .pointerLiteral = metadata->string.address }; // FIXME, string pool needed
+                       return generatorAddInstruction(generator, SVMOpcodeSET, target, source);
+               }
+
+               case SLTNodeTypeKey: {
+                       SVMOperand source = { .pointerLiteral = node->keyValue };
+                       return generatorAddInstruction(generator, SVMOpcodeSET, target, source);
+               }
+
+               default:
+                       generator_assert_msg(false, "unexpected: %s", sltNodeToString(node));// fixme
+                       return -1; // FIXME
+       }
+}
+
+static SVMPointer generateExpressionInstructions(VMGeneratorOutputScope *generator, SLTNode *node, SVMOperand target, SVMStackOffset workingStackOffset) {
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       switch (node->type) {
+               case SLTNodeTypeBinaryOperation: {
+                       SVMOperand lhsOperand = { .stackOffset = workingStackOffset };
+                       generateExpressionInstructions(generator, node->binaryOperationLHS, lhsOperand, workingStackOffset + 1);
+
+                       SVMOperand rhsOperand = { .stackOffset = workingStackOffset + 1 };
+                       generateExpressionInstructions(generator, node->binaryOperationRHS, rhsOperand, workingStackOffset + 2);
+
+                       switch (node->binaryOperationOperator->operatorType) {
+                               case SLTOperatorTypeAdd:
+                                       return generatorAddInstruction(generator, SVMOpcodeADD, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeSubtract:
+                                       return generatorAddInstruction(generator, SVMOpcodeSUB, target, lhsOperand, rhsOperand);
+                               
+                               case SLTOperatorTypeMultiply:
+                                       return generatorAddInstruction(generator, SVMOpcodeMUL, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeDivide:
+                                       return generatorAddInstruction(generator, SVMOpcodeDIV, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeModulo:
+                                       return generatorAddInstruction(generator, SVMOpcodeMOD, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeBitwiseAnd:
+                                       return generatorAddInstruction(generator, SVMOpcodeBAND, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeBitwiseOr:
+                                       return generatorAddInstruction(generator, SVMOpcodeBOR, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeBitwiseXor:
+                                       return generatorAddInstruction(generator, SVMOpcodeBXOR, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeLogicalAnd:
+                                       return generatorAddInstruction(generator, SVMOpcodeAND, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeLogicalOr:
+                                       return generatorAddInstruction(generator, SVMOpcodeOR, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeEqual:
+                                       return generatorAddInstruction(generator, SVMOpcodeEQ, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeNotEqual:
+                                       return generatorAddInstruction(generator, SVMOpcodeNEQ, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeLessThan:
+                                       return generatorAddInstruction(generator, SVMOpcodeLT, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeLessThanEqual:
+                                       return generatorAddInstruction(generator, SVMOpcodeLTEQ, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeGreaterThan:
+                                       return generatorAddInstruction(generator, SVMOpcodeGT, target, lhsOperand, rhsOperand);
+
+                               case SLTOperatorTypeGreaterThanEqual:
+                                       return generatorAddInstruction(generator, SVMOpcodeGTEQ, target, lhsOperand, rhsOperand);
+
+                               default:
+                                       generator_assert_msg(false, "invalid binary operator %s", sltOperatorTypeToString(node->binaryOperationOperator->operatorType));
+                                       return -1;
+                       }
+               }
+
+               case SLTNodeTypeUnaryOperation: {
+                       SVMOperand operand = { .stackOffset = target.stackOffset };
+                       generateExpressionInstructions(generator, node->unaryOperationOperand, operand, workingStackOffset);
+
+                       switch (node->unaryOperationOperator->operatorType) {
+                               //case SLTOperatorTypePositive:
+                               //      return -1;
+
+                               case SLTOperatorTypeNegative:
+                                       return generatorAddInstruction(generator, SVMOpcodeINV, target, operand);
+
+                               case SLTOperatorTypeBitwiseNot:
+                                       return generatorAddInstruction(generator, SVMOpcodeBNOT, target, operand);
+
+                               case SLTOperatorTypeLogicalNot:
+                                       return generatorAddInstruction(generator, SVMOpcodeNOT, target, operand);
+
+                               default:
+                                       generator_assert_msg(false, "invalid unary operator %s", sltOperatorTypeToString(node->unaryOperationOperator->operatorType));
+                                       return -1;
+                       }
+               }
+
+               case SLTNodeTypeArrayAccess:
+                       generator_assert_msg(false, "not implemented: %s", sltNodeToString(node));
+                       return -1;
+
+               case SLTNodeTypeFunctionCall: {
+                       //generator_assert_msg(sltGetNodeMetadata(node->functionCallFunction)->identifier.resolvedNode != NULL, "unresolved function: %s", node->functionCallFunction->stringValue);// fixme
+
+                       SVMPointer r = generatorNextInstruction(generator);
+
+                       SVMInteger parameterCount = 0;
+                       for (SLTNode *n = node->functionCallArguments; n != NULL; n = n->sequenceNext) {
+                               ++parameterCount;
+                               SVMStackOffset parameterTarget = workingStackOffset + parameterCount;
+                               SVMOperand target = { .stackOffset = parameterTarget, };
+                               generateExpressionInstructions(generator, n->sequenceNode->argumentExpression, target, parameterTarget);
+                       }
+
+                       // Offset the stack to make 0 where we're returning into...
+                       SVMStackOffset stackOffset = workingStackOffset;// + parameterCount;
+                       generatorAddInstruction(generator, SVMOpcodeSTK, stackOffset);
+
+                       // Call the function
+                       if (metadata->functionCall.native == false) {
+                               metadata->functionCall.instruction = generatorAddInstruction(generator, SVMOpcodePUSHJUMP, 999); // Silly marker, we patch this later...
+                       } else {
+                               metadata->functionCall.instruction = generatorAddInstruction(generator, SVMOpcodeCALL, metadata->functionCall.instruction, parameterCount);
+                       }
+
+                       // Put the stack back
+                       generatorAddInstruction(generator, SVMOpcodeSTK, -stackOffset);
+
+                       // Move result
+                       if (target.stackOffset != workingStackOffset) {
+                               SVMOperand source = { .stackOffset = workingStackOffset };
+                               generatorAddInstruction(generator, SVMOpcodeMOV, target, source);
+                       }
+
+                       return r;
+               }
+
+               case SLTNodeTypeTypeAccess:
+                       generator_assert_msg(false, "not implemented: %s", sltNodeToString(node));
+                       return -1;
+
+               case SLTNodeTypeCompound:
+                       return generateExpressionInstructions(generator, node->compoundSubexpression, target, workingStackOffset);
+
+               default:
+                       return generateValueInstructions(generator, node, target);
+       }
+}
+
+static SVMPointer generateStatementInstructions(VMGeneratorOutputScope *generator, SLTNode *node, SVMStackOffset workingStackOffset) {
+       switch (node->type) {
+               case SLTNodeTypeStatementBlock: {
+                       SVMPointer r = generatorNextInstruction(generator);
+
+               // FIXME, call the function thing...
+                       // FIXME, open some kind of scope??
+                       for (SLTNode *n = node->statementBlockContents; n != NULL; n = n->sequenceNext) {
+                               generateStatementInstructions(generator, n->sequenceNode, workingStackOffset);
+                       }
+
+                       return r;
+               }
+
+               case SLTNodeTypeVariableDefinition: {
+                       SVMPointer r = generatorNextInstruction(generator);
+
+                       if (node->variableDefinitionDefaultExpression != NULL) {
+                               SVMOperand target = { .stackOffset = generatorResolveIdentifier(generator, node->variableDefinitionIdentifier), };
+                               generateExpressionInstructions(generator, node->variableDefinitionDefaultExpression, target, workingStackOffset);
+                       }
+                       
+                       return r;
+               }
+
+               case SLTNodeTypeSelection: {
+                       SVMPointer r = generatorNextInstruction(generator);
+
+                       SVMOperand valid = { .stackOffset = 0, };
+                       generateExpressionInstructions(generator, node->selectionValidExpression, valid, workingStackOffset + 1);
+                       generatorAddInstruction(generator, SVMOpcodeNOT, valid, valid); // Inverse for this check...
+                       SVMPointer patchPre = generatorAddInstruction(generator, SVMOpcodeJT, valid, 999);
+
+                       if (node->selectionValidStatement != NULL) {
+                               generateStatementInstructions(generator, node->selectionValidStatement, workingStackOffset);
+                       }
+
+                       if (node->selectionInvalidStatement != NULL) {
+                               SVMPointer patchPost = generatorAddInstruction(generator, SVMOpcodeJUMP, 999);
+
+                               SVMOperand target = { .pointerLiteral = generatorNextInstruction(generator), };
+                               generatorPatchOperand(generator, patchPre, 1, target);
+                               
+                               generateStatementInstructions(generator, node->selectionInvalidStatement, workingStackOffset);
+
+                               target.pointerLiteral = generatorNextInstruction(generator);
+                               generatorPatchOperand(generator, patchPost, 0, target);
+                       } else {
+                               SVMOperand target = { .pointerLiteral = generatorNextInstruction(generator), };
+                               generatorPatchOperand(generator, patchPre, 1, target);
+                       }
+
+                       return r;
+               }
+
+               case SLTNodeTypeDoIteration:
+               case SLTNodeTypeForIteration:
+               case SLTNodeTypeWhileIteration: {
+                       if (node->iterationInitialExpression != NULL) {
+                               //SVMOperand target = { .stackOffset = 0, };
+                               //generateExpressionInstructions(generator, node->iterationInitialExpression, target, workingStackOffset); // FIXME, is this a statement??
+                               generateStatementInstructions(generator, node->iterationInitialExpression, workingStackOffset);
+                       }
+                       
+                       SVMPointer r = generatorNextInstruction(generator);
+
+                       SVMPointer patchPre;
+                       if (node->iterationPreValidExpression != NULL) {
+                               SVMOperand valid = { .stackOffset = 0, };
+                               generateExpressionInstructions(generator, node->iterationPreValidExpression, valid, workingStackOffset + 1);
+                               generatorAddInstruction(generator, SVMOpcodeNOT, valid, valid); // Inverse for this check...
+                               patchPre = generatorAddInstruction(generator, SVMOpcodeJT, valid, 999);
+                       }
+
+                       if (node->iterationStatement != NULL) {
+                               generateStatementInstructions(generator, node->iterationStatement, workingStackOffset);
+                       }
+
+                       if (node->iterationLoopExpression != NULL) {
+                               //SVMOperand target = { .stackOffset = 0, };
+                               //generateExpressionInstructions(generator, node->iterationLoopExpression, target, workingStackOffset); // FIXME, is this a statement??
+                               generateStatementInstructions(generator, node->iterationLoopExpression, workingStackOffset);
+                       }
+
+                       if (node->iterationPostValidExpression != NULL) {
+                               SVMOperand valid = { .stackOffset = 0, };
+                               generateExpressionInstructions(generator, node->iterationPostValidExpression, valid, workingStackOffset + 1);
+                               generatorAddInstruction(generator, SVMOpcodeJT, valid, r);
+                       } else {
+                               generatorAddInstruction(generator, SVMOpcodeJUMP, r);
+                       }
+
+                       // Patch jump...
+                       SVMOperand target = { .pointerLiteral = generatorNextInstruction(generator), };
+
+                       if (node->iterationPreValidExpression != NULL) {
+                               generatorPatchOperand(generator, patchPre, 1, target);
+                       }
+
+                       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+                       for (SLTNode *v = metadata->scope.scopedBreaksHead; v != NULL; v = sltGetNodeMetadata(v)->breakStatement.scopedBreakNext) {
+                               generatorPatchOperand(generator, sltGetNodeMetadata(v)->breakStatement.breakInstruction, 0, target);
+                       }
+
+                       return r;
+               }
+
+               case SLTNodeTypeAssignment: {
+                       SVMOperand target = { .stackOffset = generatorResolveIdentifier(generator, node->assignmentTarget) };
+                       return generateExpressionInstructions(generator, node->assignmentSource, target, workingStackOffset);
+               }
+
+               case SLTNodeTypeReturn: {
+                       SVMPointer r = generatorNextInstruction(generator);
+
+                       if (node->returnExpression != NULL) {
+                               SVMOperand target = { .stackOffset = 0, }; // return is always at 0
+                               generateExpressionInstructions(generator, node->returnExpression, target, workingStackOffset);
+                       }
+                       generatorAddInstruction(generator, SVMOpcodePOPJUMP);
+                       
+                       return r;
+               }
+
+               case SLTNodeTypeSleep:
+                       return generatorAddInstruction(generator, SVMOpcodeSLEEP);
+
+               case SLTNodeTypeBreak: {
+                       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+                       metadata->breakStatement.breakInstruction = generatorAddInstruction(generator, SVMOpcodeJUMP, 999);
+                       return metadata->breakStatement.breakInstruction;
+               }
+
+               default: {
+//                     generator_assert_msg(false, "not implemented as statement: %s", sltNodeToString(node));
+                       SVMOperand target = { .stackOffset = 0, }; // FIXME!!!
+                       return generateExpressionInstructions(generator, node, target, workingStackOffset);
+               }
+       }
+}
+
+static void generateFunctionDefinitionInstructions(VMGeneratorOutputScope *generator, SLTNode *node) {
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       // count parameters, these are first on the stack...
+       size_t numParameters = 0;
+       for (SLTNode *p = metadata->scope.scopedParametersHead; p != NULL; ++numParameters, p = sltGetNodeMetadata(p)->parameter.scopedParameterNext);
+
+       // next, count the variables
+       size_t numVariables = 0;
+       for (SLTNode *v = metadata->scope.scopedVariablesHead; v != NULL; ++numVariables, v = sltGetNodeMetadata(v)->variable.scopedVariableNext);
+
+       metadata->function.address = generatorNextInstruction(generator);
+
+       SVMStackOffset workingStackOffset = 1 + numParameters + numVariables;
+       if (node->functionDefinitionBody != NULL) {
+               generator_assert(node->functionDefinitionBody->type == SLTNodeTypeSequence);
+               for (SLTNode *n = node->functionDefinitionBody; n != NULL; n = n->sequenceNext) {
+                       generateStatementInstructions(generator, n->sequenceNode, workingStackOffset);
+               }
+       }
+
+       // fallback return
+       generatorAddInstruction(generator, SVMOpcodePOPJUMP);
+}
+
+static size_t generateModuleInstructions(VMGeneratorOutputScope *generator, SLTNode *node) {
+       generator_assert(node != NULL && node->type == SLTNodeTypeModule);
+
+       if (node->moduleStatementsAndDefinitions != NULL) {
+               SVMPointer start = generatorAddInstruction(generator, SVMOpcodeJUMP, 999);
+
+               generator_assert(node->moduleStatementsAndDefinitions->type == SLTNodeTypeSequence);
+
+               // do functions first...
+               for (SLTNode *n = node->moduleStatementsAndDefinitions; n != NULL; n = n->sequenceNext) {
+                       if (n->sequenceNode->type == SLTNodeTypeFunctionDefinition) {
+                               generateFunctionDefinitionInstructions(generator, n->sequenceNode);
+                       }
+               }
+
+               // Patch to jump to the start...
+               SVMOperand address = { .pointerLiteral = generatorNextInstruction(generator) };
+               generatorPatchOperand(generator, start, 0, address);
+
+               // then do variables
+               for (SLTNode *n = node->moduleStatementsAndDefinitions; n != NULL; n = n->sequenceNext) {
+                       switch (n->sequenceNode->type) {
+                               case SLTNodeTypeFunctionDefinition:
+                                       // Do nothing...
+                                       break;
+
+                               case SLTNodeTypeVariableDefinition:
+                                       generateStatementInstructions(generator, n->sequenceNode, 0);
+                                       break;
+
+                               default:
+                                       //generator_assert_msg(false, "could not define %s", sltNodeTypeToString(n->sequenceNode->type));
+                                       break;
+                       }
+               }
+
+               // statements
+               for (SLTNode *n = node->moduleStatementsAndDefinitions; n != NULL; n = n->sequenceNext) {
+                       switch (n->sequenceNode->type) {
+                               case SLTNodeTypeVariableDefinition:
+                               case SLTNodeTypeTypeDefinition:
+                               case SLTNodeTypeFunctionDefinition:
+                                       // Do nothing...
+                                       break;
+
+                               default:
+                                       generateStatementInstructions(generator, n->sequenceNode, 0);
+                                       break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+
+
+static void patchFunctionCalls(SLTNode *node, void *userParameter) {
+       VMGeneratorVisitor *visitor = (VMGeneratorVisitor *)userParameter;
+       VMNodeMetadata *metadata = sltGetNodeMetadata(node);
+
+       if (node->type == SLTNodeTypeFunctionCall) {
+               if (metadata->functionCall.native == false) {
+                       generator_assert_msg(sltGetNodeMetadata(node->functionCallFunction)->identifier.resolvedNode->type == SLTNodeTypeFunctionDefinition, "%s", sltNodeToString(sltGetNodeMetadata(node->functionCallFunction)->identifier.resolvedNode));
+                       SVMOperand operand = { .pointerLiteral = sltGetNodeMetadata(sltGetNodeMetadata(node->functionCallFunction)->identifier.resolvedNode)->function.address };
+                       generatorPatchOperand(visitor->generator, metadata->functionCall.instruction, 0, operand);
+               }
+       }
+}
+
+
+
+SVMModule *slcGenerateVMInstructions(SLTNode *moduleNode) {
+       VMGeneratorOutputScope *generator = generatorCreate();
+
+       VMGeneratorVisitor visitor;
+       
+       sltTreeIterate(moduleNode, addNodeMetadata, NULL, NULL);
+
+       visitor.generator = generator;
+       sltTreeIterate(moduleNode, findStrings, NULL, &visitor);
+
+       visitor.currentScope = NULL;
+       sltTreeIterate(moduleNode, beginScopeNode, endScopeNode, &visitor);
+
+       visitor.generator = generator;
+       sltTreeIterate(moduleNode, scopeDefinitions, NULL, &visitor);
+       sltTreeIterate(moduleNode, resolveDefinitions, resolveDefinitionsNativeFunctions, &visitor);
+       sltTreeIterate(moduleNode, indexDefinitions, NULL, &visitor);
+
+       sltTreeIterate(moduleNode, scopeIterationBreaks, NULL, &visitor);
+
+       /*do {
+               visitor.typeUnresolved = false;
+               visitor.typeChanged = false;
+               sltTreeIterate(moduleNode, resolveTypes, NULL, &visitor);
+       } while (visitor.typeUnresolved && visitor.typeChanged);*/
+
+       generateModuleInstructions(generator, moduleNode);
+
+       visitor.generator = generator;
+       sltTreeIterate(moduleNode, patchFunctionCalls, NULL, &visitor);
+
+
+       SVMModule *module = generatorFinalize(generator);
+
+
+       /*for (size_t i = 0; i < generator->nextInstructionIdx; ++i) {
+               SVMOpcode opcode = generator->instructions[i].instruction.opcode;
+               switch (opcodeOperandCount(opcode)) {
+                       case 0:
+                       default:
+                               printf("%u : %s\n", i, svmOpcodeToString(opcode));
+                               break;
+
+                       case 1:
+                               printf("%u : %s %d\n", i, svmOpcodeToString(opcode), generator->instructions[i].instruction.dst.stackOffset);
+                               break;
+
+                       case 2:
+                               printf("%u : %s %d %d\n", i, svmOpcodeToString(opcode), generator->instructions[i].instruction.dst.stackOffset, generator->instructions[i].instruction.p1.stackOffset);
+                               break;
+
+                       case 3:
+                               printf("%u : %s %d %d %d\n", i, svmOpcodeToString(opcode), generator->instructions[i].instruction.dst.stackOffset, generator->instructions[i].instruction.p1.stackOffset, generator->instructions[i].instruction.p2.stackOffset);
+                               break;
+               }
+       }*/
+
+       //fix references...
+
+       return module;
+}
diff --git a/runtime/src/sun/compiler/vm_generator.h b/runtime/src/sun/compiler/vm_generator.h
new file mode 100644 (file)
index 0000000..68b37a8
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SUN_COMPILER_VM_GENERATOR_H
+#define SUN_COMPILER_VM_GENERATOR_H
+
+#include <sun/tree/node.h>
+#include <sun/vm/vm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern SVMModule *slcGenerateVMInstructions(SLTNode *moduleNode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/tree/crc32.h b/runtime/src/sun/tree/crc32.h
new file mode 100644 (file)
index 0000000..a411a61
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef SUN_TREE_CRC32_H
+#define SUN_TREE_CRC32_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Taken from here: https://web.archive.org/web/20190108202303/http://www.hackersdelight.org/hdcodetxt/crc.c.txt
+// Licence: https://web.archive.org/web/20190716204559/http://www.hackersdelight.org/permissions.htm
+// See also: https://stackoverflow.com/a/21001712
+// FIXME: Look into https://gist.github.com/badboy/6267743
+
+uint32_t crc32c(char *message) {
+   int i, j;
+   uint32_t byte, crc, mask;
+   static uint32_t table[256];
+
+   /* Set up the table, if necessary. */
+
+   if (table[1] == 0) {
+      for (byte = 0; byte <= 255; byte++) {
+         crc = byte;
+         for (j = 7; j >= 0; j--) {    // Do eight times.
+            mask = -(crc & 1);
+            crc = (crc >> 1) ^ (0xEDB88320 & mask);
+         }
+         table[byte] = crc;
+      }
+   }
+
+   /* Through with table setup, now calculate the CRC. */
+
+   i = 0;
+   crc = 0xFFFFFFFF;
+   while ((byte = message[i]) != 0) {
+      crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF];
+      i = i + 1;
+   }
+   return ~crc;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/tree/data_type.c b/runtime/src/sun/tree/data_type.c
new file mode 100644 (file)
index 0000000..f84d524
--- /dev/null
@@ -0,0 +1,24 @@
+#include "data_type.h"
+
+const char *sltDataTypeToString(SLTDataType dataType) {
+       switch(dataType) {
+               default:
+                       case SLTDataTypeUnknown:
+                       return "<unknown>";
+
+               case SLTDataTypeNone:
+                       return "None";
+
+               case SLTDataTypeBoolean:
+                       return "Boolean";
+
+               case SLTDataTypeInteger:
+                       return "Integer";
+                       
+               case SLTDataTypeFloat:
+                       return "Float";
+
+               case SLTDataTypeString:
+                       return "String";
+       }
+}
diff --git a/runtime/src/sun/tree/data_type.h b/runtime/src/sun/tree/data_type.h
new file mode 100644 (file)
index 0000000..386f2ac
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef SUN_TREE_DATA_TYPE_H
+#define SUN_TREE_DATA_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum SLTDataType {
+       SLTDataTypeUnknown,
+
+       SLTDataTypeNone,
+       SLTDataTypeBoolean,
+       SLTDataTypeInteger,
+       SLTDataTypeFloat,
+       SLTDataTypeString,
+};
+typedef enum SLTDataType SLTDataType;
+
+extern const char *sltDataTypeToString(SLTDataType dataType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/tree/node.c b/runtime/src/sun/tree/node.c
new file mode 100644 (file)
index 0000000..ad91732
--- /dev/null
@@ -0,0 +1,254 @@
+#include "node_internal.h"
+
+#include <sun/tree/crc32.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *sltNodeToString(SLTNode *node) {
+       return sltNodeTypeToString(node->type);
+}
+
+static SLTNode *node_make_typed(SLTNodeType type, SLTDataType dataType) {
+       SLTNode *node = (SLTNode *)malloc(sizeof(SLTNode));
+       node->type = type;
+       node->dataType = dataType;
+       //node->next = NULL;
+       return node;
+}
+
+static SLTNode *node_make(SLTNodeType type) {
+       return node_make_typed(type, SLTDataTypeUnknown);
+}
+
+SLTNode *sltNodeMakeIdentifier(const char *name) {
+       SLTNode *node = node_make(SLTNodeTypeIdentifier);
+       node->identifierStringValue = strdup(name); // FIXME
+       node->identifierStringKeyValue = crc32c(name);
+       return node;
+}
+
+SLTNode *sltNodeMakeBoolean(bool value) {
+       SLTNode *node = node_make_typed(SLTNodeTypeBoolean, SLTDataTypeBoolean);
+       node->booleanValue = value;
+       return node;
+}
+
+SLTNode *sltNodeMakeInteger(int value) {
+       SLTNode *node = node_make_typed(SLTNodeTypeInteger, SLTDataTypeInteger);
+       node->integerValue = value;
+       return node;
+}
+
+SLTNode *sltNodeMakeRawInteger(int value) {
+       SLTNode *node = node_make_typed(SLTNodeTypeRawInteger, SLTDataTypeInteger);
+       node->integerValue = value;
+       return node;
+}
+
+SLTNode *sltNodeMakeFloat(float value) {
+       SLTNode *node = node_make_typed(SLTNodeTypeFloat, SLTDataTypeFloat);
+       node->floatValue = value;
+       return node;
+}
+
+SLTNode *sltNodeMakeString(const char *value) {
+       SLTNode *node = node_make_typed(SLTNodeTypeString, SLTDataTypeString);
+       size_t strLen = strlen(value) - 2; // -2 to remove quotes
+       node->stringValue = malloc(strLen + 1);
+       strncpy(node->stringValue, value + 1, strLen);
+       node->stringValue[strLen] = '\0';
+       return node;
+}
+
+SLTNode *sltNodeMakeKey(const char *value) {
+       SLTNode *node = node_make_typed(SLTNodeTypeKey, SLTDataTypeString);
+
+       size_t strLen = strlen(value) - 3; // -3 to remove quotes
+       unsigned char *key = alloca(strLen + 1);
+       strncpy(key, value + 2, strLen);
+       key[strLen] = '\0';
+
+       node->keyValue = crc32c(key);
+
+       return node;
+}
+
+SLTNode *sltNodeMakeCompound(SLTNode *expression) {
+       SLTNode *node = node_make(SLTNodeTypeCompound);
+       node->compoundSubexpression = expression;
+       return node;
+}
+
+SLTNode *sltNodeMakeArgument(SLTNode *expression) {
+       SLTNode *node = node_make(SLTNodeTypeArgument);
+       node->argumentExpression = expression;
+       return node;
+}
+
+SLTNode *sltNodeMakeArrayAccess(SLTNode *array, SLTNode *access) {
+       SLTNode *node = node_make(SLTNodeTypeArrayAccess);
+       node->arrayAccessArray = array;
+       node->arrayAccessAccess = access;
+       return node;
+}
+
+SLTNode *sltNodeMakeTypeAccess(SLTNode *type, SLTNode *access) {
+       SLTNode *node = node_make(SLTNodeTypeTypeAccess);
+       node->typeAccessType = type;
+       node->typeAccessAccess = access;
+       return node;
+}
+
+SLTNode *sltNodeMakeFunctionCall(SLTNode *function, SLTNode *arguments) {
+       SLTNode *node = node_make(SLTNodeTypeFunctionCall);
+       node->functionCallFunction = function;
+       node->functionCallArguments = arguments;
+       return node;
+}
+
+
+SLTNode *sltNodeMakeUnaryOperation(SLTNode *op, SLTNode *operand) { // Can't use "operator" apparently...
+       SLTNode *node = node_make(SLTNodeTypeUnaryOperation);
+       node->unaryOperationOperator = op;
+       node->unaryOperationOperand = operand;
+       return node;
+}
+
+SLTNode *sltNodeMakeBinaryOperation(SLTNode *op, SLTNode *lhs, SLTNode *rhs) {
+       SLTNode *node = node_make(SLTNodeTypeBinaryOperation);
+       node->binaryOperationOperator = op;
+       node->binaryOperationLHS = lhs;
+       node->binaryOperationRHS = rhs;
+       return node;
+}
+
+SLTNode *sltNodeMakeOperator(SLTOperatorType type) {
+       SLTNode *node = node_make(SLTNodeTypeOperator);
+       node->operatorType = type;
+       return node;
+}
+
+SLTNode *sltNodeMakeAssignment(SLTNode *target, SLTNode *source) {
+       SLTNode *node = node_make(SLTNodeTypeAssignment);
+       node->assignmentTarget = target;
+       node->assignmentSource = source;
+       return node;
+}
+
+SLTNode *sltNodeMakeReturn(SLTNode *expression) {
+       SLTNode *node = node_make(SLTNodeTypeReturn);
+       node->returnExpression = expression;
+       return node;
+}
+
+SLTNode *sltNodeMakeSleep() {
+       SLTNode *node = node_make(SLTNodeTypeSleep);
+       return node;
+}
+
+SLTNode *sltNodeMakeBreak() {
+       SLTNode *node = node_make(SLTNodeTypeBreak);
+       return node;
+}
+
+SLTNode *sltNodeMakeForIteration(SLTNode *initialExpression, SLTNode *preValidExpression, SLTNode *loopExpression, SLTNode *statement) {
+       SLTNode *node = node_make(SLTNodeTypeForIteration);
+       node->iterationInitialExpression = initialExpression;
+       node->iterationPreValidExpression = preValidExpression;
+       node->iterationLoopExpression = loopExpression;
+       node->iterationStatement = statement;
+       return node;
+}
+
+SLTNode *sltNodeMakeDoIteration(SLTNode *postValidExpression, SLTNode *statement) {
+       SLTNode *node = node_make(SLTNodeTypeDoIteration);
+       node->iterationPostValidExpression = postValidExpression;
+       node->iterationStatement = statement;
+       return node;
+}
+
+SLTNode *sltNodeMakeWhileIteration(SLTNode *preValidExpression, SLTNode *statement) {
+       SLTNode *node = node_make(SLTNodeTypeWhileIteration);
+       node->iterationPreValidExpression = preValidExpression;
+       node->iterationStatement = statement;
+       return node;
+}
+
+SLTNode *sltNodeMakeSelection(SLTNode *validExpression, SLTNode *validStatement, SLTNode *invalidStatement) {
+       SLTNode *node = node_make(SLTNodeTypeSelection);
+       node->selectionValidExpression = validExpression;
+       node->selectionValidStatement = validStatement;
+       node->selectionInvalidStatement = invalidStatement;
+       return node;
+}
+
+SLTNode *sltNodeMakeStatementBlock(SLTNode *contents) {
+       SLTNode *node = node_make(SLTNodeTypeStatementBlock);
+       node->statementBlockContents = contents;
+       return node;
+}
+
+SLTNode *sltNodeMakeVariableDefinition(SLTNode *type, SLTNode *identifier, SLTNode *defaultExpression) {
+       SLTNode *node = node_make(SLTNodeTypeVariableDefinition);
+       node->variableDefinitionType = type;
+       node->variableDefinitionIdentifier = identifier;
+       node->variableDefinitionDefaultExpression = defaultExpression;
+       return node;
+}
+
+SLTNode *sltNodeMakeTypeDefinition(SLTNode *identifier, SLTNode *members) {
+       SLTNode *node = node_make(SLTNodeTypeTypeDefinition);
+       node->typeDefinitionIdentifier = identifier;
+       node->typeDefinitionMembers = members;
+       return node;
+}
+
+SLTNode *sltNodeMakeTypeMemberDefinition(SLTNode *type, SLTNode *identifier) {
+       SLTNode *node = node_make(SLTNodeTypeTypeMemberDefinition);
+       node->typeMemberDefinitionType = type;
+       node->typeMemberDefinitionIdentifier = identifier;
+       return node;
+}
+
+SLTNode *sltNodeMakeFunctionDefinition(SLTNode *type, SLTNode *identifier, SLTNode *parameters, SLTNode *body) {
+       SLTNode *node = node_make(SLTNodeTypeFunctionDefinition);
+       node->functionDefinitionType = type;
+       node->functionDefinitionIdentifier = identifier;
+       node->functionDefinitionParameters = parameters;
+       node->functionDefinitionBody = body;
+       return node;
+}
+
+SLTNode *sltNodeMakeFunctionParameterDefinition(SLTNode *type, SLTNode *identifier) {
+       SLTNode *node = node_make(SLTNodeTypeFunctionParameterDefinition);
+       node->functionParameterDefinitionType = type;
+       node->functionParameterDefinitionIdentifier = identifier;
+       return node;
+}
+
+SLTNode *sltNodeMakeModule(SLTNode *statementsAndDefinitions) {
+       SLTNode *node = node_make(SLTNodeTypeModule);
+       node->moduleStatementsAndDefinitions = statementsAndDefinitions;
+       return node;
+}
+
+SLTNode *sltNodeMakeSequence(SLTNode *head, SLTNode *item) {
+       assert(head == NULL || head->type == SLTNodeTypeSequence);
+
+       if (item != NULL) {
+               SLTNode *node = node_make(SLTNodeTypeSequence);
+               node->sequenceNode = item;
+               node->sequenceNext = NULL;
+
+               if (head == NULL) {
+                       head = node;
+               } else {
+                       SLTNode *pos = head;
+                       while (pos->sequenceNext != NULL) pos = pos->sequenceNext;
+                       pos->sequenceNext = node;
+               }
+       }
+
+       return head;
+}
diff --git a/runtime/src/sun/tree/node.h b/runtime/src/sun/tree/node.h
new file mode 100644 (file)
index 0000000..11e4076
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef SUN_TREE_NODE_H
+#define SUN_TREE_NODE_H
+
+#include <sun/tree/operator_type.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct SLTNode SLTNode;
+
+extern const char *sltNodeToString(SLTNode *node);
+
+extern SLTNode *sltNodeMakeIdentifier(const char *name);
+
+extern SLTNode *sltNodeMakeBoolean(bool value);
+extern SLTNode *sltNodeMakeInteger(int value);
+extern SLTNode *sltNodeMakeRawInteger(int value);
+extern SLTNode *sltNodeMakeFloat(float value);
+extern SLTNode *sltNodeMakeString(const char *value);
+extern SLTNode *sltNodeMakeKey(const char *value);
+
+extern SLTNode *sltNodeMakeCompound(SLTNode *expression);
+
+extern SLTNode *sltNodeMakeArgument(SLTNode *expression);
+
+extern SLTNode *sltNodeMakeArrayAccess(SLTNode *array, SLTNode *access);
+extern SLTNode *sltNodeMakeTypeAccess(SLTNode *type, SLTNode *access);
+
+extern SLTNode *sltNodeMakeFunctionCall(SLTNode *function, SLTNode *arguments);
+
+extern SLTNode *sltNodeMakeUnaryOperation(SLTNode *op, SLTNode *operand);
+extern SLTNode *sltNodeMakeBinaryOperation(SLTNode *op, SLTNode *lhs, SLTNode *rhs);
+
+extern SLTNode *sltNodeMakeOperator(SLTOperatorType type);
+
+extern SLTNode *sltNodeMakeAssignment(SLTNode *target, SLTNode *source);
+
+extern SLTNode *sltNodeMakeReturn(SLTNode *expression);
+extern SLTNode *sltNodeMakeSleep(void);
+extern SLTNode *sltNodeMakeBreak(void);
+
+extern SLTNode *sltNodeMakeForIteration(SLTNode *initialExpression, SLTNode *preValidExpression, SLTNode *loopExpression, SLTNode *statement);
+extern SLTNode *sltNodeMakeDoIteration(SLTNode *postValidExpression, SLTNode *statement);
+extern SLTNode *sltNodeMakeWhileIteration(SLTNode *preValidExpression, SLTNode *statement);
+
+extern SLTNode *sltNodeMakeSelection(SLTNode *validExpression, SLTNode *validStatement, SLTNode *invalidStatement);
+
+extern SLTNode *sltNodeMakeStatementBlock(SLTNode *contents);
+
+extern SLTNode *sltNodeMakeVariableDefinition(SLTNode *type, SLTNode *identifier, SLTNode *defaultExpression);
+
+extern SLTNode *sltNodeMakeTypeDefinition(SLTNode *identifier, SLTNode *members);
+extern SLTNode *sltNodeMakeTypeMemberDefinition(SLTNode *type, SLTNode *identifier);
+
+extern SLTNode *sltNodeMakeFunctionDefinition(SLTNode *type, SLTNode *identifier, SLTNode *parameters, SLTNode *body);
+extern SLTNode *sltNodeMakeFunctionParameterDefinition(SLTNode *type, SLTNode *identifier);
+
+extern SLTNode *sltNodeMakeModule(SLTNode *statementsAndDefinitions);
+
+extern SLTNode *sltNodeMakeSequence(SLTNode *head, SLTNode *item);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/tree/node_internal.h b/runtime/src/sun/tree/node_internal.h
new file mode 100644 (file)
index 0000000..687a216
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef SUN_TREE_NODE_INTERNAL_H
+#define SUN_TREE_NODE_INTERNAL_H
+
+#include <sun/tree/node.h>
+
+#include <sun/tree/data_type.h>
+#include <sun/tree/node_type.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SLTNode {
+       SLTNodeType type;
+       SLTDataType dataType;
+
+       union {
+               struct {
+                       char *identifierStringValue;
+                       unsigned int identifierStringKeyValue;
+               };
+
+               struct {
+                       bool booleanValue;
+               };
+
+               struct {
+                       int integerValue;
+               };
+
+               struct {
+                       float floatValue;
+               };
+
+               struct {
+                       char *stringValue;
+               };
+
+               struct {
+                       unsigned int keyValue;
+               };
+
+               struct {
+                       SLTNode *compoundSubexpression;
+               };
+
+               struct {
+                       SLTNode *argumentExpression;
+               };
+
+               struct {
+                       SLTNode *arrayAccessArray;
+                       SLTNode *arrayAccessAccess;
+               };
+
+               struct {
+                       SLTNode *typeAccessType;
+                       SLTNode *typeAccessAccess;
+               };
+
+               struct {
+                       SLTNode *functionCallFunction;
+                       SLTNode *functionCallArguments;
+               };
+
+               struct {
+                       SLTNode *unaryOperationOperator;
+                       SLTNode *unaryOperationOperand;
+               };
+
+               struct {
+                       SLTNode *binaryOperationOperator;
+                       SLTNode *binaryOperationLHS;
+                       SLTNode *binaryOperationRHS;
+               };
+
+               struct {
+                       SLTOperatorType operatorType;
+               };
+
+               struct {
+                       SLTNode *assignmentTarget;
+                       SLTNode *assignmentSource;
+               };
+
+               struct {
+                       SLTNode *returnExpression;
+               };
+
+               struct {
+                       SLTNode *iterationInitialExpression;
+                       SLTNode *iterationPreValidExpression;
+                       SLTNode *iterationPostValidExpression;
+                       SLTNode *iterationLoopExpression;
+                       SLTNode *iterationStatement;
+               };
+
+               struct {
+                       SLTNode *selectionValidExpression;
+                       SLTNode *selectionValidStatement;
+                       SLTNode *selectionInvalidStatement;
+               };
+
+               struct {
+                       SLTNode *statementBlockContents;
+               };
+
+               struct {
+                       SLTNode *variableDefinitionType;
+                       SLTNode *variableDefinitionIdentifier;
+                       SLTNode *variableDefinitionDefaultExpression;
+               };
+
+               struct {
+                       SLTNode *typeDefinitionIdentifier;
+                       SLTNode *typeDefinitionMembers;
+               };
+
+               struct {
+                       SLTNode *typeMemberDefinitionType;
+                       SLTNode *typeMemberDefinitionIdentifier;
+               };
+
+               struct {
+                       SLTNode *functionDefinitionType;
+                       SLTNode *functionDefinitionIdentifier;
+                       SLTNode *functionDefinitionParameters;
+                       SLTNode *functionDefinitionBody;
+               };
+
+               struct {
+                       SLTNode *functionParameterDefinitionType;
+                       SLTNode *functionParameterDefinitionIdentifier;
+               };
+
+               struct {
+                       SLTNode *moduleStatementsAndDefinitions;
+               };
+
+               struct {
+                       SLTNode *sequenceNode;
+                       SLTNode *sequenceNext;
+               };
+       };
+
+       void *metadata;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/tree/node_type.c b/runtime/src/sun/tree/node_type.c
new file mode 100644 (file)
index 0000000..1dacf19
--- /dev/null
@@ -0,0 +1,96 @@
+#include "node_type.h"
+
+const char *sltNodeTypeToString(SLTNodeType nodeType) {
+       switch(nodeType) {
+               default:
+                       case SLTNodeTypeUnknown:
+                       return "<unknown>";
+
+               case SLTNodeTypeIdentifier:
+                       return "Identifier";
+
+               case SLTNodeTypeBoolean:
+                       return "Boolean";
+
+               case SLTNodeTypeInteger:
+                       return "Integer";
+
+               case SLTNodeTypeRawInteger:
+                       return "Integer (Raw)";
+                       
+               case SLTNodeTypeFloat:
+                       return "Float";
+
+               case SLTNodeTypeString:
+                       return "String";
+
+               case SLTNodeTypeCompound:
+                       return "Compound";
+
+               case SLTNodeTypeArgument:
+                       return "Argument";
+
+               case SLTNodeTypeArrayAccess:
+                       return "ArrayAccess";
+
+               case SLTNodeTypeTypeAccess:
+                       return "TypeAccess";
+               
+               case SLTNodeTypeFunctionCall:
+                       return "FunctionCall";
+
+               case SLTNodeTypeUnaryOperation:
+                       return "UnaryOperation";
+
+               case SLTNodeTypeBinaryOperation:
+                       return "BinaryOperation";
+
+               case SLTNodeTypeOperator:
+                       return "Operator";
+
+               case SLTNodeTypeAssignment:
+                       return "Assignment";
+
+               case SLTNodeTypeReturn:
+                       return "Return";
+
+               case SLTNodeTypeSleep:
+                       return "Sleep";
+
+               case SLTNodeTypeBreak:
+                       return "Break";
+
+               //case SLTNodeTypeIteration:
+               case SLTNodeTypeForIteration:
+               case SLTNodeTypeDoIteration:
+               case SLTNodeTypeWhileIteration:
+                       return "Iteration";
+
+               case SLTNodeTypeSelection:
+                       return "Selection";
+
+               case SLTNodeTypeStatementBlock:
+                       return "StatementBlock";
+
+               case SLTNodeTypeVariableDefinition:
+                       return "VariableDefinition";
+
+               case SLTNodeTypeTypeDefinition:
+                       return "TypeDefinition";
+
+               case SLTNodeTypeTypeMemberDefinition:
+                       return "TypeMemberDefinition";
+
+               case SLTNodeTypeFunctionDefinition:
+                       return "FunctionDefinition";
+
+               case SLTNodeTypeFunctionParameterDefinition:
+                       return "FunctionParameterDefinition";
+
+               case SLTNodeTypeModule:
+                       return "Module";
+
+               case SLTNodeTypeSequence:
+                       return "Sequence";
+       }
+}
diff --git a/runtime/src/sun/tree/node_type.h b/runtime/src/sun/tree/node_type.h
new file mode 100644 (file)
index 0000000..195d9e6
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef SUN_TREE_NODE_TYPE_H
+#define SUN_TREE_NODE_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum SLTNodeType {
+       SLTNodeTypeUnknown,
+
+       SLTNodeTypeIdentifier,
+
+       SLTNodeTypeBoolean,
+       SLTNodeTypeInteger,
+       SLTNodeTypeRawInteger,
+       SLTNodeTypeFloat,
+       SLTNodeTypeString,
+       SLTNodeTypeKey,
+
+       SLTNodeTypeCompound,
+
+       SLTNodeTypeArgument,
+
+       SLTNodeTypeArrayAccess,
+       SLTNodeTypeTypeAccess,
+
+       SLTNodeTypeFunctionCall,
+
+       SLTNodeTypeUnaryOperation,
+       SLTNodeTypeBinaryOperation,
+
+       SLTNodeTypeOperator,
+
+       SLTNodeTypeAssignment,
+
+       SLTNodeTypeReturn,
+       SLTNodeTypeSleep,
+       SLTNodeTypeBreak,
+
+       SLTNodeTypeForIteration,
+       SLTNodeTypeDoIteration,
+       SLTNodeTypeWhileIteration,
+
+       SLTNodeTypeSelection,
+
+       SLTNodeTypeStatementBlock,
+
+       SLTNodeTypeVariableDefinition,
+
+       SLTNodeTypeTypeDefinition,
+       SLTNodeTypeTypeMemberDefinition,
+
+       SLTNodeTypeFunctionDefinition,
+       SLTNodeTypeFunctionParameterDefinition,
+
+       SLTNodeTypeModule,
+
+       SLTNodeTypeSequence, // Meta-type, for sequence of other nodes.
+};
+typedef enum SLTNodeType SLTNodeType;
+static const SLTNodeType kSLTNodeTypeMax = SLTNodeTypeSequence;
+
+extern const char *sltNodeTypeToString(SLTNodeType nodeType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/tree/operator_type.c b/runtime/src/sun/tree/operator_type.c
new file mode 100644 (file)
index 0000000..8195d3a
--- /dev/null
@@ -0,0 +1,81 @@
+#include "operator_type.h"
+
+const char *sltOperatorTypeToString(SLTOperatorType operatorType) {
+       switch (operatorType) {
+               default:
+               case SLTOperatorTypeUnknown:
+                       return "<unknown>";
+
+               case SLTOperatorTypeAdd:
+                       return "Add";
+
+               case SLTOperatorTypeSubtract:
+                       return "Subtract";
+
+               case SLTOperatorTypeMultiply:
+                       return "Multiply";
+
+               case SLTOperatorTypeDivide:
+                       return "Divide";
+
+               case SLTOperatorTypeModulo:
+                       return "Modulo";
+
+               case SLTOperatorTypePositive:
+                       return "Positive";
+
+               case SLTOperatorTypeNegative:
+                       return "Negative";
+
+               case SLTOperatorTypeBitwiseAnd:
+                       return "BitwiseAnd";
+
+               case SLTOperatorTypeBitwiseOr:
+                       return "BitwiseOr";
+
+               case SLTOperatorTypeBitwiseXor:
+                       return "BitwiseXor";
+
+               case SLTOperatorTypeBitwiseNot:
+                       return "BitwiseNot";
+
+               case SLTOperatorTypeLogicalAnd:
+                       return "LogicalAnd";
+
+               case SLTOperatorTypeLogicalOr:
+                       return "LogicalOr";
+
+               case SLTOperatorTypeLogicalNot:
+                       return "LogicalNot";
+
+               case SLTOperatorTypeEqual:
+                       return "Equal";
+
+               case SLTOperatorTypeNotEqual:
+                       return "NotEqual";
+
+               case SLTOperatorTypeLessThan:
+                       return "LessThan";
+
+               case SLTOperatorTypeLessThanEqual:
+                       return "LessThanEqual";
+
+               case SLTOperatorTypeGreaterThan:
+                       return "GreaterThan";
+
+               case SLTOperatorTypeGreaterThanEqual:
+                       return "GreaterThanEqual";
+
+               /*case SLTOperatorTypePreIncrement:
+                       return "PreIncrement";
+
+               case SLTOperatorTypePreDecrement:
+                       return "PreDecrement";
+
+               case SLTOperatorTypePostIncrement:
+                       return "PostIncrement";
+
+               case SLTOperatorTypePostDecrement:
+                       return "PostDecrement";*/
+       }
+}
diff --git a/runtime/src/sun/tree/operator_type.h b/runtime/src/sun/tree/operator_type.h
new file mode 100644 (file)
index 0000000..3a5569e
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef SUN_TREE_OPERATOR_TYPE_H
+#define SUN_TREE_OPERATOR_TYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum SLTOperatorType {
+       SLTOperatorTypeUnknown,
+
+       SLTOperatorTypeAdd,
+       SLTOperatorTypeSubtract,
+       SLTOperatorTypeMultiply,
+       SLTOperatorTypeDivide,
+       SLTOperatorTypeModulo,
+
+       SLTOperatorTypePositive,
+       SLTOperatorTypeNegative,
+
+       SLTOperatorTypeBitwiseAnd,
+       SLTOperatorTypeBitwiseOr,
+       SLTOperatorTypeBitwiseXor,
+       SLTOperatorTypeBitwiseNot,
+
+       SLTOperatorTypeLogicalAnd,
+       SLTOperatorTypeLogicalOr,
+       SLTOperatorTypeLogicalNot,
+
+       SLTOperatorTypeEqual,
+       SLTOperatorTypeNotEqual,
+       SLTOperatorTypeLessThan,
+       SLTOperatorTypeLessThanEqual,
+       SLTOperatorTypeGreaterThan,
+       SLTOperatorTypeGreaterThanEqual,
+
+       //SLTOperatorTypePreIncrement,
+       //SLTOperatorTypePreDecrement,
+       //SLTOperatorTypePostIncrement,
+       //SLTOperatorTypePostDecrement,
+};
+typedef enum SLTOperatorType SLTOperatorType;
+
+extern const char *sltOperatorTypeToString(SLTOperatorType operatorType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/tree/tree.c b/runtime/src/sun/tree/tree.c
new file mode 100644 (file)
index 0000000..118f9c6
--- /dev/null
@@ -0,0 +1,185 @@
+#include "tree.h"
+
+#include "node_internal.h"
+#include "node_type.h"
+
+#include <stdlib.h>
+
+typedef struct {
+       SLTTreeIteratorCallback callback;
+       SLTTreeIteratorCallback postCallback;
+       void *userParameter;
+} TreeIteratorCallbackDetails;
+
+static SLTNode *treeIterateCallback(SLTNode *node, void *extra);
+static SLTNode *treeIteratePostCallback(SLTNode *node, void *extra);
+
+void sltTreeIterate(SLTNode *root, SLTTreeIteratorCallback callback, SLTTreeIteratorCallback postCallback, void *userParameter) {
+       TreeIteratorCallbackDetails details = {
+               .callback = callback,
+               .postCallback = postCallback,
+               .userParameter = userParameter,
+       };
+       sltTreeMap(root, (callback != NULL) ? treeIterateCallback : NULL, (postCallback != NULL) ? treeIteratePostCallback : NULL, &details);
+}
+
+SLTNode *sltTreeMap(SLTNode *root, SLTTreeMapCallback callback, SLTTreeMapCallback postCallback, void *userParameter){
+       SLTNode *n = root;
+
+       if (callback != NULL && n != NULL && n->type != SLTNodeTypeSequence) {
+               n = callback(n, userParameter);
+       }
+
+       if (n != NULL) {
+               switch (n->type) {
+                       default:
+                       case SLTNodeTypeUnknown:
+                               /* Produce error? */
+                               break;
+
+                       /* These have no child nodes */
+                       case SLTNodeTypeIdentifier:
+                       case SLTNodeTypeInteger:
+                       case SLTNodeTypeFloat:
+                       case SLTNodeTypeString:
+                       case SLTNodeTypeOperator:
+                               break;
+
+                       case SLTNodeTypeCompound:
+                               n->compoundSubexpression = sltTreeMap(n->compoundSubexpression, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeArgument:
+                               n->argumentExpression = sltTreeMap(n->argumentExpression, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeArrayAccess:
+                               n->arrayAccessArray = sltTreeMap(n->arrayAccessArray, callback, postCallback, userParameter);
+                               n->arrayAccessAccess = sltTreeMap(n->arrayAccessAccess, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeTypeAccess:
+                               n->typeAccessType = sltTreeMap(n->typeAccessType, callback, postCallback, userParameter);
+                               n->typeAccessAccess = sltTreeMap(n->typeAccessAccess, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeFunctionCall:
+                               n->functionCallFunction = sltTreeMap(n->functionCallFunction, callback, postCallback, userParameter);
+                               n->functionCallArguments = sltTreeMap(n->functionCallArguments, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeUnaryOperation:
+                               n->unaryOperationOperator = sltTreeMap(n->unaryOperationOperator, callback, postCallback, userParameter);
+                               n->unaryOperationOperand = sltTreeMap(n->unaryOperationOperand, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeBinaryOperation:
+                               n->binaryOperationOperator = sltTreeMap(n->binaryOperationOperator, callback, postCallback, userParameter);
+                               n->binaryOperationLHS = sltTreeMap(n->binaryOperationLHS, callback, postCallback, userParameter);
+                               n->binaryOperationRHS = sltTreeMap(n->binaryOperationRHS, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeAssignment:
+                               n->assignmentTarget = sltTreeMap(n->assignmentTarget, callback, postCallback, userParameter);
+                               n->assignmentSource = sltTreeMap(n->assignmentSource, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeReturn:
+                               n->returnExpression = sltTreeMap(n->returnExpression, callback, postCallback, userParameter);
+                               break;
+
+                       //case SLTNodeTypeIteration:
+                       case SLTNodeTypeForIteration:
+                       case SLTNodeTypeDoIteration:
+                       case SLTNodeTypeWhileIteration:
+                               n->iterationInitialExpression = sltTreeMap(n->iterationInitialExpression, callback, postCallback, userParameter);
+                               n->iterationPreValidExpression = sltTreeMap(n->iterationPreValidExpression, callback, postCallback, userParameter);
+                               n->iterationPostValidExpression = sltTreeMap(n->iterationPostValidExpression, callback, postCallback, userParameter);
+                               n->iterationLoopExpression = sltTreeMap(n->iterationLoopExpression, callback, postCallback, userParameter);
+                               n->iterationStatement = sltTreeMap(n->iterationStatement, callback, postCallback, userParameter);
+                               break;
+                       case SLTNodeTypeSelection:
+                               n->selectionValidExpression = sltTreeMap(n->selectionValidExpression, callback, postCallback, userParameter);
+                               n->selectionValidStatement = sltTreeMap(n->selectionValidStatement, callback, postCallback, userParameter);
+                               n->selectionInvalidStatement = sltTreeMap(n->selectionInvalidStatement, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeStatementBlock:
+                               n->statementBlockContents = sltTreeMap(n->statementBlockContents, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeVariableDefinition:
+                               n->variableDefinitionType = sltTreeMap(n->variableDefinitionType, callback, postCallback, userParameter);
+                               n->variableDefinitionIdentifier = sltTreeMap(n->variableDefinitionIdentifier, callback, postCallback, userParameter);
+                               n->variableDefinitionDefaultExpression = sltTreeMap(n->variableDefinitionDefaultExpression, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeTypeDefinition:
+                               n->typeDefinitionIdentifier = sltTreeMap(n->typeDefinitionIdentifier, callback, postCallback, userParameter);
+                               n->typeDefinitionMembers = sltTreeMap(n->typeDefinitionMembers, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeTypeMemberDefinition:
+                               n->typeMemberDefinitionType = sltTreeMap(n->typeMemberDefinitionType, callback, postCallback, userParameter);
+                               n->typeMemberDefinitionIdentifier = sltTreeMap(n->typeMemberDefinitionIdentifier, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeFunctionDefinition:
+                               n->functionDefinitionType = sltTreeMap(n->functionDefinitionType, callback, postCallback, userParameter);
+                               n->functionDefinitionIdentifier = sltTreeMap(n->functionDefinitionIdentifier, callback, postCallback, userParameter);
+                               n->functionDefinitionParameters = sltTreeMap(n->functionDefinitionParameters, callback, postCallback, userParameter);
+                               n->functionDefinitionBody = sltTreeMap(n->functionDefinitionBody, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeFunctionParameterDefinition:
+                               n->functionParameterDefinitionType = sltTreeMap(n->functionParameterDefinitionType, callback, postCallback, userParameter);
+                               n->functionParameterDefinitionIdentifier = sltTreeMap(n->functionParameterDefinitionIdentifier, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeModule:
+                               n->moduleStatementsAndDefinitions = sltTreeMap(n->moduleStatementsAndDefinitions, callback, postCallback, userParameter);
+                               break;
+
+                       case SLTNodeTypeSequence: {
+                               SLTNode  *readHead = n;
+                               SLTNode  *writeHead = n;
+                               SLTNode **writeLast = &n;
+
+                               *writeLast = NULL;
+
+                               while (readHead != NULL) {
+                                       writeHead->sequenceNode = sltTreeMap(readHead->sequenceNode, callback, postCallback, userParameter);
+                                       readHead = readHead->sequenceNext;
+
+                                       if (writeHead->sequenceNode != NULL) {
+                                               *writeLast = writeHead;
+                                               writeLast = &writeHead->sequenceNext;
+                                               writeHead = writeHead->sequenceNext;
+                                               *writeLast = NULL;
+                                       }
+                               }
+
+                               break;
+                       }
+               }
+       }
+
+       if (postCallback != NULL && n != NULL && n->type != SLTNodeTypeSequence) {
+               n = postCallback(n, userParameter);
+       }
+
+       return n;
+}
+
+SLTNode *treeIterateCallback(SLTNode *node, void *extra) {
+       TreeIteratorCallbackDetails *details = (TreeIteratorCallbackDetails *)extra;
+       details->callback(node, details->userParameter);
+       return node;
+}
+
+SLTNode *treeIteratePostCallback(SLTNode *node, void *extra) {
+       TreeIteratorCallbackDetails *details = (TreeIteratorCallbackDetails *)extra;
+       details->postCallback(node, details->userParameter);
+       return node;
+}
diff --git a/runtime/src/sun/tree/tree.h b/runtime/src/sun/tree/tree.h
new file mode 100644 (file)
index 0000000..366e2ad
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef SUN_TREE_TREE_H
+#define SUN_TREE_TREE_H
+
+#include <sun/tree/node.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*SLTTreeIteratorCallback)(SLTNode *node, void *userParameter);
+typedef SLTNode *(*SLTTreeMapCallback)(SLTNode *node, void *userParameter);
+
+extern void sltTreeIterate(SLTNode *root, SLTTreeIteratorCallback callback, SLTTreeIteratorCallback postCallback, void *userParameter);
+extern SLTNode *sltTreeMap(SLTNode *root, SLTTreeMapCallback callback, SLTTreeMapCallback postCallback, void *userParameter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/vm/fixed.c b/runtime/src/sun/vm/fixed.c
new file mode 100644 (file)
index 0000000..dba6b4d
--- /dev/null
@@ -0,0 +1,73 @@
+#include "fixed.h"
+
+#include <math.h>
+
+Fixed fixedSqrt(Fixed value) {
+       float f = FIXED_TO_FLOAT(value);
+       float f2 = sqrtf(f);
+       return FIXED_FROM_FLOAT(f2);
+       
+
+#if 0
+       Fixed root;
+
+       register unsigned long remHi, remLo, testDiv, count;
+
+       root.raw = 0;/* Clear root */
+       remHi = 0;/* Clear high part of partial remainder */
+       remLo = value.raw;/* Get argument into low part of partial remainder */
+       count = FIXED_FRACTIONAL_BITS;/* Load loop counter */
+       
+       do {
+               remHi = (remHi << FIXED_INTEGRAL_BITS) | (remLo >> FIXED_FRACTIONAL_BITS);
+               remLo <<= 2;  /* get 2 bits of arg */
+               root.raw <<= 1; /* Get ready for the next bit in the root */
+               testDiv = (root.raw << 1) + 1;/* Test radical */
+       
+               if (remHi >= testDiv) {
+                       remHi -= testDiv;
+                       root.raw++;
+               }
+       } while (count-- != 0);
+       
+       return(root);
+#endif
+}
+
+Fixed fixedSin(Fixed value) {
+       float f = FIXED_TO_FLOAT(value);
+       float f2 = sinf(f * M_PI * 2.0f);
+       return FIXED_FROM_FLOAT(f2);
+}
+
+Fixed fixedCos(Fixed value) {
+       float f = FIXED_TO_FLOAT(value);
+       float f2 = cosf(f * M_PI * 2.0f);
+       return FIXED_FROM_FLOAT(f2);
+}
+
+Fixed fixedAtan2(Fixed x, Fixed y) {
+       float f1 = FIXED_TO_FLOAT(y); // Notice swap
+       float f2 = FIXED_TO_FLOAT(x);
+       float f3 = atan2f(f1, f2);
+       float f4 = f3 / (M_PI * 2.0f);
+       return FIXED_FROM_FLOAT(f4);
+}
+
+Fixed fixedAbs(Fixed value) {
+       float f = FIXED_TO_FLOAT(value);
+       float f2 = fabsf(f);
+       return FIXED_FROM_FLOAT(f2);
+}
+
+Fixed fixedCeil(Fixed value) {
+       float f = FIXED_TO_FLOAT(value);
+       float f2 = ceilf(f);
+       return FIXED_FROM_FLOAT(f2);
+}
+
+Fixed fixedFloor(Fixed value) {
+       float f = FIXED_TO_FLOAT(value);
+       float f2 = floorf(f);
+       return FIXED_FROM_FLOAT(f2);
+}
diff --git a/runtime/src/sun/vm/fixed.h b/runtime/src/sun/vm/fixed.h
new file mode 100644 (file)
index 0000000..db36671
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef SUN_VM_FIXED_H
+#define SUN_VM_FIXED_H
+
+// Reference: https://en.wikipedia.org/wiki/Q_(number_format)
+//            http://www.superkits.net/whitepapers/Fixed%20Point%20Representation%20&%20Fractional%20Math.pdf
+
+#include <assert.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FIXED_FRACTIONAL_BITS 8
+#define FIXED_INTEGRAL_BITS 8
+
+#define FIXED_ONE (1 << FIXED_FRACTIONAL_BITS)
+
+typedef int32_t Fixed;
+static_assert(sizeof(Fixed) == sizeof(int32_t), "Fixed incorrect size");
+
+#define _fixed(v) ((Fixed)((v)))
+
+#define FIXED(x) (_fixed((x) * FIXED_ONE))
+#define FIXED_TO_INT(x) ((int)((int32_t)(x) / FIXED_ONE))
+
+#define FIXED_FROM_FLOAT(x) (_fixed((x) * (float)FIXED_ONE))
+#define FIXED_TO_FLOAT(x) ((float)((x) / (float)FIXED_ONE))
+
+#define fixedLT(lhs, rhs) ((int32_t)(lhs) < (int32_t)(rhs))
+#define fixedGT(lhs, rhs) ((int32_t)(lhs) > (int32_t)(rhs))
+
+#define fixedNegate(v) (_fixed(-(int32_t)(v)))
+
+#define fixedAdd(lhs, rhs) (_fixed((int32_t)(lhs) + (int32_t)(rhs)))
+#define fixedSubtract(lhs, rhs) (_fixed((int32_t)(lhs) - (int32_t)(rhs)))
+
+#define fixedMultiply(lhs, rhs) (_fixed((((int32_t)(lhs) * (int32_t)(rhs))) / FIXED_ONE))
+#define fixedDivide(lhs, rhs) (_fixed(((int32_t)(lhs * FIXED_ONE) / (int32_t)(rhs))))
+#define fixedMod(lhs, rhs) (_fixed((int32_t)(lhs) % (int32_t)(rhs)))
+
+static inline Fixed fixedSgn(Fixed v) {
+       return v == 0 ? 0 : (fixedGT(v, 0) ? FIXED(1) : FIXED(-1));
+}
+
+static inline Fixed fixedMin(Fixed lhs, Fixed rhs) {
+       return fixedLT(lhs, rhs) ? lhs : rhs;
+}
+
+static inline Fixed fixedMax(Fixed lhs, Fixed rhs) {
+       return fixedGT(lhs, rhs) ? lhs : rhs;
+}
+
+static inline Fixed fixedMid(Fixed val1, Fixed val2, Fixed val3) {
+       return fixedMin(fixedMin(fixedMax(val1, val2), fixedMax(val2, val3)), fixedMax(val1, val3));
+}
+
+static inline Fixed fixedClamp(Fixed a, Fixed b, Fixed v) {
+       return fixedMin(fixedMax(v, a), b);
+}
+
+static inline Fixed fixedUnclampedLerp(Fixed a, Fixed b, Fixed t) {
+       Fixed v = fixedSubtract(fixedMultiply(a, fixedSubtract(FIXED(1), t)), fixedMultiply(b, t));
+       return v;
+}
+
+static inline Fixed fixedUnclampedUnlerp(Fixed a, Fixed b, Fixed v) {
+       Fixed t = fixedDivide(fixedSubtract(v, a), fixedSubtract(b, a));
+       return t;
+}
+
+static inline Fixed fixedLerp(Fixed a, Fixed b, Fixed t) {
+       Fixed clampedT = fixedClamp(FIXED(0), FIXED(1), t);
+       Fixed v = fixedUnclampedLerp(a, b, clampedT);
+       return v;
+}
+
+static inline Fixed fixedUnlerp(Fixed a, Fixed b, Fixed v) {
+       Fixed t = fixedUnclampedUnlerp(a, b, v);
+       Fixed clampedT = fixedClamp(FIXED(0), FIXED(1), t);
+       return clampedT;
+}
+
+extern Fixed fixedSqrt(Fixed value);
+extern Fixed fixedSin(Fixed value);
+extern Fixed fixedCos(Fixed value);
+extern Fixed fixedAtan2(Fixed x, Fixed y);
+extern Fixed fixedAbs(Fixed value);
+extern Fixed fixedCeil(Fixed value);
+extern Fixed fixedFloor(Fixed value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/vm/instruction.c b/runtime/src/sun/vm/instruction.c
new file mode 100644 (file)
index 0000000..408d07b
--- /dev/null
@@ -0,0 +1,98 @@
+#include <sun/vm/instruction.h>
+
+#include <assert.h>
+
+static_assert(sizeof(SVMInstruction) == sizeof(SVMOpcode) + sizeof(SVMOperand) * 3, "invalid size");
+static_assert(sizeof(SVMOperand) == sizeof(uint32_t), "raw will not work...");
+
+const char *svmOpcodeToString(SVMOpcode opcode) {
+       switch(opcode) {
+               default:
+               case SVMOpcodeInvalid:
+                       return "<invalid>";
+
+               case SVMOpcodeMOV:
+                       return "MOV";
+
+               case SVMOpcodeSET:
+                       return "SET";
+
+               case SVMOpcodeINV:
+                       return "INV";
+
+               case SVMOpcodeBNOT:
+                       return "BNOT";
+
+               case SVMOpcodeNOT:
+                       return "NOT";
+
+               case SVMOpcodeADD:
+                       return "ADD";
+
+               case SVMOpcodeSUB:
+                       return "SUB";
+
+               case SVMOpcodeMUL:
+                       return "MUL";
+
+               case SVMOpcodeDIV:
+                       return "DIV";
+
+               case SVMOpcodeMOD:
+                       return "MOD";
+
+               case SVMOpcodeBAND:
+                       return "BAND";
+
+               case SVMOpcodeBOR:
+                       return "BOR";
+
+               case SVMOpcodeBXOR:
+                       return "BXOR";
+
+               case SVMOpcodeAND:
+                       return "AND";
+
+               case SVMOpcodeOR:
+                       return "OR";
+
+               case SVMOpcodeEQ:
+                       return "EQ";
+
+               case SVMOpcodeNEQ:
+                       return "NEQ";
+
+               case SVMOpcodeLT:
+                       return "LT";
+
+               case SVMOpcodeLTEQ:
+                       return "LTEQ";
+
+               case SVMOpcodeGT:
+                       return "GT";
+
+               case SVMOpcodeGTEQ:
+                       return "GTEQ";
+
+               case SVMOpcodeSLEEP:
+                       return "SLEEP";
+
+               case SVMOpcodeSTK:
+                       return "STK";
+
+               case SVMOpcodePOPJUMP:
+                       return "POPJUMP";
+
+               case SVMOpcodeJUMP:
+                       return "JUMP";
+
+               case SVMOpcodePUSHJUMP:
+                       return "PUSHJUMP";
+
+               case SVMOpcodeCALL:
+                       return "CALL";
+
+               case SVMOpcodeJT:
+                       return "JT";
+       }
+}
diff --git a/runtime/src/sun/vm/instruction.h b/runtime/src/sun/vm/instruction.h
new file mode 100644 (file)
index 0000000..4ecefd7
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef SUN_VM_INSTRUCTION_H
+#define SUN_VM_INSTRUCTION_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <sun/vm/fixed.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum SVMOpcode {
+       SVMOpcodeInvalid,
+
+       SVMOpcodeMOV,
+       SVMOpcodeSET,
+
+       SVMOpcodeINV,
+       SVMOpcodeBNOT,
+       SVMOpcodeNOT,
+       SVMOpcodeADD,
+       SVMOpcodeSUB,
+       SVMOpcodeMUL,
+       SVMOpcodeDIV,
+       SVMOpcodeMOD,
+       SVMOpcodeBAND,
+       SVMOpcodeBOR,
+       SVMOpcodeBXOR,
+       SVMOpcodeAND,
+       SVMOpcodeOR,
+       SVMOpcodeEQ,
+       SVMOpcodeNEQ,
+       SVMOpcodeLT,
+       SVMOpcodeLTEQ,
+       SVMOpcodeGT,
+       SVMOpcodeGTEQ,
+
+       SVMOpcodeSTK,
+
+       SVMOpcodeSLEEP,
+       SVMOpcodePOPJUMP,
+       SVMOpcodeJUMP,
+       SVMOpcodePUSHJUMP,
+       SVMOpcodeCALL,
+
+       SVMOpcodeJT,
+};
+typedef enum SVMOpcode SVMOpcode;
+
+extern const char *svmOpcodeToString(SVMOpcode opcode);
+
+typedef int32_t SVMStackOffset;
+typedef Fixed/*float*/ SVMFloat;
+typedef Fixed/*int32_t*/ SVMInteger;
+typedef uint32_t SVMPointer;
+
+union SVMOperand {
+       SVMStackOffset stackOffset;
+       SVMFloat floatLiteral;
+       SVMInteger integerLiteral;
+       SVMPointer pointerLiteral; // Strings, function pointer
+       int32_t __raw;
+};
+typedef union SVMOperand SVMOperand;
+
+struct SVMInstruction {
+       SVMOpcode opcode;
+       union __attribute__((__packed__)) {
+               struct __attribute__((__packed__)) {
+                       SVMOperand dst;
+                       SVMOperand p1;
+                       SVMOperand p2;
+               };
+
+               SVMOperand operands[3];
+       };
+};
+typedef struct SVMInstruction SVMInstruction;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/vm/vm.c b/runtime/src/sun/vm/vm.c
new file mode 100644 (file)
index 0000000..1d80218
--- /dev/null
@@ -0,0 +1,335 @@
+#include "vm_internal.h"
+
+#include <string.h> // memcpy
+#include <stdio.h> // printf, fixme, remove
+#include <math.h> // fmodf, fixme, remove
+
+//struct SVMVM {
+////   SVMVMConfiguration configuration;
+//};
+
+#define SVMVMMaxStack 128
+#define SVMVMMaxPCStack 32
+
+struct SVMModuleInstance {
+       //SVMVM *vm;
+       SVMFunctionLookupCallback lookupCallback;
+       SVMModule *module;
+       void *userParam;
+
+       char *strings;
+       SVMInstruction *instructions;
+       
+       uint32_t currentStackIdx;
+       SVMOperand stack[SVMVMMaxStack];
+
+       uint32_t currentPCStackIdx;
+       SVMPointer pcStack[SVMVMMaxPCStack];
+};
+
+//SVMVM *svmCreateVM(const SVMVMConfiguration *configuration) {
+//     SVMVM *vm = configuration->malloc(sizeof(SVMVM));
+//     memcpy(&vm->configuration, configuration, sizeof(SVMVMConfiguration));
+//     return vm;
+//}
+
+
+//SVMModuleInstance *svmCreateModuleInstance(SVMVM *vm, SVMModule *module, void *userParam) {
+//     SVMModuleInstance *instance = vm->configuration.malloc(sizeof(SVMModuleInstance));
+//     instance->vm = vm;
+//     instance->module = module;
+//     instance->userParam = userParam;
+//     instance->strings = (char *)((void *)module + sizeof(SVMModule));
+//     instance->instructions = (SVMInstruction *)((void *)module + sizeof(SVMModule) + module->stringBlobLength);
+//     instance->currentStackIdx = 0;
+//     instance->currentPCStackIdx = 0;
+//     instance->pcStack[0] = 0;
+//     return instance;
+//}
+
+
+size_t svmGetModuleInstanceSize(SVMModule *module) {
+       return sizeof(SVMModuleInstance);
+}
+
+SVMModuleInstance *svnResetModuleInstanceMemory(SVMModule *module, void *memory, void *userParameter, SVMFunctionLookupCallback lookupCallback) {
+       SVMModuleInstance *instance = (SVMModuleInstance *)memory;
+       instance->lookupCallback = lookupCallback;
+       instance->module = module;
+       instance->userParam = userParameter;
+       instance->strings = (char *)((void *)module + sizeof(SVMModule));
+       instance->instructions = (SVMInstruction *)((void *)module + sizeof(SVMModule) + module->stringBlobLength);
+       instance->currentStackIdx = 0;
+       instance->currentPCStackIdx = 0;
+       instance->pcStack[0] = 0;
+       return instance;
+}
+
+void *svmGetModuleInstanceUserParameter(SVMModuleInstance *instance) {
+       return instance->userParam;
+}
+
+SVMRunOutcome svmRunModuleInstance(SVMModuleInstance *instance) {
+       #define resolveStack(v) ((v) >= 0 ? (instance->currentStackIdx + (v)) : (SVMVMMaxStack + (v)))
+
+       for (;;) {
+               if(instance->currentPCStackIdx < 0 || instance->currentPCStackIdx >= SVMVMMaxPCStack) {
+                       printf("EXCEEDED PCSTACK\n");
+                       return SVMRunOutcomeError;
+               }
+
+               SVMPointer *instructionIdxP = &instance->pcStack[instance->currentPCStackIdx];
+               SVMPointer instructionIdx = *instructionIdxP;
+
+               if (instructionIdx >= instance->module->numInstructions) return SVMRunOutcomeFinished;
+
+               // ...
+               SVMInstruction instruction = instance->instructions[instructionIdx];
+
+               switch (instruction.opcode) {
+                       case SVMOpcodeInvalid:
+                       default:
+                               printf("ERROR, FOUND BAD OPCODE: %u %u\n", instruction.opcode, instructionIdx);
+                               __builtin_unreachable();
+                               //exit(1);
+                               return SVMRunOutcomeError;
+
+                       case SVMOpcodeMOV: {
+                               int32_t raw = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = raw;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeSET: {
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = instruction.p1.__raw;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       // FIXME: Use of float
+                       case SVMOpcodeINV: {
+                               SVMFloat raw = instance->stack[resolveStack(instruction.p1.stackOffset)].floatLiteral;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].floatLiteral = fixedNegate(raw);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeBNOT: {
+                               int32_t raw = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = ~(raw);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeNOT: {
+                               int32_t raw = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = !(raw);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       // FIXME: Use of float
+                       case SVMOpcodeADD: {
+                               SVMFloat rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].floatLiteral;
+                               SVMFloat rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].floatLiteral;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].floatLiteral = fixedAdd(rawLHS, rawRHS);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       // FIXME: Use of float
+                       case SVMOpcodeSUB: {
+                               SVMFloat rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].floatLiteral;
+                               SVMFloat rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].floatLiteral;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].floatLiteral = fixedSubtract(rawLHS, rawRHS);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       // FIXME: Use of float
+                       case SVMOpcodeMUL: {
+                               SVMFloat rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].floatLiteral;
+                               SVMFloat rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].floatLiteral;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].floatLiteral = fixedMultiply(rawLHS, rawRHS);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       // FIXME: Use of float
+                       case SVMOpcodeDIV: {
+                               SVMFloat rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].floatLiteral;
+                               SVMFloat rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].floatLiteral;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].floatLiteral = fixedDivide(rawLHS, rawRHS);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       // FIXME: Use of float
+                       case SVMOpcodeMOD: {
+                               SVMFloat rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].floatLiteral;
+                               SVMFloat rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].floatLiteral;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].floatLiteral = fixedMod(rawLHS, rawRHS);
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeBAND: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS & rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeBOR: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS | rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeBXOR: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS ^ rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeAND: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS && rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeOR: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS || rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeEQ: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS == rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeNEQ: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS != rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeLT: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS < rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeLTEQ: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS <= rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeGT: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS > rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeGTEQ: {
+                               int32_t rawLHS = instance->stack[resolveStack(instruction.p1.stackOffset)].__raw;
+                               int32_t rawRHS = instance->stack[resolveStack(instruction.p2.stackOffset)].__raw;
+                               instance->stack[resolveStack(instruction.dst.stackOffset)].__raw = rawLHS >= rawRHS;
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeSTK: {
+                               SVMStackOffset offset = instruction.dst.stackOffset;
+                               instance->currentStackIdx += offset;
+                               if(instance->currentStackIdx < 0 || instance->currentStackIdx >= SVMVMMaxStack) {
+                                       printf("EXCEEDED STACK\n");
+                                       return SVMRunOutcomeError;
+                               }
+                               // assert >=0 ?
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeSLEEP: {
+                               *instructionIdxP = *instructionIdxP + 1;
+                               return SVMRunOutcomeSuspended;
+                       }
+
+                       case SVMOpcodePOPJUMP: {
+                               instance->currentPCStackIdx--;
+                               // assert >=0 ?
+                               break;
+                       }
+
+                       case SVMOpcodeJUMP: {
+                               *instructionIdxP = instruction.dst.pointerLiteral;
+                               break;
+                       }
+
+                       case SVMOpcodePUSHJUMP: {
+                               *instructionIdxP = *instructionIdxP + 1;
+                               instance->currentPCStackIdx++;
+                               instance->pcStack[instance->currentPCStackIdx] = instruction.dst.pointerLiteral;
+                               break;
+                       }
+
+                       case SVMOpcodeCALL: {
+//                             const char *name = svmGetString(instance, instruction.dst.pointerLiteral);
+                               SVMFunctionCallback function = instance->lookupCallback(instruction.dst.pointerLiteral, instance->userParam);
+                               if (function != NULL) {
+                                       int32_t parameterCount = (int32_t)instruction.p1.integerLiteral;
+                                       function(instance, parameterCount, &instance->stack[instance->currentStackIdx]); // FIXME
+                               }
+                               *instructionIdxP = *instructionIdxP + 1;
+                               break;
+                       }
+
+                       case SVMOpcodeJT: {
+                               int32_t value = instance->stack[resolveStack(instruction.dst.stackOffset)].__raw;
+                               if (value) {
+                                       *instructionIdxP = instruction.p1.pointerLiteral;
+                               } else {
+                                       *instructionIdxP = *instructionIdxP + 1;
+                               }
+                               
+                               break;
+                       }
+               }
+       }
+}
+
+const char *svmGetString(SVMModuleInstance *instance, int32_t ptr) {
+       return &instance->strings[ptr];
+}
+
+SVMPublic *svmGetPublicReference(SVMModule *instance, const char *nameFmt, ...) {
+
+}
+
+SVMOperand svmGetPublicValue(SVMModuleInstance *instance, int32_t ptr) {
+
+}
diff --git a/runtime/src/sun/vm/vm.h b/runtime/src/sun/vm/vm.h
new file mode 100644 (file)
index 0000000..ae6c9fb
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef SUN_VM_VM_H
+#define SUN_VM_VM_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <sun/vm/instruction.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct SVMVM SVMVM;
+
+typedef struct SVMModule SVMModule;
+typedef struct SVMModuleInstance SVMModuleInstance;
+
+typedef struct SVMModuleInstance SVMModuleInstance;
+
+typedef struct SVMPublic SVMPublic;
+
+typedef void *(*SVMCMallocCallback)(size_t size, void *userParameter);
+typedef void (*SVMFreeCallback)(void *memory, void *userParameter);
+
+typedef void (*SVMFunctionCallback)(SVMModuleInstance *instance, int32_t parameterCount, SVMOperand stack[]);
+typedef SVMFunctionCallback (*SVMFunctionLookupCallback)(uint32_t nameCRC, void *userParameter);
+
+typedef void (*SVMErrorCallback)(SVMModuleInstance *instance, const char *errorString, void *userParameter);
+
+//struct SVMVMConfiguration {
+//     SVMCMallocCallback malloc;
+//     SVMFreeCallback free;
+//     SVMCallFunctionCallback lookup;
+//     void *lookupUserParam;
+//};
+//typedef struct SVMVMConfiguration SVMVMConfiguration;
+
+enum SVMRunOutcome {
+       SVMRunOutcomeError,
+       SVMRunOutcomeSuspended,
+       SVMRunOutcomeFinished,
+};
+typedef enum SVMRunOutcome SVMRunOutcome;
+
+//extern SVMVM *svmCreateVM(const SVMVMConfiguration *configuration);
+
+//extern SVMModuleInstance *svmCreateModuleInstance(SVMVM *vm, SVMModule *module, void *userParam); // fixme, add stack memory??
+
+extern size_t svmGetModuleInstanceSize(SVMModule *module);
+
+extern SVMModuleInstance *svnResetModuleInstanceMemory(SVMModule *module, void *memory, void *userParameter, SVMFunctionLookupCallback lookupCallback);
+extern void *svmGetModuleInstanceUserParameter(SVMModuleInstance *instance);
+
+extern SVMRunOutcome svmRunModuleInstance(SVMModuleInstance *instance);
+
+extern const char *svmGetString(SVMModuleInstance *instance, int32_t ptr);
+
+extern SVMPublic *svmGetPublicReference(SVMModule *instance, const char *nameFmt, ...);
+extern SVMOperand svmGetPublicValue(SVMModuleInstance *instance, int32_t ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/runtime/src/sun/vm/vm_internal.h b/runtime/src/sun/vm/vm_internal.h
new file mode 100644 (file)
index 0000000..73e7b4b
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef SUN_VM_VM_INTERNAL_H
+#define SUN_VM_VM_INTERNAL_H
+
+#include <sun/vm/vm.h>
+
+#include <sun/vm/instruction.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SVMModule {
+       char header[4];
+       uint32_t magic;
+       uint32_t stringBlobLength;
+       uint32_t numFunctions;
+       uint32_t numInstructions;
+};
+
+struct SVMModuleFunctionDetails {
+       SVMPointer nameStringPtr;
+       SVMPointer functionInstruction;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7730e86
--- /dev/null
@@ -0,0 +1,31 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(suntest C)
+
+set(SUNCC ${PROJECT_BINARY_DIR}/../compiler/suncc)
+function(target_add_sun_sources TARGET)
+       foreach(SRC ${ARGN})
+               cmake_path(GET SRC STEM SUN_BASENAME)
+               set(SUN_OUTPUT ${PROJECT_BINARY_DIR}/${SUN_BASENAME}.c)
+
+               add_custom_command(
+                       OUTPUT ${SUN_OUTPUT}
+                       DEPENDS ${SRC}
+                       COMMAND ${SUNCC} ${SUN_OUTPUT} ${SRC}
+               )
+
+               list(APPEND SUN_C_SOURCES ${SUN_OUTPUT})
+       endforeach()
+
+       target_sources(${TARGET} PRIVATE ${SUN_C_SOURCES})
+endfunction()
+
+set(SUN_TEST_SOURCES
+       ${CMAKE_CURRENT_SOURCE_DIR}/test_1.sun
+)
+
+add_executable(suntest main.c)
+target_add_sun_sources(suntest ${SUN_TEST_SOURCES})
+#target_include_directories(suncc PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
+#target_link_libraries(suncc suncore)
+#target_link_libraries(suncc ${FLEX_LIBRARIES})
diff --git a/tests/main.c b/tests/main.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/test_1.sun b/tests/test_1.sun
new file mode 100644 (file)
index 0000000..4c7b8f2
--- /dev/null
@@ -0,0 +1,69 @@
+struct basic_type {
+       //string a;
+       int b;
+}
+
+int a;
+int b;
+
+while (true) {
+       print();
+       sleep;
+}
+
+/* OperatorTypeNegative
+
+sdlfkjlaskdfadsf
+
+
+
+void main(int a, int b, int c) {
+       int a = 10;
+       //string fish = "hekkopo";
+       print();;;;;;
+
+       if (a) {
+               fish(this, out);
+               set();
+       }
+
+int i;
+       for (i = 20; i <= 20; ++i) {
+               this();
+
+               sleep;
+       }
+
+int z;
+       while (z>10) {
+               fish();
+       }
+
+int x;
+       do {
+               egg();
+       } while (x < 100);
+
+
+       a = a + 1;
+       a = a - 1;
+       a = a * 1;
+       a = a / 1;
+
+       a+=1;
+       a-=1;
+       a*=1;
+       a/=1;
+
+       a = a && a;
+       a = a || a;
+       a = !a;
+
+       a = a & a;
+       a = a | a;
+       a = ~a;
+
+
+}
+
+*/
\ No newline at end of file