amalgamation added and libs moved to src/libs/

This commit is contained in:
Thakee Nathees 2022-05-19 21:31:05 +05:30
parent f613153dcb
commit e3cab82978
41 changed files with 1092 additions and 941 deletions

View File

@ -11,7 +11,7 @@ LDFLAGS = -lm
TARGET_EXEC = pocket TARGET_EXEC = pocket
BUILD_DIR = ./build/ BUILD_DIR = ./build/
SRC_DIRS = ./src/ ./cli/ SRC_DIRS = ./cli/ ./src/core/ ./src/libs/
INC_DIRS = ./src/include/ INC_DIRS = ./src/include/
BIN_DIR = bin/ BIN_DIR = bin/

View File

@ -68,12 +68,12 @@ except for a c99 compatible compiler. It can be compiled with the following comm
#### GCC / MinGw / Clang (alias with gcc) #### GCC / MinGw / Clang (alias with gcc)
``` ```
gcc -o pocket cli/*.c src/*.c -Isrc/include -lm gcc -o pocket cli/*.c src/core/*.c src/libs/*.c -Isrc/include -lm
``` ```
#### MSVC #### MSVC
``` ```
cl /Fepocket cli/*.c src/*.c /Isrc/include && rm *.obj cl /Fepocket cli/*.c src/core/*.c src/libs/*.c /Isrc/include && rm *.obj
``` ```
#### Makefile #### Makefile

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
// This file will include all source files from the modules, modules/thirdparty
// sub directories here into this single file. That'll make it easy to compile
// with the command `gcc cli/*.c ...` instead of having to add every single
// sub directory to the list of source directory.
/*****************************************************************************/
/* STD MODULE SOURCES */
/*****************************************************************************/
#include "modules/std_dummy.c"
#include "modules/std_io.c"
#include "modules/std_path.c"
#include "modules/std_math.c"
/*****************************************************************************/
/* THIRDPARTY SOURCES */
/*****************************************************************************/
// Library : cwalk
// License : MIT
// Source : https://github.com/likle/cwalk/
// Doc : https://likle.github.io/cwalk/
// About : Path library for C/C++. Cross-Platform for Windows, MacOS and
// Linux. Supports UNIX and Windows path styles on those platforms.
#include "modules/thirdparty/cwalk/cwalk.c"
// Library : argparse
// License : MIT
// Source : https://github.com/cofyc/argparse/
// About : Command-line arguments parsing library.
#include "thirdparty/argparse/argparse.c"

View File

@ -1,3 +1,158 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2012-2013 Yecheng Fu <cofyc.jackson@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
* All rights reserved.
*
* Use of this source code is governed by a MIT-style license that can be found
* in the LICENSE file.
*/
#ifndef ARGPARSE_H
#define ARGPARSE_H
/* For c++ compatibility */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
struct argparse;
struct argparse_option;
typedef int argparse_callback (struct argparse *self,
const struct argparse_option *option);
enum argparse_flag {
ARGPARSE_STOP_AT_NON_OPTION = 1,
};
enum argparse_option_type {
/* special */
ARGPARSE_OPT_END,
ARGPARSE_OPT_GROUP,
/* options with no arguments */
ARGPARSE_OPT_BOOLEAN,
ARGPARSE_OPT_BIT,
/* options with arguments (optional or required) */
ARGPARSE_OPT_INTEGER,
ARGPARSE_OPT_FLOAT,
ARGPARSE_OPT_STRING,
};
enum argparse_option_flags {
OPT_NONEG = 1, /* disable negation */
};
/**
* argparse option
*
* `type`:
* holds the type of the option, you must have an ARGPARSE_OPT_END last in your
* array.
*
* `short_name`:
* the character to use as a short option name, '\0' if none.
*
* `long_name`:
* the long option name, without the leading dash, NULL if none.
*
* `value`:
* stores pointer to the value to be filled.
*
* `help`:
* the short help message associated to what the option does.
* Must never be NULL (except for ARGPARSE_OPT_END).
*
* `callback`:
* function is called when corresponding argument is parsed.
*
* `data`:
* associated data. Callbacks can use it like they want.
*
* `flags`:
* option flags.
*/
struct argparse_option {
enum argparse_option_type type;
const char short_name;
const char *long_name;
void *value;
const char *help;
argparse_callback *callback;
intptr_t data;
int flags;
};
/**
* argpparse
*/
struct argparse {
// user supplied
const struct argparse_option *options;
const char *const *usages;
int flags;
const char *description; // a description after usage
const char *epilog; // a description at the end
// internal context
int argc;
const char **argv;
const char **out;
int cpidx;
const char *optvalue; // current option value
};
// built-in callbacks
int argparse_help_cb(struct argparse *self,
const struct argparse_option *option);
// built-in option macros
#define OPT_END() { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 }
#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ }
#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ }
#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ }
#define OPT_FLOAT(...) { ARGPARSE_OPT_FLOAT, __VA_ARGS__ }
#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ }
#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 }
#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, \
"show this help message and exit", \
argparse_help_cb, 0, OPT_NONEG)
int argparse_init(struct argparse *self, struct argparse_option *options,
const char *const *usages, int flags);
void argparse_describe(struct argparse *self, const char *description,
const char *epilog);
int argparse_parse(struct argparse *self, int argc, const char **argv);
void argparse_usage(struct argparse *self);
#ifdef __cplusplus
}
#endif
#if defined(_ARGPARSE_IMPL)
/** /**
* Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com> * Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
* All rights reserved. * All rights reserved.
@ -398,3 +553,6 @@ argparse_help_cb(struct argparse *self, const struct argparse_option *option)
argparse_usage(self); argparse_usage(self);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
#endif // _ARGPARSE_IMPL
#endif

View File

@ -19,8 +19,9 @@
#pragma warning(disable:26812) #pragma warning(disable:26812)
#endif #endif
#include "modules/modules.h" #define _ARGPARSE_IMPL
#include "thirdparty/argparse/argparse.h" #include "argparse.h"
#undef _ARGPARSE_IMPL
// FIXME: // FIXME:
// Included for isatty(). This should be moved to somewhere. and I'm not sure // Included for isatty(). This should be moved to somewhere. and I'm not sure
@ -44,7 +45,6 @@
static PKVM* intializePocketVM() { static PKVM* intializePocketVM() {
PkConfiguration config = pkNewConfiguration(); PkConfiguration config = pkNewConfiguration();
config.resolve_path_fn = pathResolveImport;
// FIXME: // FIXME:
// Refactor and make it portable. Maybe custom is_tty() function?. // Refactor and make it portable. Maybe custom is_tty() function?.
@ -59,7 +59,9 @@ static PKVM* intializePocketVM() {
config.use_ansi_color = true; config.use_ansi_color = true;
} }
return pkNewVM(&config); PKVM* vm = pkNewVM(&config);
pkRegisterLibs(vm);
return vm;
} }
int main(int argc, const char** argv) { int main(int argc, const char** argv) {
@ -112,8 +114,6 @@ int main(int argc, const char** argv) {
// Create and initialize pocket VM. // Create and initialize pocket VM.
PKVM* vm = intializePocketVM(); PKVM* vm = intializePocketVM();
REGISTER_ALL_MODULES(vm);
if (cmd != NULL) { // pocket -c "print('foo')" if (cmd != NULL) { // pocket -c "print('foo')"
PkResult result = pkRunString(vm, cmd); PkResult result = pkRunString(vm, cmd);
exitcode = (int) result; exitcode = (int) result;

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#ifndef MODULES_H
#define MODULES_H
#include <pocketlang.h>
#include "common.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
void registerModuleDummy(PKVM* vm);
void registerModuleIO(PKVM* vm);
void registerModulePath(PKVM* vm);
void registerModuleMath(PKVM* vm);
// Registers all the cli modules.
#define REGISTER_ALL_MODULES(vm) \
do { \
registerModuleDummy(vm); \
registerModuleIO(vm); \
registerModulePath(vm); \
registerModuleMath(vm); \
} while (false)
/*****************************************************************************/
/* MODULES INTERNAL */
/*****************************************************************************/
// Allocate a new module object of type [Ty].
#define NEW_OBJ(Ty) (Ty*)malloc(sizeof(Ty))
// Dellocate module object, allocated by NEW_OBJ(). Called by the freeObj
// callback.
#define FREE_OBJ(ptr) free(ptr)
// Returns the docstring of the function, which is a static const char* defined
// just above the function by the DEF() macro below.
#define DOCSTRING(fn) __doc_##fn
// A macro to declare a function, with docstring, which is defined as
// ___doc_<fn> = docstring; That'll used to generate function help text.
#define DEF(fn, docstring) \
static const char* DOCSTRING(fn) = docstring; \
static void fn(PKVM* vm)
/*****************************************************************************/
/* SHARED FUNCTIONS */
/*****************************************************************************/
// These are "public" module functions that can be shared. Since some modules
// can be used for cli's internals we're defining such functions here and they
// will be imported in the cli.
// The pocketlang's import statement path resolving function. This
// implementation is required by pockelang from it's hosting application
// inorder to use the import statements.
char* pathResolveImport(PKVM * vm, const char* from, const char* path);
#endif // MODULES_H

View File

@ -1,9 +0,0 @@
MIT License
Copyright (c) 2020 Leonard Iklé
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,497 +0,0 @@
#pragma once
#ifndef CWK_LIBRARY_H
#define CWK_LIBRARY_H
#include <stdbool.h>
#include <stddef.h>
#if defined(_WIN32) || defined(__CYGWIN__)
#define CWK_EXPORT __declspec(dllexport)
#define CWK_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
#define CWK_EXPORT __attribute__((visibility("default")))
#define CWK_IMPORT __attribute__((visibility("default")))
#else
#define CWK_EXPORT
#define CWK_IMPORT
#endif
#if defined(CWK_SHARED)
#if defined(CWK_EXPORTS)
#define CWK_PUBLIC CWK_EXPORT
#else
#define CWK_PUBLIC CWK_IMPORT
#endif
#else
#define CWK_PUBLIC
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/**
* A segment represents a single component of a path. For instance, on linux a
* path might look like this "/var/log/", which consists of two segments "var"
* and "log".
*/
struct cwk_segment
{
const char* path;
const char* segments;
const char* begin;
const char* end;
size_t size;
};
/**
* The segment type can be used to identify whether a segment is a special
* segment or not.
*
* CWK_NORMAL - normal folder or file segment
* CWK_CURRENT - "./" current folder segment
* CWK_BACK - "../" relative back navigation segment
*/
enum cwk_segment_type
{
CWK_NORMAL,
CWK_CURRENT,
CWK_BACK
};
/**
* @brief Determines the style which is used for the path parsing and
* generation.
*/
enum cwk_path_style
{
CWK_STYLE_WINDOWS,
CWK_STYLE_UNIX
};
/**
* @brief Generates an absolute path based on a base.
*
* This function generates an absolute path based on a base path and another
* path. It is guaranteed to return an absolute path. If the second submitted
* path is absolute, it will override the base path. The result will be
* written to a buffer, which might be truncated if the buffer is not large
* enough to hold the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param base The absolute base path on which the relative path will be
* applied.
* @param path The relative path which will be applied on the base path.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the new absolute path.
*/
CWK_PUBLIC size_t cwk_path_get_absolute(const char* base, const char* path,
char* buffer, size_t buffer_size);
/**
* @brief Generates a relative path based on a base.
*
* This function generates a relative path based on a base path and another
* path. It determines how to get to the submitted path, starting from the
* base directory. The result will be written to a buffer, which might be
* truncated if the buffer is not large enough to hold the full path. However,
* the truncated result will always be null-terminated. The returned value is
* the amount of characters which the resulting path would take if it was not
* truncated (excluding the null-terminating character).
*
* @param base_directory The base path from which the relative path will
* start.
* @param path The target path where the relative path will point to.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full path.
*/
CWK_PUBLIC size_t cwk_path_get_relative(const char* base_directory,
const char* path, char* buffer, size_t buffer_size);
/**
* @brief Joins two paths together.
*
* This function generates a new path by combining the two submitted paths. It
* will remove double separators, and unlike cwk_path_get_absolute it permits
* the use of two relative paths to combine. The result will be written to a
* buffer, which might be truncated if the buffer is not large enough to hold
* the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param path_a The first path which comes first.
* @param path_b The second path which comes after the first.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full, combined path.
*/
CWK_PUBLIC size_t cwk_path_join(const char* path_a, const char* path_b,
char* buffer, size_t buffer_size);
/**
* @brief Joins multiple paths together.
*
* This function generates a new path by joining multiple paths together. It
* will remove double separators, and unlike cwk_path_get_absolute it permits
* the use of multiple relative paths to combine. The last path of the
* submitted string array must be set to NULL. The result will be written to a
* buffer, which might be truncated if the buffer is not large enough to hold
* the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param paths An array of paths which will be joined.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full, combined path.
*/
CWK_PUBLIC size_t cwk_path_join_multiple(const char** paths, char* buffer,
size_t buffer_size);
/**
* @brief Determines the root of a path.
*
* This function determines the root of a path by finding it's length. The
* root always starts at the submitted path. If the path has no root, the
* length will be set to zero.
*
* @param path The path which will be inspected.
* @param length The output of the root length.
*/
CWK_PUBLIC void cwk_path_get_root(const char* path, size_t* length);
/**
* @brief Changes the root of a path.
*
* This function changes the root of a path. It does not normalize the result.
* The result will be written to a buffer, which might be truncated if the
* buffer is not large enough to hold the full path. However, the truncated
* result will always be null-terminated. The returned value is the amount of
* characters which the resulting path would take if it was not truncated
* (excluding the null-terminating character).
*
* @param path The original path which will get a new root.
* @param new_root The new root which will be placed in the path.
* @param buffer The output buffer where the result is written to.
* @param buffer_size The size of the output buffer where the result is
* written to.
* @return Returns the total amount of characters of the new path.
*/
CWK_PUBLIC size_t cwk_path_change_root(const char* path, const char* new_root,
char* buffer, size_t buffer_size);
/**
* @brief Determine whether the path is absolute or not.
*
* This function checks whether the path is an absolute path or not. A path is
* considered to be absolute if the root ends with a separator.
*
* @param path The path which will be checked.
* @return Returns true if the path is absolute or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_absolute(const char* path);
/**
* @brief Determine whether the path is relative or not.
*
* This function checks whether the path is a relative path or not. A path is
* considered to be relative if the root does not end with a separator.
*
* @param path The path which will be checked.
* @return Returns true if the path is relative or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_relative(const char* path);
/**
* @brief Gets the basename of a file path.
*
* This function gets the basename of a file path. A pointer to the beginning
* of the basename will be returned through the basename parameter. This
* pointer will be positioned on the first letter after the separator. The
* length of the file path will be returned through the length parameter. The
* length will be set to zero and the basename to NULL if there is no basename
* available.
*
* @param path The path which will be inspected.
* @param basename The output of the basename pointer.
* @param length The output of the length of the basename.
*/
CWK_PUBLIC void cwk_path_get_basename(const char* path, const char** basename,
size_t* length);
/**
* @brief Changes the basename of a file path.
*
* This function changes the basename of a file path. This function will not
* write out more than the specified buffer can contain. However, the
* generated string is always null-terminated - even if not the whole path is
* written out. The function returns the total number of characters the
* complete buffer would have, even if it was not written out completely. The
* path may be the same memory address as the buffer.
*
* @param path The original path which will be used for the modified path.
* @param new_basename The new basename which will replace the old one.
* @param buffer The buffer where the changed path will be written to.
* @param buffer_size The size of the result buffer where the changed path is
* written to.
* @return Returns the size which the complete new path would have if it was
* not truncated.
*/
CWK_PUBLIC size_t cwk_path_change_basename(const char* path,
const char* new_basename, char* buffer, size_t buffer_size);
/**
* @brief Gets the dirname of a file path.
*
* This function determines the dirname of a file path and returns the length
* up to which character is considered to be part of it. If no dirname is
* found, the length will be set to zero. The beginning of the dirname is
* always equal to the submitted path pointer.
*
* @param path The path which will be inspected.
* @param length The length of the dirname.
*/
CWK_PUBLIC void cwk_path_get_dirname(const char* path, size_t* length);
/**
* @brief Gets the extension of a file path.
*
* This function extracts the extension portion of a file path. A pointer to
* the beginning of the extension will be returned through the extension
* parameter if an extension is found and true is returned. This pointer will
* be positioned on the dot. The length of the extension name will be returned
* through the length parameter. If no extension is found both parameters
* won't be touched and false will be returned.
*
* @param path The path which will be inspected.
* @param extension The output of the extension pointer.
* @param length The output of the length of the extension.
* @return Returns true if an extension is found or false otherwise.
*/
CWK_PUBLIC bool cwk_path_get_extension(const char* path, const char** extension,
size_t* length);
/**
* @brief Determines whether the file path has an extension.
*
* This function determines whether the submitted file path has an extension.
* This will evaluate to true if the last segment of the path contains a dot.
*
* @param path The path which will be inspected.
* @return Returns true if the path has an extension or false otherwise.
*/
CWK_PUBLIC bool cwk_path_has_extension(const char* path);
/**
* @brief Changes the extension of a file path.
*
* This function changes the extension of a file name. The function will
* append an extension if the basename does not have an extension, or use the
* extension as a basename if the path does not have a basename. This function
* will not write out more than the specified buffer can contain. However, the
* generated string is always null-terminated - even if not the whole path is
* written out. The function returns the total number of characters the
* complete buffer would have, even if it was not written out completely. The
* path may be the same memory address as the buffer.
*
* @param path The path which will be used to make the change.
* @param new_extension The extension which will be placed within the new
* path.
* @param buffer The output buffer where the result will be written to.
* @param buffer_size The size of the output buffer where the result will be
* written to.
* @return Returns the total size which the output would have if it was not
* truncated.
*/
CWK_PUBLIC size_t cwk_path_change_extension(const char* path,
const char* new_extension, char* buffer, size_t buffer_size);
/**
* @brief Creates a normalized version of the path.
*
* This function creates a normalized version of the path within the specified
* buffer. This function will not write out more than the specified buffer can
* contain. However, the generated string is always null-terminated - even if
* not the whole path is written out. The function returns the total number of
* characters the complete buffer would have, even if it was not written out
* completely. The path may be the same memory address as the buffer.
*
* The following will be true for the normalized path:
* 1) "../" will be resolved.
* 2) "./" will be removed.
* 3) double separators will be fixed with a single separator.
* 4) separator suffixes will be removed.
*
* @param path The path which will be normalized.
* @param buffer The buffer where the new path is written to.
* @param buffer_size The size of the buffer.
* @return The size which the complete normalized path has if it was not
* truncated.
*/
CWK_PUBLIC size_t cwk_path_normalize(const char* path, char* buffer,
size_t buffer_size);
/**
* @brief Finds common portions in two paths.
*
* This function finds common portions in two paths and returns the number
* characters from the beginning of the base path which are equal to the other
* path.
*
* @param path_base The base path which will be compared with the other path.
* @param path_other The other path which will compared with the base path.
* @return Returns the number of characters which are common in the base path.
*/
CWK_PUBLIC size_t cwk_path_get_intersection(const char* path_base,
const char* path_other);
/**
* @brief Gets the first segment of a path.
*
* This function finds the first segment of a path. The position of the
* segment is set to the first character after the separator, and the length
* counts all characters until the next separator (excluding the separator).
*
* @param path The path which will be inspected.
* @param segment The segment which will be extracted.
* @return Returns true if there is a segment or false if there is none.
*/
CWK_PUBLIC bool cwk_path_get_first_segment(const char* path,
struct cwk_segment* segment);
/**
* @brief Gets the last segment of the path.
*
* This function gets the last segment of a path. This function may return
* false if the path doesn't contain any segments, in which case the submitted
* segment parameter is not modified. The position of the segment is set to
* the first character after the separator, and the length counts all
* characters until the end of the path (excluding the separator).
*
* @param path The path which will be inspected.
* @param segment The segment which will be extracted.
* @return Returns true if there is a segment or false if there is none.
*/
CWK_PUBLIC bool cwk_path_get_last_segment(const char* path,
struct cwk_segment* segment);
/**
* @brief Advances to the next segment.
*
* This function advances the current segment to the next segment. If there
* are no more segments left, the submitted segment structure will stay
* unchanged and false is returned.
*
* @param segment The current segment which will be advanced to the next one.
* @return Returns true if another segment was found or false otherwise.
*/
CWK_PUBLIC bool cwk_path_get_next_segment(struct cwk_segment* segment);
/**
* @brief Moves to the previous segment.
*
* This function moves the current segment to the previous segment. If the
* current segment is the first one, the submitted segment structure will stay
* unchanged and false is returned.
*
* @param segment The current segment which will be moved to the previous one.
* @return Returns true if there is a segment before this one or false
* otherwise.
*/
CWK_PUBLIC bool cwk_path_get_previous_segment(struct cwk_segment* segment);
/**
* @brief Gets the type of the submitted path segment.
*
* This function inspects the contents of the segment and determines the type
* of it. Currently, there are three types CWK_NORMAL, CWK_CURRENT and
* CWK_BACK. A CWK_NORMAL segment is a normal folder or file entry. A
* CWK_CURRENT is a "./" and a CWK_BACK a "../" segment.
*
* @param segment The segment which will be inspected.
* @return Returns the type of the segment.
*/
CWK_PUBLIC enum cwk_segment_type cwk_path_get_segment_type(
const struct cwk_segment* segment);
/**
* @brief Changes the content of a segment.
*
* This function overrides the content of a segment to the submitted value and
* outputs the whole new path to the submitted buffer. The result might
* require less or more space than before if the new value length differs from
* the original length. The output is truncated if the new path is larger than
* the submitted buffer size, but it is always null-terminated. The source of
* the segment and the submitted buffer may be the same.
*
* @param segment The segment which will be modifier.
* @param value The new content of the segment.
* @param buffer The buffer where the modified path will be written to.
* @param buffer_size The size of the output buffer.
* @return Returns the total size which would have been written if the output
* was not truncated.
*/
CWK_PUBLIC size_t cwk_path_change_segment(struct cwk_segment* segment,
const char* value, char* buffer, size_t buffer_size);
/**
* @brief Checks whether the submitted pointer points to a separator.
*
* This function simply checks whether the submitted pointer points to a
* separator, which has to be null-terminated (but not necessarily after the
* separator). The function will return true if it is a separator, or false
* otherwise.
*
* @param symbol A pointer to a string.
* @return Returns true if it is a separator, or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_separator(const char* str);
/**
* @brief Guesses the path style.
*
* This function guesses the path style based on a submitted path-string. The
* guessing will look at the root and the type of slashes contained in the
* path and return the style which is more likely used in the path.
*
* @param path The path which will be inspected.
* @return Returns the style which is most likely used for the path.
*/
CWK_PUBLIC enum cwk_path_style cwk_path_guess_style(const char* path);
/**
* @brief Configures which path style is used.
*
* This function configures which path style is used. The following styles are
* currently supported.
*
* CWK_STYLE_WINDOWS: Use backslashes as a separator and volume for the root.
* CWK_STYLE_UNIX: Use slashes as a separator and a slash for the root.
*
* @param style The style which will be used from now on.
*/
CWK_PUBLIC void cwk_path_set_style(enum cwk_path_style style);
/**
* @brief Gets the path style configuration.
*
* This function gets the style configuration which is currently used for the
* paths. This configuration determines how paths are parsed and generated.
*
* @return Returns the current path style configuration.
*/
CWK_PUBLIC enum cwk_path_style cwk_path_get_style(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 1998-2019 Toni Ronkko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2012-2013 Yecheng Fu <cofyc.jackson@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,130 +0,0 @@
/**
* Copyright (C) 2012-2015 Yecheng Fu <cofyc.jackson at gmail dot com>
* All rights reserved.
*
* Use of this source code is governed by a MIT-style license that can be found
* in the LICENSE file.
*/
#ifndef ARGPARSE_H
#define ARGPARSE_H
/* For c++ compatibility */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
struct argparse;
struct argparse_option;
typedef int argparse_callback (struct argparse *self,
const struct argparse_option *option);
enum argparse_flag {
ARGPARSE_STOP_AT_NON_OPTION = 1,
};
enum argparse_option_type {
/* special */
ARGPARSE_OPT_END,
ARGPARSE_OPT_GROUP,
/* options with no arguments */
ARGPARSE_OPT_BOOLEAN,
ARGPARSE_OPT_BIT,
/* options with arguments (optional or required) */
ARGPARSE_OPT_INTEGER,
ARGPARSE_OPT_FLOAT,
ARGPARSE_OPT_STRING,
};
enum argparse_option_flags {
OPT_NONEG = 1, /* disable negation */
};
/**
* argparse option
*
* `type`:
* holds the type of the option, you must have an ARGPARSE_OPT_END last in your
* array.
*
* `short_name`:
* the character to use as a short option name, '\0' if none.
*
* `long_name`:
* the long option name, without the leading dash, NULL if none.
*
* `value`:
* stores pointer to the value to be filled.
*
* `help`:
* the short help message associated to what the option does.
* Must never be NULL (except for ARGPARSE_OPT_END).
*
* `callback`:
* function is called when corresponding argument is parsed.
*
* `data`:
* associated data. Callbacks can use it like they want.
*
* `flags`:
* option flags.
*/
struct argparse_option {
enum argparse_option_type type;
const char short_name;
const char *long_name;
void *value;
const char *help;
argparse_callback *callback;
intptr_t data;
int flags;
};
/**
* argpparse
*/
struct argparse {
// user supplied
const struct argparse_option *options;
const char *const *usages;
int flags;
const char *description; // a description after usage
const char *epilog; // a description at the end
// internal context
int argc;
const char **argv;
const char **out;
int cpidx;
const char *optvalue; // current option value
};
// built-in callbacks
int argparse_help_cb(struct argparse *self,
const struct argparse_option *option);
// built-in option macros
#define OPT_END() { ARGPARSE_OPT_END, 0, NULL, NULL, 0, NULL, 0, 0 }
#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ }
#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ }
#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ }
#define OPT_FLOAT(...) { ARGPARSE_OPT_FLOAT, __VA_ARGS__ }
#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ }
#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL, 0, 0 }
#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, \
"show this help message and exit", \
argparse_help_cb, 0, OPT_NONEG)
int argparse_init(struct argparse *self, struct argparse_option *options,
const char *const *usages, int flags);
void argparse_describe(struct argparse *self, const char *description,
const char *epilog);
int argparse_parse(struct argparse *self, int argc, const char **argv);
void argparse_usage(struct argparse *self);
#ifdef __cplusplus
}
#endif
#endif

109
scripts/amalgamate.py Normal file
View File

@ -0,0 +1,109 @@
##
## Copyright (c) 2020-2022 Thakee Nathees
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License
##
##
## USAGE: python amalgamate.py > pocketlang.h
##
import os, re, sys
from os.path import *
## Pocket lang root directory. All the listed paths bellow are relative to
## the root path.
ROOT_PATH = abspath(join(dirname(__file__), ".."))
## Filter all the files in the [path] with extension and return them.
def files(path, ext, filter_= lambda file : True):
return [
join(ROOT_PATH, path, file) for file in os.listdir(join(ROOT_PATH, path))
if file.endswith(ext) and filter_(file)
]
SOURCES = [
*files('src/core/', '.c'),
*files('src/libs/', '.c'),
]
PUBLIC_HEADER = join(ROOT_PATH, 'src/include/pocketlang.h')
HEADERS = [
*[ ## The order of the headers are important.
join(ROOT_PATH, header)
for header in [
'src/core/common.h',
'src/core/utils.h',
'src/core/internal.h',
'src/core/buffers.h',
'src/core/value.h',
'src/core/compiler.h',
'src/core/core.h',
'src/core/debug.h',
'src/core/vm.h',
'src/libs/libs.h',
]
]
]
## return include path from a linclude "statement" line.
def _get_include_path(line):
assert '#include ' in line
index = line.find('#include ')
start = line.find('"', index)
end = line.find('"', start + 1)
return line[start+1:end]
## Since the stdout is redirected to a file, stderr can be
## used for logging.
def log(*msg):
message = ' '.join(map(lambda x: str(x), msg))
sys.stderr.write(message + '\n')
def parse(path):
text = ""
with open(path, 'r') as fp:
for line in fp.readlines():
if "//<< AMALG_INLINE >>" in line:
path = join(dirname(path), _get_include_path(line))
path = path.replace('\\', '/') ## Aaah windows path.
text += parse(path) + '\n'
else: text += line
## Note that this comment stripping regex is dubious, and wont
## work on all cases ex:
##
## const char* s = "//";\n
##
## The above '//' considered as comment but it's inside a string.
text = re.sub('/\*.*?\*/', '', text, flags=re.S)
text = re.sub('//.*?\n', '\n', text, flags=re.S)
text = re.sub('[^\n\S]*\n', '\n', text, flags=re.S)
text = re.sub('\n\n+', '\n\n', text, flags=re.S)
return text
def generate():
gen = ''
with open(PUBLIC_HEADER, 'r') as fp:
gen = fp.read()
gen += '\n#define PK_AMALGAMATED\n'
for header in HEADERS:
gen += '// Amalgamated file: ' +\
relpath(header, ROOT_PATH).replace("\\", "/") +\
'\n'
gen += parse(header) + '\n'
gen += '#ifdef PK_IMPL\n\n'
for source in SOURCES:
gen += parse(source)
gen += '#endif // PK_IMPL\n'
return gen
if __name__ == '__main__':
print(generate())

View File

@ -128,7 +128,7 @@ if not exist %target_dir%obj\cli\ mkdir %target_dir%obj\cli\
cd %target_dir%obj\pocket cd %target_dir%obj\pocket
cl /nologo /c %addnl_cdefines% %addnl_cflags% %pocket_root%src\*.c cl /nologo /c %addnl_cdefines% %addnl_cflags% /I%pocket_root%src\include\ %pocket_root%src\core\*.c %pocket_root%src\libs\*.c
if errorlevel 1 goto :FAIL if errorlevel 1 goto :FAIL
:: If compiling shared lib, jump pass the lib/cli binaries. :: If compiling shared lib, jump pass the lib/cli binaries.

View File

@ -7,8 +7,10 @@
-- Requires premake5.0.0-alpha-12 or greater. -- Requires premake5.0.0-alpha-12 or greater.
local build_dir = "../build/" local build_dir = "../build/"
local src_dir = "../src/"
local cli_dir = "../cli/" local cli_dir = "../cli/"
local include_dir = "../src/include/"
local core_dir = "../src/core/"
local libs_dir = "../src/libs/"
workspace "pocketlang" workspace "pocketlang"
location (build_dir) location (build_dir)
@ -47,16 +49,26 @@ project "pocket_static"
kind "StaticLib" kind "StaticLib"
targetname "pocket" targetname "pocket"
proj_commons("lib/") proj_commons("lib/")
files { src_dir .. "*.c", includedirs { include_dir }
src_dir .. "**.h"} files { core_dir .. "*.c",
core_dir .. "*.h",
libs_dir .. "*.c",
libs_dir .. "*.h",
include_dir .. "*.h",
}
-- pocketlang sources as shared library. -- pocketlang sources as shared library.
project "pocket_shared" project "pocket_shared"
kind "SharedLib" kind "SharedLib"
targetname "pocket" targetname "pocket"
proj_commons("bin/") proj_commons("bin/")
files { src_dir .. "*.c", includedirs { include_dir }
src_dir .. "**.h"} files { core_dir .. "*.c",
core_dir .. "*.h",
libs_dir .. "*.c",
libs_dir .. "*.h",
include_dir .. "*.h",
}
defines { "PK_DLL", "PK_COMPILE" } defines { "PK_DLL", "PK_COMPILE" }
-- command line executable. -- command line executable.
@ -65,6 +77,6 @@ project "pocket_cli"
targetname "pocket" targetname "pocket"
proj_commons("bin/") proj_commons("bin/")
files { cli_dir .. "*.c", files { cli_dir .. "*.c",
cli_dir .. "**.h" } cli_dir .. "*.h" }
includedirs ({ src_dir .. "include/" }) includedirs { include_dir }
links { "pocket_static" } links { "pocket_static" }

View File

@ -8,7 +8,7 @@
import os, sys, re import os, sys, re
from os import listdir from os import listdir
from os.path import join, abspath, dirname, relpath, normpath from os.path import *
## Pocket lang root directory. All the listed paths bellow are relative to ## Pocket lang root directory. All the listed paths bellow are relative to
## the root path. ## the root path.
@ -17,8 +17,8 @@ ROOT_PATH = abspath(join(dirname(__file__), ".."))
## A list of source files, to check if the fnv1a hash values match it's ## A list of source files, to check if the fnv1a hash values match it's
## corresponding cstring in the CASE_ATTRIB(name, hash) macro calls. ## corresponding cstring in the CASE_ATTRIB(name, hash) macro calls.
HASH_CHECK_LIST = [ HASH_CHECK_LIST = [
"src/pk_core.c", "src/core/core.c",
"src/pk_value.c", "src/core/value.c",
] ]
## A list of extension to perform static checks, of all the files in the ## A list of extension to perform static checks, of all the files in the
@ -29,18 +29,21 @@ CHECK_EXTENTIONS = ('.c', '.h', '.py', '.pk', '.js')
## 79 characters, It's not "the correct way" but it works. ## 79 characters, It's not "the correct way" but it works.
ALLOW_LONG_LINES = ('http://', 'https://', '<script ', '<link ', '<svg ') ALLOW_LONG_LINES = ('http://', 'https://', '<script ', '<link ', '<svg ')
## A list of files that are allowed to be longer than 79 characters. ## A list of files that are ignored for static check. Usually third party
ALLOW_LONG_FILES = ( ## files and generated source files.
"cli/native.py", IGNORE_FILES = (
"cli/modules/pknative.gen.c", "cli/modules/pknative.gen.c", ## FIXME: set gen path.
"cli/argparse.h", ## FIXME: collect all thirdparty files.
"src/libs/tp_dirent.h",
"src/libs/tp_cwalk.h",
) )
## A list of directory, contains C source files to perform static checks. ## A list of directory, contains C source files to perform static checks.
## This will include all files with extension from CHECK_EXTENTIONS. ## This will include all files with extension from CHECK_EXTENTIONS.
SOURCE_DIRS = [ SOURCE_DIRS = [
"src/", "src/core/",
"src/libs/",
"cli/", "cli/",
"cli/modules/",
"docs/", "docs/",
"docs/wasm/", "docs/wasm/",
@ -98,6 +101,13 @@ def check_static(dirs):
if os.path.isdir(join(dir, file)): continue if os.path.isdir(join(dir, file)): continue
curr_file = normpath(join(dir, file)) curr_file = normpath(join(dir, file))
skip = False
for ignore in IGNORE_FILES:
if curr_file == normpath(join(ROOT_PATH, ignore)):
skip = True; break;
if skip: continue
fp = open(curr_file, 'r') fp = open(curr_file, 'r')
## Path of the file relative to top-level. ## Path of the file relative to top-level.
@ -124,11 +134,6 @@ def check_static(dirs):
if ignore in line: if ignore in line:
skip = True skip = True
break break
for ignore in ALLOW_LONG_FILES:
## TODO: the bellow normpath(join()) should be calcuated once.
if curr_file == normpath(join(ROOT_PATH, ignore)):
skip = True
break
if skip: continue if skip: continue
_location = location(file_path, line_no) _location = location(file_path, line_no)

View File

@ -7,7 +7,9 @@
#ifndef PK_BUFFERS_TEMPLATE_H #ifndef PK_BUFFERS_TEMPLATE_H
#define PK_BUFFERS_TEMPLATE_H #define PK_BUFFERS_TEMPLATE_H
#include "pk_internal.h" #ifndef PK_AMALGAMATED
#include "internal.h"
#endif
// The macro 'DECLARE_BUFFER()' emulate the C++ template to declare and define // The macro 'DECLARE_BUFFER()' emulate the C++ template to declare and define
// different types of buffer objects. // different types of buffer objects.

View File

@ -4,13 +4,14 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "pk_compiler.h" #ifndef PK_AMALGAMATED
#include "compiler.h"
#include "pk_core.h" #include "core.h"
#include "pk_buffers.h" #include "buffers.h"
#include "pk_utils.h" #include "utils.h"
#include "pk_vm.h" #include "vm.h"
#include "pk_debug.h" #include "debug.h"
#endif
// The maximum number of locals or global (if compiling top level module) // The maximum number of locals or global (if compiling top level module)
// to lookup from the compiling context. Also it's limited by it's opcode // to lookup from the compiling context. Also it's limited by it's opcode
@ -155,10 +156,12 @@ typedef enum {
* TK_STRING " e" */ * TK_STRING " e" */
TK_STRING_INTERP, TK_STRING_INTERP,
} TokenType; } _TokenType;
// Winint.h has already defined TokenType which breaks amalgam build so I've
// change the name from TokenType to _TokenType.
typedef struct { typedef struct {
TokenType type; _TokenType type;
const char* start; //< Begining of the token in the source. const char* start; //< Begining of the token in the source.
int length; //< Number of chars of the token. int length; //< Number of chars of the token.
@ -169,7 +172,7 @@ typedef struct {
typedef struct { typedef struct {
const char* identifier; const char* identifier;
int length; int length;
TokenType tk_type; _TokenType tk_type;
} _Keyword; } _Keyword;
// List of keywords mapped into their identifiers. // List of keywords mapped into their identifiers.
@ -202,7 +205,7 @@ static _Keyword _keywords[] = {
{ "continue", 8, TK_CONTINUE }, { "continue", 8, TK_CONTINUE },
{ "return", 6, TK_RETURN }, { "return", 6, TK_RETURN },
{ NULL, 0, (TokenType)(0) }, // Sentinel to mark the end of the array. { NULL, 0, (_TokenType)(0) }, // Sentinel to mark the end of the array.
}; };
/*****************************************************************************/ /*****************************************************************************/
@ -493,7 +496,7 @@ typedef struct {
static OpInfo opcode_info[] = { static OpInfo opcode_info[] = {
#define OPCODE(name, params, stack) { params, stack }, #define OPCODE(name, params, stack) { params, stack },
#include "pk_opcodes.h" #include "opcodes.h" //<< AMALG_INLINE >>
#undef OPCODE #undef OPCODE
}; };
@ -657,8 +660,8 @@ static Token makeErrToken(Parser* parser);
static char peekChar(Parser* parser); static char peekChar(Parser* parser);
static char peekNextChar(Parser* parser); static char peekNextChar(Parser* parser);
static char eatChar(Parser* parser); static char eatChar(Parser* parser);
static void setNextValueToken(Parser* parser, TokenType type, Var value); static void setNextValueToken(Parser* parser, _TokenType type, Var value);
static void setNextToken(Parser* parser, TokenType type); static void setNextToken(Parser* parser, _TokenType type);
static bool matchChar(Parser* parser, char c); static bool matchChar(Parser* parser, char c);
static void eatString(Compiler* compiler, bool single_quote) { static void eatString(Compiler* compiler, bool single_quote) {
@ -670,7 +673,7 @@ static void eatString(Compiler* compiler, bool single_quote) {
char quote = (single_quote) ? '\'' : '"'; char quote = (single_quote) ? '\'' : '"';
// For interpolated string it'll be TK_STRING_INTERP. // For interpolated string it'll be TK_STRING_INTERP.
TokenType tk_type = TK_STRING; _TokenType tk_type = TK_STRING;
while (true) { while (true) {
char c = eatChar(parser); char c = eatChar(parser);
@ -786,7 +789,7 @@ static void eatName(Parser* parser) {
const char* name_start = parser->token_start; const char* name_start = parser->token_start;
TokenType type = TK_NAME; _TokenType type = TK_NAME;
int length = (int)(parser->current_char - name_start); int length = (int)(parser->current_char - name_start);
for (int i = 0; _keywords[i].identifier != NULL; i++) { for (int i = 0; _keywords[i].identifier != NULL; i++) {
@ -950,8 +953,8 @@ static bool matchChar(Parser* parser, char c) {
// If the current char is [c] eat the char and add token two otherwise eat // If the current char is [c] eat the char and add token two otherwise eat
// append token one. // append token one.
static void setNextTwoCharToken(Parser* parser, char c, TokenType one, static void setNextTwoCharToken(Parser* parser, char c, _TokenType one,
TokenType two) { _TokenType two) {
if (matchChar(parser, c)) { if (matchChar(parser, c)) {
setNextToken(parser, two); setNextToken(parser, two);
} else { } else {
@ -970,7 +973,7 @@ static Token makeErrToken(Parser* parser) {
} }
// Initialize the next token as the type. // Initialize the next token as the type.
static void setNextToken(Parser* parser, TokenType type) { static void setNextToken(Parser* parser, _TokenType type) {
Token* next = &parser->next; Token* next = &parser->next;
next->type = type; next->type = type;
next->start = parser->token_start; next->start = parser->token_start;
@ -979,7 +982,7 @@ static void setNextToken(Parser* parser, TokenType type) {
} }
// Initialize the next token as the type and assign the value. // Initialize the next token as the type and assign the value.
static void setNextValueToken(Parser* parser, TokenType type, Var value) { static void setNextValueToken(Parser* parser, _TokenType type, Var value) {
setNextToken(parser, type); setNextToken(parser, type);
parser->next.value = value; parser->next.value = value;
} }
@ -1186,13 +1189,13 @@ static void lexToken(Compiler* compiler) {
/*****************************************************************************/ /*****************************************************************************/
// Returns current token type without lexing a new token. // Returns current token type without lexing a new token.
static TokenType peek(Compiler* compiler) { static _TokenType peek(Compiler* compiler) {
return compiler->parser.current.type; return compiler->parser.current.type;
} }
// Consume the current token if it's expected and lex for the next token // Consume the current token if it's expected and lex for the next token
// and return true otherwise return false. // and return true otherwise return false.
static bool match(Compiler* compiler, TokenType expected) { static bool match(Compiler* compiler, _TokenType expected) {
if (peek(compiler) != expected) return false; if (peek(compiler) != expected) return false;
lexToken(compiler); lexToken(compiler);
@ -1203,7 +1206,7 @@ static bool match(Compiler* compiler, TokenType expected) {
// Consume the the current token and if it's not [expected] emits error log // Consume the the current token and if it's not [expected] emits error log
// and continue parsing for more error logs. // and continue parsing for more error logs.
static void consume(Compiler* compiler, TokenType expected, static void consume(Compiler* compiler, _TokenType expected,
const char* err_msg) { const char* err_msg) {
lexToken(compiler); lexToken(compiler);
@ -1272,7 +1275,7 @@ static void consumeEndStatement(Compiler* compiler) {
} }
// Match optional "do" or "then" keyword and new lines. // Match optional "do" or "then" keyword and new lines.
static void consumeStartBlock(Compiler* compiler, TokenType delimiter) { static void consumeStartBlock(Compiler* compiler, _TokenType delimiter) {
bool consumed = false; bool consumed = false;
// Match optional "do" or "then". // Match optional "do" or "then".
@ -1500,7 +1503,7 @@ static int emitByte(Compiler* compiler, int byte);
static int emitShort(Compiler* compiler, int arg); static int emitShort(Compiler* compiler, int arg);
static void emitLoopJump(Compiler* compiler); static void emitLoopJump(Compiler* compiler);
static void emitAssignedOp(Compiler* compiler, TokenType assignment); static void emitAssignedOp(Compiler* compiler, _TokenType assignment);
static void emitFunctionEnd(Compiler* compiler); static void emitFunctionEnd(Compiler* compiler);
static void patchJump(Compiler* compiler, int addr_index); static void patchJump(Compiler* compiler, int addr_index);
@ -1628,7 +1631,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
/* TK_STRING_INTERP */ { exprInterpolation, NULL, NO_INFIX }, /* TK_STRING_INTERP */ { exprInterpolation, NULL, NO_INFIX },
}; };
static GrammarRule* getRule(TokenType type) { static GrammarRule* getRule(_TokenType type) {
return &(rules[(int)type]); return &(rules[(int)type]);
} }
@ -1764,7 +1767,7 @@ static void _compileCall(Compiler* compiler, Opcode call_type, int method) {
// emit the call. Return true if such call matched. If [method] >= 0 it'll // emit the call. Return true if such call matched. If [method] >= 0 it'll
// compile a method call otherwise a regular call. // compile a method call otherwise a regular call.
static bool _compileOptionalParanCall(Compiler* compiler, int method) { static bool _compileOptionalParanCall(Compiler* compiler, int method) {
static TokenType tk[] = { static _TokenType tk[] = {
TK_FN, TK_FN,
//TK_STRING, //TK_STRING,
//TK_STRING_INTERP, //TK_STRING_INTERP,
@ -1861,7 +1864,7 @@ static void exprName(Compiler* compiler) {
NameSearchResult result = compilerSearchName(compiler, start, length); NameSearchResult result = compilerSearchName(compiler, start, length);
if (compiler->l_value && matchAssignment(compiler)) { if (compiler->l_value && matchAssignment(compiler)) {
TokenType assignment = compiler->parser.previous.type; _TokenType assignment = compiler->parser.previous.type;
skipNewLines(compiler); skipNewLines(compiler);
// Type of the name that's being assigned. Could only be local, global // Type of the name that's being assigned. Could only be local, global
@ -1995,7 +1998,7 @@ void exprAnd(Compiler* compiler) {
} }
static void exprBinaryOp(Compiler* compiler) { static void exprBinaryOp(Compiler* compiler) {
TokenType op = compiler->parser.previous.type; _TokenType op = compiler->parser.previous.type;
skipNewLines(compiler); skipNewLines(compiler);
parsePrecedence(compiler, (Precedence)(getRule(op)->precedence + 1)); parsePrecedence(compiler, (Precedence)(getRule(op)->precedence + 1));
@ -2032,7 +2035,7 @@ static void exprBinaryOp(Compiler* compiler) {
} }
static void exprUnaryOp(Compiler* compiler) { static void exprUnaryOp(Compiler* compiler) {
TokenType op = compiler->parser.previous.type; _TokenType op = compiler->parser.previous.type;
skipNewLines(compiler); skipNewLines(compiler);
parsePrecedence(compiler, (Precedence)(PREC_UNARY + 1)); parsePrecedence(compiler, (Precedence)(PREC_UNARY + 1));
@ -2120,7 +2123,7 @@ static void exprAttrib(Compiler* compiler) {
if (_compileOptionalParanCall(compiler, index)) return; if (_compileOptionalParanCall(compiler, index)) return;
if (compiler->l_value && matchAssignment(compiler)) { if (compiler->l_value && matchAssignment(compiler)) {
TokenType assignment = compiler->parser.previous.type; _TokenType assignment = compiler->parser.previous.type;
skipNewLines(compiler); skipNewLines(compiler);
if (assignment != TK_EQ) { if (assignment != TK_EQ) {
@ -2146,7 +2149,7 @@ static void exprSubscript(Compiler* compiler) {
consume(compiler, TK_RBRACKET, "Expected ']' after subscription ends."); consume(compiler, TK_RBRACKET, "Expected ']' after subscription ends.");
if (compiler->l_value && matchAssignment(compiler)) { if (compiler->l_value && matchAssignment(compiler)) {
TokenType assignment = compiler->parser.previous.type; _TokenType assignment = compiler->parser.previous.type;
skipNewLines(compiler); skipNewLines(compiler);
if (assignment != TK_EQ) { if (assignment != TK_EQ) {
@ -2166,7 +2169,7 @@ static void exprSubscript(Compiler* compiler) {
} }
static void exprValue(Compiler* compiler) { static void exprValue(Compiler* compiler) {
TokenType op = compiler->parser.previous.type; _TokenType op = compiler->parser.previous.type;
switch (op) { switch (op) {
case TK_NULL: emitOpcode(compiler, OP_PUSH_NULL); break; case TK_NULL: emitOpcode(compiler, OP_PUSH_NULL); break;
case TK_TRUE: emitOpcode(compiler, OP_PUSH_TRUE); break; case TK_TRUE: emitOpcode(compiler, OP_PUSH_TRUE); break;
@ -2262,7 +2265,7 @@ static void parsePrecedence(Compiler* compiler, Precedence precedence) {
lexToken(compiler); lexToken(compiler);
if (compiler->parser.has_syntax_error) return; if (compiler->parser.has_syntax_error) return;
TokenType op = compiler->parser.previous.type; _TokenType op = compiler->parser.previous.type;
GrammarFn infix = getRule(op)->infix; GrammarFn infix = getRule(op)->infix;
infix(compiler); infix(compiler);
@ -2459,7 +2462,7 @@ static void emitLoopJump(Compiler* compiler) {
emitShort(compiler, offset); emitShort(compiler, offset);
} }
static void emitAssignedOp(Compiler* compiler, TokenType assignment) { static void emitAssignedOp(Compiler* compiler, _TokenType assignment) {
// Emits the opcode and 1 (means true) as inplace operation. // Emits the opcode and 1 (means true) as inplace operation.
#define EMIT_BINARY_OP_INPLACE(opcode)\ #define EMIT_BINARY_OP_INPLACE(opcode)\
do { emitOpcode(compiler, opcode); emitByte(compiler, 1); } while (false) do { emitOpcode(compiler, opcode); emitByte(compiler, 1); } while (false)
@ -2834,7 +2837,7 @@ static void compileBlockBody(Compiler* compiler, BlockType type) {
skipNewLines(compiler); skipNewLines(compiler);
} }
TokenType next = peek(compiler); _TokenType next = peek(compiler);
while (!(next == TK_END || next == TK_EOF || while (!(next == TK_END || next == TK_EOF ||
((type == BLOCK_IF) && (next == TK_ELSE)))) { ((type == BLOCK_IF) && (next == TK_ELSE)))) {

View File

@ -7,11 +7,13 @@
#ifndef PK_COMPILER_H #ifndef PK_COMPILER_H
#define PK_COMPILER_H #define PK_COMPILER_H
#include "pk_value.h" #ifndef PK_AMALGAMATED
#include "value.h"
#endif
typedef enum { typedef enum {
#define OPCODE(name, _, __) OP_##name, #define OPCODE(name, _, __) OP_##name,
#include "pk_opcodes.h" #include "opcodes.h" //<< AMALG_INLINE >>
#undef OPCODE #undef OPCODE
} Opcode; } Opcode;

View File

@ -4,26 +4,17 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "pk_core.h"
#include <ctype.h> #include <ctype.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include "pk_debug.h" #ifndef PK_AMALGAMATED
#include "pk_utils.h" #include "core.h"
#include "pk_vm.h" #include "debug.h"
#include "utils.h"
// Returns the docstring of the function, which is a static const char* defined #include "vm.h"
// just above the function by the DEF() macro below. #endif
#define DOCSTRING(fn) _pk_doc_##fn
// A macro to declare a function, with docstring, which is defined as
// _pk_doc_<fn> = docstring; That'll used to generate function help text.
#define DEF(fn, docstring) \
static const char* DOCSTRING(fn) = docstring; \
static void fn(PKVM* vm)
// A convenient macro to get the nth (1 based) argument of the current // A convenient macro to get the nth (1 based) argument of the current
// function. // function.
@ -955,8 +946,6 @@ static void initializePrimitiveClasses(PKVM* vm) {
} }
#undef IS_NUM_BYTE #undef IS_NUM_BYTE
#undef DOCSTRING
#undef DEF
/*****************************************************************************/ /*****************************************************************************/
/* OPERATORS */ /* OPERATORS */

View File

@ -7,8 +7,10 @@
#ifndef PK_CORE_H #ifndef PK_CORE_H
#define PK_CORE_H #define PK_CORE_H
#include "pk_internal.h" #ifndef PK_AMALGAMATED
#include "pk_value.h" #include "internal.h"
#include "value.h"
#endif
// Literal strings used in various places in pocketlang. For now these are // Literal strings used in various places in pocketlang. For now these are
// defined as macros so that it'll be easier in the future to refactor or // defined as macros so that it'll be easier in the future to refactor or

View File

@ -4,10 +4,12 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "pk_debug.h"
#include <stdio.h> #include <stdio.h>
#include "pk_vm.h"
#ifndef PK_AMALGAMATED
#include "debug.h"
#include "vm.h"
#endif
// FIXME: // FIXME:
// Refactor this. Maybe move to a module, Rgb values are hardcoded ?! // Refactor this. Maybe move to a module, Rgb values are hardcoded ?!
@ -257,7 +259,7 @@ void reportRuntimeError(PKVM* vm, Fiber* fiber) {
// Opcode names array. // Opcode names array.
static const char* op_names[] = { static const char* op_names[] = {
#define OPCODE(name, params, stack) #name, #define OPCODE(name, params, stack) #name,
#include "pk_opcodes.h" #include "opcodes.h" //<< AMALG_INLINE >>
#undef OPCODE #undef OPCODE
}; };

View File

@ -7,8 +7,10 @@
#ifndef PK_DEBUG_H #ifndef PK_DEBUG_H
#define PK_DEBUG_H #define PK_DEBUG_H
#include "pk_internal.h" #ifndef PK_AMALGAMATED
#include "pk_value.h" #include "internal.h"
#include "value.h"
#endif
// Pretty print compile time error. // Pretty print compile time error.
void reportCompileTimeError(PKVM* vm, const char* path, int line, void reportCompileTimeError(PKVM* vm, const char* path, int line,

View File

@ -7,9 +7,10 @@
#ifndef PK_INTERNAL #ifndef PK_INTERNAL
#define PK_INTERNAL #define PK_INTERNAL
#include "include/pocketlang.h" #ifndef PK_AMALGAMATED
#include <pocketlang.h>
#include "pk_common.h" #include "common.h"
#endif
// Commonly used C standard headers across the sources. Don't include any // Commonly used C standard headers across the sources. Don't include any
// headers that are specific to a single source here, instead include them in // headers that are specific to a single source here, instead include them in
@ -112,6 +113,16 @@
/* REUSABLE INTERNAL MACROS */ /* REUSABLE INTERNAL MACROS */
/*****************************************************************************/ /*****************************************************************************/
// Returns the docstring of the function, which is a static const char* defined
// just above the function by the DEF() macro below.
#define DOCSTRING(fn) _pk_doc_##fn
// A macro to declare a function, with docstring, which is defined as
// _pk_doc_<fn> = docstring; That'll used to generate function help text.
#define DEF(fn, docstring) \
static const char* DOCSTRING(fn) = docstring; \
static void fn(PKVM* vm)
// Here we're switching the FNV-1a hash value of the name (cstring). Which is // Here we're switching the FNV-1a hash value of the name (cstring). Which is
// an efficient way than having multiple if (attrib == "name"). From O(n) * k // an efficient way than having multiple if (attrib == "name"). From O(n) * k
// to O(1) where n is the length of the string and k is the number of string // to O(1) where n is the length of the string and k is the number of string

View File

@ -6,13 +6,14 @@
// This file contains all the pocketlang public function implementations. // This file contains all the pocketlang public function implementations.
#include "include/pocketlang.h" #ifndef PK_AMALGAMATED
#include <pocketlang.h>
#include "pk_core.h" #include "core.h"
#include "pk_compiler.h" #include "compiler.h"
#include "pk_utils.h" #include "utils.h"
#include "pk_value.h" #include "value.h"
#include "pk_vm.h" #include "vm.h"
#endif
#define CHECK_ARG_NULL(name) \ #define CHECK_ARG_NULL(name) \
ASSERT((name) != NULL, "Argument " #name " was NULL."); ASSERT((name) != NULL, "Argument " #name " was NULL.");
@ -85,20 +86,35 @@ void pkDeAllocString(PKVM* vm, char* str) {
vm->config.realloc_fn(str, 0, vm->config.user_data); vm->config.realloc_fn(str, 0, vm->config.user_data);
} }
// TODO: Document this or Find a better way.
//
// Pocketlang core doesn't implement path resolving funcionality. Rather it
// should be provided the host application. By default we're using an
// implementation from the path library. However pocket core cannot be depend
// on its libs, otherwise it'll breaks the encapsulation.
//
// As a workaround we declare the default path resolver here and use it.
// But if someone wants to compile just the core pocketlang without libs
// they have to define PK_NO_LIBS to prevent the compiler from not be able
// to find functions when linking.
#if !defined(PK_NO_LIBS)
char* pathResolveImport(PKVM* vm, const char* from, const char* path);
#endif
PkConfiguration pkNewConfiguration() { PkConfiguration pkNewConfiguration() {
PkConfiguration config; PkConfiguration config;
memset(&config, 0, sizeof(config));
config.realloc_fn = defaultRealloc; config.realloc_fn = defaultRealloc;
config.stdout_write = stdoutWrite; config.stdout_write = stdoutWrite;
config.stderr_write = stderrWrite; config.stderr_write = stderrWrite;
config.stdin_read = stdinRead; config.stdin_read = stdinRead;
#if !defined(PK_NO_LIBS)
config.resolve_path_fn = NULL; config.resolve_path_fn = pathResolveImport;
#endif
config.load_script_fn = loadScript; config.load_script_fn = loadScript;
config.use_ansi_color = false;
config.user_data = NULL;
return config; return config;
} }

View File

@ -4,7 +4,9 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "pk_utils.h" #ifndef PK_AMALGAMATED
#include "utils.h"
#endif
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>

View File

@ -4,13 +4,14 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "pk_value.h"
#include <math.h> #include <math.h>
#include <ctype.h> #include <ctype.h>
#include "pk_utils.h" #ifndef PK_AMALGAMATED
#include "pk_vm.h" #include "value.h"
#include "utils.h"
#include "vm.h"
#endif
// The maximum percentage of the map entries that can be filled before the map // The maximum percentage of the map entries that can be filled before the map
// is grown. A lower percentage reduce collision which makes looks up faster // is grown. A lower percentage reduce collision which makes looks up faster

View File

@ -7,8 +7,10 @@
#ifndef PK_VALUE_H #ifndef PK_VALUE_H
#define PK_VALUE_H #define PK_VALUE_H
#include "pk_buffers.h" #ifndef PK_AMALGAMATED
#include "pk_internal.h" #include "buffers.h"
#include "internal.h"
#endif
/** /**
* A simple dynamic type system library for small dynamic typed languages using * A simple dynamic type system library for small dynamic typed languages using

View File

@ -4,11 +4,13 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "pk_vm.h"
#include <math.h> #include <math.h>
#include "pk_utils.h"
#include "pk_debug.h" #ifndef PK_AMALGAMATED
#include "vm.h"
#include "utils.h"
#include "debug.h"
#endif
PkHandle* vmNewHandle(PKVM* vm, Var value) { PkHandle* vmNewHandle(PKVM* vm, Var value) {
PkHandle* handle = (PkHandle*)ALLOCATE(vm, PkHandle); PkHandle* handle = (PkHandle*)ALLOCATE(vm, PkHandle);
@ -634,7 +636,7 @@ static void closeUpvalues(Fiber* fiber, Var* top) {
} }
} }
static void reportError(PKVM* vm) { static void vmReportError(PKVM* vm) {
ASSERT(VM_HAS_ERROR(vm), "runtimeError() should be called after an error."); ASSERT(VM_HAS_ERROR(vm), "runtimeError() should be called after an error.");
// TODO: pass the error to the caller of the fiber. // TODO: pass the error to the caller of the fiber.
@ -701,7 +703,7 @@ PkResult vmRunFiber(PKVM* vm, Fiber* fiber_) {
do { \ do { \
if (VM_HAS_ERROR(vm)) { \ if (VM_HAS_ERROR(vm)) { \
UPDATE_FRAME(); \ UPDATE_FRAME(); \
reportError(vm); \ vmReportError(vm); \
FIBER_SWITCH_BACK(); \ FIBER_SWITCH_BACK(); \
return PK_RESULT_RUNTIME_ERROR; \ return PK_RESULT_RUNTIME_ERROR; \
} \ } \
@ -712,7 +714,7 @@ PkResult vmRunFiber(PKVM* vm, Fiber* fiber_) {
do { \ do { \
VM_SET_ERROR(vm, err_msg); \ VM_SET_ERROR(vm, err_msg); \
UPDATE_FRAME(); \ UPDATE_FRAME(); \
reportError(vm); \ vmReportError(vm); \
FIBER_SWITCH_BACK(); \ FIBER_SWITCH_BACK(); \
return PK_RESULT_RUNTIME_ERROR; \ return PK_RESULT_RUNTIME_ERROR; \
} while (false) } while (false)

View File

@ -7,8 +7,10 @@
#ifndef PK_VM_H #ifndef PK_VM_H
#define PK_VM_H #define PK_VM_H
#include "pk_compiler.h" #ifndef PK_AMALGAMATED
#include "pk_core.h" #include "compiler.h"
#include "core.h"
#endif
// The maximum number of temporary object reference to protect them from being // The maximum number of temporary object reference to protect them from being
// garbage collected. // garbage collected.

View File

@ -197,6 +197,11 @@ PK_PUBLIC PKVM* pkNewVM(PkConfiguration* config);
// Clean the VM and dispose all the resources allocated by the VM. // Clean the VM and dispose all the resources allocated by the VM.
PK_PUBLIC void pkFreeVM(PKVM* vm); PK_PUBLIC void pkFreeVM(PKVM* vm);
// This will register all the standard libraries of pocketlang to the VM. The
// libraries are not part of the core implementation, and one can use just the
// bare bone of the language without any libraries if they don't call this.
PK_PUBLIC void pkRegisterLibs(PKVM* vm);
// Update the user data of the vm. // Update the user data of the vm.
PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data); PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data);

21
src/libs/libs.c Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2020-2022 Thakee Nathees
* Copyright (c) 2021-2022 Pocketlang Contributors
* Distributed Under The MIT License
*/
#ifndef PK_AMALGAMATED
#include "libs.h"
#endif
void registerModuleDummy(PKVM* vm);
void registerModuleIO(PKVM* vm);
void registerModulePath(PKVM* vm);
void registerModuleMath(PKVM* vm);
void pkRegisterLibs(PKVM* vm) {
registerModuleDummy(vm);
registerModuleIO(vm);
registerModulePath(vm);
registerModuleMath(vm);
}

View File

@ -4,11 +4,25 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#ifndef PK_COMMON_H #ifndef LIBS_H
#define PK_COMMON_H #define LIBS_H
#include <stdio.h> //< Only needed here for ASSERT() macro and for release mode #ifndef PK_AMALGAMATED
//< TODO; macro use this to print a crash report. #include <pocketlang.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <string.h>
/*****************************************************************************/
/* MODULES INTERNAL */
/*****************************************************************************/
// We're re defining some core internal macros here which should be considered
// as macro re-definition in amalgamated source, so we're skipping it for
// amalgumated build.
#ifndef PK_AMALGAMATED
#define TOSTRING(x) #x #define TOSTRING(x) #x
#define STRINGIFY(x) TOSTRING(x) #define STRINGIFY(x) TOSTRING(x)
@ -83,23 +97,40 @@
#endif // DEBUG #endif // DEBUG
#if defined(_MSC_VER)
#define forceinline __forceinline
#else
#define forceinline __attribute__((always_inline))
#endif
// To use dynamic variably-sized struct with a tail array add an array at the
// end of the struct with size DYNAMIC_TAIL_ARRAY. This method was a legacy
// standard called "struct hack".
#if defined(_MSC_VER) || __STDC_VERSION__ >= 199901L // stdc >= c99
#define DYNAMIC_TAIL_ARRAY
#else
#define DYNAMIC_TAIL_ARRAY 0
#endif
// Using __ASSERT() for make it crash in release binary too. // Using __ASSERT() for make it crash in release binary too.
#define TODO __ASSERT(false, "TODO: It hasn't implemented yet.") #define TODO __ASSERT(false, "TODO: It hasn't implemented yet.")
#define OOPS "Oops a bug!! report please." #define OOPS "Oops a bug!! report please."
#endif //PK_COMMON_H // Returns the docstring of the function, which is a static const char* defined
// just above the function by the DEF() macro below.
#define DOCSTRING(fn) __doc_##fn
// A macro to declare a function, with docstring, which is defined as
// ___doc_<fn> = docstring; That'll used to generate function help text.
#define DEF(fn, docstring) \
static const char* DOCSTRING(fn) = docstring; \
static void fn(PKVM* vm)
#endif // PK_AMALGAMATED
// Allocate a new module object of type [Ty].
#define NEW_OBJ(Ty) (Ty*) malloc(sizeof(Ty))
// Dellocate module object, allocated by NEW_OBJ(). Called by the freeObj
// callback.
#define FREE_OBJ(ptr) free(ptr)
/*****************************************************************************/
/* SHARED FUNCTIONS */
/*****************************************************************************/
// These are "public" module functions that can be shared. Since some modules
// can be used for cli's internals we're defining such functions here and they
// will be imported in the cli.
// The pocketlang's import statement path resolving function. This
// implementation is required by pockelang from it's hosting application
// inorder to use the import statements.
char* pathResolveImport(PKVM * vm, const char* from, const char* path);
#endif // LIBS_H

View File

@ -4,7 +4,9 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "modules.h" #ifndef PK_AMALGAMATED
#include "libs.h"
#endif
// A DUMMY MODULE TO TEST NATIVE INTERFACE AND CLASSES. // A DUMMY MODULE TO TEST NATIVE INTERFACE AND CLASSES.

View File

@ -4,7 +4,9 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "modules.h" #ifndef PK_AMALGAMATED
#include "libs.h"
#endif
/*****************************************************************************/ /*****************************************************************************/
/* FILE CLASS */ /* FILE CLASS */
@ -161,8 +163,7 @@ DEF(_fileClose, "") {
} }
if (fclose(file->fp) != 0) { if (fclose(file->fp) != 0) {
pkSetRuntimeError(vm, "fclose() failed!\n" \ pkSetRuntimeError(vm, "fclose() failed!.");
" at " __FILE__ ":" STRINGIFY(__LINE__) ".");
} }
file->closed = true; file->closed = true;
} }

View File

@ -4,10 +4,12 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "modules.h"
#include <math.h> #include <math.h>
#ifndef PK_AMALGAMATED
#include "libs.h"
#endif
// M_PI is non standard. For a portable solution, we're defining it ourselves. // M_PI is non standard. For a portable solution, we're defining it ourselves.
#define PK_PI 3.14159265358979323846 #define PK_PI 3.14159265358979323846

View File

@ -4,14 +4,18 @@
* Distributed Under The MIT License * Distributed Under The MIT License
*/ */
#include "modules.h" #ifndef PK_AMALGAMATED
#include "libs.h"
#endif
// FIXME: // FIXME:
// In windows MinGw support most of the posix libraries. So we only need to // In windows MinGw support most of the posix libraries. So we only need to
// check if it's MSVC (and tcc in windows) or not for posix headers and // check if it's MSVC (and tcc in windows) or not for posix headers and
// Refactor the bellow macro includes. // Refactor the bellow macro includes.
#include "thirdparty/cwalk/cwalk.h" #define _CWALK_IMPL
#include "tp_cwalk.h" //<< AMALG_INLINE >>
#undef _CWALK_IMPL
#include <errno.h> #include <errno.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -21,10 +25,11 @@
#endif #endif
#if defined(_MSC_VER) || (defined(_WIN32) && defined(__TINYC__)) #if defined(_MSC_VER) || (defined(_WIN32) && defined(__TINYC__))
#include "thirdparty/dirent/dirent.h"
#include <direct.h> #include <direct.h>
#include <io.h> #include <io.h>
#include "tp_dirent.h" //<< AMALG_INLINE >>
// access() function flag defines for windows. // access() function flag defines for windows.
// Reference :https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=msvc-170#remarks // Reference :https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=msvc-170#remarks
#define F_OK 0 #define F_OK 0

View File

@ -1,10 +1,525 @@
/*
* MIT License
*
* Copyright (c) 2020 Leonard Iklé
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CWK_LIBRARY_H
#define CWK_LIBRARY_H
#include <stdbool.h>
#include <stddef.h>
#if defined(_WIN32) || defined(__CYGWIN__)
#define CWK_EXPORT __declspec(dllexport)
#define CWK_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
#define CWK_EXPORT __attribute__((visibility("default")))
#define CWK_IMPORT __attribute__((visibility("default")))
#else
#define CWK_EXPORT
#define CWK_IMPORT
#endif
#if defined(CWK_SHARED)
#if defined(CWK_EXPORTS)
#define CWK_PUBLIC CWK_EXPORT
#else
#define CWK_PUBLIC CWK_IMPORT
#endif
#else
#define CWK_PUBLIC
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/**
* A segment represents a single component of a path. For instance, on linux a
* path might look like this "/var/log/", which consists of two segments "var"
* and "log".
*/
struct cwk_segment
{
const char* path;
const char* segments;
const char* begin;
const char* end;
size_t size;
};
/**
* The segment type can be used to identify whether a segment is a special
* segment or not.
*
* CWK_NORMAL - normal folder or file segment
* CWK_CURRENT - "./" current folder segment
* CWK_BACK - "../" relative back navigation segment
*/
enum cwk_segment_type
{
CWK_NORMAL,
CWK_CURRENT,
CWK_BACK
};
/**
* @brief Determines the style which is used for the path parsing and
* generation.
*/
enum cwk_path_style
{
CWK_STYLE_WINDOWS,
CWK_STYLE_UNIX
};
/**
* @brief Generates an absolute path based on a base.
*
* This function generates an absolute path based on a base path and another
* path. It is guaranteed to return an absolute path. If the second submitted
* path is absolute, it will override the base path. The result will be
* written to a buffer, which might be truncated if the buffer is not large
* enough to hold the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param base The absolute base path on which the relative path will be
* applied.
* @param path The relative path which will be applied on the base path.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the new absolute path.
*/
CWK_PUBLIC size_t cwk_path_get_absolute(const char* base, const char* path,
char* buffer, size_t buffer_size);
/**
* @brief Generates a relative path based on a base.
*
* This function generates a relative path based on a base path and another
* path. It determines how to get to the submitted path, starting from the
* base directory. The result will be written to a buffer, which might be
* truncated if the buffer is not large enough to hold the full path. However,
* the truncated result will always be null-terminated. The returned value is
* the amount of characters which the resulting path would take if it was not
* truncated (excluding the null-terminating character).
*
* @param base_directory The base path from which the relative path will
* start.
* @param path The target path where the relative path will point to.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full path.
*/
CWK_PUBLIC size_t cwk_path_get_relative(const char* base_directory,
const char* path, char* buffer, size_t buffer_size);
/**
* @brief Joins two paths together.
*
* This function generates a new path by combining the two submitted paths. It
* will remove double separators, and unlike cwk_path_get_absolute it permits
* the use of two relative paths to combine. The result will be written to a
* buffer, which might be truncated if the buffer is not large enough to hold
* the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param path_a The first path which comes first.
* @param path_b The second path which comes after the first.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full, combined path.
*/
CWK_PUBLIC size_t cwk_path_join(const char* path_a, const char* path_b,
char* buffer, size_t buffer_size);
/**
* @brief Joins multiple paths together.
*
* This function generates a new path by joining multiple paths together. It
* will remove double separators, and unlike cwk_path_get_absolute it permits
* the use of multiple relative paths to combine. The last path of the
* submitted string array must be set to NULL. The result will be written to a
* buffer, which might be truncated if the buffer is not large enough to hold
* the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param paths An array of paths which will be joined.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full, combined path.
*/
CWK_PUBLIC size_t cwk_path_join_multiple(const char** paths, char* buffer,
size_t buffer_size);
/**
* @brief Determines the root of a path.
*
* This function determines the root of a path by finding it's length. The
* root always starts at the submitted path. If the path has no root, the
* length will be set to zero.
*
* @param path The path which will be inspected.
* @param length The output of the root length.
*/
CWK_PUBLIC void cwk_path_get_root(const char* path, size_t* length);
/**
* @brief Changes the root of a path.
*
* This function changes the root of a path. It does not normalize the result.
* The result will be written to a buffer, which might be truncated if the
* buffer is not large enough to hold the full path. However, the truncated
* result will always be null-terminated. The returned value is the amount of
* characters which the resulting path would take if it was not truncated
* (excluding the null-terminating character).
*
* @param path The original path which will get a new root.
* @param new_root The new root which will be placed in the path.
* @param buffer The output buffer where the result is written to.
* @param buffer_size The size of the output buffer where the result is
* written to.
* @return Returns the total amount of characters of the new path.
*/
CWK_PUBLIC size_t cwk_path_change_root(const char* path, const char* new_root,
char* buffer, size_t buffer_size);
/**
* @brief Determine whether the path is absolute or not.
*
* This function checks whether the path is an absolute path or not. A path is
* considered to be absolute if the root ends with a separator.
*
* @param path The path which will be checked.
* @return Returns true if the path is absolute or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_absolute(const char* path);
/**
* @brief Determine whether the path is relative or not.
*
* This function checks whether the path is a relative path or not. A path is
* considered to be relative if the root does not end with a separator.
*
* @param path The path which will be checked.
* @return Returns true if the path is relative or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_relative(const char* path);
/**
* @brief Gets the basename of a file path.
*
* This function gets the basename of a file path. A pointer to the beginning
* of the basename will be returned through the basename parameter. This
* pointer will be positioned on the first letter after the separator. The
* length of the file path will be returned through the length parameter. The
* length will be set to zero and the basename to NULL if there is no basename
* available.
*
* @param path The path which will be inspected.
* @param basename The output of the basename pointer.
* @param length The output of the length of the basename.
*/
CWK_PUBLIC void cwk_path_get_basename(const char* path, const char** basename,
size_t* length);
/**
* @brief Changes the basename of a file path.
*
* This function changes the basename of a file path. This function will not
* write out more than the specified buffer can contain. However, the
* generated string is always null-terminated - even if not the whole path is
* written out. The function returns the total number of characters the
* complete buffer would have, even if it was not written out completely. The
* path may be the same memory address as the buffer.
*
* @param path The original path which will be used for the modified path.
* @param new_basename The new basename which will replace the old one.
* @param buffer The buffer where the changed path will be written to.
* @param buffer_size The size of the result buffer where the changed path is
* written to.
* @return Returns the size which the complete new path would have if it was
* not truncated.
*/
CWK_PUBLIC size_t cwk_path_change_basename(const char* path,
const char* new_basename, char* buffer, size_t buffer_size);
/**
* @brief Gets the dirname of a file path.
*
* This function determines the dirname of a file path and returns the length
* up to which character is considered to be part of it. If no dirname is
* found, the length will be set to zero. The beginning of the dirname is
* always equal to the submitted path pointer.
*
* @param path The path which will be inspected.
* @param length The length of the dirname.
*/
CWK_PUBLIC void cwk_path_get_dirname(const char* path, size_t* length);
/**
* @brief Gets the extension of a file path.
*
* This function extracts the extension portion of a file path. A pointer to
* the beginning of the extension will be returned through the extension
* parameter if an extension is found and true is returned. This pointer will
* be positioned on the dot. The length of the extension name will be returned
* through the length parameter. If no extension is found both parameters
* won't be touched and false will be returned.
*
* @param path The path which will be inspected.
* @param extension The output of the extension pointer.
* @param length The output of the length of the extension.
* @return Returns true if an extension is found or false otherwise.
*/
CWK_PUBLIC bool cwk_path_get_extension(const char* path, const char** extension,
size_t* length);
/**
* @brief Determines whether the file path has an extension.
*
* This function determines whether the submitted file path has an extension.
* This will evaluate to true if the last segment of the path contains a dot.
*
* @param path The path which will be inspected.
* @return Returns true if the path has an extension or false otherwise.
*/
CWK_PUBLIC bool cwk_path_has_extension(const char* path);
/**
* @brief Changes the extension of a file path.
*
* This function changes the extension of a file name. The function will
* append an extension if the basename does not have an extension, or use the
* extension as a basename if the path does not have a basename. This function
* will not write out more than the specified buffer can contain. However, the
* generated string is always null-terminated - even if not the whole path is
* written out. The function returns the total number of characters the
* complete buffer would have, even if it was not written out completely. The
* path may be the same memory address as the buffer.
*
* @param path The path which will be used to make the change.
* @param new_extension The extension which will be placed within the new
* path.
* @param buffer The output buffer where the result will be written to.
* @param buffer_size The size of the output buffer where the result will be
* written to.
* @return Returns the total size which the output would have if it was not
* truncated.
*/
CWK_PUBLIC size_t cwk_path_change_extension(const char* path,
const char* new_extension, char* buffer, size_t buffer_size);
/**
* @brief Creates a normalized version of the path.
*
* This function creates a normalized version of the path within the specified
* buffer. This function will not write out more than the specified buffer can
* contain. However, the generated string is always null-terminated - even if
* not the whole path is written out. The function returns the total number of
* characters the complete buffer would have, even if it was not written out
* completely. The path may be the same memory address as the buffer.
*
* The following will be true for the normalized path:
* 1) "../" will be resolved.
* 2) "./" will be removed.
* 3) double separators will be fixed with a single separator.
* 4) separator suffixes will be removed.
*
* @param path The path which will be normalized.
* @param buffer The buffer where the new path is written to.
* @param buffer_size The size of the buffer.
* @return The size which the complete normalized path has if it was not
* truncated.
*/
CWK_PUBLIC size_t cwk_path_normalize(const char* path, char* buffer,
size_t buffer_size);
/**
* @brief Finds common portions in two paths.
*
* This function finds common portions in two paths and returns the number
* characters from the beginning of the base path which are equal to the other
* path.
*
* @param path_base The base path which will be compared with the other path.
* @param path_other The other path which will compared with the base path.
* @return Returns the number of characters which are common in the base path.
*/
CWK_PUBLIC size_t cwk_path_get_intersection(const char* path_base,
const char* path_other);
/**
* @brief Gets the first segment of a path.
*
* This function finds the first segment of a path. The position of the
* segment is set to the first character after the separator, and the length
* counts all characters until the next separator (excluding the separator).
*
* @param path The path which will be inspected.
* @param segment The segment which will be extracted.
* @return Returns true if there is a segment or false if there is none.
*/
CWK_PUBLIC bool cwk_path_get_first_segment(const char* path,
struct cwk_segment* segment);
/**
* @brief Gets the last segment of the path.
*
* This function gets the last segment of a path. This function may return
* false if the path doesn't contain any segments, in which case the submitted
* segment parameter is not modified. The position of the segment is set to
* the first character after the separator, and the length counts all
* characters until the end of the path (excluding the separator).
*
* @param path The path which will be inspected.
* @param segment The segment which will be extracted.
* @return Returns true if there is a segment or false if there is none.
*/
CWK_PUBLIC bool cwk_path_get_last_segment(const char* path,
struct cwk_segment* segment);
/**
* @brief Advances to the next segment.
*
* This function advances the current segment to the next segment. If there
* are no more segments left, the submitted segment structure will stay
* unchanged and false is returned.
*
* @param segment The current segment which will be advanced to the next one.
* @return Returns true if another segment was found or false otherwise.
*/
CWK_PUBLIC bool cwk_path_get_next_segment(struct cwk_segment* segment);
/**
* @brief Moves to the previous segment.
*
* This function moves the current segment to the previous segment. If the
* current segment is the first one, the submitted segment structure will stay
* unchanged and false is returned.
*
* @param segment The current segment which will be moved to the previous one.
* @return Returns true if there is a segment before this one or false
* otherwise.
*/
CWK_PUBLIC bool cwk_path_get_previous_segment(struct cwk_segment* segment);
/**
* @brief Gets the type of the submitted path segment.
*
* This function inspects the contents of the segment and determines the type
* of it. Currently, there are three types CWK_NORMAL, CWK_CURRENT and
* CWK_BACK. A CWK_NORMAL segment is a normal folder or file entry. A
* CWK_CURRENT is a "./" and a CWK_BACK a "../" segment.
*
* @param segment The segment which will be inspected.
* @return Returns the type of the segment.
*/
CWK_PUBLIC enum cwk_segment_type cwk_path_get_segment_type(
const struct cwk_segment* segment);
/**
* @brief Changes the content of a segment.
*
* This function overrides the content of a segment to the submitted value and
* outputs the whole new path to the submitted buffer. The result might
* require less or more space than before if the new value length differs from
* the original length. The output is truncated if the new path is larger than
* the submitted buffer size, but it is always null-terminated. The source of
* the segment and the submitted buffer may be the same.
*
* @param segment The segment which will be modifier.
* @param value The new content of the segment.
* @param buffer The buffer where the modified path will be written to.
* @param buffer_size The size of the output buffer.
* @return Returns the total size which would have been written if the output
* was not truncated.
*/
CWK_PUBLIC size_t cwk_path_change_segment(struct cwk_segment* segment,
const char* value, char* buffer, size_t buffer_size);
/**
* @brief Checks whether the submitted pointer points to a separator.
*
* This function simply checks whether the submitted pointer points to a
* separator, which has to be null-terminated (but not necessarily after the
* separator). The function will return true if it is a separator, or false
* otherwise.
*
* @param symbol A pointer to a string.
* @return Returns true if it is a separator, or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_separator(const char* str);
/**
* @brief Guesses the path style.
*
* This function guesses the path style based on a submitted path-string. The
* guessing will look at the root and the type of slashes contained in the
* path and return the style which is more likely used in the path.
*
* @param path The path which will be inspected.
* @return Returns the style which is most likely used for the path.
*/
CWK_PUBLIC enum cwk_path_style cwk_path_guess_style(const char* path);
/**
* @brief Configures which path style is used.
*
* This function configures which path style is used. The following styles are
* currently supported.
*
* CWK_STYLE_WINDOWS: Use backslashes as a separator and volume for the root.
* CWK_STYLE_UNIX: Use slashes as a separator and a slash for the root.
*
* @param style The style which will be used from now on.
*/
CWK_PUBLIC void cwk_path_set_style(enum cwk_path_style style);
/**
* @brief Gets the path style configuration.
*
* This function gets the style configuration which is currently used for the
* paths. This configuration determines how paths are parsed and generated.
*
* @return Returns the current path style configuration.
*/
CWK_PUBLIC enum cwk_path_style cwk_path_get_style(void);
#ifdef __cplusplus
} // extern "C"
#endif
#if defined(_CWALK_IMPL)
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
/* Modified By : https://www.github.com/ThakeeNathees */
#include "cwalk.h"
/* -------------------------------------------------- */
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -1438,3 +1953,6 @@ enum cwk_path_style cwk_path_get_style(void)
// Simply return the path style which we store in a global variable. // Simply return the path style which we store in a global variable.
return path_style; return path_style;
} }
#endif // _CWALK_IMPL
#endif

View File

@ -1,3 +1,27 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 1998-2019 Toni Ronkko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* /*
* Dirent interface for Microsoft Visual Studio * Dirent interface for Microsoft Visual Studio
* *