X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/2c1d569a0ed9ddd14d3d1d73ee8be776e0889d35..2c4a8bb6222b88ff96fbf25372179646ce15f706:/Complete.cpp diff --git a/Complete.cpp b/Complete.cpp index 75b80c0..47acf10 100644 --- a/Complete.cpp +++ b/Complete.cpp @@ -1,5 +1,5 @@ -/* Cycript - Optimizing JavaScript Compiler/Runtime - * Copyright (C) 2009-2015 Jay Freeman (saurik) +/* Cycript - The Truly Universal Scripting Language + * Copyright (C) 2009-2016 Jay Freeman (saurik) */ /* GNU Affero General Public License, Version 3 {{{ */ @@ -19,30 +19,29 @@ **/ /* }}} */ +#include + #include "cycript.hpp" #include "Driver.hpp" -#include "Cycript.tab.hh" #include "Replace.hpp" #include "String.hpp" static CYExpression *ParseExpression(CYPool &pool, CYUTF8String code) { std::stringstream stream; stream << '(' << code << ')'; - CYDriver driver(pool, stream); - - cy::parser parser(driver); - if (parser.parse() != 0 || !driver.errors_.empty()) + CYDriver driver(pool, *stream.rdbuf()); + if (driver.Parse() || !driver.errors_.empty()) return NULL; CYOptions options; CYContext context(options); - CYStatement *statement(driver.program_->code_); + CYStatement *statement(driver.script_->code_); _assert(statement != NULL); _assert(statement->next_ == NULL); - CYExpress *express(dynamic_cast(driver.program_->code_)); + CYExpress *express(dynamic_cast(driver.script_->code_)); _assert(express != NULL); CYParenthetical *parenthetical(dynamic_cast(express->expression_)); @@ -54,13 +53,12 @@ static CYExpression *ParseExpression(CYPool &pool, CYUTF8String code) { _visible char **CYComplete(const char *word, const std::string &line, CYUTF8String (*run)(CYPool &pool, const std::string &)) { CYLocalPool pool; - std::istringstream stream(line); + std::stringbuf stream(line); CYDriver driver(pool, stream); driver.auto_ = true; - cy::parser parser(driver); - if (parser.parse() != 0 || !driver.errors_.empty()) + if (driver.Parse() || !driver.errors_.empty()) return NULL; if (driver.mode_ == CYDriver::AutoNone) @@ -88,35 +86,68 @@ _visible char **CYComplete(const char *word, const std::string &line, CYUTF8Stri case CYDriver::AutoMessage: { CYDriver::Context &thing(driver.contexts_.back()); - expression = $M($C1($V("object_getClass"), thing.context_), $S("messages")); + expression = $M($C1($V("object_getClass"), thing.context_), $S("prototype")); for (CYDriver::Context::Words::const_iterator part(thing.words_.begin()); part != thing.words_.end(); ++part) prefix << (*part)->word_ << ':'; } break; + case CYDriver::AutoResolve: + expression = $M(driver.context_, $S("$cyr")); + break; + + case CYDriver::AutoStruct: + expression = $ CYThis(); + prefix << "$cys"; + break; + + case CYDriver::AutoEnum: + expression = $ CYThis(); + prefix << "$cye"; + break; + default: _assert(false); } std::string begin(prefix.str()); - driver.program_ = $ CYProgram($ CYExpress($C3(ParseExpression(pool, - " function(object, prefix, word) {\n" + CYBoolean *message; + if (driver.mode_ == CYDriver::AutoMessage) + message = $ CYTrue(); + else + message = $ CYFalse(); + + driver.script_ = $ CYScript($ CYExpress($C4(ParseExpression(pool, + " function(object, prefix, word, message) {\n" " var names = [];\n" " var before = prefix.length;\n" " prefix += word;\n" " var entire = prefix.length;\n" - " for (var name in object)\n" - " if (name.substring(0, entire) == prefix)\n" - " names.push(name.substr(before));\n" + " if (false) {\n" + " for (var name in object)\n" + " if (name.substring(0, entire) == prefix)\n" + " names.push(name);\n" + " } else do {\n" + " if (object.hasOwnProperty(\"cy$complete\"))\n" + " names = names.concat(object.cy$complete(prefix, message));\n" + " try {\n" + " var local = Object.getOwnPropertyNames(object);\n" + " } catch (e) {\n" + " continue;\n" + " }\n" + " for (var name of local)\n" + " if (name.substring(0, entire) == prefix)\n" + " names.push(name);\n" + " } while (object = typeof object === 'object' ? Object.getPrototypeOf(object) : object.__proto__);\n" " return names;\n" " }\n" - ), expression, $S(begin.c_str()), $S(word)))); + ), expression, $S(begin.c_str()), $S(word), message))); - driver.program_->Replace(context); + driver.script_->Replace(context); std::stringbuf str; CYOutput out(str, options); - out << *driver.program_; + out << *driver.script_; std::string code(str.str()); CYUTF8String json(run(pool, code)); @@ -131,37 +162,45 @@ _visible char **CYComplete(const char *word, const std::string &line, CYUTF8Stri return NULL; // XXX: use an std::set? - typedef std::vector Completions; + typedef std::vector Completions; Completions completions; std::string common; bool rest(false); - CYForEach (element, array->elements_) { - CYString *string(dynamic_cast(element->value_)); - _assert(string != NULL); + for (CYElement *element(array->elements_); element != NULL; ) { + CYElementValue *value(dynamic_cast(element)); + _assert(value != NULL); + element = value->next_; - std::string completion; - if (string->size_ != 0) - completion.assign(string->value_, string->size_); - else if (driver.mode_ == CYDriver::AutoMessage) + _assert(value->value_ != NULL); + CYString *string(value->value_->String(context)); + if (string == NULL) + CYThrow("string was actually %s", typeid(*value->value_).name()); + + CYUTF8String completion(string->value_, string->size_); + _assert(completion.size >= begin.size()); + completion.data += begin.size(); + completion.size -= begin.size(); + + if (completion.size == 0 && driver.mode_ == CYDriver::AutoMessage) completion = "]"; - else - continue; + if (CYStartsWith(completion, "$cy")) + continue; completions.push_back(completion); if (!rest) { common = completion; rest = true; } else { - size_t limit(completion.size()), size(common.size()); + size_t limit(completion.size), size(common.size()); if (size > limit) common = common.substr(0, limit); else limit = size; for (limit = 0; limit != size; ++limit) - if (common[limit] != completion[limit]) + if (common[limit] != completion.data[limit]) break; if (limit != size) common = common.substr(0, limit); @@ -183,7 +222,7 @@ _visible char **CYComplete(const char *word, const std::string &line, CYUTF8Stri results[0] = strdup(common.c_str()); size_t index(0); for (Completions::const_iterator i(completions.begin()); i != completions.end(); ++i) - results[++index] = strdup(i->c_str()); + results[++index] = strdup(i->data); results[count + 1] = NULL; return results;