mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
[goos/goal] user profiles (#977)
* implement user profiles * example usage! * typo * use a cond * fix errors * fixes * fix potential commandline args disaster
This commit is contained in:
parent
8544e95b4b
commit
59d071eccb
|
@ -6,10 +6,11 @@
|
|||
#include <utility>
|
||||
#include "Interpreter.h"
|
||||
#include "ParseHelpers.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include <third-party/fmt/core.h>
|
||||
|
||||
namespace goos {
|
||||
Interpreter::Interpreter() {
|
||||
Interpreter::Interpreter(const std::string& username) {
|
||||
// Interpreter startup:
|
||||
goal_to_goos.reset();
|
||||
|
||||
|
@ -21,9 +22,14 @@ Interpreter::Interpreter() {
|
|||
|
||||
// make both environments available in both.
|
||||
define_var_in_env(global_environment, global_environment, "*global-env*");
|
||||
define_var_in_env(global_environment, goal_env, "*goal-env*");
|
||||
define_var_in_env(goal_env, goal_env, "*goal-env*");
|
||||
define_var_in_env(goal_env, global_environment, "*global-env*");
|
||||
define_var_in_env(global_environment, goal_env, "*goal-env*");
|
||||
|
||||
// set user profile name
|
||||
auto user = SymbolObject::make_new(reader.symbolTable, username);
|
||||
define_var_in_env(global_environment, user, "*user*");
|
||||
define_var_in_env(goal_env, user, "*user*");
|
||||
|
||||
// setup maps
|
||||
special_forms = {
|
||||
|
@ -47,6 +53,7 @@ Interpreter::Interpreter() {
|
|||
{"print", &Interpreter::eval_print},
|
||||
{"inspect", &Interpreter::eval_inspect},
|
||||
{"load-file", &Interpreter::eval_load_file},
|
||||
{"try-load-file", &Interpreter::eval_try_load_file},
|
||||
{"eq?", &Interpreter::eval_equals},
|
||||
{"gensym", &Interpreter::eval_gensym},
|
||||
{"eval", &Interpreter::eval_eval},
|
||||
|
@ -1030,6 +1037,35 @@ Object Interpreter::eval_load_file(const Object& form,
|
|||
return Object::make_empty_list();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Combines read-file and eval to load in a file. Return #f if it doesn't exist.
|
||||
*/
|
||||
Object Interpreter::eval_try_load_file(const Object& form,
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>& env) {
|
||||
(void)env;
|
||||
vararg_check(form, args, {ObjectType::STRING}, {});
|
||||
|
||||
auto path = {args.unnamed.at(0).as_string()->data};
|
||||
if (!std::filesystem::exists(file_util::get_file_path(path))) {
|
||||
return SymbolObject::make_new(reader.symbolTable, "#f");
|
||||
}
|
||||
|
||||
Object o;
|
||||
try {
|
||||
o = reader.read_from_file(path);
|
||||
} catch (std::runtime_error& e) {
|
||||
throw_eval_error(form, std::string("reader error inside of try-load-file:\n") + e.what());
|
||||
}
|
||||
|
||||
try {
|
||||
return eval_with_rewind(o, global_environment.as_env_ptr());
|
||||
} catch (std::runtime_error& e) {
|
||||
throw_eval_error(form, std::string("eval error inside of try-load-file:\n") + e.what());
|
||||
}
|
||||
return SymbolObject::make_new(reader.symbolTable, "#t");
|
||||
}
|
||||
|
||||
/*!
|
||||
* Print the form to stdout, including a newline.
|
||||
* Returns ()
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
namespace goos {
|
||||
class Interpreter {
|
||||
public:
|
||||
Interpreter();
|
||||
Interpreter(const std::string& user_profile = "#f");
|
||||
~Interpreter();
|
||||
void execute_repl(ReplWrapper& repl);
|
||||
void throw_eval_error(const Object& o, const std::string& err);
|
||||
|
@ -128,6 +128,9 @@ class Interpreter {
|
|||
Object eval_load_file(const Object& form,
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>& env);
|
||||
Object eval_try_load_file(const Object& form,
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>& env);
|
||||
Object eval_print(const Object& form,
|
||||
Arguments& args,
|
||||
const std::shared_ptr<EnvironmentObject>& env);
|
||||
|
|
|
@ -64,6 +64,7 @@ void TextStream::seek_past_whitespace_and_comments() {
|
|||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
// just a whitespace, eat it!
|
||||
read();
|
||||
break;
|
||||
|
|
|
@ -1455,7 +1455,7 @@
|
|||
(let ((startup-level (case *kernel-boot-message*
|
||||
(('play)
|
||||
(if *debug-segment*
|
||||
'village1
|
||||
(#if (user? dass) 'finalboss 'village1)
|
||||
'title
|
||||
)
|
||||
)
|
||||
|
|
|
@ -109,6 +109,10 @@
|
|||
`(#cond ((not ,clause) ,@body))
|
||||
)
|
||||
|
||||
(defmacro #if (clause true false)
|
||||
`(#cond (,clause ,true) (#t ,false))
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; TARGET CONTROL
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -288,7 +288,6 @@
|
|||
`(seval (desfun ,name ,args ,@body))
|
||||
)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;
|
||||
;; enum stuff
|
||||
;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -341,3 +340,26 @@
|
|||
|
||||
;; this is checked in a test to see if this file is loaded.
|
||||
(define __goos-lib-loaded__ #t)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; USER PROFILES ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; *user* is defined when goos starts!
|
||||
(when *user*
|
||||
(fmt #t "Loading user scripts for user: {}...\n" *user*)
|
||||
;; i'm not sure what naming scheme to use here. user/<name>/user.gs?
|
||||
;; the GOAL one is loaded in Compiler.cpp
|
||||
(load-file (fmt #f "goal_src/user/{}/user.gs" *user*))
|
||||
)
|
||||
|
||||
(defsmacro user? (&rest users)
|
||||
(cond
|
||||
((null? users) #f)
|
||||
((eq? *user* (car users)) #t)
|
||||
(#t `(user? ,@(cdr users)))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
3
goal_src/user/.gitignore
vendored
Normal file
3
goal_src/user/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!.gitignore
|
||||
!readme.md
|
14
goal_src/user/readme.md
Normal file
14
goal_src/user/readme.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
This directory holds the user profiles.
|
||||
|
||||
To make your own profile, create a new directory here with your username.
|
||||
e.g. for username `mark` make a directory called `mark`
|
||||
Inside that directory, create `user.gs` and `user.gc` files.
|
||||
These are your own user scripts, loaded after the GOOS library and GOAL library respectively.
|
||||
|
||||
The rest of the directory can be used however you please!
|
||||
|
||||
To automatically log in as a specific user, create a `user.txt` file in this directory
|
||||
which contains just the username you want to log in as. That way you don't have to
|
||||
modify multiple scripts when you want to change users.
|
||||
|
||||
If you want to make your profile public, edit the .gitignore in this directory.
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
using namespace goos;
|
||||
|
||||
Compiler::Compiler(std::unique_ptr<ReplWrapper> repl)
|
||||
: m_debugger(&m_listener, &m_goos.reader), m_repl(std::move(repl)) {
|
||||
Compiler::Compiler(const std::string& user_profile, std::unique_ptr<ReplWrapper> repl)
|
||||
: m_goos(user_profile), m_debugger(&m_listener, &m_goos.reader), m_repl(std::move(repl)) {
|
||||
m_listener.add_debugger(&m_debugger);
|
||||
m_ts.add_builtin_types();
|
||||
m_global_env = std::make_unique<GlobalEnv>();
|
||||
|
@ -25,6 +25,11 @@ Compiler::Compiler(std::unique_ptr<ReplWrapper> repl)
|
|||
Object library_code = m_goos.reader.read_from_file({"goal_src", "goal-lib.gc"});
|
||||
compile_object_file("goal-lib", library_code, false);
|
||||
|
||||
if (user_profile != "#f") {
|
||||
Object user_code = m_goos.reader.read_from_file({"goal_src", "user", user_profile, "user.gc"});
|
||||
compile_object_file(user_profile, user_code, false);
|
||||
}
|
||||
|
||||
// add built-in forms to symbol info
|
||||
for (auto& builtin : g_goal_forms) {
|
||||
m_symbol_info.add_builtin(builtin.first);
|
||||
|
|
|
@ -25,7 +25,7 @@ enum class ReplStatus { OK, WANT_EXIT, WANT_RELOAD };
|
|||
|
||||
class Compiler {
|
||||
public:
|
||||
Compiler(std::unique_ptr<ReplWrapper> repl = nullptr);
|
||||
Compiler(const std::string& user_profile = "#f", std::unique_ptr<ReplWrapper> repl = nullptr);
|
||||
ReplStatus execute_repl(bool auto_listen = false, bool auto_debug = false);
|
||||
goos::Interpreter& get_goos() { return m_goos; }
|
||||
FileEnv* compile_object_file(const std::string& name, goos::Object code, bool allow_emit);
|
||||
|
|
|
@ -28,21 +28,44 @@ int main(int argc, char** argv) {
|
|||
(void)argv;
|
||||
|
||||
std::string argument;
|
||||
std::string username = "#f";
|
||||
bool verbose = false;
|
||||
bool auto_listen = false;
|
||||
bool auto_debug = false;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (std::string("-v") == argv[i]) {
|
||||
verbose = true;
|
||||
}
|
||||
if (std::string("-cmd") == argv[i] && i < argc - 1) {
|
||||
} else if (std::string("-cmd") == argv[i] && i + 1 < argc) {
|
||||
argument = argv[++i];
|
||||
}
|
||||
if (std::string("-auto-lt") == argv[i]) {
|
||||
} else if (std::string("-auto-lt") == argv[i]) {
|
||||
auto_listen = true;
|
||||
}
|
||||
if (std::string("-auto-dbg") == argv[i]) {
|
||||
} else if (std::string("-auto-dbg") == argv[i]) {
|
||||
auto_debug = true;
|
||||
} else if (std::string("-user") == argv[i] && i + 1 < argc) {
|
||||
username = argv[++i];
|
||||
} else if (std::string("-user-auto") == argv[i]) {
|
||||
try {
|
||||
auto text = std::make_shared<goos::FileText>(
|
||||
file_util::get_file_path({"goal_src", "user", "user.txt"}), "goal_src/user/user.txt");
|
||||
goos::TextStream ts(text);
|
||||
ts.seek_past_whitespace_and_comments();
|
||||
username.clear();
|
||||
while (ts.text_remains()) {
|
||||
char c = ts.read();
|
||||
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
||||
c == '-' || c == '.' || c == '!' || c == '?' || c == '<' || c == '>') {
|
||||
username.push_back(c);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (username.empty()) {
|
||||
username = "#f";
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
printf("error opening user desc file: %s\n", e.what());
|
||||
username = "#f";
|
||||
}
|
||||
}
|
||||
}
|
||||
setup_logging(verbose);
|
||||
|
@ -56,7 +79,7 @@ int main(int argc, char** argv) {
|
|||
if (argument.empty()) {
|
||||
ReplStatus status = ReplStatus::WANT_RELOAD;
|
||||
while (status == ReplStatus::WANT_RELOAD) {
|
||||
compiler = std::make_unique<Compiler>(std::make_unique<ReplWrapper>());
|
||||
compiler = std::make_unique<Compiler>(username, std::make_unique<ReplWrapper>());
|
||||
status = compiler->execute_repl(auto_listen, auto_debug);
|
||||
if (status == ReplStatus::WANT_RELOAD) {
|
||||
fmt::print("Reloading compiler...\n");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@echo off
|
||||
cd ..\..
|
||||
out\build\Release\bin\goalc -v
|
||||
out\build\Release\bin\goalc -v -user-auto
|
||||
pause
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@echo off
|
||||
cd ..\..
|
||||
out\build\Release\bin\goalc -v -auto-dbg
|
||||
out\build\Release\bin\goalc -v -auto-dbg -user-auto
|
||||
pause
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
cd ..\..
|
||||
git update-index --assume-unchanged decompiler\config\jak1_ntsc_black_label.jsonc decompiler\config\jak1_ntsc_black_label\inputs.jsonc
|
||||
git update-index --assume-unchanged decompiler\config\jak1_ntsc_black_label.jsonc decompiler\config\jak1_ntsc_black_label\inputs.jsonc goal_src\user\user.txt
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
cd ..\..
|
||||
git update-index --no-assume-unchanged decompiler\config\jak1_ntsc_black_label.jsonc decompiler\config\jak1_ntsc_black_label\inputs.jsonc
|
||||
git update-index --no-assume-unchanged decompiler\config\jak1_ntsc_black_label.jsonc decompiler\config\jak1_ntsc_black_label\inputs.jsonc goal_src\user\user.txt
|
||||
|
|
Loading…
Reference in a new issue