diff --git a/src/Module/CppLibrary/CppLibrary.hpp b/src/Module/CppLibrary/CppLibrary.hpp new file mode 100644 index 0000000..0db4adb --- /dev/null +++ b/src/Module/CppLibrary/CppLibrary.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "File/File.hpp" \ No newline at end of file diff --git a/src/Module/CppLibrary/File/File.hpp b/src/Module/CppLibrary/File/File.hpp new file mode 100644 index 0000000..0341d74 --- /dev/null +++ b/src/Module/CppLibrary/File/File.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace Fig::CppLibrary +{ + using FileIDType = uint16_t; + struct File + { + FileIDType id; + std::fstream *fs; + }; + class FileManager + { + private: + std::vector handlers; + std::vector free_handlers; + + FileIDType allocated = 0; + + public: + static constexpr FileIDType MAX_HANDLERS = std::numeric_limits::max(); + static constexpr unsigned int MAX_FILE_BUF = 961200; // bytes + + FileIDType AllocFile(std::fstream *fs) + { + FileIDType id = allocated++; + File *f = new File{.id = id, .fs = fs}; + handlers.push_back(f); + return id; + } + + void CloseFile(FileIDType id) + { + assert(id < allocated && "CloseHandler: id out of range"); + File *f = handlers[id]; + if (f == nullptr) { return; } + f->fs->close(); + delete f->fs; + delete f; + free_handlers.push_back(id); + handlers[id] = nullptr; + } + + File *GetNextFreeFile() + { + // if there is no free handler, create a new one + if (free_handlers.size() > 0) + { + FileIDType id = *free_handlers.begin(); + handlers[id] = new File{.id = id, .fs = new std::fstream}; + free_handlers.erase(free_handlers.begin()); + return handlers[id]; + } + return handlers[AllocFile(new std::fstream)]; + } + + File *GetFile(FileIDType id) + { + assert(id < allocated && "GetFile: id out of range"); + return handlers[id]; + } + + static FileManager &getInstance() + { + static FileManager fm; + return fm; + } + }; +}; // namespace Fig::CppLibrary \ No newline at end of file diff --git a/src/Module/Library/std/file/file.fig b/src/Module/Library/std/file/file.fig new file mode 100644 index 0000000..fffdb94 --- /dev/null +++ b/src/Module/Library/std/file/file.fig @@ -0,0 +1,101 @@ +/* + Official Module `std.file` + Library/std/file/file.fig + + Copyright © 2026 PuqiAR. All rights reserved. +*/ + +import _builtins; +import std.io; + + +public struct __OpenMode +{ + public App: Int = 1; + public Ate: Int = 2; + public Bin: Int = 4; + public In: Int = 8; + public Out: Int = 16; + public Trunc: Int = 32; + + public __openmode_to_string: Map = + { + 1 : "App", + 2 : "Ate", + 4 : "Bin", + 8 : "In", + 16 : "Out", + 32 : "Trunc" + }; +} +public const OpenMode := new __OpenMode{}; + +public func repr_mode(mode: Int) -> String +{ + return OpenMode.__openmode_to_string[mode]; +} + + + +public struct FileError +{ + msg: String; +} + +impl Error for FileError +{ + getErrorClass() + { + return "FileError"; + } + getErrorMessage() + { + return msg; + } + toString() + { + return getErrorClass() + ": " + msg; + } +} + +public struct File +{ + path: String; + mode: Int; + + id: Int; + + public func read() -> Any + { + return __fstdfile_read(id); + } + + public func write(object: String) -> Null + { + __fstdfile_write(id, object); + } + + public func close() -> Null + { + __fstdfile_close(id); + } + + public func getID() -> Int + { + return id; + } +} + +public func open(path: String, mode: Int) +{ + const id := __fstdfile_open(path, mode); + if not __fstdfile_is_open(id) + { + throw new FileError{"File " + path + " open failed"}; + } + return new File{ + path: path, + mode: mode, + id: id + }; +} \ No newline at end of file diff --git a/src/Module/builtins.cpp b/src/Module/builtins.cpp index 6e6dbb6..0582d68 100644 --- a/src/Module/builtins.cpp +++ b/src/Module/builtins.cpp @@ -5,13 +5,19 @@ #include #include #include -#include -#include #include + #include #include -#include +#include +#include +#include + +#include +#include + +#include #include #include #include @@ -132,9 +138,18 @@ namespace Fig::Builtins {u8"__fmath_tan", 1}, {u8"__fmath_tanh", 1}, {u8"__fmath_trunc", 1}, + + /* file start */ + {u8"__fstdfile_open", 2}, + {u8"__fstdfile_close", 1}, + {u8"__fstdfile_is_open", 1}, + + {u8"__fstdfile_read", 1}, + {u8"__fstdfile_write", 2}, }; return builtinFunctionArgCounts; } + const std::unordered_map &getBuiltinFunctions() { static const std::unordered_map builtinFunctions{ @@ -421,6 +436,47 @@ namespace Fig::Builtins ValueType::DoubleClass d = val->getNumericValue(); return std::make_shared(trunc(d)); }}, + /* file start */ + {u8"__fstdfile_open", + [](const std::vector &args) -> ObjectPtr { + const FString &path = args[0]->as(); + const ValueType::IntClass &mode = args[1]->as(); + + CppLibrary::File *f = CppLibrary::FileManager::getInstance().GetNextFreeFile(); + f->fs->open(path.toBasicString(), static_cast(mode)); + return std::make_shared(static_cast(f->id)); + }}, + {u8"__fstdfile_close", + [](const std::vector &args) -> ObjectPtr { + const ValueType::IntClass &id = args[0]->as(); + CppLibrary::FileManager::getInstance().CloseFile(id); + return Object::getNullInstance(); + }}, + {u8"__fstdfile_is_open", + [](const std::vector &args) -> ObjectPtr { + const ValueType::IntClass &id = args[0]->as(); + return std::make_shared(CppLibrary::FileManager::getInstance().GetFile(id)->fs->is_open()); + }}, + {u8"__fstdfile_read", + [](const std::vector &args) -> ObjectPtr { + const ValueType::IntClass &id = args[0]->as(); + CppLibrary::File *f = CppLibrary::FileManager::getInstance().GetFile(id); + + char *buf = new char[CppLibrary::FileManager::MAX_FILE_BUF]; + f->fs->read(buf, CppLibrary::FileManager::MAX_FILE_BUF); + return std::make_shared(ValueType::StringClass(reinterpret_cast(buf))); + }}, + {u8"__fstdfile_write", + [](const std::vector &args) -> ObjectPtr { + const ValueType::IntClass &id = args[0]->as(); + const ValueType::StringClass &str = args[1]->as(); + + CppLibrary::File *f = CppLibrary::FileManager::getInstance().GetFile(id); + const char *data = reinterpret_cast(str.c_str()); + f->fs->write(data, str.size()); + return std::make_shared(static_cast(str.length())); + // bytes wrote + }}, }; return builtinFunctions; } diff --git a/src/Module/builtins.hpp b/src/Module/builtins.hpp index 86b3d26..7e9da06 100644 --- a/src/Module/builtins.hpp +++ b/src/Module/builtins.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace Fig { @@ -44,7 +45,20 @@ namespace Fig using BuiltinFunction = std::function &)>; const std::unordered_map &getBuiltinFunctionArgCounts(); - const std::unordered_map &getBuiltinFunctions(); + + /* + File + */ + + struct FileHandler + { + int64_t id; + std::fstream *fs; + }; + + std::vector &getFileHandlers(); // global + + const std::unordered_map &getBuiltinFunctions(); inline bool isBuiltinFunction(const FString &name) {