5 Commits
Author SHA1 Message Date
samsonium 567bf49d27 wip: working on dynamic linking
- Feat: add example for wrapping dynamically linked library
- Feat: add new tokens (import, extern, type, handle, struct, ref, out)
2026-10-28 21:43:56 +03:00
samsonium d93c315359 fix: clear first AST node if got error inside parse_program 2026-10-28 19:37:17 +03:00
samsonium e11089c90f feat: implement format strings 2026-10-28 17:57:18 +03:00
samsonium ea28c470d2 wip: begin dynamic library loading dev 2026-10-28 15:20:58 +03:00
samsonium 70bf63e2ea feat: add libffi cmake dependency 2026-10-28 00:31:09 +03:00
21 changed files with 525 additions and 86 deletions
+1
View File
@@ -5,6 +5,7 @@ skip is
skip -rfunction fzl_mk* skip -rfunction fzl_mk*
skip -rfunction fzl_free* skip -rfunction fzl_free*
skip -rfunction fzl_symt* skip -rfunction fzl_symt*
skip -rfunction fzl_linked*
skip add_const skip add_const
skip push_op skip push_op
skip push_word skip push_word
+9
View File
@@ -11,6 +11,13 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
endif() endif()
include_directories(include) include_directories(include)
include(FetchContent)
FetchContent_Declare(ffi
GIT_REPOSITORY "https://git.samsonium.dev/samsonium/libffi.git"
GIT_TAG "main"
)
FetchContent_MakeAvailable(ffi)
# Compiler # Compiler
add_executable(fzc add_executable(fzc
@@ -56,6 +63,8 @@ add_executable(fz
src/vm/fzl_vm_debug.c src/vm/fzl_vm_debug.c
src/vm/main.c) src/vm/main.c)
target_link_libraries(fz PRIVATE ffi_static dl)
# #
# ========== Tests ========== # ========== Tests ==========
# #
+38
View File
@@ -0,0 +1,38 @@
extern "libglfw" {
type GLFWwindow = handle;
type GLFWmonitor = handle;
struct GLFWvidmode {
int width;
int height;
int redBits;
int greenBits;
int blueBits;
int refreshRate;
}
/// GLFWvidmode*
type GLFWvidmodeRef = ref GLFWvidmode;
/// Create window with specified [width], [height] and [title]
fn glfw_mkWindow(
int width,
int height,
str title,
GLFWmonitor mon,
GLFWwindow shr
) GLFWwindow = "glfwCreateWindow";
/// Get videomode from monitor [mon]
fn glfw_getVideoMode(
GLFWmonitor mon
) GLFWvidmodeRef = "glfwGetVideoMode";
/// Get framebuffer [width] and [height]
fn glfw_getFrameBufferSize(
GLFWwindow win,
out int width,
out int height
) = "glfwGetFramebufferSize";
}
+2
View File
@@ -35,6 +35,8 @@ typedef enum
FZL_OPCODE_MOD = 0xA00006, // Get module of two numbers in dstack FZL_OPCODE_MOD = 0xA00006, // Get module of two numbers in dstack
FZL_OPCODE_NEG = 0xA00007, // Negotiate number in dstack FZL_OPCODE_NEG = 0xA00007, // Negotiate number in dstack
FZL_OPCODE_BUILD_STR = 0xA10001, // Build a string from N values in dstack
FZL_OPCODE_CMP_EQ = 0xB00001, // Equal FZL_OPCODE_CMP_EQ = 0xB00001, // Equal
FZL_OPCODE_CMP_NEQ = 0xB00002, // Not equal FZL_OPCODE_CMP_NEQ = 0xB00002, // Not equal
FZL_OPCODE_CMP_LT = 0xB00003, // Less than FZL_OPCODE_CMP_LT = 0xB00003, // Less than
+2
View File
@@ -6,6 +6,8 @@ typedef enum
FZL_TYPE_NULL, FZL_TYPE_NULL,
FZL_TYPE_OBJECT, FZL_TYPE_OBJECT,
FZL_TYPE_EXTERN_FN,
FZL_TYPE_STRING, FZL_TYPE_STRING,
FZL_TYPE_CHAR, FZL_TYPE_CHAR,
FZL_TYPE_BOOL, FZL_TYPE_BOOL,
+1
View File
@@ -11,6 +11,7 @@ typedef enum
FZL_NODETYPE_BLOCK, FZL_NODETYPE_BLOCK,
FZL_NODETYPE_CALL, FZL_NODETYPE_CALL,
FZL_NODETYPE_LITERAL, FZL_NODETYPE_LITERAL,
FZL_NODETYPE_FMT_STRING,
FZL_NODETYPE_IDENTIFIER, FZL_NODETYPE_IDENTIFIER,
FZL_NODETYPE_CONDITIONAL, FZL_NODETYPE_CONDITIONAL,
FZL_NODETYPE_FUNCTION, FZL_NODETYPE_FUNCTION,
+44 -33
View File
@@ -8,57 +8,68 @@
// Token type // Token type
typedef enum typedef enum
{ {
FZL_TOKTYPE_CLASS, // class FZL_TOKTYPE_IMPORT, // `import`
FZL_TOKTYPE_NEW, // new FZL_TOKTYPE_EXTERN, // `extern`
FZL_TOKTYPE_TYPEDEF, // `type`
FZL_TOKTYPE_HANDLE, // `handle`
FZL_TOKTYPE_STRUCT, // `struct`
FZL_TOKTYPE_REFERENCE, // `ref`
FZL_TOKTYPE_OUT, // `out`
FZL_TOKTYPE_FUNCTION, // fn FZL_TOKTYPE_CLASS, // `class`
FZL_TOKTYPE_RETURN, // return FZL_TOKTYPE_NEW, // `new`
FZL_TOKTYPE_FOR, // for FZL_TOKTYPE_FUNCTION, // `fn`
FZL_TOKTYPE_WHILE, // while FZL_TOKTYPE_RETURN, // `return`
FZL_TOKTYPE_BREAK, // break
FZL_TOKTYPE_IF, // if FZL_TOKTYPE_FOR, // `for`
FZL_TOKTYPE_ELSE, // else FZL_TOKTYPE_WHILE, // `while`
FZL_TOKTYPE_BREAK, // `break`
FZL_TOKTYPE_IF, // `if`
FZL_TOKTYPE_ELSE, // `else`
FZL_TOKTYPE_NAME, // abc FZL_TOKTYPE_NAME, // abc
FZL_TOKTYPE_TYPE, // i16 FZL_TOKTYPE_TYPE, // i16
FZL_TOKTYPE_DDASH, // // :D FZL_TOKTYPE_DDASH, // `//` :D
FZL_TOKTYPE_LPAREN, // ( FZL_TOKTYPE_LPAREN, // `(`
FZL_TOKTYPE_RPAREN, // ) FZL_TOKTYPE_RPAREN, // `)`
FZL_TOKTYPE_LBRACE, // { FZL_TOKTYPE_LBRACE, // `{`
FZL_TOKTYPE_RBRACE, // } FZL_TOKTYPE_RBRACE, // `}`
FZL_TOKTYPE_COMMA, // , FZL_TOKTYPE_COMMA, // `,`
FZL_TOKTYPE_DOT, // . FZL_TOKTYPE_DOT, // `.`
FZL_TOKTYPE_SEMICOLON, // ; FZL_TOKTYPE_SEMICOLON, // `;`
FZL_TOKTYPE_STR_LITERAL, // "" FZL_TOKTYPE_STR_LITERAL, // ""
FZL_TOKTYPE_NUM_LITERAL, // 123 FZL_TOKTYPE_NUM_LITERAL, // 123
FZL_TOKTYPE_BOOL_LITERAL, // true FZL_TOKTYPE_BOOL_LITERAL, // true
FZL_TOKTYPE_NULL_LITERAL, // null FZL_TOKTYPE_NULL_LITERAL, // null
FZL_TOKTYPE_DAMPERSAND, // && FZL_TOKTYPE_STR_FORMAT_START, // `$` before `"`
FZL_TOKTYPE_DVBAR, // || FZL_TOKTYPE_STR_FORMAT_END, // end of string formatting sequence
FZL_TOKTYPE_EQEQ, // == FZL_TOKTYPE_DAMPERSAND, // `&&`
FZL_TOKTYPE_REQ, // >= FZL_TOKTYPE_DVBAR, // `||`
FZL_TOKTYPE_LEQ, // <=
FZL_TOKTYPE_NEQ, // !=
FZL_TOKTYPE_LANGLE, // <
FZL_TOKTYPE_RANGLE, // >
FZL_TOKTYPE_NOT, // !
FZL_TOKTYPE_STAR, // * FZL_TOKTYPE_EQEQ, // `==`
FZL_TOKTYPE_SLASH, // / FZL_TOKTYPE_REQ, // `>=`
FZL_TOKTYPE_PLUS, // + FZL_TOKTYPE_LEQ, // `<=`
FZL_TOKTYPE_MINUS, // - FZL_TOKTYPE_NEQ, // `!=`
FZL_TOKTYPE_CARET, // ^ FZL_TOKTYPE_LANGLE, // `<`
FZL_TOKTYPE_PERCENT, // % FZL_TOKTYPE_RANGLE, // `>`
FZL_TOKTYPE_NOT, // `!`
FZL_TOKTYPE_EQ // = FZL_TOKTYPE_STAR, // `*`
FZL_TOKTYPE_SLASH, // `/`
FZL_TOKTYPE_PLUS, // `+`
FZL_TOKTYPE_MINUS, // `-`
FZL_TOKTYPE_CARET, // `^`
FZL_TOKTYPE_PERCENT, // `%`
FZL_TOKTYPE_EQ // `=`
} fzl_toktype_t; } fzl_toktype_t;
// Token descriptor // Token descriptor
+4
View File
@@ -6,6 +6,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <vm/fzl_vm_env.h> #include <vm/fzl_vm_env.h>
#include <vm/fzl_vm_extern.h>
#include <vm/fzl_vm_object.h> #include <vm/fzl_vm_object.h>
// VM descriptor // VM descriptor
@@ -14,6 +15,9 @@ typedef struct
fzl_const_t *consts; fzl_const_t *consts;
size_t consts_count; size_t consts_count;
fzl_vm_extern_t *externs;
size_t externs_count;
uint64_t *ops; uint64_t *ops;
size_t ops_count; size_t ops_count;
+14
View File
@@ -0,0 +1,14 @@
#ifndef FZL_VM_EXTERN_H
#define FZL_VM_EXTERN_H
#include <ffi.h>
// Loaded extern function definition
typedef struct
{
void *func_ptr;
ffi_cif cif;
ffi_type **arg_types;
} fzl_vm_extern_t;
#endif // FZL_VM_EXTERN_H
+20 -3
View File
@@ -31,6 +31,26 @@ void print_node(fzl_node_t *node, int level)
switch (node->type) switch (node->type)
{ {
case FZL_NODETYPE_UNARY_MINUS:
printf("%s Unary '-':\n", levelbuf);
print_node(node->unary_op.operand, level + 1);
break;
case FZL_NODETYPE_UNARY_PLUS:
printf("%s Unary '+':\n", levelbuf);
print_node(node->unary_op.operand, level + 1);
break;
case FZL_NODETYPE_BREAK:
printf("%s Break\n", levelbuf);
break;
case FZL_NODETYPE_FMT_STRING:
printf("%s Format string:\n", levelbuf);
for (size_t i = 0; i < node->list.entry_count; i++)
print_node(node->list.entries[i], level + 1);
break;
case FZL_NODETYPE_LOOP: case FZL_NODETYPE_LOOP:
printf("%s Loop:\n", levelbuf); printf("%s Loop:\n", levelbuf);
printf("-%s Init:\n", levelbuf); printf("-%s Init:\n", levelbuf);
@@ -172,9 +192,6 @@ void print_node(fzl_node_t *node, int level)
case FZL_NODETYPE_IDENTIFIER: case FZL_NODETYPE_IDENTIFIER:
printf("%s Identifier ('%s')\n", levelbuf, (char *)node->token->value); printf("%s Identifier ('%s')\n", levelbuf, (char *)node->token->value);
break; break;
default:
printf("%s Secure node\n", levelbuf);
} }
} }
+100 -23
View File
@@ -1,5 +1,5 @@
#include "compiler/fzl_token.h"
#include <compiler/fzl_parser.h> #include <compiler/fzl_parser.h>
#include <compiler/fzl_token.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
@@ -151,6 +151,99 @@ fzl_node_t *parse_primary(fzl_parser_t *parser)
fzl_token_t *tok = consume(parser); fzl_token_t *tok = consume(parser);
return fzl_mknode(FZL_NODETYPE_LITERAL, tok); return fzl_mknode(FZL_NODETYPE_LITERAL, tok);
} }
else if (is(parser, FZL_TOKTYPE_STR_FORMAT_START))
{
consume(parser);
size_t remainder = 2;
size_t count = 0;
fzl_node_t **entries = malloc(remainder * sizeof(fzl_node_t *));
if (!entries)
{
snprintf(plast_err, sizeof(plast_err), "out of memory");
return NULL;
}
while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_STR_FORMAT_END)
{
if (is(parser, FZL_TOKTYPE_STR_FORMAT_END))
break;
if (remainder <= count)
{
remainder *= 2;
fzl_node_t **newentries =
realloc(entries, remainder * sizeof(fzl_node_t *));
if (!newentries)
{
snprintf(plast_err, sizeof(plast_err), "out of memory");
for (size_t i = 0; i < count; i++)
fzl_freeast(entries[i]);
free(entries);
return NULL;
}
entries = newentries;
}
fzl_node_t *expr = parse_expression(parser);
if (expr == NULL)
{
for (size_t i = 0; i < count; i++)
fzl_freeast(entries[i]);
free(entries);
return NULL;
}
entries[count++] = expr;
}
fzl_token_t *end = consume(parser);
if (end->type != FZL_TOKTYPE_STR_FORMAT_END)
{
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => unterminated format string",
last_known_tok->filename, last_known_tok->ln,
last_known_tok->cn);
for (size_t i = 0; i < count; i++)
fzl_freeast(entries[i]);
free(entries);
}
if (count < 1)
{
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => do you really need empty format string?",
last_known_tok->filename, last_known_tok->ln,
last_known_tok->cn);
for (size_t i = 0; i < count; i++)
fzl_freeast(entries[i]);
free(entries);
return NULL;
}
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FMT_STRING, entries[0]->token);
if (!node)
{
snprintf(plast_err, sizeof(plast_err), "out of memory");
for (size_t i = 0; i < count; i++)
fzl_freeast(entries[i]);
free(entries);
return NULL;
}
node->list.entries = entries;
node->list.entry_count = count;
return node;
}
else if (is(parser, FZL_TOKTYPE_LPAREN)) else if (is(parser, FZL_TOKTYPE_LPAREN))
{ {
consume(parser); consume(parser);
@@ -559,8 +652,8 @@ fzl_node_t *parse_new(fzl_parser_t *parser)
fzl_token_t *new = consume(parser); fzl_token_t *new = consume(parser);
fzl_node_t *objname = parse_or(parser); fzl_node_t *objname = parse_or(parser);
if (objname->type != FZL_NODETYPE_IDENTIFIER && if (!objname || (objname->type != FZL_NODETYPE_IDENTIFIER &&
objname->type != FZL_NODETYPE_FIELD) objname->type != FZL_NODETYPE_FIELD))
{ {
fzl_freeast(objname); fzl_freeast(objname);
snprintf(plast_err, sizeof(plast_err), snprintf(plast_err, sizeof(plast_err),
@@ -1247,7 +1340,10 @@ fzl_node_t *parse_program(fzl_parser_t *parser)
{ {
node = parse_statement(parser); node = parse_statement(parser);
if (!node) if (!node)
{
fzl_freeast(first);
return NULL; return NULL;
}
if (!last) if (!last)
{ {
@@ -1308,11 +1404,11 @@ void fzl_freeast(fzl_node_t *root)
case FZL_NODETYPE_LITERAL: case FZL_NODETYPE_LITERAL:
break; break;
case FZL_NODETYPE_FMT_STRING:
case FZL_NODETYPE_BLOCK: case FZL_NODETYPE_BLOCK:
if (root->list.entries) if (root->list.entries)
{ {
for (size_t i = 0; i < root->list.entry_count; i++) for (size_t i = 0; i < root->list.entry_count; i++)
if (root->list.entries[i])
fzl_freeast(root->list.entries[i]); fzl_freeast(root->list.entries[i]);
free(root->list.entries); free(root->list.entries);
@@ -1320,13 +1416,11 @@ void fzl_freeast(fzl_node_t *root)
break; break;
case FZL_NODETYPE_CALL: case FZL_NODETYPE_CALL:
if (root->call.callee)
fzl_freeast(root->call.callee); fzl_freeast(root->call.callee);
if (root->call.args_count) if (root->call.args_count)
{ {
for (size_t i = 0; i < root->call.args_count; i++) for (size_t i = 0; i < root->call.args_count; i++)
if (root->call.args[i])
fzl_freeast(root->call.args[i]); fzl_freeast(root->call.args[i]);
} }
if (root->call.args) if (root->call.args)
@@ -1334,27 +1428,15 @@ void fzl_freeast(fzl_node_t *root)
break; break;
case FZL_NODETYPE_CONDITIONAL: case FZL_NODETYPE_CONDITIONAL:
if (root->cond.condition)
fzl_freeast(root->cond.condition); fzl_freeast(root->cond.condition);
if (root->cond.true_block)
fzl_freeast(root->cond.true_block); fzl_freeast(root->cond.true_block);
if (root->cond.else_block)
fzl_freeast(root->cond.else_block); fzl_freeast(root->cond.else_block);
break; break;
case FZL_NODETYPE_LOOP: case FZL_NODETYPE_LOOP:
if (root->loop.init)
fzl_freeast(root->loop.init); fzl_freeast(root->loop.init);
if (root->loop.cond)
fzl_freeast(root->loop.cond); fzl_freeast(root->loop.cond);
if (root->loop.step)
fzl_freeast(root->loop.step); fzl_freeast(root->loop.step);
if (root->loop.body)
fzl_freeast(root->loop.body); fzl_freeast(root->loop.body);
break; break;
@@ -1373,16 +1455,13 @@ void fzl_freeast(fzl_node_t *root)
case FZL_NODETYPE_GREATER: case FZL_NODETYPE_GREATER:
case FZL_NODETYPE_GREATER_EQUAL: case FZL_NODETYPE_GREATER_EQUAL:
case FZL_NODETYPE_ASSIGN: case FZL_NODETYPE_ASSIGN:
if (root->binary_op.left)
fzl_freeast(root->binary_op.left); fzl_freeast(root->binary_op.left);
if (root->binary_op.right)
fzl_freeast(root->binary_op.right); fzl_freeast(root->binary_op.right);
break; break;
case FZL_NODETYPE_UNARY_PLUS: case FZL_NODETYPE_UNARY_PLUS:
case FZL_NODETYPE_UNARY_MINUS: case FZL_NODETYPE_UNARY_MINUS:
case FZL_NODETYPE_NOT: case FZL_NODETYPE_NOT:
if (root->unary_op.operand)
fzl_freeast(root->unary_op.operand); fzl_freeast(root->unary_op.operand);
break; break;
@@ -1395,7 +1474,6 @@ void fzl_freeast(fzl_node_t *root)
break; break;
case FZL_NODETYPE_RETURN: case FZL_NODETYPE_RETURN:
if (root->ret.value)
fzl_freeast(root->ret.value); fzl_freeast(root->ret.value);
break; break;
@@ -1421,7 +1499,6 @@ void fzl_freeast(fzl_node_t *root)
break; break;
case FZL_NODETYPE_DECLARATION: case FZL_NODETYPE_DECLARATION:
if (root->var.identifier)
fzl_freeast(root->var.identifier); fzl_freeast(root->var.identifier);
break; break;
} }
+85 -1
View File
@@ -251,11 +251,83 @@ void skip_comment(fzl_reader_t *reader)
} }
} }
// Parse string format
fzl_token_t *parse_fmtstring_part(fzl_reader_t *reader)
{
size_t p = reader->position;
char *src = reader->source;
fzl_file_loc l;
bool ok = fzl_linked_getpos(reader->linked, reader->position, &l);
if (!ok)
{
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
return NULL;
}
if (src[p] == '{')
{
move(reader, 1);
fzl_token_t *id = parse_name(reader);
if (id == NULL || src[reader->position] != '}')
{
snprintf(last_err, sizeof(last_err),
"'%s':%zu:%zu => failed to parse format string", l.filename,
l.line, l.col);
fzl_freetoken(id);
return NULL;
}
move(reader, 1);
return id;
}
if (src[p] == '"')
{
move(reader, 1);
return fzl_mktoken(FZL_TOKTYPE_STR_FORMAT_END, l.line, l.col, NULL, 0,
l.filename);
}
size_t size = 0;
size_t lpos = p;
do
{
if (src[lpos + 1] == '"')
break;
size++;
lpos++;
} while (lpos < reader->size && reader->source[lpos] != '{' &&
reader->source[lpos] != '"');
ok = fzl_linked_getpos(reader->linked, reader->position, &l);
if (!ok)
{
snprintf(last_err, sizeof(last_err), "failed to locate line:col");
return NULL;
}
char *value = malloc(size);
memcpy(value, reader->source + reader->position, size);
fzl_token_t *tok = fzl_mktoken(FZL_TOKTYPE_STR_LITERAL, l.line, l.col, value,
size, l.filename);
free(value);
move(reader, size);
return tok;
}
int fzl_read(fzl_reader_t *reader) int fzl_read(fzl_reader_t *reader)
{ {
if (reader->position >= reader->size) if (reader->position >= reader->size)
return 0; return 0;
bool is_format_str = false;
do do
{ {
size_t p = reader->position; size_t p = reader->position;
@@ -268,7 +340,13 @@ int fzl_read(fzl_reader_t *reader)
continue; continue;
} }
if (curr == '\'' || curr == '"') if (is_format_str)
{
token = parse_fmtstring_part(reader);
if (token && token->type == FZL_TOKTYPE_STR_FORMAT_END)
is_format_str = false;
}
else if (curr == '\'' || curr == '"')
token = parse_string_literal(reader); token = parse_string_literal(reader);
else if (curr == '/' && reader->source[p + 1] == '/') else if (curr == '/' && reader->source[p + 1] == '/')
{ {
@@ -321,6 +399,12 @@ int fzl_read(fzl_reader_t *reader)
token = add_single(reader, FZL_TOKTYPE_PERCENT); token = add_single(reader, FZL_TOKTYPE_PERCENT);
else if (curr == '=') else if (curr == '=')
token = add_single(reader, FZL_TOKTYPE_EQ); token = add_single(reader, FZL_TOKTYPE_EQ);
else if (curr == '$' && reader->source[p + 1] == '"')
{
move(reader, 2);
is_format_str = true;
token = fzl_mktoken(FZL_TOKTYPE_STR_FORMAT_START, 0, 0, NULL, 0, "");
}
else if ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z') || else if ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z') ||
curr == '_') curr == '_')
token = parse_name(reader); token = parse_name(reader);
+4
View File
@@ -30,7 +30,11 @@ fzl_token_t *fzl_mktoken(const fzl_toktype_t type, size_t line, size_t col,
// Free allocated token // Free allocated token
void fzl_freetoken(fzl_token_t *tok) void fzl_freetoken(fzl_token_t *tok)
{ {
if (!tok)
return;
if (tok->store_value) if (tok->store_value)
free(tok->value); free(tok->value);
free(tok); free(tok);
} }
+14
View File
@@ -203,6 +203,20 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
{ {
switch (node->type) switch (node->type)
{ {
case FZL_NODETYPE_FMT_STRING:
{
for (size_t i = 0; i < node->list.entry_count; i++)
{
fzl_walk_res_t res = walk(walker, node->list.entries[i]);
if (res.error)
return res;
}
push_op(walker, FZL_OPCODE_BUILD_STR);
push_word(walker, node->list.entry_count);
break;
}
case FZL_NODETYPE_BREAK: case FZL_NODETYPE_BREAK:
{ {
fzl_walk_ctx_t *ctx = walker->ctx; fzl_walk_ctx_t *ctx = walker->ctx;
+6
View File
@@ -0,0 +1,6 @@
/// Converts integer [value] to string
extern fn itos(int value) str;
/// Converts string [value] to integer
extern fn stoi(str value) int;
+6
View File
@@ -0,0 +1,6 @@
/// Get the minimum of specified values
extern fn min([]int ...values) int;
/// Get the maximum of specified values
extern fn max([]int ...values) int;
+139
View File
@@ -13,6 +13,7 @@
#include <vm/fzl_vm_env.h> #include <vm/fzl_vm_env.h>
#include <vm/fzl_vm_object.h> #include <vm/fzl_vm_object.h>
char build_result[512];
char last_err[256]; char last_err[256];
size_t last_jmp_ip = 0; size_t last_jmp_ip = 0;
size_t total_jmp_on_same = 0; size_t total_jmp_on_same = 0;
@@ -32,6 +33,8 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
vm->consts_count = 0; vm->consts_count = 0;
vm->ops = NULL; vm->ops = NULL;
vm->ops_count = 0; vm->ops_count = 0;
vm->externs = NULL;
vm->externs_count = 0;
vm->ip = 0; vm->ip = 0;
vm->dtop = 0; vm->dtop = 0;
vm->ctop = 0; vm->ctop = 0;
@@ -63,6 +66,7 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
size_t consts_count, ops_count; size_t consts_count, ops_count;
fread(&consts_count, sizeof(size_t), 1, fd); fread(&consts_count, sizeof(size_t), 1, fd);
fread(&ops_count, sizeof(size_t), 1, fd); fread(&ops_count, sizeof(size_t), 1, fd);
// TODO: read externs count
if (ops_count < 1) if (ops_count < 1)
{ {
@@ -116,6 +120,8 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
fread(&op, sizeof(uint64_t), 1, fd); fread(&op, sizeof(uint64_t), 1, fd);
vm->ops[i] = op; vm->ops[i] = op;
} }
// TODO: read externs
fclose(fd); fclose(fd);
return vm; return vm;
@@ -292,6 +298,139 @@ int fzl_vm_run(fzl_vm_t *vm, bool allow_infinite, uint64_t max_iter)
switch (opcode) switch (opcode)
{ {
case FZL_OPCODE_BUILD_STR:
{
uint64_t n = vm->ops[++vm->ip];
if (vm->dtop < n)
{
snprintf(last_err, sizeof(last_err),
"runtime error - expected %zu value(s) in dstack", n);
print_err_data(vm);
return -1;
}
char temp[64];
size_t gi = 0;
memset(build_result, 0, sizeof(build_result));
for (size_t i = 0; i < n; i++)
{
if (gi >= 512)
{
for (size_t i = 511; i > 508; i--)
build_result[i] = '.';
break;
}
memset(temp, 0, sizeof(temp));
fzl_value_t val = vm->dstack[i];
switch (val.type)
{
case FZL_TYPE_UINT:
snprintf(temp, sizeof(temp), "%zu", val.as.u);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_UINT64:
snprintf(temp, sizeof(temp), "%lu", val.as.u64);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_UINT32:
snprintf(temp, sizeof(temp), "%u", val.as.u32);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_UINT16:
snprintf(temp, sizeof(temp), "%u", val.as.u16);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_UINT8:
snprintf(temp, sizeof(temp), "%u", val.as.u8);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_INT:
snprintf(temp, sizeof(temp), "%zd", val.as.i);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_INT64:
snprintf(temp, sizeof(temp), "%ld", val.as.i64);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_INT32:
snprintf(temp, sizeof(temp), "%d", val.as.i32);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_INT16:
snprintf(temp, sizeof(temp), "%d", val.as.i16);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_INT8:
snprintf(temp, sizeof(temp), "%d", val.as.i8);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_BOOL:
snprintf(build_result + gi, sizeof(build_result) - gi, "%s",
val.as.b ? "true" : "false");
gi += val.as.b ? 4 : 5;
break;
case FZL_TYPE_CHAR:
snprintf(build_result + gi, sizeof(build_result) - gi, "%d",
val.as.c);
gi += 1;
break;
case FZL_TYPE_STRING:
snprintf(build_result + gi, sizeof(build_result) - gi, "%s",
val.as.s.value);
gi += val.as.s.length;
break;
case FZL_TYPE_EXTERN_FN:
snprintf(temp, sizeof(temp), "<extern:%zu>", val.as.u);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_OBJECT:
snprintf(temp, sizeof(temp), "<ref:%p>", val.as.obj);
strcpy(build_result + gi, temp);
gi += strlen(temp);
break;
case FZL_TYPE_NULL:
snprintf(build_result + gi, sizeof(build_result) - gi, "<null>");
gi += 6;
break;
}
}
vm->dtop -= n;
vm->dstack[vm->dtop++] =
(fzl_value_t){.type = FZL_TYPE_STRING,
.as.s.length = strlen(build_result),
.as.s.value = build_result};
break;
}
case FZL_OPCODE_DEREFERENCE: case FZL_OPCODE_DEREFERENCE:
{ {
if (vm->dtop < 1) if (vm->dtop < 1)
+4 -3
View File
@@ -20,6 +20,10 @@ void fzl_vm_print_ops(fzl_vm_t *vm)
switch (vm->ops[i]) switch (vm->ops[i])
{ {
case FZL_OPCODE_BUILD_STR:
printf("BUILD_STR %zu\n", vm->ops[++i]);
break;
case FZL_OPCODE_DEREFERENCE: case FZL_OPCODE_DEREFERENCE:
printf("DEREFERENCE\n"); printf("DEREFERENCE\n");
break; break;
@@ -163,9 +167,6 @@ void fzl_vm_print_ops(fzl_vm_t *vm)
case FZL_OPCODE_JMP: case FZL_OPCODE_JMP:
printf("JMP IP: %ld\n", vm->ops[++i]); printf("JMP IP: %ld\n", vm->ops[++i]);
break; break;
default:
printf("<UNKNOWN>\n");
} }
} }
} }
@@ -0,0 +1,2 @@
printline($"Something's on the {way}")
@@ -0,0 +1 @@
$"jopa {abc}
+6
View File
@@ -0,0 +1,6 @@
int a1 = 2 * 2;
printline($"First tests: build string and print. 2 * 2 = {a1}");
str a2 = "Mike Tyson";
printline($"Hello, {a2}");