X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/7ba62cfde8941d0c5ff27a789c8b81796c0847bb..8fdedb7558e72275f70444b0f5941c3443d15c31:/Application.mm diff --git a/Application.mm b/Application.mm index a5be46b..31b7a45 100644 --- a/Application.mm +++ b/Application.mm @@ -1,50 +1,220 @@ -#include -#include +#define _GNU_SOURCE -#include -#include +#include +#include "cycript.hpp" -#include +#include +#include -#include -#include -#include -#include -#include -#include +#include -#define _trace() do { \ - CFLog(kCFLogLevelNotice, CFSTR("_trace(%u)"), __LINE__); \ -} while (false) +#include +#include -JSContextRef JSGetContext(void); -CFStringRef JSValueToJSONCopy(JSContextRef ctx, JSValueRef value); +#include -int main() { - for (;;) { - NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); +#include +#include - std::cout << ">>> " << std::flush; +#include +#include +#include - std::string line; - if (!std::getline(std::cin, line)) +#include "Cycript.tab.hh" + +static jmp_buf ctrlc_; + +void sigint(int) { + longjmp(ctrlc_, 1); +} + +void Run(const char *code, FILE *fout) { _pooled + JSStringRef script(JSStringCreateWithUTF8CString(code)); + + JSContextRef context(CYGetJSContext()); + + JSValueRef exception(NULL); + JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception)); + JSStringRelease(script); + + if (exception != NULL) { error: + result = exception; + exception = NULL; + } + + if (!JSValueIsUndefined(context, result)) { + CYPool pool; + const char *json; + + json = CYPoolJSONString(pool, context, result, &exception); + if (exception != NULL) + goto error; + + if (fout != NULL) { + fputs(json, fout); + fputs("\n", fout); + fflush(fout); + } + } +} + +void Console() { + bool bypass(false); + bool debug(false); + + FILE *fout(stdout); + + rl_bind_key('\t', rl_insert); + + struct sigaction action; + sigemptyset(&action.sa_mask); + action.sa_handler = &sigint; + action.sa_flags = 0; + sigaction(SIGINT, &action, NULL); + + restart: for (;;) { + std::string command; + std::vector lines; + + bool extra(false); + const char *prompt("cy# "); + + if (setjmp(ctrlc_) != 0) { + fputs("\n", fout); + fflush(fout); + goto restart; + } + + read: + char *line(readline(prompt)); + if (line == NULL) break; - JSStringRef script(JSStringCreateWithUTF8CString(line.c_str())); + if (!extra) { + extra = true; + if (line[0] == '\\') { + std::string data(line + 1); + if (data == "bypass") { + bypass = !bypass; + fprintf(fout, "bypass == %s\n", bypass ? "true" : "false"); + fflush(fout); + } else if (data == "debug") { + debug = !debug; + fprintf(fout, "debug == %s\n", debug ? "true" : "false"); + fflush(fout); + } + add_history(line); + goto restart; + } + } + + lines.push_back(line); + command += line; + free(line); + + std::string code; - JSValueRef exception; - JSValueRef result(JSEvaluateScript(JSGetContext(), script, NULL, NULL, 0, &exception)); - if (result == NULL) - result = exception; - JSStringRelease(script); + if (bypass) + code = command; + else { + CYDriver driver(""); + cy::parser parser(driver); - if (!JSValueIsUndefined(JSGetContext(), result)) { - CFStringRef json(JSValueToJSONCopy(JSGetContext(), result)); - std::cout << [reinterpret_cast(json) UTF8String] << std::endl; - CFRelease(json); + driver.data_ = command.c_str(); + driver.size_ = command.size(); + + if (parser.parse() != 0 || !driver.errors_.empty()) { + for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) { + cy::position begin(i->location_.begin); + if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) { + std::cerr << i->message_ << std::endl; + add_history(command.c_str()); + goto restart; + } + } + + driver.errors_.clear(); + + command += '\n'; + prompt = "cy> "; + goto read; + } + + if (driver.source_ == NULL) + goto restart; + + std::ostringstream str; + driver.source_->Show(str); + code = str.str(); + } + + add_history(command.c_str()); + + if (debug) + std::cout << code << std::endl; + + Run(code.c_str(), fout); + } + + fputs("\n", fout); + fflush(fout); +} + +void *Map(const char *path, size_t *psize) { + int fd; + _syscall(fd = open(path, O_RDONLY)); + + struct stat stat; + _syscall(fstat(fd, &stat)); + size_t size(stat.st_size); + + *psize = size; + + void *base; + _syscall(base = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0)); + + _syscall(close(fd)); + return base; +} + +int main(int argc, const char *argv[]) { + const char *script; + + if (argc == 1) + script = NULL; + else { + CYSetArgs(argc - 1, argv + 1); + script = argv[1]; + } + + if (script == NULL || strcmp(script, "-") == 0) + Console(); + else { + CYDriver driver(script); + cy::parser parser(driver); + + size_t size; + char *start(reinterpret_cast(Map(script, &size))); + char *end(start + size); + + if (size >= 2 && start[0] == '#' && start[1] == '!') { + start += 2; + while (start != end && *start++ != '\n'); } - [pool release]; + driver.data_ = start; + driver.size_ = end - start; + + if (parser.parse() != 0 || !driver.errors_.empty()) { + for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) + std::cerr << i->location_.begin << ": " << i->message_ << std::endl; + } else if (driver.source_ != NULL) { + std::ostringstream str; + driver.source_->Show(str); + std::string code(str.str()); + std::cout << code << std::endl; + Run(code.c_str(), stdout); + } } return 0;